From 11db0f0dbf73ab933d43352183430f64c4d1d70e Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 16:31:36 -0400 Subject: [PATCH 01/52] qt_common init Signed-off-by: crueter --- ffmpeg.patch | 40 ++++++++++++++++ src/CMakeLists.txt | 1 + src/qt_common/CMakeLists.txt | 23 +++++++++ src/{yuzu => qt_common}/qt_common.cpp | 25 ++++++++-- src/qt_common/qt_common.h | 47 +++++++++++++++++++ .../configuration => qt_common}/qt_config.cpp | 0 .../configuration => qt_common}/qt_config.h | 0 .../shared_translation.cpp | 10 ++-- .../shared_translation.h | 9 ++-- src/{yuzu => qt_common}/uisettings.cpp | 2 +- src/{yuzu => qt_common}/uisettings.h | 2 +- src/yuzu/CMakeLists.txt | 13 ++--- src/yuzu/bootmanager.cpp | 9 ++-- src/yuzu/configuration/configure_audio.cpp | 4 +- src/yuzu/configuration/configure_cpu.h | 2 +- src/yuzu/configuration/configure_debug.cpp | 2 +- src/yuzu/configuration/configure_dialog.cpp | 2 +- src/yuzu/configuration/configure_dialog.h | 2 +- .../configuration/configure_filesystem.cpp | 28 +++++------ src/yuzu/configuration/configure_general.cpp | 2 +- src/yuzu/configuration/configure_graphics.cpp | 4 +- src/yuzu/configuration/configure_graphics.h | 2 +- .../configure_graphics_advanced.cpp | 2 +- .../configure_graphics_extensions.cpp | 2 +- src/yuzu/configuration/configure_hotkeys.cpp | 2 +- .../configuration/configure_input_per_game.h | 2 +- .../configuration/configure_input_player.cpp | 2 +- src/yuzu/configuration/configure_per_game.cpp | 2 +- src/yuzu/configuration/configure_per_game.h | 4 +- .../configure_per_game_addons.cpp | 2 +- src/yuzu/configuration/configure_ringcon.cpp | 2 +- src/yuzu/configuration/configure_tas.cpp | 2 +- src/yuzu/configuration/configure_ui.cpp | 2 +- src/yuzu/configuration/configure_web.cpp | 2 +- src/yuzu/configuration/input_profiles.h | 2 +- src/yuzu/configuration/shared_widget.cpp | 2 +- src/yuzu/configuration/shared_widget.h | 2 +- src/yuzu/debugger/console.cpp | 2 +- src/yuzu/debugger/wait_tree.cpp | 2 +- src/yuzu/game_list.cpp | 15 ++---- src/yuzu/game_list.h | 5 +- src/yuzu/game_list_p.h | 2 +- src/yuzu/game_list_worker.cpp | 30 ++++-------- src/yuzu/game_list_worker.h | 7 +-- src/yuzu/hotkeys.cpp | 2 +- src/yuzu/install_dialog.cpp | 2 +- src/yuzu/main.cpp | 27 ++++++----- src/yuzu/main.h | 2 +- src/yuzu/multiplayer/direct_connect.cpp | 2 +- src/yuzu/multiplayer/host_room.cpp | 2 +- src/yuzu/multiplayer/lobby.cpp | 2 +- src/yuzu/multiplayer/state.cpp | 2 +- src/yuzu/play_time_manager.cpp | 1 - src/yuzu/play_time_manager.h | 3 +- src/yuzu/qt_common.h | 15 ------ src/yuzu/vk_device_info.cpp | 2 +- 56 files changed, 233 insertions(+), 153 deletions(-) create mode 100644 ffmpeg.patch create mode 100644 src/qt_common/CMakeLists.txt rename src/{yuzu => qt_common}/qt_common.cpp (80%) create mode 100644 src/qt_common/qt_common.h rename src/{yuzu/configuration => qt_common}/qt_config.cpp (100%) rename src/{yuzu/configuration => qt_common}/qt_config.h (100%) rename src/{yuzu/configuration => qt_common}/shared_translation.cpp (99%) rename src/{yuzu/configuration => qt_common}/shared_translation.h (94%) rename src/{yuzu => qt_common}/uisettings.cpp (99%) rename src/{yuzu => qt_common}/uisettings.h (99%) delete mode 100644 src/yuzu/qt_common.h diff --git a/ffmpeg.patch b/ffmpeg.patch new file mode 100644 index 0000000000..58fa9dff61 --- /dev/null +++ b/ffmpeg.patch @@ -0,0 +1,40 @@ +diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt +index 54c852f831..ff35c8dc2c 100644 +--- a/externals/ffmpeg/CMakeLists.txt ++++ b/externals/ffmpeg/CMakeLists.txt +@@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID) + set(FFmpeg_HWACCEL_INCLUDE_DIRS) + set(FFmpeg_HWACCEL_LDFLAGS) + +- # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so +- if(PLATFORM_SUN) +- list(APPEND FFmpeg_HWACCEL_LIBRARIES +- X11 +- "/usr/lib/xorg/amd64/libdrm.so") +- else() +- pkg_check_modules(LIBDRM libdrm REQUIRED) +- list(APPEND FFmpeg_HWACCEL_LIBRARIES +- ${LIBDRM_LIBRARIES}) +- list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS +- ${LIBDRM_INCLUDE_DIRS}) ++ if (NOT APPLE) ++ # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so ++ if(PLATFORM_SUN) ++ list(APPEND FFmpeg_HWACCEL_LIBRARIES ++ X11 ++ "/usr/lib/xorg/amd64/libdrm.so") ++ else() ++ pkg_check_modules(LIBDRM libdrm REQUIRED) ++ list(APPEND FFmpeg_HWACCEL_LIBRARIES ++ ${LIBDRM_LIBRARIES}) ++ list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ++ ${LIBDRM_INCLUDE_DIRS}) ++ endif() ++ list(APPEND FFmpeg_HWACCEL_FLAGS ++ --enable-libdrm) + endif() +- list(APPEND FFmpeg_HWACCEL_FLAGS +- --enable-libdrm) + + if(LIBVA_FOUND) + find_package(X11 REQUIRED) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb66e55964..0032b20029 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ if (YUZU_ROOM_STANDALONE) endif() if (ENABLE_QT) + add_subdirectory(qt_common) add_subdirectory(yuzu) endif() diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt new file mode 100644 index 0000000000..be1a8ebbd0 --- /dev/null +++ b/src/qt_common/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2023 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +add_library(qt_common STATIC + qt_common.h + qt_common.cpp + + uisettings.cpp + uisettings.h + + qt_config.cpp + qt_config.h + + shared_translation.cpp + shared_translation.h +) + +create_target_directory_groups(qt_common) +target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni) + +if (NOT WIN32) + target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) +endif() diff --git a/src/yuzu/qt_common.cpp b/src/qt_common/qt_common.cpp similarity index 80% rename from src/yuzu/qt_common.cpp rename to src/qt_common/qt_common.cpp index 413402165c..29379c1d54 100644 --- a/src/yuzu/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,12 +1,13 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +#include "qt_common.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "uisettings.h" #include #include #include #include "common/logging/log.h" #include "core/frontend/emu_window.h" -#include "yuzu/qt_common.h" #if !defined(WIN32) && !defined(__APPLE__) #include @@ -15,6 +16,21 @@ #endif namespace QtCommon { + +MetadataResult ResetMetadata() +{ + if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) + / "game_list/")) { + return Empty; + } else if (Common::FS::RemoveDirRecursively( + Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { + return Success; + UISettings::values.is_game_list_reload_pending.exchange(true); + } else { + return Failure; + } +} + Core::Frontend::WindowSystemType GetWindowSystemType() { // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); @@ -57,4 +73,5 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -} // namespace QtCommon + +} diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h new file mode 100644 index 0000000000..3c7dddfc1f --- /dev/null +++ b/src/qt_common/qt_common.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef QT_COMMON_H +#define QT_COMMON_H + +#include + +#include +#include + +namespace QtCommon { + +static constexpr std::array METADATA_RESULTS = { + "The operation completed successfully.", + "The metadata cache couldn't be deleted. It might be in use or non-existent.", + "The metadata cache is already empty.", +}; + +enum MetadataResult { + Success, + Failure, + Empty, +}; +/** + * @brief ResetMetadata Reset game list metadata. + * @return A result code. + */ +MetadataResult ResetMetadata(); + +/** + * \brief Get a string representation of a result from ResetMetadata. + * \param result The result code. + * \return A string representation of the passed result code. + */ +inline constexpr const char *GetResetMetadataResultString(MetadataResult result) +{ + return METADATA_RESULTS.at(static_cast(result)); +} + +Core::Frontend::WindowSystemType GetWindowSystemType(); + +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); + + +} // namespace QtCommon +#endif diff --git a/src/yuzu/configuration/qt_config.cpp b/src/qt_common/qt_config.cpp similarity index 100% rename from src/yuzu/configuration/qt_config.cpp rename to src/qt_common/qt_config.cpp diff --git a/src/yuzu/configuration/qt_config.h b/src/qt_common/qt_config.h similarity index 100% rename from src/yuzu/configuration/qt_config.h rename to src/qt_common/qt_config.h diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/qt_common/shared_translation.cpp similarity index 99% rename from src/yuzu/configuration/shared_translation.cpp rename to src/qt_common/shared_translation.cpp index 1137145659..018af56c67 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -7,23 +7,21 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "yuzu/configuration/shared_translation.h" +#include "shared_translation.h" #include -#include #include "common/settings.h" #include "common/settings_enums.h" #include "common/settings_setting.h" #include "common/time_zone.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include #include -#include #include namespace ConfigurationShared { -std::unique_ptr InitializeTranslations(QWidget* parent) +std::unique_ptr InitializeTranslations(QObject* parent) { std::unique_ptr translations = std::make_unique(); const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; @@ -473,7 +471,7 @@ std::unique_ptr InitializeTranslations(QWidget* parent) return translations; } -std::unique_ptr ComboboxEnumeration(QWidget* parent) +std::unique_ptr ComboboxEnumeration(QObject* parent) { std::unique_ptr translations = std::make_unique(); const auto& tr = [&](const char* text, const char* context = "") { diff --git a/src/yuzu/configuration/shared_translation.h b/src/qt_common/shared_translation.h similarity index 94% rename from src/yuzu/configuration/shared_translation.h rename to src/qt_common/shared_translation.h index 574b1e2c78..48a2cb5205 100644 --- a/src/yuzu/configuration/shared_translation.h +++ b/src/qt_common/shared_translation.h @@ -11,23 +11,20 @@ #include #include -#include #include #include #include #include "common/common_types.h" -#include "common/settings.h" - -class QWidget; +#include "common/settings_enums.h" namespace ConfigurationShared { using TranslationMap = std::map>; using ComboboxTranslations = std::vector>; using ComboboxTranslationMap = std::map; -std::unique_ptr InitializeTranslations(QWidget* parent); +std::unique_ptr InitializeTranslations(QObject *parent); -std::unique_ptr ComboboxEnumeration(QWidget* parent); +std::unique_ptr ComboboxEnumeration(QObject* parent); static const std::map anti_aliasing_texts_map = { {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, diff --git a/src/yuzu/uisettings.cpp b/src/qt_common/uisettings.cpp similarity index 99% rename from src/yuzu/uisettings.cpp rename to src/qt_common/uisettings.cpp index 6da5424775..a17f3c0a4a 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/qt_common/uisettings.cpp @@ -7,7 +7,7 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifndef CANNOT_EXPLICITLY_INSTANTIATE namespace Settings { diff --git a/src/yuzu/uisettings.h b/src/qt_common/uisettings.h similarity index 99% rename from src/yuzu/uisettings.h rename to src/qt_common/uisettings.h index 3322b31ca3..4981d98dbf 100644 --- a/src/yuzu/uisettings.h +++ b/src/qt_common/uisettings.h @@ -17,7 +17,7 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/settings_enums.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" using Settings::Category; using Settings::ConfirmStop; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index d663f6c282..9e052b385d 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -150,12 +150,8 @@ add_executable(yuzu configuration/configure_web.ui configuration/input_profiles.cpp configuration/input_profiles.h - configuration/shared_translation.cpp - configuration/shared_translation.h configuration/shared_widget.cpp configuration/shared_widget.h - configuration/qt_config.cpp - configuration/qt_config.h debugger/console.cpp debugger/console.h debugger/controller.cpp @@ -205,12 +201,8 @@ add_executable(yuzu play_time_manager.cpp play_time_manager.h precompiled_headers.h - qt_common.cpp - qt_common.h startup_checks.cpp startup_checks.h - uisettings.cpp - uisettings.h util/clickable_label.cpp util/clickable_label.h util/controller_navigation.cpp @@ -396,14 +388,17 @@ elseif(WIN32) endif() endif() -target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core) target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json) +target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common) target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) if (NOT WIN32) target_include_directories(yuzu PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) endif() + +target_link_libraries(yuzu PRIVATE Vulkan::Headers) + if (UNIX AND NOT APPLE) target_link_libraries(yuzu PRIVATE Qt6::DBus) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 63e7a74003..7b5f2a314f 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -12,7 +12,7 @@ #include #include "common/settings_enums.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA #include #include @@ -58,7 +58,7 @@ #include "video_core/renderer_base.h" #include "yuzu/bootmanager.h" #include "yuzu/main.h" -#include "yuzu/qt_common.h" +#include "qt_common/qt_common.h" class QObject; class QPaintEngine; @@ -234,7 +234,7 @@ class DummyContext : public Core::Frontend::GraphicsContext {}; class RenderWidget : public QWidget { public: - explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { + explicit RenderWidget(GRenderWindow* parent) : QWidget(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); if (QtCommon::GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { @@ -247,9 +247,6 @@ public: QPaintEngine* paintEngine() const override { return nullptr; } - -private: - GRenderWindow* render_window; }; struct OpenGLRenderWidget : public RenderWidget { diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index c235b0fca4..8d11920d31 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -16,9 +16,9 @@ #include "ui_configure_audio.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_audio.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureAudio::ConfigureAudio(const Core::System& system_, std::shared_ptr> group_, diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 098e0e397b..16cf74af33 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -7,7 +7,7 @@ #include #include #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" class QComboBox; diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 733c419c4b..18f629f639 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -15,7 +15,7 @@ #include "ui_configure_debug.h" #include "yuzu/configuration/configure_debug.h" #include "yuzu/debugger/console.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent) : QScrollArea(parent), ui{std::make_unique()}, system{system_} { diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 987b1462db..4e128106e7 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -27,7 +27,7 @@ #include "yuzu/configuration/configure_ui.h" #include "yuzu/configuration/configure_web.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, InputCommon::InputSubsystem* input_subsystem, diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 0b6b285678..bf96035752 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -8,7 +8,7 @@ #include #include "configuration/shared_widget.h" #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/vk_device_info.h" namespace Core { diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index f25f14708b..392155d2a3 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -1,14 +1,15 @@ // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "yuzu/configuration/configure_filesystem.h" #include #include #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/settings.h" +#include "qt_common/qt_common.h" +#include "qt_common/uisettings.h" #include "ui_configure_filesystem.h" -#include "yuzu/configuration/configure_filesystem.h" -#include "yuzu/uisettings.h" ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { @@ -126,19 +127,16 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) } void ConfigureFilesystem::ResetMetadata() { - if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / - "game_list/")) { - QMessageBox::information(this, tr("Reset Metadata Cache"), - tr("The metadata cache is already empty.")); - } else if (Common::FS::RemoveDirRecursively( - Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - QMessageBox::information(this, tr("Reset Metadata Cache"), - tr("The operation completed successfully.")); - UISettings::values.is_game_list_reload_pending.exchange(true); - } else { - QMessageBox::warning( - this, tr("Reset Metadata Cache"), - tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); + auto result = QtCommon::ResetMetadata(); + const QString resultMessage = tr(QtCommon::GetResetMetadataResultString(result)); + const QString title = tr("Reset Metadata Cache"); + + switch (result) { + case QtCommon::Failure: + QMessageBox::warning(this, title, resultMessage); + break; + default: + QMessageBox::information(this, title, resultMessage); } } diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 918fa15d4d..352ae8ab85 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -11,7 +11,7 @@ #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_general.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureGeneral::ConfigureGeneral(const Core::System& system_, std::shared_ptr> group_, diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 16846878f9..e1e68b917a 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -40,8 +40,8 @@ #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/qt_common.h" -#include "yuzu/uisettings.h" +#include "qt_common/qt_common.h" +#include "qt_common/uisettings.h" #include "yuzu/vk_device_info.h" static const std::vector default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR, diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index b92b4496ba..9f7ece5714 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -15,7 +15,7 @@ #include #include "common/common_types.h" #include "common/settings_enums.h" -#include "configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 4db18673d4..921cb83b08 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -9,7 +9,7 @@ #include "ui_configure_graphics_advanced.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics_advanced.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( diff --git a/src/yuzu/configuration/configure_graphics_extensions.cpp b/src/yuzu/configuration/configure_graphics_extensions.cpp index 322fa9ea08..c4c7fbb31f 100644 --- a/src/yuzu/configuration/configure_graphics_extensions.cpp +++ b/src/yuzu/configuration/configure_graphics_extensions.cpp @@ -11,7 +11,7 @@ #include "ui_configure_graphics_extensions.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics_extensions.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" ConfigureGraphicsExtensions::ConfigureGraphicsExtensions( diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 3f68de12d8..53f7401ef4 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -13,7 +13,7 @@ #include "ui_configure_hotkeys.h" #include "yuzu/configuration/configure_hotkeys.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/sequence_dialog/sequence_dialog.h" constexpr int name_column = 0; diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 4420e856cb..1323d101d3 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -9,7 +9,7 @@ #include "ui_configure_input_per_game.h" #include "yuzu/configuration/input_profiles.h" -#include "yuzu/configuration/qt_config.h" +#include "qt_common/qt_config.h" class QComboBox; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index d0dc0ff44c..6afa8320a2 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -14,7 +14,7 @@ #include #include "common/assert.h" #include "common/param_package.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 031a8d4c2d..545c37a2c9 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -38,7 +38,7 @@ #include "yuzu/configuration/configure_per_game.h" #include "yuzu/configuration/configure_per_game_addons.h" #include "yuzu/configuration/configure_system.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/util.h" #include "yuzu/vk_device_info.h" diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index e0f4e5cd67..a756b561a8 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -15,8 +15,8 @@ #include "frontend_common/config.h" #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/qt_config.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/qt_config.h" +#include "qt_common/shared_translation.h" namespace Core { class System; diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 078f2e8288..90c94cb923 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -21,7 +21,7 @@ #include "ui_configure_per_game_addons.h" #include "yuzu/configuration/configure_input.h" #include "yuzu/configuration/configure_per_game_addons.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* parent) : QWidget(parent), ui{std::make_unique()}, system{system_} { diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index f7249be97e..7e7877aaf6 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -8,7 +8,7 @@ #include #include -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "input_common/drivers/keyboard.h" diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 773658bf22..290e825fe6 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -8,7 +8,7 @@ #include "common/settings.h" #include "ui_configure_tas.h" #include "yuzu/configuration/configure_tas.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureTasDialog::ConfigureTasDialog(QWidget* parent) : QDialog(parent), ui(std::make_unique()) { diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 8dafee628b..ac6d6e34aa 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -27,7 +27,7 @@ #include "core/core.h" #include "core/frontend/framebuffer_layout.h" #include "ui_configure_ui.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace { constexpr std::array default_game_icon_sizes{ diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index d62b5b0853..15a0029901 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -17,7 +17,7 @@ #include #include "common/settings.h" #include "ui_configure_web.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureWeb::ConfigureWeb(QWidget* parent) : QWidget(parent) diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 023ec74a63..64dcf0e603 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -6,7 +6,7 @@ #include #include -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" namespace Core { class System; diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index e23d86dc69..02b354b0a5 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -42,7 +42,7 @@ #include "common/logging/log.h" #include "common/settings.h" #include "common/settings_common.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" namespace ConfigurationShared { diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index 5c67d83542..a793347ce5 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -11,7 +11,7 @@ #include #include #include -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" class QCheckBox; class QComboBox; diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp index 1c1342ff18..40b2fddbc9 100644 --- a/src/yuzu/debugger/console.cpp +++ b/src/yuzu/debugger/console.cpp @@ -9,7 +9,7 @@ #include "common/logging/backend.h" #include "yuzu/debugger/console.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace Debugger { void ToggleConsole() { diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 9f9e21bc28..f32f6348a5 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -5,7 +5,7 @@ #include #include "yuzu/debugger/wait_tree.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "core/arm/debug.h" #include "core/core.h" diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 1ecef4af92..0d89dc892e 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -24,7 +24,7 @@ #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" #include "yuzu/main.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/controller_navigation.h" GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) @@ -820,7 +820,7 @@ QStandardItemModel* GameList::GetModel() const { return item_model; } -void GameList::PopulateAsync(QVector& game_dirs, const bool cached) +void GameList::PopulateAsync(QVector& game_dirs) { tree_view->setEnabled(false); @@ -843,8 +843,7 @@ void GameList::PopulateAsync(QVector& game_dirs, const bool game_dirs, compatibility_list, play_time_manager, - system, - cached); + system); // Get events from the worker as data becomes available connect(current_worker.get(), &GameListWorker::DataAvailable, this, &GameList::WorkerEvent, @@ -873,14 +872,6 @@ const QStringList GameList::supported_file_extensions = { QStringLiteral("nso"), QStringLiteral("nro"), QStringLiteral("nca"), QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; -void GameList::ForceRefreshGameDirectory() -{ - if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { - LOG_INFO(Frontend, "Force-reloading game list per user request."); - PopulateAsync(UISettings::values.game_dirs, false); - } -} - void GameList::RefreshGameDirectory() { if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 7c492bc19f..328432138c 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -20,7 +20,7 @@ #include "common/common_types.h" #include "core/core.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -97,7 +97,7 @@ public: bool IsEmpty() const; void LoadCompatibilityList(); - void PopulateAsync(QVector& game_dirs, const bool cached = true); + void PopulateAsync(QVector& game_dirs); void SaveInterfaceLayout(); void LoadInterfaceLayout(); @@ -110,7 +110,6 @@ public: static const QStringList supported_file_extensions; public slots: - void ForceRefreshGameDirectory(); void RefreshGameDirectory(); signals: diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index c330b574f9..b3e05b8b34 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -19,7 +19,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "yuzu/play_time_manager.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/util.h" enum class GameListItemType { diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 60109769bf..267faa7182 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -27,7 +27,7 @@ #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace { @@ -199,8 +199,7 @@ QList MakeGameListEntry(const std::string& path, u64 program_id, const CompatibilityList& compatibility_list, const PlayTime::PlayTimeManager& play_time_manager, - const FileSys::PatchManager& patch, - const bool cached) + const FileSys::PatchManager& patch) { const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); @@ -224,14 +223,10 @@ QList MakeGameListEntry(const std::string& path, QString patch_versions; - if (cached) { - patch_versions = GetGameListCachedObject( - fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { - return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); - }); - } else { - patch_versions = FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); - } + patch_versions = GetGameListCachedObject( + fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { + return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); + }); list.insert(2, new GameListItem(patch_versions)); @@ -244,15 +239,13 @@ GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_, QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_, - const bool cached_) + Core::System& system_) : vfs{std::move(vfs_)} , provider{provider_} , game_dirs{game_dirs_} , compatibility_list{compatibility_list_} , play_time_manager{play_time_manager_} , system{system_} - , cached{cached_} { // We want the game list to manage our lifetime. setAutoDelete(false); @@ -355,8 +348,7 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { program_id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent([=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); } } @@ -439,8 +431,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); @@ -463,8 +454,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa program_id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 0afd7c7849..5c5fbb251f 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -15,7 +15,7 @@ #include "common/thread.h" #include "core/file_sys/registered_cache.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -45,8 +45,7 @@ public: QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_, - const bool cached = true); + Core::System& system_); ~GameListWorker() override; /// Starts the processing of directory tree information. @@ -95,6 +94,4 @@ private: Common::Event processing_completed; Core::System& system; - - const bool cached; }; diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 1931dcd1f6..e9d0b4e23f 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -8,7 +8,7 @@ #include "hid_core/frontend/emulated_controller.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" HotkeyRegistry::HotkeyRegistry() = default; HotkeyRegistry::~HotkeyRegistry() = default; diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp index 673bbaa836..0e8e785ae9 100644 --- a/src/yuzu/install_dialog.cpp +++ b/src/yuzu/install_dialog.cpp @@ -8,7 +8,7 @@ #include #include #include "yuzu/install_dialog.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) { file_list = new QListWidget(this); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e23e9a6a48..34423589cc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -11,6 +11,7 @@ #include "core/loader/nca.h" #include "core/tools/renderdoc.h" #include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" #include @@ -156,7 +157,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/compatibility_list.h" #include "yuzu/configuration/configure_dialog.h" #include "yuzu/configuration/configure_input_per_game.h" -#include "yuzu/configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "yuzu/debugger/console.h" #include "yuzu/debugger/controller.h" #include "yuzu/debugger/wait_tree.h" @@ -170,7 +171,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/main.h" #include "yuzu/play_time_manager.h" #include "yuzu/startup_checks.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/clickable_label.h" #include "yuzu/vk_device_info.h" @@ -559,7 +560,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) game_list->LoadCompatibilityList(); // force reload on first load to ensure add-ons get updated - game_list->PopulateAsync(UISettings::values.game_dirs, false); + game_list->PopulateAsync(UISettings::values.game_dirs); // make sure menubar has the arrow cursor instead of inheriting from this ui->menubar->setCursor(QCursor()); @@ -4609,9 +4610,11 @@ void GMainWindow::OnToggleStatusBar() { statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); } -void GMainWindow::OnGameListRefresh() { - // force reload add-ons etc - game_list->ForceRefreshGameDirectory(); +void GMainWindow::OnGameListRefresh() +{ + // Resets metadata cache and reloads + QtCommon::ResetMetadata(); + game_list->RefreshGameDirectory(); SetFirmwareVersion(); } @@ -4620,7 +4623,7 @@ void GMainWindow::OnAlbum() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Album applet.")); + tr("Please install firmware to use the Album applet.")); return; } @@ -4643,7 +4646,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Cabinet applet.")); + tr("Please install firmware to use the Cabinet applet.")); return; } @@ -4667,7 +4670,7 @@ void GMainWindow::OnMiiEdit() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Mii editor.")); + tr("Please install firmware to use the Mii editor.")); return; } @@ -4690,7 +4693,7 @@ void GMainWindow::OnOpenControllerMenu() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Controller Menu.")); + tr("Please install firmware to use the Controller Menu.")); return; } @@ -4745,6 +4748,8 @@ void GMainWindow::OnHomeMenu() { break; } + // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); @@ -4767,7 +4772,7 @@ void GMainWindow::OnInitialSetup() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use Starter.")); + tr("Please install firmware to use Starter.")); return; } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7857788fcf..b20f601381 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -17,7 +17,7 @@ #include #include "common/common_types.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" #include "user_data_migration.h" diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index 30f37c2b4a..deac3b9e59 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp @@ -21,7 +21,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" enum class ConnectionType : u8 { TraversalServer, IP }; diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index d8e63da600..4dd3958550 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -25,7 +25,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifdef ENABLE_WEB_SERVICE #include "web_service/verify_user_jwt.h" #endif diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index ed6ba6a15c..84723041df 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -22,7 +22,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifdef ENABLE_WEB_SERVICE #include "web_service/web_backend.h" #endif diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index d5529712b0..2eed3cba63 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -19,7 +19,7 @@ #include "yuzu/multiplayer/lobby.h" #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/clickable_label.h" MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model_, diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp index 8317386816..d9579706ca 100644 --- a/src/yuzu/play_time_manager.cpp +++ b/src/yuzu/play_time_manager.cpp @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/alignment.h" #include "common/fs/file.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/yuzu/play_time_manager.h b/src/yuzu/play_time_manager.h index 1714b91313..ea7d9debc3 100644 --- a/src/yuzu/play_time_manager.h +++ b/src/yuzu/play_time_manager.h @@ -9,8 +9,9 @@ #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/polyfill_thread.h" +#include +// TODO(crueter): Extract this into frontend_common namespace Service::Account { class ProfileManager; } diff --git a/src/yuzu/qt_common.h b/src/yuzu/qt_common.h deleted file mode 100644 index 9c63f08f34..0000000000 --- a/src/yuzu/qt_common.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include "core/frontend/emu_window.h" - -namespace QtCommon { - -Core::Frontend::WindowSystemType GetWindowSystemType(); - -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); - -} // namespace QtCommon diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index ab0d39c256..65838f7d42 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -4,7 +4,7 @@ #include #include -#include "yuzu/qt_common.h" +#include "qt_common/qt_common.h" #include "common/dynamic_library.h" #include "common/logging/log.h" From 7a0712af1f537e7f508cb2e065b950c3a931faba Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:05:57 -0400 Subject: [PATCH 02/52] move fw install Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 105 +++++++++++++++-- src/qt_common/qt_common.h | 35 +++++- .../configuration/configure_filesystem.cpp | 2 +- src/yuzu/main.cpp | 110 ++++-------------- 4 files changed, 155 insertions(+), 97 deletions(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 29379c1d54..260255c62e 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,6 +1,7 @@ #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/hle/service/filesystem/filesystem.h" #include "uisettings.h" #include @@ -21,17 +22,18 @@ MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list/")) { - return Empty; + return MetadataResult::Empty; } else if (Common::FS::RemoveDirRecursively( Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return Success; + return MetadataResult::Success; UISettings::values.is_game_list_reload_pending.exchange(true); } else { - return Failure; + return MetadataResult::Failure; } } -Core::Frontend::WindowSystemType GetWindowSystemType() { +Core::Frontend::WindowSystemType GetWindowSystemType() +{ // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); if (platform_name == QStringLiteral("windows")) @@ -51,7 +53,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType() { return Core::Frontend::WindowSystemType::Windows; } // namespace Core::Frontend::WindowSystemType -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) +{ Core::Frontend::EmuWindow::WindowSystemInfo wsi; wsi.type = GetWindowSystemType(); @@ -59,8 +62,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) // Our Win32 Qt external doesn't have the private API. wsi.render_surface = reinterpret_cast(window->winId()); #elif defined(__APPLE__) - wsi.render_surface = reinterpret_cast(objc_msgSend)( - reinterpret_cast(window->winId()), sel_registerName("layer")); + wsi.render_surface = reinterpret_cast( + objc_msgSend)(reinterpret_cast(window->winId()), sel_registerName("layer")); #else QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); wsi.display_connection = pni->nativeResourceForWindow("display", window); @@ -74,4 +77,92 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } +FirmwareInstallResult InstallFirmware(const QString& location, + bool recursive, + std::function QtProgressCallback, + Core::System* system, + FileSys::VfsFilesystem* vfs) +{ + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector out; + const Common::FS::DirEntryCallable callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") { + out.emplace_back(entry.path()); + } + + return true; + }; + + QtProgressCallback(100, 10); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + return FirmwareInstallResult::NoNCAs; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + return FirmwareInstallResult::FailedDelete; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + QtProgressCallback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), + FileSys::OpenMode::Read); + auto firmware_dst_vfile = firmware_vdir + ->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, + "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), + firmware_src_path.filename().string()); + success = false; + } + + if (QtProgressCallback(100, + 20 + + static_cast(((i) / static_cast(out.size())) + * 70.0))) { + return FirmwareInstallResult::FailedCorrupted; + } + } + + if (!success) { + return FirmwareInstallResult::FailedCopy; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + return FirmwareInstallResult::Success; +} + } diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 3c7dddfc1f..31adcf05c7 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -7,8 +7,11 @@ #include #include +#include "core/core.h" #include +#include + namespace QtCommon { static constexpr std::array METADATA_RESULTS = { @@ -17,7 +20,7 @@ static constexpr std::array METADATA_RESULTS = { "The metadata cache is already empty.", }; -enum MetadataResult { +enum class MetadataResult { Success, Failure, Empty, @@ -38,6 +41,36 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } +static constexpr std::array FIRMWARE_RESULTS = { + "", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware." +}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware(const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 392155d2a3..5459dc0377 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -132,7 +132,7 @@ void ConfigureFilesystem::ResetMetadata() { const QString title = tr("Reset Metadata Cache"); switch (result) { - case QtCommon::Failure: + case QtCommon::MetadataResult::Failure: QMessageBox::warning(this, title, resultMessage); break; default: diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 34423589cc..b0aaa953a9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4356,106 +4356,40 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); + const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); - // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in - // there.) - std::filesystem::path firmware_source_path = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - progress.close(); + progress.close(); + + QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); + + switch (result) { + case QtCommon::FirmwareInstallResult::NoNCAs: + case QtCommon::FirmwareInstallResult::FailedCorrupted: + box->setIcon(QMessageBox::Icon::Warning); + box->exec(); return; - } - - std::vector out; - const Common::FS::DirEntryCallable callback = - [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") { - out.emplace_back(entry.path()); - } - - return true; - }; - - QtProgressCallback(100, 10); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback, - Common::FS::DirEntryFilter::File); - } else { - Common::FS::IterateDirEntries(firmware_source_path, callback, - Common::FS::DirEntryFilter::File); - } - - if (out.size() <= 0) { - progress.close(); - QMessageBox::warning(this, tr("Firmware install failed"), - tr("Unable to locate potential firmware NCA files")); + case QtCommon::FirmwareInstallResult::FailedCopy: + case QtCommon::FirmwareInstallResult::FailedDelete: + box->setIcon(QMessageBox::Icon::Critical); + box->exec(); return; + default: + box->deleteLater(); + break; } - // Locate and erase the content of nand/system/Content/registered/*.nca, if any. - auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - progress.close(); - QMessageBox::critical(this, tr("Firmware install failed"), - tr("Failed to delete one or more firmware file.")); - return; - } - - LOG_INFO(Frontend, - "Cleaned nand/system/Content/registered folder in preparation for new firmware."); - - QtProgressCallback(100, 20); - - auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); - - bool success = true; - int i = 0; - for (const auto& firmware_src_path : out) { - i++; - auto firmware_src_vfile = - vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read); - auto firmware_dst_vfile = - firmware_vdir->CreateFileRelative(firmware_src_path.filename().string()); - - if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { - LOG_ERROR(Frontend, "Failed to copy firmware file {} to {} in registered folder!", - firmware_src_path.generic_string(), firmware_src_path.filename().string()); - success = false; - } - - if (QtProgressCallback( - 100, 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - progress.close(); - QMessageBox::warning( - this, tr("Firmware install failed"), - tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "Restart Eden or re-install firmware.")); - return; - } - } - - if (!success) { - progress.close(); - QMessageBox::critical(this, tr("Firmware install failed"), - tr("One or more firmware files failed to copy into NAND.")); - return; - } - - // Re-scan VFS for the newly placed firmware files. - system->GetFileSystemController().CreateFactories(*vfs); - auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); return progress.wasCanceled(); }; - auto result = - ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + auto results = + ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); - if (result.size() > 0) { + if (results.size() > 0) { const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + QString::fromStdString(fmt::format("{}", fmt::join(results, "\n"))); progress.close(); QMessageBox::critical( this, tr("Firmware integrity verification failed!"), From 35082084731f802326100129e810954131001428 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:12:24 -0400 Subject: [PATCH 03/52] Fix license headers Signed-off-by: crueter --- .ci/license-header.sh | 12 +++++++++--- src/qt_common/qt_common.cpp | 3 +++ src/qt_common/qt_config.cpp | 3 +++ src/qt_common/qt_config.h | 3 +++ src/yuzu/configuration/configure_audio.cpp | 3 +++ src/yuzu/configuration/configure_cpu.h | 3 +++ src/yuzu/configuration/configure_dialog.cpp | 3 +++ src/yuzu/configuration/configure_dialog.h | 3 +++ src/yuzu/configuration/configure_filesystem.cpp | 3 +++ src/yuzu/configuration/configure_general.cpp | 3 +++ src/yuzu/configuration/configure_graphics.cpp | 3 +++ src/yuzu/configuration/configure_graphics.h | 3 +++ .../configuration/configure_graphics_advanced.cpp | 3 +++ .../configuration/configure_graphics_extensions.cpp | 3 +++ src/yuzu/configuration/configure_hotkeys.cpp | 3 +++ src/yuzu/configuration/configure_input_per_game.h | 3 +++ src/yuzu/configuration/configure_per_game.cpp | 3 +++ src/yuzu/configuration/configure_per_game.h | 3 +++ src/yuzu/configuration/configure_per_game_addons.cpp | 3 +++ src/yuzu/configuration/configure_ringcon.cpp | 3 +++ src/yuzu/configuration/configure_tas.cpp | 3 +++ src/yuzu/configuration/input_profiles.h | 3 +++ src/yuzu/configuration/shared_widget.cpp | 3 +++ src/yuzu/configuration/shared_widget.h | 3 +++ src/yuzu/debugger/console.cpp | 3 +++ src/yuzu/debugger/wait_tree.cpp | 3 +++ src/yuzu/game_list_p.h | 3 +++ src/yuzu/game_list_worker.cpp | 3 +++ src/yuzu/game_list_worker.h | 3 +++ src/yuzu/hotkeys.cpp | 3 +++ src/yuzu/install_dialog.cpp | 3 +++ src/yuzu/multiplayer/state.cpp | 3 +++ src/yuzu/play_time_manager.cpp | 3 +++ src/yuzu/play_time_manager.h | 3 +++ src/yuzu/vk_device_info.cpp | 3 +++ 35 files changed, 111 insertions(+), 3 deletions(-) diff --git a/.ci/license-header.sh b/.ci/license-header.sh index fecffaa7d3..f1e16abbe6 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -5,13 +5,19 @@ HEADER_HASH="$(cat "$PWD/.ci/license/header-hash.txt")" echo "Getting branch changes" -BRANCH=`git rev-parse --abbrev-ref HEAD` -COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"` -RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" +# BRANCH=`git rev-parse --abbrev-ref HEAD` +# COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"` +# RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" +# FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` + +CURRENT=`git rev-parse --short=10 HEAD` +BASE=`git merge-base master $CURRENT` +RANGE="$CURRENT^..$BASE" FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` #FILES=$(git diff --name-only master) +echo $FILES echo "Done" check_header() { diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 260255c62e..4a27566107 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/qt_common/qt_config.cpp b/src/qt_common/qt_config.cpp index ae5b330e23..f787873cf6 100644 --- a/src/qt_common/qt_config.cpp +++ b/src/qt_common/qt_config.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/qt_common/qt_config.h b/src/qt_common/qt_config.h index dc2dceb4d7..a8c80dd273 100644 --- a/src/qt_common/qt_config.h +++ b/src/qt_common/qt_config.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 8d11920d31..a7ebae91f8 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 16cf74af33..bbc6096f9b 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 4e128106e7..0816782282 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index bf96035752..c1e148fc8e 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 5459dc0377..d02e6dec2b 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 352ae8ab85..18c2c9cb77 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index e1e68b917a..cd806e5ef8 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 9f7ece5714..38d97aae80 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 921cb83b08..e07ad8c466 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics_extensions.cpp b/src/yuzu/configuration/configure_graphics_extensions.cpp index c4c7fbb31f..f165e703d9 100644 --- a/src/yuzu/configuration/configure_graphics_extensions.cpp +++ b/src/yuzu/configuration/configure_graphics_extensions.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 53f7401ef4..a5c1ee009a 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2017 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 1323d101d3..dcd6dd841b 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 545c37a2c9..b51ede0de8 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index a756b561a8..83afc27f3d 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 90c94cb923..ed4cbc1147 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 7e7877aaf6..795ad1a85e 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 290e825fe6..898a1a3e59 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 64dcf0e603..dba5ce1318 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index 02b354b0a5..e30ecc4848 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index a793347ce5..9e718098a3 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp index 40b2fddbc9..8fb22db192 100644 --- a/src/yuzu/debugger/console.cpp +++ b/src/yuzu/debugger/console.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index f32f6348a5..feb814b25e 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index b3e05b8b34..5a3b5829f5 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 267faa7182..538c7ab822 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 5c5fbb251f..f5d5f6341b 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index e9d0b4e23f..31932e6f43 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp index 0e8e785ae9..e6f1392ce0 100644 --- a/src/yuzu/install_dialog.cpp +++ b/src/yuzu/install_dialog.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index 2eed3cba63..8ff1d991ec 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp index d9579706ca..6d06bc7614 100644 --- a/src/yuzu/play_time_manager.cpp +++ b/src/yuzu/play_time_manager.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/play_time_manager.h b/src/yuzu/play_time_manager.h index ea7d9debc3..cd81bdb061 100644 --- a/src/yuzu/play_time_manager.h +++ b/src/yuzu/play_time_manager.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index 65838f7d42..d961d550a1 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later From cb5719ec0e0f3f348428de35c408b75d6afb3ae0 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:56:58 -0400 Subject: [PATCH 04/52] debug: log user/save id Signed-off-by: crueter --- src/core/file_sys/savedata_factory.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 106922e04f..0591517727 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -126,6 +126,10 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, std::string out = GetSaveDataSpaceIdPath(space); + LOG_INFO(Common_Filesystem, "Save ID: {:016X}", save_id); + LOG_INFO(Common_Filesystem, "User ID[1]: {:016X}", user_id[1]); + LOG_INFO(Common_Filesystem, "User ID[0]: {:016X}", user_id[0]); + switch (type) { case SaveDataType::System: return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); From ae62ee3d27e39dd7a28cecfb8578c291fa7cf6b7 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 18:17:20 -0400 Subject: [PATCH 05/52] explicitly check write status for dir Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 4a27566107..abeae4c3a1 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -123,7 +123,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { return FirmwareInstallResult::FailedDelete; } From 195bd7005e3afe85199619b6a5fa59cc709b5355 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 23:23:14 -0400 Subject: [PATCH 06/52] more common funcs Signed-off-by: crueter --- .ci/license-header.sh | 6 +- src/core/file_sys/savedata_factory.cpp | 3 + src/qt_common/CMakeLists.txt | 4 +- src/qt_common/qt_common.cpp | 43 ++++- src/qt_common/qt_common.h | 4 +- src/qt_common/qt_game_util.cpp | 171 +++++++++++++++++ src/qt_common/qt_game_util.h | 41 +++++ src/qt_common/qt_path_util.cpp | 20 ++ src/qt_common/qt_path_util.h | 7 + src/yuzu/main.cpp | 243 +++++-------------------- src/yuzu/main.h | 9 - 11 files changed, 331 insertions(+), 220 deletions(-) create mode 100644 src/qt_common/qt_game_util.cpp create mode 100644 src/qt_common/qt_game_util.h create mode 100644 src/qt_common/qt_path_util.cpp create mode 100644 src/qt_common/qt_path_util.h diff --git a/.ci/license-header.sh b/.ci/license-header.sh index f1e16abbe6..d98f42fc97 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -10,10 +10,8 @@ echo "Getting branch changes" # RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" # FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` -CURRENT=`git rev-parse --short=10 HEAD` -BASE=`git merge-base master $CURRENT` -RANGE="$CURRENT^..$BASE" -FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` +BASE=`git merge-base master HEAD` +FILES=`git diff --name-only $BASE` #FILES=$(git diff --name-only master) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 0591517727..edf51e74de 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index be1a8ebbd0..d6ef427ba6 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -13,10 +13,12 @@ add_library(qt_common STATIC shared_translation.cpp shared_translation.h + qt_path_util.h qt_path_util.cpp + qt_game_util.h qt_game_util.cpp ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni) +target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index abeae4c3a1..0cd4c86b4a 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -15,6 +15,11 @@ #if !defined(WIN32) && !defined(__APPLE__) #include + +#include + +#include + #elif defined(__APPLE__) #include #endif @@ -80,11 +85,12 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -FirmwareInstallResult InstallFirmware(const QString& location, - bool recursive, - std::function QtProgressCallback, - Core::System* system, - FileSys::VfsFilesystem* vfs) +FirmwareInstallResult InstallFirmware( + const QString& location, + bool recursive, + std::function QtProgressCallback, + Core::System* system, + FileSys::VfsFilesystem* vfs) { LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); @@ -123,7 +129,8 @@ FirmwareInstallResult InstallFirmware(const QString& location, // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + if (sysnand_content_vdir->IsWritable() + && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { return FirmwareInstallResult::FailedDelete; } @@ -168,4 +175,28 @@ FirmwareInstallResult InstallFirmware(const QString& location, return FirmwareInstallResult::Success; } +QString UnzipFirmwareToTmp(const QString& location) +{ + namespace fs = std::filesystem; + fs::path tmp{fs::temp_directory_path()}; + + if (!fs::create_directories(tmp / "eden" / "firmware")) { + return ""; + } + + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + return ""; + } + + return qCacheDir; } + +} // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 31adcf05c7..b3ca99e65a 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -62,10 +62,12 @@ enum class FirmwareInstallResult { FirmwareInstallResult InstallFirmware(const QString &location, bool recursive, - std::function QtProgressCallback, + std::function QtProgressCallback, Core::System *system, FileSys::VfsFilesystem *vfs); +QString UnzipFirmwareToTmp(const QString &location); + inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) { return FIRMWARE_RESULTS.at(static_cast(result)); diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp new file mode 100644 index 0000000000..9aba4e393c --- /dev/null +++ b/src/qt_common/qt_game_util.cpp @@ -0,0 +1,171 @@ +#include "qt_game_util.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" + +#include +#include +#include "fmt/ostream.h" +#include + +#ifdef _WIN32 +#include +#endif + +namespace QtCommon { + +bool CreateShortcutLink(const std::filesystem::path& shortcut_path, + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, const std::string& categories, + const std::string& keywords, const std::string& name) try { +#ifdef _WIN32 // Windows + HRESULT hr = CoInitialize(nullptr); + if (FAILED(hr)) { + LOG_ERROR(Frontend, "CoInitialize failed"); + return false; + } + SCOPE_EXIT { + CoUninitialize(); + }; + IShellLinkW* ps1 = nullptr; + IPersistFile* persist_file = nullptr; + SCOPE_EXIT { + if (persist_file != nullptr) { + persist_file->Release(); + } + if (ps1 != nullptr) { + ps1->Release(); + } + }; + HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + reinterpret_cast(&ps1)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); + return false; + } + hres = ps1->SetPath(command.c_str()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set path"); + return false; + } + if (!arguments.empty()) { + hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set arguments"); + return false; + } + } + if (!comment.empty()) { + hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set description"); + return false; + } + } + if (std::filesystem::is_regular_file(icon_path)) { + hres = ps1->SetIconLocation(icon_path.c_str(), 0); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set icon location"); + return false; + } + } + hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast(&persist_file)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); + return false; + } + hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to save shortcut"); + return false; + } + return true; +#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Any desktop NIX + std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); + std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); + if (!shortcut_stream.is_open()) { + LOG_ERROR(Frontend, "Failed to create shortcut"); + return false; + } + // TODO: Migrate fmt::print to std::print in futures STD C++ 23. + fmt::print(shortcut_stream, "[Desktop Entry]\n"); + fmt::print(shortcut_stream, "Type=Application\n"); + fmt::print(shortcut_stream, "Version=1.0\n"); + fmt::print(shortcut_stream, "Name={}\n", name); + if (!comment.empty()) { + fmt::print(shortcut_stream, "Comment={}\n", comment); + } + if (std::filesystem::is_regular_file(icon_path)) { + fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); + } + fmt::print(shortcut_stream, "TryExec={}\n", command.string()); + fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); + if (!categories.empty()) { + fmt::print(shortcut_stream, "Categories={}\n", categories); + } + if (!keywords.empty()) { + fmt::print(shortcut_stream, "Keywords={}\n", keywords); + } + return true; +#else // Unsupported platform + return false; +#endif +} + catch (const std::exception& e) { + LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); + return false; +} + +bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, + std::filesystem::path& out_icon_path) { + // Get path to Yuzu icons directory & icon extension + std::string ico_extension = "png"; +#if defined(_WIN32) + out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); + ico_extension = "ico"; +#elif defined(__linux__) || defined(__FreeBSD__) + out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; +#endif + // Create icons directory if it doesn't exist + if (!Common::FS::CreateDirs(out_icon_path)) { + out_icon_path.clear(); + return false; + } + + // Create icon file path + out_icon_path /= (program_id == 0 ? fmt::format("eden-{}.{}", game_file_name, ico_extension) + : fmt::format("eden-{:016X}.{}", program_id, ico_extension)); + return true; +} + +void OpenRootDataFolder() { + QDesktopServices::openUrl(QUrl( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); +} + +void OpenNANDFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); +} + +void OpenSDMCFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); +} + +void OpenModFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); +} + +void OpenLogFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); +} + +} diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h new file mode 100644 index 0000000000..98d17027c4 --- /dev/null +++ b/src/qt_common/qt_game_util.h @@ -0,0 +1,41 @@ +#ifndef QT_GAME_UTIL_H +#define QT_GAME_UTIL_H + +#include "frontend_common/content_manager.h" +#include + +namespace QtCommon { + +static constexpr std::array GAME_VERIFICATION_RESULTS = { + "The operation completed successfully.", + "File contents may be corrupt or missing..", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "File contents could not be checked for validity." +}; + +inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result) +{ + return GAME_VERIFICATION_RESULTS.at(static_cast(result)); +} + +bool CreateShortcutLink(const std::filesystem::path& shortcut_path, + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, + const std::string& categories, + const std::string& keywords, + const std::string& name); + +bool MakeShortcutIcoPath(const u64 program_id, + const std::string_view game_file_name, + std::filesystem::path& out_icon_path); + +void OpenRootDataFolder(); +void OpenNANDFolder(); +void OpenSDMCFolder(); +void OpenModFolder(); +void OpenLogFolder(); +} + +#endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp new file mode 100644 index 0000000000..2ca2f6bf72 --- /dev/null +++ b/src/qt_common/qt_path_util.cpp @@ -0,0 +1,20 @@ +#include "qt_path_util.h" +#include +#include +#include +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include + +bool QtCommon::PathUtil::OpenShaderCache(u64 program_id) +{ + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; + if (!Common::FS::CreateDirs(shader_cache_folder_path)) { + return false; + } + + const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; + const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); + return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); +} diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h new file mode 100644 index 0000000000..6fafad7ed9 --- /dev/null +++ b/src/qt_common/qt_path_util.h @@ -0,0 +1,7 @@ +#ifndef QT_PATH_UTIL_H +#define QT_PATH_UTIL_H + +#include "common/common_types.h" +namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); } + +#endif // QT_PATH_UTIL_H diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b0aaa953a9..88f3a3d743 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -12,6 +12,8 @@ #include "core/tools/renderdoc.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/qt_path_util.h" #include @@ -1166,7 +1168,7 @@ void GMainWindow::InitializeWidgets() { loading_screen = new LoadingScreen(this); loading_screen->hide(); ui->horizontalLayout->addWidget(loading_screen); - connect(loading_screen, &LoadingScreen::Hidden, [&] { + connect(loading_screen, &LoadingScreen::Hidden, this, [&] { loading_screen->Clear(); if (emulation_running) { render_window->show(); @@ -2613,16 +2615,9 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; - if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), - tr("Failed to create the shader cache directory for this title.")); - return; + if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { + QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); } - const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; - const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); - QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, @@ -2687,6 +2682,7 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& return true; } +// TODO(crueter): All this can be transfered to qt_common QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { switch (type) { case InstalledEntryType::Game: @@ -3043,12 +3039,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } } +// END void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { - const auto NotImplemented = [this] { - QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"), - tr("File contents were not checked for validity.")); - }; - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(100); @@ -3061,18 +3053,20 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { }; const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback); + const QString resultString = tr(QtCommon::GetGameVerificationResultString(result)); progress.close(); switch (result) { case ContentManager::GameVerificationResult::Success: QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); + resultString); break; case ContentManager::GameVerificationResult::Failed: QMessageBox::critical(this, tr("Integrity verification failed!"), - tr("File contents may be corrupt.")); + resultString); break; case ContentManager::GameVerificationResult::NotImplemented: - NotImplemented(); + QMessageBox::warning(this, tr("Integrity verification couldn't be performed"), + resultString); } } @@ -3094,109 +3088,8 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QUrl(QStringLiteral("https://eden-emulator.github.io/game/") + directory)); } -bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, - const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { -#ifdef _WIN32 // Windows - HRESULT hr = CoInitialize(nullptr); - if (FAILED(hr)) { - LOG_ERROR(Frontend, "CoInitialize failed"); - return false; - } - SCOPE_EXIT { - CoUninitialize(); - }; - IShellLinkW* ps1 = nullptr; - IPersistFile* persist_file = nullptr; - SCOPE_EXIT { - if (persist_file != nullptr) { - persist_file->Release(); - } - if (ps1 != nullptr) { - ps1->Release(); - } - }; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - reinterpret_cast(&ps1)); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); - return false; - } - hres = ps1->SetPath(command.c_str()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set path"); - return false; - } - if (!arguments.empty()) { - hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set arguments"); - return false; - } - } - if (!comment.empty()) { - hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set description"); - return false; - } - } - if (std::filesystem::is_regular_file(icon_path)) { - hres = ps1->SetIconLocation(icon_path.c_str(), 0); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set icon location"); - return false; - } - } - hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast(&persist_file)); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); - return false; - } - hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to save shortcut"); - return false; - } - return true; -#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Any desktop NIX - std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); - std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); - if (!shortcut_stream.is_open()) { - LOG_ERROR(Frontend, "Failed to create shortcut"); - return false; - } - // TODO: Migrate fmt::print to std::print in futures STD C++ 23. - fmt::print(shortcut_stream, "[Desktop Entry]\n"); - fmt::print(shortcut_stream, "Type=Application\n"); - fmt::print(shortcut_stream, "Version=1.0\n"); - fmt::print(shortcut_stream, "Name={}\n", name); - if (!comment.empty()) { - fmt::print(shortcut_stream, "Comment={}\n", comment); - } - if (std::filesystem::is_regular_file(icon_path)) { - fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); - } - fmt::print(shortcut_stream, "TryExec={}\n", command.string()); - fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); - if (!categories.empty()) { - fmt::print(shortcut_stream, "Categories={}\n", categories); - } - if (!keywords.empty()) { - fmt::print(shortcut_stream, "Keywords={}\n", keywords); - } - return true; -#else // Unsupported platform - return false; -#endif -} catch (const std::exception& e) { - LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); - return false; -} // Messages in pre-defined message boxes for less code spaghetti +// TODO(crueter): Still need to decide what to do re: message boxes w/ qml bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { int result = 0; QMessageBox::StandardButtons buttons; @@ -3227,33 +3120,6 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt } } -bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path) { - // Get path to Yuzu icons directory & icon extension - std::string ico_extension = "png"; -#if defined(_WIN32) - out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); - ico_extension = "ico"; -#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) - out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; -#endif - // Create icons directory if it doesn't exist - if (!Common::FS::CreateDirs(out_icon_path)) { - QMessageBox::critical( - this, tr("Create Icon"), - tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(out_icon_path.string())), - QMessageBox::StandardButton::Ok); - out_icon_path.clear(); - return false; - } - - // Create icon file path - out_icon_path /= (program_id == 0 ? fmt::format("eden-{}.{}", game_file_name, ico_extension) - : fmt::format("eden-{:016X}.{}", program_id, ico_extension)); - return true; -} - void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { // Create shortcut @@ -4288,28 +4154,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } void GMainWindow::OnOpenRootDataFolder() { - QDesktopServices::openUrl( - QUrl(QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); + QtCommon::OpenRootDataFolder(); } -void GMainWindow::OnOpenNANDFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); +void GMainWindow::OnOpenNANDFolder() +{ + QtCommon::OpenNANDFolder(); } -void GMainWindow::OnOpenSDMCFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); +void GMainWindow::OnOpenSDMCFolder() +{ + QtCommon::OpenSDMCFolder(); } -void GMainWindow::OnOpenModFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); +void GMainWindow::OnOpenModFolder() +{ + QtCommon::OpenModFolder(); } -void GMainWindow::OnOpenLogFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); +void GMainWindow::OnOpenLogFolder() +{ + QtCommon::OpenLogFolder(); } void GMainWindow::OnVerifyInstalledContents() { @@ -4444,32 +4309,14 @@ void GMainWindow::OnInstallFirmwareFromZIP() { return; } - namespace fs = std::filesystem; - fs::path tmp{std::filesystem::temp_directory_path()}; + const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location); - if (!std::filesystem::create_directories(tmp / "eden" / "firmware")) { - goto unzipFailed; - } - - { - tmp /= "eden"; - tmp /= "firmware"; - - QString qCacheDir = QString::fromStdString(tmp.string()); - - QFile zip(firmware_zip_location); - - QStringList result = JlCompress::extractDir(&zip, qCacheDir); - if (result.isEmpty()) { - goto unzipFailed; - } - - // In this case, it has to be done recursively, since sometimes people - // will pack it into a subdirectory after dumping + // In this case, it has to be done recursively, since sometimes people + // will pack it into a subdirectory after dumping + if (!qCacheDir.isEmpty()) { InstallFirmware(qCacheDir, true); - std::error_code ec; - std::filesystem::remove_all(tmp, ec); + std::filesystem::remove_all(std::filesystem::temp_directory_path() / "eden" / "firmware", ec); if (ec) { QMessageBox::warning(this, tr("Firmware cleanup failed"), @@ -4478,14 +4325,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() { "again.\nOS reported error: %1") .arg(QString::fromStdString(ec.message()))); } - - return; } -unzipFailed: - QMessageBox::critical( - this, tr("Firmware unzip failed"), - tr("Check write permissions in the system temp directory and try again.")); - return; } void GMainWindow::OnInstallDecryptionKeys() { @@ -4764,10 +4604,8 @@ std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target return shortcut_path; } -void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program_id, - const std::string& game_title_, GameListShortcutTarget target, - std::string arguments_, const bool needs_title) { - // Get path to yuzu executable +void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { + // Get path to Eden executable std::filesystem::path command = GetEdenCommand(); // Shortcut path @@ -4819,10 +4657,16 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); std::filesystem::path out_icon_path; - if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } + } else { + QMessageBox::critical( + this, tr("Create Icon"), + tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") + .arg(QString::fromStdString(out_icon_path.string())), + QMessageBox::StandardButton::Ok); } #if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) @@ -4843,12 +4687,12 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qgame_title)) { arguments = "-f " + arguments; } - const std::string comment = fmt::format("Start {:s} with the eden Emulator", game_title); + const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments, - categories, keywords, game_title)) { + if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, qgame_title); return; @@ -4876,6 +4720,7 @@ void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); const auto game_path = qlaunch_applet_nca->GetFullPath(); + // TODO(crueter): Make this use the Eden icon CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b20f601381..8d00fef4f8 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -478,15 +478,6 @@ private: QString GetTasStateDescription() const; bool CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title); - bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path); - bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, const std::string& arguments, - const std::string& categories, const std::string& keywords, - const std::string& name); - - bool OnCheckNcaVerification(); /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog From 886b649a0db5439fa25c3d3c5f3f5bfe952038c4 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 23:28:13 -0400 Subject: [PATCH 07/52] Fix license headers --- src/qt_common/qt_game_util.cpp | 3 +++ src/qt_common/qt_game_util.h | 3 +++ src/qt_common/qt_path_util.cpp | 3 +++ src/qt_common/qt_path_util.h | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 9aba4e393c..9264c782d1 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_game_util.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 98d17027c4..3d27839672 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 2ca2f6bf72..6875d01dea 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_path_util.h" #include #include diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h index 6fafad7ed9..7f399c4bb4 100644 --- a/src/qt_common/qt_path_util.h +++ b/src/qt_common/qt_path_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_PATH_UTIL_H #define QT_PATH_UTIL_H From 115d0484a65dfed9663dc601d80078edc5576fe2 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 01:21:18 -0400 Subject: [PATCH 08/52] thank you Qt Creator, very cool Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 7 ++----- src/qt_common/qt_game_util.cpp | 10 +++++++--- src/yuzu/main.cpp | 3 --- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 0cd4c86b4a..54c79c93e1 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -9,17 +9,14 @@ #include #include -#include #include "common/logging/log.h" #include "core/frontend/emu_window.h" -#if !defined(WIN32) && !defined(__APPLE__) -#include - #include - #include +#if !defined(WIN32) && !defined(__APPLE__) +#include #elif defined(__APPLE__) #include #endif diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 9264c782d1..add9d46a39 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -7,11 +7,15 @@ #include #include -#include "fmt/ostream.h" -#include #ifdef _WIN32 -#include + #include + #include + #include "common/scope_exit.h" + #include "common/string_util.h" +#else + #include "fmt/ostream.h" + #include #endif namespace QtCommon { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 88f3a3d743..86e0755ce8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -15,8 +15,6 @@ #include "qt_common/qt_game_util.h" #include "qt_common/qt_path_util.h" -#include - #ifdef __APPLE__ #include // for chdir #endif @@ -121,7 +119,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/scm_rev.h" #include "common/scope_exit.h" #ifdef _WIN32 -#include #include "common/windows/timer_resolution.h" #endif #ifdef ARCHITECTURE_x86_64 From 49670ebb0ff8187323a04350494998bc273b2e04 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 21:10:17 -0400 Subject: [PATCH 09/52] [qt] frontend abstraction and message box early handling Signed-off-by: crueter --- src/CMakeLists.txt | 1 + src/frontend_common/firmware_manager.h | 5 ++- src/qt_common/CMakeLists.txt | 6 ++- src/qt_common/qt_common.cpp | 59 ++++++++++++++++++++++---- src/qt_common/qt_common.h | 34 +++++++-------- src/qt_common/qt_frontend_util.cpp | 25 +++++++++++ src/qt_common/qt_frontend_util.h | 29 +++++++++++++ src/yuzu/main.cpp | 24 +++-------- 8 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 src/qt_common/qt_frontend_util.cpp create mode 100644 src/qt_common/qt_frontend_util.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0032b20029..184b049d06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ if (YUZU_ROOM_STANDALONE) endif() if (ENABLE_QT) + add_definitions(-DYUZU_QT_WIDGETS) add_subdirectory(qt_common) add_subdirectory(yuzu) endif() diff --git a/src/frontend_common/firmware_manager.h b/src/frontend_common/firmware_manager.h index 20f3b41478..23fce59eb3 100644 --- a/src/frontend_common/firmware_manager.h +++ b/src/frontend_common/firmware_manager.h @@ -7,6 +7,7 @@ #include "common/common_types.h" #include "core/core.h" #include "core/file_sys/nca_metadata.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/registered_cache.h" #include "core/hle/service/filesystem/filesystem.h" #include @@ -143,6 +144,8 @@ inline std::pair GetFirmwareVersion return {firmware_data, result}; } + +// TODO(crueter): GET AS STRING } -#endif // FIRMWARE_MANAGER_H +#endif diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index d6ef427ba6..0c9bb54b11 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) + add_library(qt_common STATIC qt_common.h qt_common.cpp @@ -15,10 +17,12 @@ add_library(qt_common STATIC shared_translation.h qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp + qt_frontend_util.h qt_frontend_util.cpp ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 54c79c93e1..c7b75a196d 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -5,6 +5,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "core/hle/service/filesystem/filesystem.h" +#include "frontend_common/firmware_manager.h" #include "uisettings.h" #include @@ -13,6 +14,10 @@ #include "core/frontend/emu_window.h" #include + +#include +#include "qt_frontend_util.h" + #include #if !defined(WIN32) && !defined(__APPLE__) @@ -22,7 +27,6 @@ #endif namespace QtCommon { - MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) @@ -87,8 +91,24 @@ FirmwareInstallResult InstallFirmware( bool recursive, std::function QtProgressCallback, Core::System* system, - FileSys::VfsFilesystem* vfs) + FileSys::VfsFilesystem* vfs, + QWidget* parent) { + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + parent); + }; + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in @@ -121,14 +141,20 @@ FirmwareInstallResult InstallFirmware( } if (out.size() <= 0) { - return FirmwareInstallResult::NoNCAs; + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - return FirmwareInstallResult::FailedDelete; + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } LOG_INFO(Frontend, @@ -159,17 +185,35 @@ FirmwareInstallResult InstallFirmware( 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - return FirmwareInstallResult::FailedCorrupted; + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } } if (!success) { - return FirmwareInstallResult::FailedCopy; + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } // Re-scan VFS for the newly placed firmware files. system->GetFileSystemController().CreateFactories(*vfs); - return FirmwareInstallResult::Success; + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::ShowMessage(QMessageBox::Information, + qApp->tr(successTitle), + qApp->tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons, + parent); + return result; } QString UnzipFirmwareToTmp(const QString& location) @@ -195,5 +239,4 @@ QString UnzipFirmwareToTmp(const QString& location) return qCacheDir; } - } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index b3ca99e65a..ef9b5577f1 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -13,7 +13,6 @@ #include namespace QtCommon { - static constexpr std::array METADATA_RESULTS = { "The operation completed successfully.", "The metadata cache couldn't be deleted. It might be in use or non-existent.", @@ -41,15 +40,14 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } -static constexpr std::array FIRMWARE_RESULTS = { - "", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware." -}; +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; enum class FirmwareInstallResult { Success, @@ -60,11 +58,13 @@ enum class FirmwareInstallResult { FailedCorrupted, }; -FirmwareInstallResult InstallFirmware(const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs); +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs, + QWidget *parent = nullptr); QString UnzipFirmwareToTmp(const QString &location); @@ -75,8 +75,6 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul Core::Frontend::WindowSystemType GetWindowSystemType(); -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); - - +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); } // namespace QtCommon #endif diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp new file mode 100644 index 0000000000..6cbe82e000 --- /dev/null +++ b/src/qt_common/qt_frontend_util.cpp @@ -0,0 +1,25 @@ +#include "qt_frontend_util.h" + +namespace QtCommon::Frontend { +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ +#ifdef YUZU_QT_WIDGETS + QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + return static_cast(box->exec()); +#endif +} + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ + return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); +} + +} // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h new file mode 100644 index 0000000000..8508e29f18 --- /dev/null +++ b/src/qt_common/qt_frontend_util.h @@ -0,0 +1,29 @@ +#ifndef QT_FRONTEND_UTIL_H +#define QT_FRONTEND_UTIL_H + +#include +#include + +#ifdef YUZU_QT_WIDGETS +#include +#endif + +/** + * manages common functionality e.g. message boxes and such for Qt/QML + */ +namespace QtCommon::Frontend { +Q_NAMESPACE + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); +} // namespace QtCommon::Frontend +#endif // QT_FRONTEND_UTIL_H diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 86e0755ce8..19110781bf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2611,6 +2611,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } +// TODO(crueter): Transfer ts to showmessage void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); @@ -2680,6 +2681,8 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& } // TODO(crueter): All this can be transfered to qt_common +// Aldoe I need to decide re: message boxes for QML +// translations_common? strings_common? qt_strings? who knows QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { switch (type) { case InstalledEntryType::Game: @@ -4218,28 +4221,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); - const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); progress.close(); - QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); - - switch (result) { - case QtCommon::FirmwareInstallResult::NoNCAs: - case QtCommon::FirmwareInstallResult::FailedCorrupted: - box->setIcon(QMessageBox::Icon::Warning); - box->exec(); - return; - case QtCommon::FirmwareInstallResult::FailedCopy: - case QtCommon::FirmwareInstallResult::FailedDelete: - box->setIcon(QMessageBox::Icon::Critical); - box->exec(); - return; - default: - box->deleteLater(); - break; - } + if (result != QtCommon::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); From 092e645296a7f79b5428347124e41dbe61231ece Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 21:12:22 -0400 Subject: [PATCH 10/52] Fix license headers --- src/qt_common/qt_frontend_util.cpp | 3 +++ src/qt_common/qt_frontend_util.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 6cbe82e000..9a05c89928 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_frontend_util.h" namespace QtCommon::Frontend { diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 8508e29f18..8a38c033bf 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_FRONTEND_UTIL_H #define QT_FRONTEND_UTIL_H From 75f18095e0616b805daea98d932f74c415644e2c Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 7 Aug 2025 20:45:16 -0400 Subject: [PATCH 11/52] [qt_common] update translations Signed-off-by: crueter --- src/qt_common/qt_frontend_util.cpp | 2 + src/qt_common/qt_game_util.cpp | 20 ++--- src/qt_common/qt_game_util.h | 4 +- src/qt_common/shared_translation.cpp | 110 +++++++++++++-------------- 4 files changed, 70 insertions(+), 66 deletions(-) diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 9a05c89928..bcb662239b 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -14,6 +14,8 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); return static_cast(box->exec()); #endif + // TODO(crueter): If Qt Widgets is disabled... + // need a way to reference icon/buttons too } QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index add9d46a39..a870c2ab27 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -146,33 +146,33 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_ return true; } -void OpenRootDataFolder() { +void OpenEdenFolder(const Common::FS::EdenPath& path) { QDesktopServices::openUrl(QUrl( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); + QString::fromStdString(Common::FS::GetEdenPathString(path)))); +} + +void OpenRootDataFolder() { + OpenEdenFolder(Common::FS::EdenPath::EdenDir); } void OpenNANDFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); + OpenEdenFolder(Common::FS::EdenPath::NANDDir); } void OpenSDMCFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); + OpenEdenFolder(Common::FS::EdenPath::SDMCDir); } void OpenModFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); + OpenEdenFolder(Common::FS::EdenPath::LoadDir); } void OpenLogFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); + OpenEdenFolder(Common::FS::EdenPath::LogDir); } } diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 3d27839672..12916d8a98 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -4,6 +4,7 @@ #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H +#include "common/fs/path_util.h" #include "frontend_common/content_manager.h" #include @@ -12,7 +13,7 @@ namespace QtCommon { static constexpr std::array GAME_VERIFICATION_RESULTS = { "The operation completed successfully.", "File contents may be corrupt or missing..", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Firmware installation cancelled, firmware may be in a bad state or corrupted. " "File contents could not be checked for validity." }; @@ -34,6 +35,7 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, std::filesystem::path& out_icon_path); +void OpenEdenFolder(const Common::FS::EdenPath &path); void OpenRootDataFolder(); void OpenNANDFolder(); void OpenSDMCFolder(); diff --git a/src/qt_common/shared_translation.cpp b/src/qt_common/shared_translation.cpp index 018af56c67..81ec35b6d8 100644 --- a/src/qt_common/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -29,10 +29,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) #define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) - // A setting can be ignored by giving it a blank name + // A setting can be ignored by giving it a blank name - // Applets - INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); + // Applets + INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); INSERT(Settings, error_applet_mode, tr("Error"), QString()); @@ -648,58 +648,58 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) translations->insert( {Settings::EnumMetadata::Index(), { - {static_cast(Settings::TimeZone::Auto), - tr("Auto (%1)", "Auto select time zone") - .arg(QString::fromStdString( - Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, - {static_cast(Settings::TimeZone::Default), - tr("Default (%1)", "Default time zone") - .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, - PAIR(TimeZone, Cet, tr("CET")), - PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), - PAIR(TimeZone, Cuba, tr("Cuba")), - PAIR(TimeZone, Eet, tr("EET")), - PAIR(TimeZone, Egypt, tr("Egypt")), - PAIR(TimeZone, Eire, tr("Eire")), - PAIR(TimeZone, Est, tr("EST")), - PAIR(TimeZone, Est5Edt, tr("EST5EDT")), - PAIR(TimeZone, Gb, tr("GB")), - PAIR(TimeZone, GbEire, tr("GB-Eire")), - PAIR(TimeZone, Gmt, tr("GMT")), - PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), - PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), - PAIR(TimeZone, GmtZero, tr("GMT0")), - PAIR(TimeZone, Greenwich, tr("Greenwich")), - PAIR(TimeZone, Hongkong, tr("Hongkong")), - PAIR(TimeZone, Hst, tr("HST")), - PAIR(TimeZone, Iceland, tr("Iceland")), - PAIR(TimeZone, Iran, tr("Iran")), - PAIR(TimeZone, Israel, tr("Israel")), - PAIR(TimeZone, Jamaica, tr("Jamaica")), - PAIR(TimeZone, Japan, tr("Japan")), - PAIR(TimeZone, Kwajalein, tr("Kwajalein")), - PAIR(TimeZone, Libya, tr("Libya")), - PAIR(TimeZone, Met, tr("MET")), - PAIR(TimeZone, Mst, tr("MST")), - PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), - PAIR(TimeZone, Navajo, tr("Navajo")), - PAIR(TimeZone, Nz, tr("NZ")), - PAIR(TimeZone, NzChat, tr("NZ-CHAT")), - PAIR(TimeZone, Poland, tr("Poland")), - PAIR(TimeZone, Portugal, tr("Portugal")), - PAIR(TimeZone, Prc, tr("PRC")), - PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), - PAIR(TimeZone, Roc, tr("ROC")), - PAIR(TimeZone, Rok, tr("ROK")), - PAIR(TimeZone, Singapore, tr("Singapore")), - PAIR(TimeZone, Turkey, tr("Turkey")), - PAIR(TimeZone, Uct, tr("UCT")), - PAIR(TimeZone, Universal, tr("Universal")), - PAIR(TimeZone, Utc, tr("UTC")), - PAIR(TimeZone, WSu, tr("W-SU")), - PAIR(TimeZone, Wet, tr("WET")), - PAIR(TimeZone, Zulu, tr("Zulu")), - }}); + {static_cast(Settings::TimeZone::Auto), + tr("Auto (%1)", "Auto select time zone") + .arg(QString::fromStdString( + Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, + {static_cast(Settings::TimeZone::Default), + tr("Default (%1)", "Default time zone") + .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, + PAIR(TimeZone, Cet, tr("CET")), + PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), + PAIR(TimeZone, Cuba, tr("Cuba")), + PAIR(TimeZone, Eet, tr("EET")), + PAIR(TimeZone, Egypt, tr("Egypt")), + PAIR(TimeZone, Eire, tr("Eire")), + PAIR(TimeZone, Est, tr("EST")), + PAIR(TimeZone, Est5Edt, tr("EST5EDT")), + PAIR(TimeZone, Gb, tr("GB")), + PAIR(TimeZone, GbEire, tr("GB-Eire")), + PAIR(TimeZone, Gmt, tr("GMT")), + PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), + PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), + PAIR(TimeZone, GmtZero, tr("GMT0")), + PAIR(TimeZone, Greenwich, tr("Greenwich")), + PAIR(TimeZone, Hongkong, tr("Hongkong")), + PAIR(TimeZone, Hst, tr("HST")), + PAIR(TimeZone, Iceland, tr("Iceland")), + PAIR(TimeZone, Iran, tr("Iran")), + PAIR(TimeZone, Israel, tr("Israel")), + PAIR(TimeZone, Jamaica, tr("Jamaica")), + PAIR(TimeZone, Japan, tr("Japan")), + PAIR(TimeZone, Kwajalein, tr("Kwajalein")), + PAIR(TimeZone, Libya, tr("Libya")), + PAIR(TimeZone, Met, tr("MET")), + PAIR(TimeZone, Mst, tr("MST")), + PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), + PAIR(TimeZone, Navajo, tr("Navajo")), + PAIR(TimeZone, Nz, tr("NZ")), + PAIR(TimeZone, NzChat, tr("NZ-CHAT")), + PAIR(TimeZone, Poland, tr("Poland")), + PAIR(TimeZone, Portugal, tr("Portugal")), + PAIR(TimeZone, Prc, tr("PRC")), + PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), + PAIR(TimeZone, Roc, tr("ROC")), + PAIR(TimeZone, Rok, tr("ROK")), + PAIR(TimeZone, Singapore, tr("Singapore")), + PAIR(TimeZone, Turkey, tr("Turkey")), + PAIR(TimeZone, Uct, tr("UCT")), + PAIR(TimeZone, Universal, tr("Universal")), + PAIR(TimeZone, Utc, tr("UTC")), + PAIR(TimeZone, WSu, tr("W-SU")), + PAIR(TimeZone, Wet, tr("WET")), + PAIR(TimeZone, Zulu, tr("Zulu")), + }}); translations->insert({Settings::EnumMetadata::Index(), { PAIR(AudioMode, Mono, tr("Mono")), From ca349ad7b0cc50c87548b5c41e1e108568183ad5 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:48:13 -0400 Subject: [PATCH 12/52] [qt_common] reorg, move more stuff out of main Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 5 + src/qt_common/qt_common.cpp | 175 +------- src/qt_common/qt_common.h | 76 +--- src/qt_common/qt_content_util.cpp | 202 +++++++++ src/qt_common/qt_content_util.h | 48 +++ src/qt_common/qt_frontend_util.cpp | 73 +++- src/qt_common/qt_frontend_util.h | 44 +- src/qt_common/qt_game_util.cpp | 270 ++++++++++-- src/qt_common/qt_game_util.h | 40 +- src/qt_common/qt_meta.cpp | 72 ++++ src/qt_common/qt_meta.h | 12 + src/qt_common/qt_path_util.cpp | 9 +- src/qt_common/qt_path_util.h | 4 +- src/qt_common/qt_rom_util.cpp | 75 ++++ src/qt_common/qt_rom_util.h | 17 + .../configuration/configure_filesystem.cpp | 13 +- src/yuzu/game_list.cpp | 25 +- src/yuzu/game_list.h | 19 +- src/yuzu/main.cpp | 403 +++--------------- src/yuzu/main.h | 21 +- 20 files changed, 923 insertions(+), 680 deletions(-) create mode 100644 src/qt_common/qt_content_util.cpp create mode 100644 src/qt_common/qt_content_util.h create mode 100644 src/qt_common/qt_meta.cpp create mode 100644 src/qt_common/qt_meta.h create mode 100644 src/qt_common/qt_rom_util.cpp create mode 100644 src/qt_common/qt_rom_util.h diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 0c9bb54b11..da6c9b0481 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -18,11 +19,15 @@ add_library(qt_common STATIC qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp qt_frontend_util.h qt_frontend_util.cpp + qt_meta.h qt_meta.cpp + qt_content_util.h qt_content_util.cpp + qt_rom_util.h qt_rom_util.cpp ) create_target_directory_groups(qt_common) target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) target_link_libraries(qt_common PRIVATE Qt6::Core) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index c7b75a196d..6f8808ca32 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -2,11 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_common.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "frontend_common/firmware_manager.h" -#include "uisettings.h" #include #include @@ -16,7 +11,6 @@ #include #include -#include "qt_frontend_util.h" #include @@ -27,19 +21,9 @@ #endif namespace QtCommon { -MetadataResult ResetMetadata() -{ - if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) - / "game_list/")) { - return MetadataResult::Empty; - } else if (Common::FS::RemoveDirRecursively( - Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return MetadataResult::Success; - UISettings::values.is_game_list_reload_pending.exchange(true); - } else { - return MetadataResult::Failure; - } -} + +QObject *rootObject = nullptr; +Core::System *system = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -86,157 +70,14 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -FirmwareInstallResult InstallFirmware( - const QString& location, - bool recursive, - std::function QtProgressCallback, - Core::System* system, - FileSys::VfsFilesystem* vfs, - QWidget* parent) +const QString tr(const char* str) { - static constexpr const char* failedTitle = "Firmware Install Failed"; - static constexpr const char* successTitle = "Firmware Install Failed"; - static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; - - QMessageBox::Icon icon; - FirmwareInstallResult result; - - const auto ShowMessage = [&]() { - QtCommon::Frontend::ShowMessage(icon, - failedTitle, - GetFirmwareInstallResultString(result), - buttons, - parent); - }; - - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); - - // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in - // there.) - std::filesystem::path firmware_source_path = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - return FirmwareInstallResult::NoOp; - } - - std::vector out; - const Common::FS::DirEntryCallable callback = - [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") { - out.emplace_back(entry.path()); - } - - return true; - }; - - QtProgressCallback(100, 10); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } else { - Common::FS::IterateDirEntries(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } - - if (out.size() <= 0) { - result = FirmwareInstallResult::NoNCAs; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - - // Locate and erase the content of nand/system/Content/registered/*.nca, if any. - auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (sysnand_content_vdir->IsWritable() - && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - result = FirmwareInstallResult::FailedDelete; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - LOG_INFO(Frontend, - "Cleaned nand/system/Content/registered folder in preparation for new firmware."); - - QtProgressCallback(100, 20); - - auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); - - bool success = true; - int i = 0; - for (const auto& firmware_src_path : out) { - i++; - auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), - FileSys::OpenMode::Read); - auto firmware_dst_vfile = firmware_vdir - ->CreateFileRelative(firmware_src_path.filename().string()); - - if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { - LOG_ERROR(Frontend, - "Failed to copy firmware file {} to {} in registered folder!", - firmware_src_path.generic_string(), - firmware_src_path.filename().string()); - success = false; - } - - if (QtProgressCallback(100, - 20 - + static_cast(((i) / static_cast(out.size())) - * 70.0))) { - result = FirmwareInstallResult::FailedCorrupted; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - } - - if (!success) { - result = FirmwareInstallResult::FailedCopy; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - // Re-scan VFS for the newly placed firmware files. - system->GetFileSystemController().CreateFactories(*vfs); - - const auto pair = FirmwareManager::GetFirmwareVersion(*system); - const auto firmware_data = pair.first; - const std::string display_version(firmware_data.display_version.data()); - - result = FirmwareInstallResult::Success; - QtCommon::Frontend::ShowMessage(QMessageBox::Information, - qApp->tr(successTitle), - qApp->tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version)), - buttons, - parent); - return result; + return QGuiApplication::tr(str); } -QString UnzipFirmwareToTmp(const QString& location) +const QString tr(const std::string& str) { - namespace fs = std::filesystem; - fs::path tmp{fs::temp_directory_path()}; - - if (!fs::create_directories(tmp / "eden" / "firmware")) { - return ""; - } - - tmp /= "eden"; - tmp /= "firmware"; - - QString qCacheDir = QString::fromStdString(tmp.string()); - - QFile zip(location); - - QStringList result = JlCompress::extractDir(&zip, qCacheDir); - if (result.isEmpty()) { - return ""; - } - - return qCacheDir; + return QGuiApplication::tr(str.c_str()); } + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index ef9b5577f1..cf52cedc32 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,8 +4,6 @@ #ifndef QT_COMMON_H #define QT_COMMON_H -#include - #include #include "core/core.h" #include @@ -13,68 +11,28 @@ #include namespace QtCommon { -static constexpr std::array METADATA_RESULTS = { - "The operation completed successfully.", - "The metadata cache couldn't be deleted. It might be in use or non-existent.", - "The metadata cache is already empty.", -}; -enum class MetadataResult { - Success, - Failure, - Empty, -}; -/** - * @brief ResetMetadata Reset game list metadata. - * @return A result code. - */ -MetadataResult ResetMetadata(); +extern QObject *rootObject; +extern Core::System *system; -/** - * \brief Get a string representation of a result from ResetMetadata. - * \param result The result code. - * \return A string representation of the passed result code. - */ -inline constexpr const char *GetResetMetadataResultString(MetadataResult result) -{ - return METADATA_RESULTS.at(static_cast(result)); -} - -static constexpr std::array FIRMWARE_RESULTS - = {"Successfully installed firmware version %1", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware."}; - -enum class FirmwareInstallResult { - Success, - NoOp, - NoNCAs, - FailedDelete, - FailedCopy, - FailedCorrupted, -}; - -FirmwareInstallResult InstallFirmware( - const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs, - QWidget *parent = nullptr); - -QString UnzipFirmwareToTmp(const QString &location); - -inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) -{ - return FIRMWARE_RESULTS.at(static_cast(result)); -} +typedef std::function QtProgressCallback; Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); + +static inline void SetRootObject(QObject *parent) +{ + rootObject = parent; +} + +static inline void SetSystem(Core::System *newSystem) +{ + system = newSystem; +} + +const QString tr(const char *str); +const QString tr(const std::string &str); + } // namespace QtCommon #endif diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp new file mode 100644 index 0000000000..81ec7c9cea --- /dev/null +++ b/src/qt_common/qt_content_util.cpp @@ -0,0 +1,202 @@ +#include "qt_content_util.h" +#include "common/fs/fs.h" +#include "frontend_common/content_manager.h" +#include "frontend_common/firmware_manager.h" +#include "qt_common/qt_game_util.h" +#include "qt_frontend_util.h" + +#include + +namespace QtCommon::Content { + +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent) +{ + if (FirmwareManager::GameRequiresFirmware(program_id) + && !FirmwareManager::CheckFirmwarePresence(system)) { + auto result = QtCommon::Frontend::ShowMessage( + QMessageBox::Warning, + "Game Requires Firmware", + "The game you are trying to launch requires firmware to boot or to get past the " + "opening menu. Please " + "dump and install firmware, or press \"OK\" to launch anyways.", + QMessageBox::Ok | QMessageBox::Cancel, + parent); + + return result == QMessageBox::Ok; + } + + return true; +} + +FirmwareInstallResult InstallFirmware( + const QString& location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem* vfs) +{ + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + rootObject); + }; + + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector out; + const Common::FS::DirEntryCallable dir_callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") { + out.emplace_back(entry.path()); + } + + return true; + }; + + callback(100, 10); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (sysnand_content_vdir->IsWritable() + && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + callback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), + FileSys::OpenMode::Read); + auto firmware_dst_vfile = firmware_vdir + ->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, + "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), + firmware_src_path.filename().string()); + success = false; + } + + if (callback(100, 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + } + + if (!success) { + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::Information(rootObject, + tr(successTitle), + tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons); + return result; +} + +QString UnzipFirmwareToTmp(const QString& location) +{ + namespace fs = std::filesystem; + fs::path tmp{fs::temp_directory_path()}; + + if (!fs::create_directories(tmp / "eden" / "firmware")) { + return ""; + } + + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + return ""; + } + + return qCacheDir; +} + +// Content // +void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) { + const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); + + switch (result) { + case ContentManager::GameVerificationResult::Success: + QtCommon::Frontend::Information(rootObject, tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + break; + case ContentManager::GameVerificationResult::Failed: + QtCommon::Frontend::Critical(rootObject, tr("Integrity verification failed!"), + tr("File contents may be corrupt or missing.")); + break; + case ContentManager::GameVerificationResult::NotImplemented: + QtCommon::Frontend::Warning( + rootObject, + tr("Integrity verification couldn't be performed"), + tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " + "File contents could not be checked for validity.")); + } +} + + +} diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h new file mode 100644 index 0000000000..9a1a4e5bc2 --- /dev/null +++ b/src/qt_common/qt_content_util.h @@ -0,0 +1,48 @@ +#ifndef QT_CONTENT_UTIL_H +#define QT_CONTENT_UTIL_H + +#include +#include "common/common_types.h" +#include "core/core.h" +#include "qt_common/qt_common.h" + +namespace QtCommon::Content { + +// +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent); + +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem *vfs); + +QString UnzipFirmwareToTmp(const QString &location); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + +// Content // +void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); +} +#endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index bcb662239b..6b96a26a21 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -4,27 +4,84 @@ #include "qt_frontend_util.h" namespace QtCommon::Frontend { + QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, - QWidget *parent) + QObject *parent) { #ifdef YUZU_QT_WIDGETS - QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + QMessageBox *box = new QMessageBox(icon, title, text, buttons, (QWidget *) parent); return static_cast(box->exec()); #endif // TODO(crueter): If Qt Widgets is disabled... // need a way to reference icon/buttons too } -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons, - QWidget *parent) +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) { - return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); + return ShowMessage(QMessageBox::Information, title, text, buttons, parent); } +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, title, text, buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, title, text, buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, title, text, buttons, parent); +} + +QMessageBox::StandardButton Information(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Information, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, parent->tr(title), parent->tr(text), buttons, parent); +} + + } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 8a38c033bf..a91a0db07b 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -17,16 +17,52 @@ namespace QtCommon::Frontend { Q_NAMESPACE +// TODO(crueter) widgets-less impl, choices et al. QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QObject *parent = nullptr); -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Information(QObject *parent, const char *title, const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index a870c2ab27..488eb8c971 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -4,40 +4,50 @@ #include "qt_game_util.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/file_sys/savedata_factory.h" +#include "frontend_common/content_manager.h" +#include "qt_common.h" +#include "qt_common/uisettings.h" +#include "qt_frontend_util.h" #include #include #ifdef _WIN32 - #include - #include - #include "common/scope_exit.h" - #include "common/string_util.h" +#include "common/scope_exit.h" +#include "common/string_util.h" +#include +#include #else - #include "fmt/ostream.h" - #include +#include "fmt/ostream.h" +#include #endif -namespace QtCommon { +namespace QtCommon::Game { bool CreateShortcutLink(const std::filesystem::path& shortcut_path, - const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, + const std::string& categories, + const std::string& keywords, + const std::string& name) +try { #ifdef _WIN32 // Windows HRESULT hr = CoInitialize(nullptr); if (FAILED(hr)) { LOG_ERROR(Frontend, "CoInitialize failed"); return false; } - SCOPE_EXIT { + SCOPE_EXIT + { CoUninitialize(); }; IShellLinkW* ps1 = nullptr; IPersistFile* persist_file = nullptr; - SCOPE_EXIT { + SCOPE_EXIT + { if (persist_file != nullptr) { persist_file->Release(); } @@ -45,7 +55,10 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, ps1->Release(); } }; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + HRESULT hres = CoCreateInstance(CLSID_ShellLink, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IShellLinkW, reinterpret_cast(&ps1)); if (FAILED(hres)) { LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); @@ -115,17 +128,18 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, fmt::print(shortcut_stream, "Keywords={}\n", keywords); } return true; -#else // Unsupported platform +#else // Unsupported platform return false; #endif -} - catch (const std::exception& e) { +} catch (const std::exception& e) { LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); return false; } -bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path) { +bool MakeShortcutIcoPath(const u64 program_id, + const std::string_view game_file_name, + std::filesystem::path& out_icon_path) +{ // Get path to Yuzu icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) @@ -146,12 +160,13 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_ return true; } -void OpenEdenFolder(const Common::FS::EdenPath& path) { - QDesktopServices::openUrl(QUrl( - QString::fromStdString(Common::FS::GetEdenPathString(path)))); +void OpenEdenFolder(const Common::FS::EdenPath& path) +{ + QDesktopServices::openUrl(QUrl(QString::fromStdString(Common::FS::GetEdenPathString(path)))); } -void OpenRootDataFolder() { +void OpenRootDataFolder() +{ OpenEdenFolder(Common::FS::EdenPath::EdenDir); } @@ -175,4 +190,211 @@ void OpenLogFolder() OpenEdenFolder(Common::FS::EdenPath::LogDir); } +static QString GetGameListErrorRemoving(QtCommon::Game::InstalledEntryType type) +{ + switch (type) { + case QtCommon::Game::InstalledEntryType::Game: + return tr("Error Removing Contents"); + case QtCommon::Game::InstalledEntryType::Update: + return tr("Error Removing Update"); + case QtCommon::Game::InstalledEntryType::AddOnContent: + return tr("Error Removing DLC"); + default: + return QStringLiteral("Error Removing "); + } } + +// Game Content // +void RemoveBaseContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveBaseContent(system->GetFileSystemController(), + program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed base game."); + } else { + QtCommon::Frontend::Warning( + rootObject, + GetGameListErrorRemoving(type), + tr("The base game is not installed in the NAND and cannot be removed.")); + } +} + +void RemoveUpdateContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed update."); + } else { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There is no update installed for this title.")); + } +} + +void RemoveAddOnContent(u64 program_id, InstalledEntryType type) +{ + const size_t count = ContentManager::RemoveAllDLC(*system, program_id); + if (count == 0) { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There are no DLCs installed for this title.")); + return; + } + + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed %1 installed DLC.").arg(count)); +} + +// Global Content // + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) +{ + const auto target_file_name = [target] { + switch (target) { + case GameListRemoveTarget::GlShaderCache: + return "opengl.bin"; + case GameListRemoveTarget::VkShaderCache: + return "vulkan.bin"; + default: + return ""; + } + }(); + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader cache.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("Failed to remove the transferable shader cache.")); + } +} + +void RemoveVulkanDriverPipelineCache(u64 program_id) +{ + static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; + + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + return; + } + if (!Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Vulkan Driver Pipeline Cache"), + tr("Failed to remove the driver pipeline cache.")); + } +} + +void RemoveAllTransferableShaderCaches(u64 program_id) +{ + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); + + if (!Common::FS::Exists(program_shader_cache_dir)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader caches.")); + } else { + QtCommon::Frontend::Warning( + rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("Failed to remove the transferable shader cache directory.")); + } +} + +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path) +{ + const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); + const auto config_file_name = program_id == 0 + ? Common::FS::PathToUTF8String(file_path.filename()) + .append(".ini") + : fmt::format("{:016X}.ini", program_id); + const auto custom_config_file_path = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) + / "custom" / config_file_name; + + if (!Common::FS::Exists(custom_config_file_path)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("A custom configuration for this title does not exist.")); + return; + } + + if (Common::FS::RemoveFile(custom_config_file_path)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the custom game configuration.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("Failed to remove the custom game configuration.")); + } +} + +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs) +{ + const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); + auto vfs_nand_dir = vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), + FileSys::OpenMode::Read); + + const auto cache_storage_path + = FileSys::SaveDataFactory::GetFullPath({}, + vfs_nand_dir, + FileSys::SaveDataSpaceId::User, + FileSys::SaveDataType::Cache, + 0 /* program_id */, + {}, + 0); + + const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); + + // Not an error if it wasn't cleared. + Common::FS::RemoveDirRecursively(path); +} + +// Metadata // +void ResetMetadata() +{ + const QString title = tr("Reset Metadata Cache"); + + if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) + / "game_list/")) { + QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty.")); + } else if (Common::FS::RemoveDirRecursively( + Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { + QtCommon::Frontend::Information(rootObject, + title, + tr("The operation completed successfully.")); + UISettings::values.is_game_list_reload_pending.exchange(true); + } else { + QtCommon::Frontend::Warning( + rootObject, + title, + tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); + } +} + +} // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 12916d8a98..9861910833 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -4,23 +4,25 @@ #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H +#include #include "common/fs/path_util.h" -#include "frontend_common/content_manager.h" -#include +#include -namespace QtCommon { +namespace QtCommon::Game { -static constexpr std::array GAME_VERIFICATION_RESULTS = { - "The operation completed successfully.", - "File contents may be corrupt or missing..", - "Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "File contents could not be checked for validity." +enum class InstalledEntryType { + Game, + Update, + AddOnContent, }; -inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result) -{ - return GAME_VERIFICATION_RESULTS.at(static_cast(result)); -} +enum class GameListRemoveTarget { + GlShaderCache, + VkShaderCache, + AllShaderCache, + CustomConfiguration, + CacheStorage, +}; bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, @@ -41,6 +43,20 @@ void OpenNANDFolder(); void OpenSDMCFolder(); void OpenModFolder(); void OpenLogFolder(); + +void RemoveBaseContent(u64 program_id, InstalledEntryType type); +void RemoveUpdateContent(u64 program_id, InstalledEntryType type); +void RemoveAddOnContent(u64 program_id, InstalledEntryType type); + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); +void RemoveVulkanDriverPipelineCache(u64 program_id); +void RemoveAllTransferableShaderCaches(u64 program_id); +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); + +// Metadata // +void ResetMetadata(); + } #endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_meta.cpp b/src/qt_common/qt_meta.cpp new file mode 100644 index 0000000000..c972c0fe45 --- /dev/null +++ b/src/qt_common/qt_meta.cpp @@ -0,0 +1,72 @@ +#include "qt_meta.h" +#include "common/common_types.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" + +namespace QtCommon::Meta { + +void RegisterMetaTypes() +{ + // Register integral and floating point types + qRegisterMetaType("u8"); + qRegisterMetaType("u16"); + qRegisterMetaType("u32"); + qRegisterMetaType("u64"); + qRegisterMetaType("u128"); + qRegisterMetaType("s8"); + qRegisterMetaType("s16"); + qRegisterMetaType("s32"); + qRegisterMetaType("s64"); + qRegisterMetaType("f32"); + qRegisterMetaType("f64"); + + // Register string types + qRegisterMetaType("std::string"); + qRegisterMetaType("std::wstring"); + qRegisterMetaType("std::u8string"); + qRegisterMetaType("std::u16string"); + qRegisterMetaType("std::u32string"); + qRegisterMetaType("std::string_view"); + qRegisterMetaType("std::wstring_view"); + qRegisterMetaType("std::u8string_view"); + qRegisterMetaType("std::u16string_view"); + qRegisterMetaType("std::u32string_view"); + + // Register applet types + + // Cabinet Applet + qRegisterMetaType("Core::Frontend::CabinetParameters"); + qRegisterMetaType>( + "std::shared_ptr"); + + // Controller Applet + qRegisterMetaType("Core::Frontend::ControllerParameters"); + + // Profile Select Applet + qRegisterMetaType( + "Core::Frontend::ProfileSelectParameters"); + + // Software Keyboard Applet + qRegisterMetaType( + "Core::Frontend::KeyboardInitializeParameters"); + qRegisterMetaType( + "Core::Frontend::InlineAppearParameters"); + qRegisterMetaType("Core::Frontend::InlineTextParameters"); + qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdTextCheckResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdReplyType"); + + // Web Browser Applet + qRegisterMetaType("Service::AM::Frontend::WebExitReason"); + + // Register loader types + qRegisterMetaType("Core::SystemResultStatus"); +} + +} diff --git a/src/qt_common/qt_meta.h b/src/qt_common/qt_meta.h new file mode 100644 index 0000000000..36cafba2bf --- /dev/null +++ b/src/qt_common/qt_meta.h @@ -0,0 +1,12 @@ +#ifndef QT_META_H +#define QT_META_H + +#include + +namespace QtCommon::Meta { + +// +void RegisterMetaTypes(); + +} +#endif // QT_META_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 6875d01dea..761e6e8405 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -7,17 +7,22 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "qt_common/qt_frontend_util.h" #include -bool QtCommon::PathUtil::OpenShaderCache(u64 program_id) +namespace QtCommon::Path { + +bool OpenShaderCache(u64 program_id, QObject *parent) { const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - return false; + QtCommon::Frontend::ShowMessage(QMessageBox::Warning, "Error Opening Shader Cache", "Failed to create or open shader cache for this title, ensure your app data directory has write permissions.", QMessageBox::Ok, parent); } const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } + +} diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h index 7f399c4bb4..855b06caa9 100644 --- a/src/qt_common/qt_path_util.h +++ b/src/qt_common/qt_path_util.h @@ -5,6 +5,8 @@ #define QT_PATH_UTIL_H #include "common/common_types.h" -namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); } +#include + +namespace QtCommon::Path { bool OpenShaderCache(u64 program_id, QObject *parent); } #endif // QT_PATH_UTIL_H diff --git a/src/qt_common/qt_rom_util.cpp b/src/qt_common/qt_rom_util.cpp new file mode 100644 index 0000000000..e707d1e471 --- /dev/null +++ b/src/qt_common/qt_rom_util.cpp @@ -0,0 +1,75 @@ +#include "qt_rom_util.h" + +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full) +{ + // TODO(crueter) + // if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) + // return false; + // if (dialog.wasCanceled()) + // return false; + + // std::vector buffer(CopyBufferSize); + // auto last_timestamp = std::chrono::steady_clock::now(); + + // const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file, + // const FileSys::VirtualFile& dest_file) { + // if (src_file == nullptr || dest_file == nullptr) { + // return false; + // } + // if (!dest_file->Resize(src_file->GetSize())) { + // return false; + // } + + // for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) { + // if (dialog.wasCanceled()) { + // dest_file->Resize(0); + // return false; + // } + + // using namespace std::literals::chrono_literals; + // const auto new_timestamp = std::chrono::steady_clock::now(); + + // if ((new_timestamp - last_timestamp) > 33ms) { + // last_timestamp = new_timestamp; + // dialog.setValue( + // static_cast(std::min(read_size, total_size) * 100 / total_size)); + // QCoreApplication::processEvents(); + // } + + // const auto read = src_file->Read(buffer.data(), buffer.size(), i); + // dest_file->Write(buffer.data(), read, i); + + // read_size += read; + // } + + // return true; + // }; + + // if (full) { + // for (const auto& file : src->GetFiles()) { + // const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); + // if (!QtRawCopy(file, out)) + // return false; + // } + // } + + // for (const auto& dir : src->GetSubdirectories()) { + // const auto out = dest->CreateSubdirectory(dir->GetName()); + // if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full)) + // return false; + // } + + // return true; + return true; +} + +} diff --git a/src/qt_common/qt_rom_util.h b/src/qt_common/qt_rom_util.h new file mode 100644 index 0000000000..52ebb1e8d0 --- /dev/null +++ b/src/qt_common/qt_rom_util.h @@ -0,0 +1,17 @@ +#ifndef QT_ROM_UTIL_H +#define QT_ROM_UTIL_H + +#include "qt_common/qt_common.h" +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full); + +} +#endif // QT_ROM_UTIL_H diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index d02e6dec2b..d461bd2cc9 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -11,6 +11,7 @@ #include "common/fs/path_util.h" #include "common/settings.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" #include "qt_common/uisettings.h" #include "ui_configure_filesystem.h" @@ -130,17 +131,7 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) } void ConfigureFilesystem::ResetMetadata() { - auto result = QtCommon::ResetMetadata(); - const QString resultMessage = tr(QtCommon::GetResetMetadataResultString(result)); - const QString title = tr("Reset Metadata Cache"); - - switch (result) { - case QtCommon::MetadataResult::Failure: - QMessageBox::warning(this, title, resultMessage); - break; - default: - QMessageBox::information(this, title, resultMessage); - } + QtCommon::Game::ResetMetadata(); } void ConfigureFilesystem::UpdateEnabledControls() { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 0d89dc892e..7c89730651 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include +#include "yuzu/game_list.h" #include #include #include @@ -13,19 +13,20 @@ #include #include #include -#include #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" -#include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" #include "yuzu/main.h" -#include "qt_common/uisettings.h" #include "yuzu/util/controller_navigation.h" +#include +#include GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) : QObject(parent), gamelist{gamelist_} {} @@ -608,30 +609,30 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(open_transferable_shader_cache, &QAction::triggered, [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); connect(remove_all_content, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Game); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Game); }); connect(remove_update, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Update); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Update); }); connect(remove_dlc, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::AddOnContent); }); connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::GlShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::GlShaderCache, path); }); connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::VkShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::VkShaderCache, path); }); connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::AllShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::AllShaderCache, path); }); connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CustomConfiguration, path); }); connect(remove_play_time_data, &QAction::triggered, [this, program_id]() { emit RemovePlayTimeRequested(program_id); }); connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CacheStorage, path); }); connect(dump_romfs, &QAction::triggered, [this, program_id, path]() { emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 328432138c..367d047c40 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -21,6 +21,7 @@ #include "common/common_types.h" #include "core/core.h" #include "qt_common/uisettings.h" +#include "qt_common/qt_game_util.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -46,14 +47,6 @@ enum class GameListOpenTarget { ModData, }; -enum class GameListRemoveTarget { - GlShaderCache, - VkShaderCache, - AllShaderCache, - CustomConfiguration, - CacheStorage, -}; - enum class DumpRomFSTarget { Normal, SDMC, @@ -64,12 +57,6 @@ enum class GameListShortcutTarget { Applications, }; -enum class InstalledEntryType { - Game, - Update, - AddOnContent, -}; - class GameList : public QWidget { Q_OBJECT @@ -118,8 +105,8 @@ signals: void OpenFolderRequested(u64 program_id, GameListOpenTarget target, const std::string& game_path); void OpenTransferableShaderCacheRequested(u64 program_id); - void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); - void RemoveFileRequested(u64 program_id, GameListRemoveTarget target, + void RemoveInstalledEntryRequested(u64 program_id, QtCommon::Game::InstalledEntryType type); + void RemoveFileRequested(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void RemovePlayTimeRequested(u64 program_id); void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 19110781bf..7db448af01 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -14,6 +14,8 @@ #include "qt_common/qt_common.h" #include "qt_common/qt_game_util.h" #include "qt_common/qt_path_util.h" +#include "qt_common/qt_meta.h" +#include "qt_common/qt_content_util.h" #ifdef __APPLE__ #include // for chdir @@ -299,14 +301,6 @@ enum class CalloutFlag : uint32_t { DRDDeprecation = 0x2, }; -/** - * Some games perform worse or straight-up don't work with updates, - * so this tracks which games are bad in this regard. - */ -constexpr std::array bad_update_games{ - 0x0100F2C0115B6000 // Tears of the Kingdom -}; - const int GMainWindow::max_recent_files_item; static void RemoveCachedContents() { @@ -389,6 +383,7 @@ static void OverrideWindowsFont() { #endif #ifndef _WIN32 +// TODO(crueter): carboxyl does this, is it needed in qml? inline static bool isDarkMode() { #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) const auto scheme = QGuiApplication::styleHints()->colorScheme(); @@ -407,6 +402,9 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) input_subsystem{std::make_shared()}, user_data_migrator{this}, vfs{std::make_shared()}, provider{std::make_unique()} { + QtCommon::SetSystem(system.get()); + QtCommon::SetRootObject(this); + Common::FS::CreateEdenPaths(); this->config = std::make_unique(); @@ -463,7 +461,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) Network::Init(); - RegisterMetaTypes(); + QtCommon::Meta::RegisterMetaTypes(); InitializeWidgets(); InitializeDebugWidgets(); @@ -734,65 +732,6 @@ GMainWindow::~GMainWindow() { #endif } -void GMainWindow::RegisterMetaTypes() { - // Register integral and floating point types - qRegisterMetaType("u8"); - qRegisterMetaType("u16"); - qRegisterMetaType("u32"); - qRegisterMetaType("u64"); - qRegisterMetaType("u128"); - qRegisterMetaType("s8"); - qRegisterMetaType("s16"); - qRegisterMetaType("s32"); - qRegisterMetaType("s64"); - qRegisterMetaType("f32"); - qRegisterMetaType("f64"); - - // Register string types - qRegisterMetaType("std::string"); - qRegisterMetaType("std::wstring"); - qRegisterMetaType("std::u8string"); - qRegisterMetaType("std::u16string"); - qRegisterMetaType("std::u32string"); - qRegisterMetaType("std::string_view"); - qRegisterMetaType("std::wstring_view"); - qRegisterMetaType("std::u8string_view"); - qRegisterMetaType("std::u16string_view"); - qRegisterMetaType("std::u32string_view"); - - // Register applet types - - // Cabinet Applet - qRegisterMetaType("Core::Frontend::CabinetParameters"); - qRegisterMetaType>( - "std::shared_ptr"); - - // Controller Applet - qRegisterMetaType("Core::Frontend::ControllerParameters"); - - // Profile Select Applet - qRegisterMetaType( - "Core::Frontend::ProfileSelectParameters"); - - // Software Keyboard Applet - qRegisterMetaType( - "Core::Frontend::KeyboardInitializeParameters"); - qRegisterMetaType( - "Core::Frontend::InlineAppearParameters"); - qRegisterMetaType("Core::Frontend::InlineTextParameters"); - qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdTextCheckResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdReplyType"); - - // Web Browser Applet - qRegisterMetaType("Service::AM::Frontend::WebExitReason"); - - // Register loader types - qRegisterMetaType("Core::SystemResultStatus"); -} - void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr nfp_device) { cabinet_applet = @@ -1634,8 +1573,9 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory); connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); - connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, - &GMainWindow::OnTransferableShaderCacheOpenFile); + connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, [this](u64 program_id) { + QtCommon::Path::OpenShaderCache(program_id, this); + }); connect(game_list, &GameList::RemoveInstalledEntryRequested, this, &GMainWindow::OnGameListRemoveInstalledEntry); connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile); @@ -1970,74 +1910,10 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa nullptr, // Net Connect }); - /** Game Updates check */ + /** firmware check */ - // yuzu's configuration doesn't actually support lists so this is a bit hacky - QSettings settings; - QStringList currentIgnored = settings.value("ignoredBadUpdates", {}).toStringList(); - - if (std::find(bad_update_games.begin(), bad_update_games.end(), params.program_id) != - bad_update_games.end() && - !currentIgnored.contains(QString::number(params.program_id))) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Updates Warning")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch is known to have performance or booting " - "issues when updates are applied. Please try increasing the memory layout to " - "6GB or 8GB if any issues occur.

Press \"OK\" to continue launching, or " - "\"Cancel\" to cancel the launch.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - QCheckBox* dontShowAgain = new QCheckBox(msg); - dontShowAgain->setText(tr("Don't show again for this game")); - msg->setCheckBox(dontShowAgain); - - int result = msg->exec(); - - // wtf - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - if (dontShowAgain->isChecked()) { - currentIgnored << QString::number(params.program_id); - settings.setValue("ignoredBadUpdates", currentIgnored); - settings.sync(); - } - break; - } - } - - if (FirmwareManager::GameRequiresFirmware(params.program_id) && - !FirmwareManager::CheckFirmwarePresence(*system)) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Requires Firmware")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch requires firmware to boot or to get past the " - "opening menu. Please " - "dump and install firmware, or press \"OK\" to launch anyways.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - int exec_result = msg->exec(); - - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)exec_result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - break; - } + if (!QtCommon::Content::CheckGameFirmware(params.program_id, *system, this)) { + return false; } if (!OnCheckNcaVerification()) { @@ -2459,6 +2335,7 @@ void GMainWindow::ShutdownGame() { return; } + // TODO(crueter): make this common as well (frontend_common?) play_time_manager->Stop(); OnShutdownBegin(); OnEmulationStopTimeExpired(); @@ -2503,6 +2380,7 @@ void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { BootGame(game_path, params); } +// TODO(crueter): Common profile selector void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path) { std::filesystem::path path; @@ -2611,13 +2489,6 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } -// TODO(crueter): Transfer ts to showmessage -void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { - if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { - QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); - } -} - static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest, bool full) { @@ -2683,26 +2554,14 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& // TODO(crueter): All this can be transfered to qt_common // Aldoe I need to decide re: message boxes for QML // translations_common? strings_common? qt_strings? who knows -QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { - switch (type) { - case InstalledEntryType::Game: - return tr("Error Removing Contents"); - case InstalledEntryType::Update: - return tr("Error Removing Update"); - case InstalledEntryType::AddOnContent: - return tr("Error Removing DLC"); - default: - return QStringLiteral("Error Removing "); - } -} -void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) { +void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type) { const QString entry_question = [type] { switch (type) { - case InstalledEntryType::Game: + case QtCommon::Game::InstalledEntryType::Game: return tr("Remove Installed Game Contents?"); - case InstalledEntryType::Update: + case QtCommon::Game::InstalledEntryType::Update: return tr("Remove Installed Game Update?"); - case InstalledEntryType::AddOnContent: + case QtCommon::Game::InstalledEntryType::AddOnContent: return tr("Remove Installed Game DLC?"); default: return QStringLiteral("Remove Installed Game ?"); @@ -2714,18 +2573,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT return; } + // TODO(crueter): move this to QtCommon (populate async?) switch (type) { - case InstalledEntryType::Game: - RemoveBaseContent(program_id, type); + case QtCommon::Game::InstalledEntryType::Game: + QtCommon::Game::RemoveBaseContent(program_id, type); [[fallthrough]]; - case InstalledEntryType::Update: - RemoveUpdateContent(program_id, type); - if (type != InstalledEntryType::Game) { + case QtCommon::Game::InstalledEntryType::Update: + QtCommon::Game::RemoveUpdateContent(program_id, type); + if (type != QtCommon::Game::InstalledEntryType::Game) { break; } [[fallthrough]]; - case InstalledEntryType::AddOnContent: - RemoveAddOnContent(program_id, type); + case QtCommon::Game::InstalledEntryType::AddOnContent: + QtCommon::Game::RemoveAddOnContent(program_id, type); break; } Common::FS::RemoveDirRecursively(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / @@ -2733,55 +2593,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { - const auto res = - ContentManager::RemoveBaseContent(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed base game.")); - } else { - QMessageBox::warning( - this, GetGameListErrorRemoving(type), - tr("The base game is not installed in the NAND and cannot be removed.")); - } -} - -void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { - const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed update.")); - } else { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There is no update installed for this title.")); - } -} - -void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { - const size_t count = ContentManager::RemoveAllDLC(*system, program_id); - if (count == 0) { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There are no DLC installed for this title.")); - return; - } - - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed %1 installed DLC.").arg(count)); -} - -void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, +void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path) { const QString question = [target] { switch (target) { - case GameListRemoveTarget::GlShaderCache: + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: return tr("Delete OpenGL Transferable Shader Cache?"); - case GameListRemoveTarget::VkShaderCache: + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: return tr("Delete Vulkan Transferable Shader Cache?"); - case GameListRemoveTarget::AllShaderCache: + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: return tr("Delete All Transferable Shader Caches?"); - case GameListRemoveTarget::CustomConfiguration: + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: return tr("Remove Custom Game Configuration?"); - case GameListRemoveTarget::CacheStorage: + case QtCommon::Game::GameListRemoveTarget::CacheStorage: return tr("Remove Cache Storage?"); default: return QString{}; @@ -2794,20 +2618,20 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ } switch (target) { - case GameListRemoveTarget::VkShaderCache: - RemoveVulkanDriverPipelineCache(program_id); + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: + QtCommon::Game::RemoveVulkanDriverPipelineCache(program_id); [[fallthrough]]; - case GameListRemoveTarget::GlShaderCache: - RemoveTransferableShaderCache(program_id, target); + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: + QtCommon::Game::RemoveTransferableShaderCache(program_id, target); break; - case GameListRemoveTarget::AllShaderCache: - RemoveAllTransferableShaderCaches(program_id); + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: + QtCommon::Game::RemoveAllTransferableShaderCaches(program_id); break; - case GameListRemoveTarget::CustomConfiguration: - RemoveCustomConfiguration(program_id, game_path); + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: + QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; - case GameListRemoveTarget::CacheStorage: - RemoveCacheStorage(program_id); + case QtCommon::Game::GameListRemoveTarget::CacheStorage: + QtCommon::Game::RemoveCacheStorage(program_id, vfs.get()); break; } } @@ -2823,107 +2647,6 @@ void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) { game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) { - const auto target_file_name = [target] { - switch (target) { - case GameListRemoveTarget::GlShaderCache: - return "opengl.bin"; - case GameListRemoveTarget::VkShaderCache: - return "vulkan.bin"; - default: - return ""; - } - }(); - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveFile(target_file)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader cache.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("Failed to remove the transferable shader cache.")); - } -} - -void GMainWindow::RemoveVulkanDriverPipelineCache(u64 program_id) { - static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; - - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - return; - } - if (!Common::FS::RemoveFile(target_file)) { - QMessageBox::warning(this, tr("Error Removing Vulkan Driver Pipeline Cache"), - tr("Failed to remove the driver pipeline cache.")); - } -} - -void GMainWindow::RemoveAllTransferableShaderCaches(u64 program_id) { - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); - - if (!Common::FS::Exists(program_shader_cache_dir)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader caches.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("Failed to remove the transferable shader cache directory.")); - } -} - -void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& game_path) { - const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); - const auto config_file_name = - program_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()).append(".ini") - : fmt::format("{:016X}.ini", program_id); - const auto custom_config_file_path = - Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "custom" / config_file_name; - - if (!Common::FS::Exists(custom_config_file_path)) { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("A custom configuration for this title does not exist.")); - return; - } - - if (Common::FS::RemoveFile(custom_config_file_path)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the custom game configuration.")); - } else { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("Failed to remove the custom game configuration.")); - } -} - -void GMainWindow::RemoveCacheStorage(u64 program_id) { - const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); - auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); - - const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( - {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache, - 0 /* program_id */, {}, 0); - - const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); - - // Not an error if it wasn't cleared. - Common::FS::RemoveDirRecursively(path); -} - void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target) { const auto failed = [this] { @@ -3052,22 +2775,7 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { return progress.wasCanceled(); }; - const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback); - const QString resultString = tr(QtCommon::GetGameVerificationResultString(result)); - progress.close(); - switch (result) { - case ContentManager::GameVerificationResult::Success: - QMessageBox::information(this, tr("Integrity verification succeeded!"), - resultString); - break; - case ContentManager::GameVerificationResult::Failed: - QMessageBox::critical(this, tr("Integrity verification failed!"), - resultString); - break; - case ContentManager::GameVerificationResult::NotImplemented: - QMessageBox::warning(this, tr("Integrity verification couldn't be performed"), - resultString); - } + QtCommon::Content::VerifyGameContents(game_path, QtProgressCallback); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -4103,6 +3811,7 @@ void GMainWindow::OnLoadAmiibo() { LoadAmiibo(filename); } +// TODO(crueter): does this need to be ported to QML? bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { @@ -4154,27 +3863,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } void GMainWindow::OnOpenRootDataFolder() { - QtCommon::OpenRootDataFolder(); + QtCommon::Game::OpenRootDataFolder(); } void GMainWindow::OnOpenNANDFolder() { - QtCommon::OpenNANDFolder(); + QtCommon::Game::OpenNANDFolder(); } void GMainWindow::OnOpenSDMCFolder() { - QtCommon::OpenSDMCFolder(); + QtCommon::Game::OpenSDMCFolder(); } void GMainWindow::OnOpenModFolder() { - QtCommon::OpenModFolder(); + QtCommon::Game::OpenModFolder(); } void GMainWindow::OnOpenLogFolder() { - QtCommon::OpenLogFolder(); + QtCommon::Game::OpenLogFolder(); } void GMainWindow::OnVerifyInstalledContents() { @@ -4221,11 +3930,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); + auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, vfs.get()); progress.close(); - if (result != QtCommon::FirmwareInstallResult::Success) return; + if (result != QtCommon::Content::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); @@ -4292,7 +4001,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() { return; } - const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location); + const QString qCacheDir = QtCommon::Content::UnzipFirmwareToTmp(firmware_zip_location); // In this case, it has to be done recursively, since sometimes people // will pack it into a subdirectory after dumping @@ -4370,7 +4079,7 @@ void GMainWindow::OnToggleStatusBar() { void GMainWindow::OnGameListRefresh() { // Resets metadata cache and reloads - QtCommon::ResetMetadata(); + QtCommon::Game::ResetMetadata(); game_list->RefreshGameDirectory(); SetFirmwareVersion(); } @@ -4640,7 +4349,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); std::filesystem::path out_icon_path; - if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } @@ -4674,7 +4383,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, qgame_title); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8d00fef4f8..f523561628 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -17,9 +17,10 @@ #include #include "common/common_types.h" -#include "qt_common/qt_config.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" +#include "qt_common/qt_config.h" +#include "qt_common/qt_game_util.h" #include "user_data_migration.h" #include "yuzu/compatibility_list.h" #include "yuzu/hotkeys.h" @@ -53,10 +54,8 @@ class QSlider; class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; -enum class GameListRemoveTarget; enum class GameListShortcutTarget; enum class DumpRomFSTarget; -enum class InstalledEntryType; class GameListPlaceholder; class QtAmiiboSettingsDialog; @@ -258,8 +257,6 @@ private: void LinkActionShortcut(QAction* action, const QString& action_name, const bool tas_allowed = false); - void RegisterMetaTypes(); - void InitializeWidgets(); void InitializeDebugWidgets(); void InitializeRecentFileMenuActions(); @@ -353,9 +350,8 @@ private slots: void OnGameListLoadFile(QString game_path, u64 program_id); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path); - void OnTransferableShaderCacheOpenFile(u64 program_id); - void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); - void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, + void OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type); + void OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void OnGameListRemovePlayTimeData(u64 program_id); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target); @@ -436,16 +432,7 @@ private slots: #endif private: - QString GetGameListErrorRemoving(InstalledEntryType type) const; - void RemoveBaseContent(u64 program_id, InstalledEntryType type); - void RemoveUpdateContent(u64 program_id, InstalledEntryType type); - void RemoveAddOnContent(u64 program_id, InstalledEntryType type); - void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); - void RemoveVulkanDriverPipelineCache(u64 program_id); - void RemoveAllTransferableShaderCaches(u64 program_id); - void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemovePlayTimeData(u64 program_id); - void RemoveCacheStorage(u64 program_id); bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, u64* selected_title_id, u8* selected_content_record_type); ContentManager::InstallResult InstallNCA(const QString& filename); From c6a2d2acad2f781747fbd2e3d57dd53504917ad5 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:50:05 -0400 Subject: [PATCH 13/52] Fix license headers Signed-off-by: crueter --- ffmpeg.patch | 40 ------------------------------- src/qt_common/qt_content_util.cpp | 3 +++ src/qt_common/qt_content_util.h | 3 +++ src/qt_common/qt_meta.cpp | 3 +++ src/qt_common/qt_meta.h | 3 +++ src/qt_common/qt_rom_util.cpp | 3 +++ src/qt_common/qt_rom_util.h | 3 +++ 7 files changed, 18 insertions(+), 40 deletions(-) delete mode 100644 ffmpeg.patch diff --git a/ffmpeg.patch b/ffmpeg.patch deleted file mode 100644 index 58fa9dff61..0000000000 --- a/ffmpeg.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt -index 54c852f831..ff35c8dc2c 100644 ---- a/externals/ffmpeg/CMakeLists.txt -+++ b/externals/ffmpeg/CMakeLists.txt -@@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID) - set(FFmpeg_HWACCEL_INCLUDE_DIRS) - set(FFmpeg_HWACCEL_LDFLAGS) - -- # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -- if(PLATFORM_SUN) -- list(APPEND FFmpeg_HWACCEL_LIBRARIES -- X11 -- "/usr/lib/xorg/amd64/libdrm.so") -- else() -- pkg_check_modules(LIBDRM libdrm REQUIRED) -- list(APPEND FFmpeg_HWACCEL_LIBRARIES -- ${LIBDRM_LIBRARIES}) -- list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS -- ${LIBDRM_INCLUDE_DIRS}) -+ if (NOT APPLE) -+ # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -+ if(PLATFORM_SUN) -+ list(APPEND FFmpeg_HWACCEL_LIBRARIES -+ X11 -+ "/usr/lib/xorg/amd64/libdrm.so") -+ else() -+ pkg_check_modules(LIBDRM libdrm REQUIRED) -+ list(APPEND FFmpeg_HWACCEL_LIBRARIES -+ ${LIBDRM_LIBRARIES}) -+ list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS -+ ${LIBDRM_INCLUDE_DIRS}) -+ endif() -+ list(APPEND FFmpeg_HWACCEL_FLAGS -+ --enable-libdrm) - endif() -- list(APPEND FFmpeg_HWACCEL_FLAGS -- --enable-libdrm) - - if(LIBVA_FOUND) - find_package(X11 REQUIRED) diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 81ec7c9cea..9c3ae6e115 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_content_util.h" #include "common/fs/fs.h" #include "frontend_common/content_manager.h" diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index 9a1a4e5bc2..b7073d2d35 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_CONTENT_UTIL_H #define QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_meta.cpp b/src/qt_common/qt_meta.cpp index c972c0fe45..67ae659771 100644 --- a/src/qt_common/qt_meta.cpp +++ b/src/qt_common/qt_meta.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_meta.h" #include "common/common_types.h" #include "core/core.h" diff --git a/src/qt_common/qt_meta.h b/src/qt_common/qt_meta.h index 36cafba2bf..c0a37db983 100644 --- a/src/qt_common/qt_meta.h +++ b/src/qt_common/qt_meta.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_META_H #define QT_META_H diff --git a/src/qt_common/qt_rom_util.cpp b/src/qt_common/qt_rom_util.cpp index e707d1e471..08ccb05a97 100644 --- a/src/qt_common/qt_rom_util.cpp +++ b/src/qt_common/qt_rom_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_rom_util.h" #include diff --git a/src/qt_common/qt_rom_util.h b/src/qt_common/qt_rom_util.h index 52ebb1e8d0..f76b09753d 100644 --- a/src/qt_common/qt_rom_util.h +++ b/src/qt_common/qt_rom_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_ROM_UTIL_H #define QT_ROM_UTIL_H From fd7711aa5d28e64cf27713b335506febacf6a8d9 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:54:46 -0400 Subject: [PATCH 14/52] cleanup Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index da6c9b0481..add8e59311 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,7 +1,6 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later -find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -25,9 +24,13 @@ add_library(qt_common STATIC ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) -target_link_libraries(qt_common PRIVATE Qt6::Core) -target_link_libraries(qt_common PRIVATE Qt6::Core) + +# TODO(crueter) +if (ENABLE_QT) + target_link_libraries(qt_common PRIVATE Qt6::Widgets) +endif() + +target_link_libraries(qt_common PUBLIC core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) From c45d9a71e80af4a13ad5f1105df7eaa6c649f4f7 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:08:30 -0400 Subject: [PATCH 15/52] fix win Signed-off-by: crueter --- src/qt_common/qt_content_util.cpp | 5 ++--- src/qt_common/qt_content_util.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 9c3ae6e115..5ad361a527 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -5,17 +5,16 @@ #include "common/fs/fs.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" -#include "qt_common/qt_game_util.h" #include "qt_frontend_util.h" #include namespace QtCommon::Content { -bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent) +bool CheckGameFirmware(u64 program_id, QObject *parent) { if (FirmwareManager::GameRequiresFirmware(program_id) - && !FirmwareManager::CheckFirmwarePresence(system)) { + && !FirmwareManager::CheckFirmwarePresence(*system)) { auto result = QtCommon::Frontend::ShowMessage( QMessageBox::Warning, "Game Requires Firmware", diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b7073d2d35..529b887146 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -12,7 +12,7 @@ namespace QtCommon::Content { // -bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent); +bool CheckGameFirmware(u64 program_id, QObject *parent); static constexpr std::array FIRMWARE_RESULTS = {"Successfully installed firmware version %1", From 4356e80e50ed3bf2b8ba77de8d2d72ffad457a5f Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:30:19 -0400 Subject: [PATCH 16/52] fix Signed-off-by: crueter --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7db448af01..30ea8702be 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1912,7 +1912,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa /** firmware check */ - if (!QtCommon::Content::CheckGameFirmware(params.program_id, *system, this)) { + if (!QtCommon::Content::CheckGameFirmware(params.program_id, this)) { return false; } From c65f07563815bfafad6f053d91c3c54ce75f64ac Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 14:56:25 -0400 Subject: [PATCH 17/52] better handling for sys/vfs/rootobject Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 5 +- .../externals/CMakeLists.txt | 0 .../externals/cpmfile.json | 0 src/qt_common/qt_applet_util.cpp | 1 + src/qt_common/qt_applet_util.h | 8 + src/qt_common/qt_common.cpp | 10 +- src/qt_common/qt_common.h | 14 +- src/qt_common/qt_content_util.cpp | 51 ++- src/qt_common/qt_content_util.h | 11 +- src/qt_common/qt_frontend_util.cpp | 75 +---- src/qt_common/qt_frontend_util.h | 97 +++--- src/yuzu/CMakeLists.txt | 4 - src/yuzu/main.cpp | 297 ++++++++---------- src/yuzu/main.h | 3 - src/yuzu/user_data_migration.h | 1 + 15 files changed, 286 insertions(+), 291 deletions(-) rename src/{yuzu => qt_common}/externals/CMakeLists.txt (100%) rename src/{yuzu => qt_common}/externals/cpmfile.json (100%) create mode 100644 src/qt_common/qt_applet_util.cpp create mode 100644 src/qt_common/qt_applet_util.h diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index add8e59311..1acf8344a1 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(qt_common STATIC qt_meta.h qt_meta.cpp qt_content_util.h qt_content_util.cpp qt_rom_util.h qt_rom_util.cpp + qt_applet_util.h qt_applet_util.cpp ) create_target_directory_groups(qt_common) @@ -30,7 +31,9 @@ if (ENABLE_QT) target_link_libraries(qt_common PRIVATE Qt6::Widgets) endif() -target_link_libraries(qt_common PUBLIC core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) +add_subdirectory(externals) + +target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/yuzu/externals/CMakeLists.txt b/src/qt_common/externals/CMakeLists.txt similarity index 100% rename from src/yuzu/externals/CMakeLists.txt rename to src/qt_common/externals/CMakeLists.txt diff --git a/src/yuzu/externals/cpmfile.json b/src/qt_common/externals/cpmfile.json similarity index 100% rename from src/yuzu/externals/cpmfile.json rename to src/qt_common/externals/cpmfile.json diff --git a/src/qt_common/qt_applet_util.cpp b/src/qt_common/qt_applet_util.cpp new file mode 100644 index 0000000000..332f4796e8 --- /dev/null +++ b/src/qt_common/qt_applet_util.cpp @@ -0,0 +1 @@ +#include "qt_applet_util.h" diff --git a/src/qt_common/qt_applet_util.h b/src/qt_common/qt_applet_util.h new file mode 100644 index 0000000000..9ceb4a2522 --- /dev/null +++ b/src/qt_common/qt_applet_util.h @@ -0,0 +1,8 @@ +#ifndef QT_APPLET_UTIL_H +#define QT_APPLET_UTIL_H + +// TODO +namespace QtCommon::Applets { + +} +#endif // QT_APPLET_UTIL_H diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 6f8808ca32..9c20f1e6d9 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -23,7 +23,8 @@ namespace QtCommon { QObject *rootObject = nullptr; -Core::System *system = nullptr; +std::unique_ptr system = nullptr; +std::shared_ptr vfs = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -80,4 +81,11 @@ const QString tr(const std::string& str) return QGuiApplication::tr(str.c_str()); } +void Init(QObject* root) +{ + system = std::make_unique(); + rootObject = root; + vfs = std::make_unique(); +} + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index cf52cedc32..5f9b5d7de9 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,6 +4,7 @@ #ifndef QT_COMMON_H #define QT_COMMON_H +#include #include #include "core/core.h" #include @@ -13,7 +14,8 @@ namespace QtCommon { extern QObject *rootObject; -extern Core::System *system; +extern std::unique_ptr system; +extern std::shared_ptr vfs; typedef std::function QtProgressCallback; @@ -21,15 +23,7 @@ Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); -static inline void SetRootObject(QObject *parent) -{ - rootObject = parent; -} - -static inline void SetSystem(Core::System *newSystem) -{ - system = newSystem; -} +void Init(QObject *root); const QString tr(const char *str); const QString tr(const std::string &str); diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 5ad361a527..5f8ca14504 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -5,13 +5,14 @@ #include "common/fs/fs.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" #include "qt_frontend_util.h" #include namespace QtCommon::Content { -bool CheckGameFirmware(u64 program_id, QObject *parent) +bool CheckGameFirmware(u64 program_id, QObject* parent) { if (FirmwareManager::GameRequiresFirmware(program_id) && !FirmwareManager::CheckFirmwarePresence(*system)) { @@ -30,11 +31,10 @@ bool CheckGameFirmware(u64 program_id, QObject *parent) return true; } -FirmwareInstallResult InstallFirmware( - const QString& location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem* vfs) +FirmwareInstallResult InstallFirmware(const QString& location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem* vfs) { static constexpr const char* failedTitle = "Firmware Install Failed"; static constexpr const char* successTitle = "Firmware Install Failed"; @@ -179,16 +179,19 @@ QString UnzipFirmwareToTmp(const QString& location) } // Content // -void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) { +void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) +{ const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); switch (result) { case ContentManager::GameVerificationResult::Success: - QtCommon::Frontend::Information(rootObject, tr("Integrity verification succeeded!"), + QtCommon::Frontend::Information(rootObject, + tr("Integrity verification succeeded!"), tr("The operation completed successfully.")); break; case ContentManager::GameVerificationResult::Failed: - QtCommon::Frontend::Critical(rootObject, tr("Integrity verification failed!"), + QtCommon::Frontend::Critical(rootObject, + tr("Integrity verification failed!"), tr("File contents may be corrupt or missing.")); break; case ContentManager::GameVerificationResult::NotImplemented: @@ -200,5 +203,35 @@ void VerifyGameContents(const std::string& game_path, QtProgressCallback callbac } } +void InstallKeys() +{ + const QString key_source_location + = QtCommon::Frontend::GetOpenFileName(tr("Select Dumped Keys Location"), + {}, + QStringLiteral("Decryption Keys (*.keys)"), + {}, + QtCommon::Frontend::Option::ReadOnly); + if (key_source_location.isEmpty()) { + return; + } + + FirmwareManager::KeyInstallResult result = FirmwareManager::InstallKeys(key_source_location + .toStdString(), + "keys"); + + system->GetFileSystemController().CreateFactories(*QtCommon::vfs); + + switch (result) { + case FirmwareManager::KeyInstallResult::Success: + QtCommon::Frontend::Information(tr("Decryption Keys install succeeded"), + tr("Decryption Keys were successfully installed")); + break; + default: + QtCommon::Frontend::Critical(tr("Decryption Keys install failed"), + tr(FirmwareManager::GetKeyInstallResultString(result))); + break; + } } + +} // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index 529b887146..b401bdf1e3 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -32,6 +32,11 @@ enum class FirmwareInstallResult { FailedCorrupted, }; +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + FirmwareInstallResult InstallFirmware( const QString &location, bool recursive, @@ -40,10 +45,8 @@ FirmwareInstallResult InstallFirmware( QString UnzipFirmwareToTmp(const QString &location); -inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) -{ - return FIRMWARE_RESULTS.at(static_cast(result)); -} +// Keys // +void InstallKeys(); // Content // void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 6b96a26a21..d357c11338 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -2,6 +2,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_frontend_util.h" +#include "qt_common/qt_common.h" + +#ifdef YUZU_QT_WIDGETS +#include +#endif namespace QtCommon::Frontend { @@ -19,69 +24,15 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, // need a way to reference icon/buttons too } -QMessageBox::StandardButton Information(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) +const QString GetOpenFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter, + Options options) { - return ShowMessage(QMessageBox::Information, title, text, buttons, parent); +#ifdef YUZU_QT_WIDGETS + return QFileDialog::getOpenFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options); +#endif } -QMessageBox::StandardButton Warning(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Warning, title, text, buttons, parent); -} - -QMessageBox::StandardButton Critical(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Critical, title, text, buttons, parent); -} - -QMessageBox::StandardButton Question(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Question, title, text, buttons, parent); -} - -QMessageBox::StandardButton Information(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Information, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Warning(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Warning, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Critical(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Critical, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Question(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Question, parent->tr(title), parent->tr(text), buttons, parent); -} - - } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index a91a0db07b..7f43286430 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -6,8 +6,10 @@ #include #include +#include "qt_common/qt_common.h" #ifdef YUZU_QT_WIDGETS +#include #include #endif @@ -15,8 +17,27 @@ * manages common functionality e.g. message boxes and such for Qt/QML */ namespace QtCommon::Frontend { + Q_NAMESPACE +#ifdef YUZU_QT_WIDGETS +using Options = QFileDialog::Options; +using Option = QFileDialog::Option; +#else +enum Option { + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseNativeDialog = 0x00000008, + ReadOnly = 0x00000010, + HideNameFilterDetails = 0x00000020, + DontUseCustomDirectoryIcons = 0x00000040 +}; +Q_ENUM_NS(Option) +Q_DECLARE_FLAGS(Options, Option) +Q_FLAG_NS(Options) +#endif + // TODO(crueter) widgets-less impl, choices et al. QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, @@ -24,45 +45,47 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, QObject *parent = nullptr); -QMessageBox::StandardButton Information(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +#define UTIL_OVERRIDES(level) \ + inline QMessageBox::StandardButton level(QObject *parent, \ + const QString &title, \ + const QString &text, \ + QMessageBox::StandardButtons buttons = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, title, text, buttons, parent); \ + } \ + inline QMessageBox::StandardButton level(QObject *parent, \ + const char *title, \ + const char *text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, parent); \ + } \ + inline QMessageBox::StandardButton level(const char *title, \ + const char *text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, rootObject); \ + } \ + inline QMessageBox::StandardButton level(const QString title, \ + const QString &text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, title, text, buttons, rootObject); \ + } -QMessageBox::StandardButton Warning(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +UTIL_OVERRIDES(Information) +UTIL_OVERRIDES(Warning) +UTIL_OVERRIDES(Critical) +UTIL_OVERRIDES(Question) -QMessageBox::StandardButton Critical(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Question(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Information(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Warning(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Critical(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Question(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +const QString GetOpenFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter = nullptr, + Options options = Options()); } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 9e052b385d..8a1d760c50 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -496,8 +496,4 @@ if (YUZU_ROOM) target_link_libraries(yuzu PRIVATE yuzu-room) endif() -# Extra deps -add_subdirectory(externals) -target_link_libraries(yuzu PRIVATE QuaZip::QuaZip) - create_target_directory_groups(yuzu) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 30ea8702be..728ed2068c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -70,9 +70,8 @@ // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows // defines. -static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper( - const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) { - return vfs->CreateDirectory(path, mode); +static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(const std::string& path, FileSys::OpenMode mode) { + return QtCommon::vfs->CreateDirectory(path, mode); } static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::VirtualDir& dir, @@ -398,12 +397,10 @@ inline static bool isDarkMode() { #endif // _WIN32 GMainWindow::GMainWindow(bool has_broken_vulkan) - : ui{std::make_unique()}, system{std::make_unique()}, + : ui{std::make_unique()}, input_subsystem{std::make_shared()}, user_data_migrator{this}, - vfs{std::make_shared()}, provider{std::make_unique()} { - QtCommon::SetSystem(system.get()); - QtCommon::SetRootObject(this); + QtCommon::Init(this); Common::FS::CreateEdenPaths(); this->config = std::make_unique(); @@ -435,7 +432,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) UISettings::RestoreWindowState(config); - system->Initialize(); + QtCommon::system->Initialize(); Common::Log::Initialize(); Common::Log::Start(); @@ -457,7 +454,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); discord_rpc->Update(); - play_time_manager = std::make_unique(system->GetProfileManager()); + play_time_manager = std::make_unique(QtCommon::system->GetProfileManager()); Network::Init(); @@ -474,7 +471,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) ConnectMenuEvents(); ConnectWidgetEvents(); - system->HIDCore().ReloadInputDevices(); + QtCommon::system->HIDCore().ReloadInputDevices(); controller_dialog->refreshConfiguration(); const auto branch_name = std::string(Common::g_scm_branch); @@ -518,7 +515,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) std::chrono::duration_cast>( Common::Windows::SetCurrentTimerResolutionToMaximum()) .count()); - system->CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution()); + QtCommon::system->CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution()); #endif UpdateWindowTitle(); @@ -544,10 +541,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) } #endif - system->SetContentProvider(std::make_unique()); - system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, + QtCommon::system->SetContentProvider(std::make_unique()); + QtCommon::system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); - system->GetFileSystemController().CreateFactories(*vfs); + QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); // Remove cached contents generated during the previous session RemoveCachedContents(); @@ -661,7 +658,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) if (!argument_ok) { // try to look it up by username, only finds the first username that matches. const std::string user_arg_str = args[user_arg_idx].toStdString(); - const auto user_idx = system->GetProfileManager().GetUserIndex(user_arg_str); + const auto user_idx = QtCommon::system->GetProfileManager().GetUserIndex(user_arg_str); if (user_idx == std::nullopt) { LOG_ERROR(Frontend, "Invalid user argument"); @@ -671,7 +668,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) selected_user = user_idx.value(); } - if (!system->GetProfileManager().UserExistsIndex(selected_user)) { + if (!QtCommon::system->GetProfileManager().UserExistsIndex(selected_user)) { LOG_ERROR(Frontend, "Selected user doesn't exist"); continue; } @@ -762,7 +759,7 @@ void GMainWindow::AmiiboSettingsRequestExit() { void GMainWindow::ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters) { controller_applet = - new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); + new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *QtCommon::system); SCOPE_EXIT { controller_applet->deleteLater(); controller_applet = nullptr; @@ -775,8 +772,8 @@ void GMainWindow::ControllerSelectorReconfigureControllers( bool is_success = controller_applet->exec() != QDialog::Rejected; // Don't forget to apply settings. - system->HIDCore().DisableAllControllerConfiguration(); - system->ApplySettings(); + QtCommon::system->HIDCore().DisableAllControllerConfiguration(); + QtCommon::system->ApplySettings(); config->SaveAllValues(); UpdateStatusButtons(); @@ -792,7 +789,7 @@ void GMainWindow::ControllerSelectorRequestExit() { void GMainWindow::ProfileSelectorSelectProfile( const Core::Frontend::ProfileSelectParameters& parameters) { - profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); + profile_select_applet = new QtProfileSelectionDialog(*QtCommon::system, this, parameters); SCOPE_EXIT { profile_select_applet->deleteLater(); profile_select_applet = nullptr; @@ -807,7 +804,7 @@ void GMainWindow::ProfileSelectorSelectProfile( return; } - const auto uuid = system->GetProfileManager().GetUser( + const auto uuid = QtCommon::system->GetProfileManager().GetUser( static_cast(profile_select_applet->GetIndex())); if (!uuid.has_value()) { emit ProfileSelectorFinishedSelection(std::nullopt); @@ -830,7 +827,7 @@ void GMainWindow::SoftwareKeyboardInitialize( return; } - software_keyboard = new QtSoftwareKeyboardDialog(render_window, *system, is_inline, + software_keyboard = new QtSoftwareKeyboardDialog(render_window, *QtCommon::system, is_inline, std::move(initialize_parameters)); if (is_inline) { @@ -947,7 +944,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, return; } - web_applet = new QtNXWebEngineView(this, *system, input_subsystem.get()); + web_applet = new QtNXWebEngineView(this, *QtCommon::system, input_subsystem.get()); ui->action_Pause->setEnabled(false); ui->action_Restart->setEnabled(false); @@ -1091,10 +1088,10 @@ void GMainWindow::InitializeWidgets() { #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING ui->action_Report_Compatibility->setVisible(true); #endif - render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *system); + render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *QtCommon::system); render_window->hide(); - game_list = new GameList(vfs, provider.get(), *play_time_manager, *system, this); + game_list = new GameList(QtCommon::vfs, provider.get(), *play_time_manager, *QtCommon::system, this); ui->horizontalLayout->addWidget(game_list); game_list_placeholder = new GameListPlaceholder(this); @@ -1113,7 +1110,7 @@ void GMainWindow::InitializeWidgets() { }); multiplayer_state = new MultiplayerState(this, game_list->GetModel(), ui->action_Leave_Room, - ui->action_Show_Room, *system); + ui->action_Show_Room, *QtCommon::system); multiplayer_state->setVisible(false); // Create status bar @@ -1367,12 +1364,12 @@ void GMainWindow::InitializeWidgets() { void GMainWindow::InitializeDebugWidgets() { QMenu* debug_menu = ui->menu_View_Debugging; - waitTreeWidget = new WaitTreeWidget(*system, this); + waitTreeWidget = new WaitTreeWidget(*QtCommon::system, this); addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this); + controller_dialog = new ControllerDialog(QtCommon::system->HIDCore(), input_subsystem, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); @@ -1412,7 +1409,7 @@ void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name this->addAction(action); - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = hotkey_registry.GetControllerHotkey(main_window, action_name.toStdString(), controller); connect( @@ -1457,7 +1454,7 @@ void GMainWindow::InitializeHotkeys() { const auto connect_shortcut = [&](const QString& action_name, const Fn& function) { const auto* hotkey = hotkey_registry.GetHotkey(main_window.toStdString(), action_name.toStdString(), this); - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = hotkey_registry.GetControllerHotkey( main_window.toStdString(), action_name.toStdString(), controller); connect(hotkey, &QShortcut::activated, this, function); @@ -1483,7 +1480,7 @@ void GMainWindow::InitializeHotkeys() { }); connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [this] { if (Settings::values.enable_renderdoc_hotkey) { - system->GetRenderdocAPI().ToggleCapture(); + QtCommon::system->GetRenderdocAPI().ToggleCapture(); } }); connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { @@ -1889,13 +1886,13 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa return false; } - system->SetFilesystem(vfs); + QtCommon::system->SetFilesystem(QtCommon::vfs); if (params.launch_type == Service::AM::LaunchType::FrontendInitiated) { - system->GetUserChannel().clear(); + QtCommon::system->GetUserChannel().clear(); } - system->SetFrontendAppletSet({ + QtCommon::system->SetFrontendAppletSet({ std::make_unique(*this), // Amiibo Settings (UISettings::values.controller_applet_disabled.GetValue() == true) ? nullptr @@ -1922,13 +1919,13 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa /** Exec */ const Core::SystemResultStatus result{ - system->Load(*render_window, filename.toStdString(), params)}; + QtCommon::system->Load(*render_window, filename.toStdString(), params)}; const auto drd_callout = (UISettings::values.callout_flags.GetValue() & static_cast(CalloutFlag::DRDDeprecation)) == 0; if (result == Core::SystemResultStatus::Success && - system->GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && + QtCommon::system->GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && drd_callout) { UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() | static_cast(CalloutFlag::DRDDeprecation); @@ -1993,7 +1990,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa bool GMainWindow::SelectAndSetCurrentUser( const Core::Frontend::ProfileSelectParameters& parameters) { - QtProfileSelectionDialog dialog(*system, this, parameters); + QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2008,12 +2005,12 @@ bool GMainWindow::SelectAndSetCurrentUser( void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { // Ensure all NCAs are registered before launching the game - const auto file = vfs->OpenFile(filepath, FileSys::OpenMode::Read); + const auto file = QtCommon::vfs->OpenFile(filepath, FileSys::OpenMode::Read); if (!file) { return; } - auto loader = Loader::GetLoader(*system, file); + auto loader = Loader::GetLoader(*QtCommon::system, file); if (!loader) { return; } @@ -2062,8 +2059,8 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP last_filename_booted = filename; ConfigureFilesystemProvider(filename.toStdString()); - const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); - const auto loader = Loader::GetLoader(*system, v_file, params.program_id, params.program_index); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, filename.toUtf8().constData()); + const auto loader = Loader::GetLoader(*QtCommon::system, v_file, params.program_id, params.program_index); if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && type == StartGameType::Normal) { @@ -2074,8 +2071,8 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); QtConfig per_game_config(config_file_name, Config::ConfigType::PerGameConfig); - system->HIDCore().ReloadInputDevices(); - system->ApplySettings(); + QtCommon::system->HIDCore().ReloadInputDevices(); + QtCommon::system->ApplySettings(); } Settings::LogSettings(); @@ -2101,19 +2098,19 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP return; } - system->SetShuttingDown(false); + QtCommon::system->SetShuttingDown(false); game_list->setDisabled(true); // Create and start the emulation thread - emu_thread = std::make_unique(*system); + emu_thread = std::make_unique(*QtCommon::system); emit EmulationStarting(emu_thread.get()); emu_thread->start(); // Register an ExecuteProgram callback such that Core can execute a sub-program - system->RegisterExecuteProgramCallback( + QtCommon::system->RegisterExecuteProgramCallback( [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); - system->RegisterExitCallback([this] { + QtCommon::system->RegisterExitCallback([this] { emu_thread->ForceStop(); render_window->Exit(); }); @@ -2153,11 +2150,11 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::string title_name; std::string title_version; - const auto res = system->GetGameName(title_name); + const auto res = QtCommon::system->GetGameName(title_name); const auto metadata = [this, title_id] { - const FileSys::PatchManager pm(title_id, system->GetFileSystemController(), - system->GetContentProvider()); + const FileSys::PatchManager pm(title_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()); return pm.GetControlMetadata(); }(); if (metadata.first != nullptr) { @@ -2169,16 +2166,16 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::filesystem::path{Common::U16StringFromBuffer(filename.utf16(), filename.size())} .filename()); } - const bool is_64bit = system->Kernel().ApplicationProcess()->Is64Bit(); + const bool is_64bit = QtCommon::system->Kernel().ApplicationProcess()->Is64Bit(); const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); title_name = tr("%1 %2", "%1 is the title name. %2 indicates if the title is 64-bit or 32-bit") .arg(QString::fromStdString(title_name), instruction_set_suffix) .toStdString(); LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); - const auto gpu_vendor = system->GPU().Renderer().GetDeviceVendor(); + const auto gpu_vendor = QtCommon::system->GPU().Renderer().GetDeviceVendor(); UpdateWindowTitle(title_name, title_version, gpu_vendor); - loading_screen->Prepare(system->GetAppLoader()); + loading_screen->Prepare(QtCommon::system->GetAppLoader()); loading_screen->show(); emulation_running = true; @@ -2206,11 +2203,11 @@ bool GMainWindow::OnShutdownBegin() { // Disable unlimited frame rate Settings::values.use_speed_limit.SetValue(true); - if (system->IsShuttingDown()) { + if (QtCommon::system->IsShuttingDown()) { return false; } - system->SetShuttingDown(true); + QtCommon::system->SetShuttingDown(true); discord_rpc->Pause(); RequestGameExit(); @@ -2221,9 +2218,9 @@ bool GMainWindow::OnShutdownBegin() { int shutdown_time = 1000; - if (system->DebuggerEnabled()) { + if (QtCommon::system->DebuggerEnabled()) { shutdown_time = 0; - } else if (system->GetExitLocked()) { + } else if (QtCommon::system->GetExitLocked()) { shutdown_time = 5000; } @@ -2241,7 +2238,7 @@ bool GMainWindow::OnShutdownBegin() { } void GMainWindow::OnShutdownBeginDialog() { - shutdown_dialog = new OverlayDialog(this, *system, QString{}, tr("Closing software..."), + shutdown_dialog = new OverlayDialog(this, *QtCommon::system, QString{}, tr("Closing software..."), QString{}, QString{}, Qt::AlignHCenter | Qt::AlignVCenter); shutdown_dialog->open(); } @@ -2293,10 +2290,10 @@ void GMainWindow::OnEmulationStopped() { OnTasStateChanged(); render_window->FinalizeCamera(); - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None); // Enable all controllers - system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); + QtCommon::system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); render_window->removeEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, false); @@ -2325,8 +2322,8 @@ void GMainWindow::OnEmulationStopped() { // Enable game list game_list->setEnabled(true); - Settings::RestoreGlobalState(system->IsPoweredOn()); - system->HIDCore().ReloadInputDevices(); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); + QtCommon::system->HIDCore().ReloadInputDevices(); UpdateStatusButtons(); } @@ -2387,15 +2384,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QString open_target; const auto [user_save_size, device_save_size] = [this, &game_path, &program_id] { - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata().first; if (control != nullptr) { return std::make_pair(control->GetDefaultNormalSaveSize(), control->GetDeviceSaveDataSize()); } else { - const auto file = Core::GetGameFileFromPath(vfs, game_path); - const auto loader = Loader::GetLoader(*system, file); + const auto file = Core::GetGameFileFromPath(QtCommon::vfs, game_path); + const auto loader = Loader::GetLoader(*QtCommon::system, file); FileSys::NACP nacp{}; loader->ReadControlData(nacp); @@ -2414,7 +2411,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target open_target = tr("Save Data"); const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); + QtCommon::vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); if (has_user_save) { // User save data @@ -2425,7 +2422,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target .display_options = {}, .purpose = Service::AM::Frontend::UserSelectionPurpose::General, }; - QtProfileSelectionDialog dialog(*system, this, parameters); + QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2443,7 +2440,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } const auto user_id = - system->GetProfileManager().GetUser(static_cast(index)); + QtCommon::system->GetProfileManager().GetUser(static_cast(index)); ASSERT(user_id); const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( @@ -2631,7 +2628,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListR QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; case QtCommon::Game::GameListRemoveTarget::CacheStorage: - QtCommon::Game::RemoveCacheStorage(program_id, vfs.get()); + QtCommon::Game::RemoveCacheStorage(program_id, QtCommon::vfs.get()); break; } } @@ -2656,7 +2653,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa }; const auto loader = - Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); if (loader == nullptr) { failed(); return; @@ -2665,7 +2662,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa FileSys::VirtualFile packed_update_raw{}; loader->ReadUpdateRaw(packed_update_raw); - const auto& installed = system->GetContentProvider(); + const auto& installed = QtCommon::system->GetContentProvider(); u64 title_id{}; u8 raw_type{}; @@ -2697,14 +2694,14 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir); - const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed}; + const FileSys::PatchManager pm{title_id, QtCommon::system->GetFileSystemController(), installed}; auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false); - const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::OpenMode::ReadWrite); + const auto out = VfsFilesystemCreateDirectoryWrapper(path, FileSys::OpenMode::ReadWrite); if (out == nullptr) { failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); return; } @@ -2718,7 +2715,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa selections, 0, false, &ok); if (!ok) { failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); return; } @@ -2758,7 +2755,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } else { progress.close(); failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); } } @@ -2888,8 +2885,8 @@ void GMainWindow::OnGameListShowList(bool show) { void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { u64 title_id{}; - const auto v_file = Core::GetGameFileFromPath(vfs, file); - const auto loader = Loader::GetLoader(*system, v_file); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, file); + const auto loader = Loader::GetLoader(*QtCommon::system, v_file); if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { QMessageBox::information(this, tr("Properties"), @@ -3017,7 +3014,7 @@ void GMainWindow::OnMenuInstallToNAND() { return false; }; future = QtConcurrent::run([this, &file, progress_callback] { - return ContentManager::InstallNSP(*system, *vfs, file.toStdString(), + return ContentManager::InstallNSP(*QtCommon::system, *QtCommon::vfs, file.toStdString(), progress_callback); }); @@ -3109,7 +3106,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { } const bool is_application = index >= static_cast(FileSys::TitleType::Application); - const auto& fs_controller = system->GetFileSystemController(); + const auto& fs_controller = QtCommon::system->GetFileSystemController(); auto* registered_cache = is_application ? fs_controller.GetUserNANDContents() : fs_controller.GetSystemNANDContents(); @@ -3120,7 +3117,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { } return false; }; - return ContentManager::InstallNCA(*vfs, filename.toStdString(), *registered_cache, + return ContentManager::InstallNCA(*QtCommon::vfs, filename.toStdString(), *registered_cache, static_cast(index), progress_callback); } @@ -3149,7 +3146,7 @@ void GMainWindow::OnStartGame() { UpdateMenuState(); OnTasStateChanged(); - play_time_manager->SetProgramId(system->GetApplicationProcessProgramID()); + play_time_manager->SetProgramId(QtCommon::system->GetApplicationProcessProgramID()); play_time_manager->Start(); discord_rpc->Update(); @@ -3160,7 +3157,7 @@ void GMainWindow::OnStartGame() { } void GMainWindow::OnRestartGame() { - if (!system->IsPoweredOn()) { + if (!QtCommon::system->IsPoweredOn()) { return; } @@ -3208,7 +3205,7 @@ void GMainWindow::OnStopGame() { bool GMainWindow::ConfirmShutdownGame() { if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Always) { - if (system->GetExitLocked()) { + if (QtCommon::system->GetExitLocked()) { if (!ConfirmForceLockedExit()) { return false; } @@ -3220,7 +3217,7 @@ bool GMainWindow::ConfirmShutdownGame() { } else { if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game && - system->GetExitLocked()) { + QtCommon::system->GetExitLocked()) { if (!ConfirmForceLockedExit()) { return false; } @@ -3247,12 +3244,12 @@ void GMainWindow::OnExit() { } void GMainWindow::OnSaveConfig() { - system->ApplySettings(); + QtCommon::system->ApplySettings(); config->SaveAllValues(); } void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { - error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, + error_applet = new OverlayDialog(render_window, *QtCommon::system, error_code, error_text, QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); SCOPE_EXIT { error_applet->deleteLater(); @@ -3481,7 +3478,7 @@ void GMainWindow::OnConfigure() { Settings::SetConfiguringGlobal(true); ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), - vk_device_records, *system, + vk_device_records, *QtCommon::system, !multiplayer_state->IsHostingPublicRoom()); connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, &GMainWindow::OnLanguageChanged); @@ -3582,7 +3579,7 @@ void GMainWindow::OnConfigure() { UpdateStatusButtons(); controller_dialog->refreshConfiguration(); - system->ApplySettings(); + QtCommon::system->ApplySettings(); } void GMainWindow::OnConfigureTas() { @@ -3590,7 +3587,7 @@ void GMainWindow::OnConfigureTas() { const auto result = dialog.exec(); if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { - Settings::RestoreGlobalState(system->IsPoweredOn()); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); return; } else if (result == QDialog::Accepted) { dialog.ApplyConfiguration(); @@ -3604,7 +3601,7 @@ void GMainWindow::OnTasStartStop() { } // Disable system buttons to prevent TAS from executing a hotkey - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); controller->ResetSystemButtons(); input_subsystem->GetTas()->StartStop(); @@ -3620,7 +3617,7 @@ void GMainWindow::OnTasRecord() { } // Disable system buttons to prevent TAS from recording a hotkey - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); controller->ResetSystemButtons(); const bool is_recording = input_subsystem->GetTas()->Record(); @@ -3642,8 +3639,8 @@ void GMainWindow::OnTasReset() { void GMainWindow::OnToggleDockedMode() { const bool is_docked = Settings::IsDockedMode(); - auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + auto* player_1 = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* handheld = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); if (!is_docked && handheld->IsConnected()) { QMessageBox::warning(this, tr("Invalid config detected"), @@ -3658,7 +3655,7 @@ void GMainWindow::OnToggleDockedMode() { Settings::values.use_docked_mode.SetValue(is_docked ? Settings::ConsoleMode::Handheld : Settings::ConsoleMode::Docked); UpdateDockedButton(); - OnDockedModeChanged(is_docked, !is_docked, *system); + OnDockedModeChanged(is_docked, !is_docked, *QtCommon::system); } void GMainWindow::OnToggleGpuAccuracy() { @@ -3675,7 +3672,7 @@ void GMainWindow::OnToggleGpuAccuracy() { } } - system->ApplySettings(); + QtCommon::system->ApplySettings(); UpdateGPUAccuracyButton(); } @@ -3740,20 +3737,20 @@ void GMainWindow::OnToggleGraphicsAPI() { } void GMainWindow::OnConfigurePerGame() { - const u64 title_id = system->GetApplicationProcessProgramID(); + const u64 title_id = QtCommon::system->GetApplicationProcessProgramID(); OpenPerGameConfiguration(title_id, current_game_path.toStdString()); } void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) { - const auto v_file = Core::GetGameFileFromPath(vfs, file_name); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, file_name); Settings::SetConfiguringGlobal(false); - ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *system); + ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *QtCommon::system); dialog.LoadFromFile(v_file); const auto result = dialog.exec(); if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { - Settings::RestoreGlobalState(system->IsPoweredOn()); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); return; } else if (result == QDialog::Accepted) { dialog.ApplyConfiguration(); @@ -3765,9 +3762,9 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file } // Do not cause the global config to write local settings into the config file - const bool is_powered_on = system->IsPoweredOn(); + const bool is_powered_on = QtCommon::system->IsPoweredOn(); Settings::RestoreGlobalState(is_powered_on); - system->HIDCore().ReloadInputDevices(); + QtCommon::system->HIDCore().ReloadInputDevices(); UISettings::values.configuration_applied = false; @@ -3822,7 +3819,7 @@ bool GMainWindow::question(QWidget* parent, const QString& title, const QString& box_dialog->setDefaultButton(defaultButton); ControllerNavigation* controller_navigation = - new ControllerNavigation(system->HIDCore(), box_dialog); + new ControllerNavigation(QtCommon::system->HIDCore(), box_dialog); connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, [box_dialog](Qt::Key key) { QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); @@ -3901,7 +3898,7 @@ void GMainWindow::OnVerifyInstalledContents() { }; const std::vector result = - ContentManager::VerifyInstalledContents(*system, *provider, QtProgressCallback); + ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, QtProgressCallback); progress.close(); if (result.empty()) { @@ -3930,7 +3927,7 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, vfs.get()); + auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, QtCommon::vfs.get()); progress.close(); @@ -3942,7 +3939,7 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { }; auto results = - ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, VerifyFirmwareCallback, true); if (results.size() > 0) { const auto failed_names = @@ -4026,30 +4023,9 @@ void GMainWindow::OnInstallDecryptionKeys() { return; } - const QString key_source_location = QFileDialog::getOpenFileName( - this, tr("Select Dumped Keys Location"), {}, QStringLiteral("Decryption Keys (*.keys)"), {}, - QFileDialog::ReadOnly); - if (key_source_location.isEmpty()) { - return; - } + QtCommon::Content::InstallKeys(); - FirmwareManager::KeyInstallResult result = - FirmwareManager::InstallKeys(key_source_location.toStdString(), "keys"); - - system->GetFileSystemController().CreateFactories(*vfs); game_list->PopulateAsync(UISettings::values.game_dirs); - - switch (result) { - case FirmwareManager::KeyInstallResult::Success: - QMessageBox::information(this, tr("Decryption Keys install succeeded"), - tr("Decryption Keys were successfully installed")); - break; - default: - QMessageBox::critical(this, tr("Decryption Keys install failed"), - tr(FirmwareManager::GetKeyInstallResultString(result))); - break; - } - OnCheckFirmwareDecryption(); } @@ -4086,7 +4062,7 @@ void GMainWindow::OnGameListRefresh() void GMainWindow::OnAlbum() { constexpr u64 AlbumId = static_cast(Service::AM::AppletProgramId::PhotoViewer); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Album applet.")); @@ -4100,7 +4076,7 @@ void GMainWindow::OnAlbum() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer); const auto filename = QString::fromStdString(album_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4109,7 +4085,7 @@ void GMainWindow::OnAlbum() { void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { constexpr u64 CabinetId = static_cast(Service::AM::AppletProgramId::Cabinet); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Cabinet applet.")); @@ -4123,8 +4099,8 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet); - system->GetFrontendAppletHolder().SetCabinetMode(mode); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet); + QtCommon::system->GetFrontendAppletHolder().SetCabinetMode(mode); const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4133,7 +4109,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { void GMainWindow::OnMiiEdit() { constexpr u64 MiiEditId = static_cast(Service::AM::AppletProgramId::MiiEdit); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Mii editor.")); @@ -4147,7 +4123,7 @@ void GMainWindow::OnMiiEdit() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit); const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4156,7 +4132,7 @@ void GMainWindow::OnMiiEdit() { void GMainWindow::OnOpenControllerMenu() { constexpr u64 ControllerAppletId = static_cast(Service::AM::AppletProgramId::Controller); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Controller Menu.")); @@ -4171,7 +4147,7 @@ void GMainWindow::OnOpenControllerMenu() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller); const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4180,7 +4156,7 @@ void GMainWindow::OnOpenControllerMenu() { } void GMainWindow::OnHomeMenu() { - auto result = FirmwareManager::VerifyFirmware(*system.get()); + auto result = FirmwareManager::VerifyFirmware(*QtCommon::system.get()); switch (result) { case FirmwareManager::ErrorFirmwareMissing: @@ -4217,7 +4193,7 @@ void GMainWindow::OnHomeMenu() { // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); if (!qlaunch_applet_nca) { @@ -4226,7 +4202,7 @@ void GMainWindow::OnHomeMenu() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch); const auto filename = QString::fromStdString((qlaunch_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4235,7 +4211,7 @@ void GMainWindow::OnHomeMenu() { void GMainWindow::OnInitialSetup() { constexpr u64 Starter = static_cast(Service::AM::AppletProgramId::Starter); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use Starter.")); @@ -4249,7 +4225,7 @@ void GMainWindow::OnInitialSetup() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Starter); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Starter); const auto filename = QString::fromStdString((qlaunch_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4296,6 +4272,7 @@ std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target return shortcut_path; } +// TODO(crueter): Migrate void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { // Get path to Eden executable std::filesystem::path command = GetEdenCommand(); @@ -4311,11 +4288,11 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program return; } - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata(); const auto loader = - Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); std::string game_title{game_title_}; @@ -4395,7 +4372,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the home menu.")); @@ -4421,7 +4398,7 @@ void GMainWindow::OnCaptureScreenshot() { return; } - const u64 title_id = system->GetApplicationProcessProgramID(); + const u64 title_id = QtCommon::system->GetApplicationProcessProgramID(); const auto screenshot_path = QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::ScreenshotsDir)); const auto date = @@ -4583,7 +4560,7 @@ void GMainWindow::OnTasStateChanged() { } void GMainWindow::UpdateStatusBar() { - if (emu_thread == nullptr || !system->IsPoweredOn()) { + if (emu_thread == nullptr || !QtCommon::system->IsPoweredOn()) { status_bar_update_timer.stop(); return; } @@ -4594,8 +4571,8 @@ void GMainWindow::UpdateStatusBar() { tas_label->clear(); } - auto results = system->GetAndResetPerfStats(); - auto& shader_notify = system->GPU().ShaderNotify(); + auto results = QtCommon::system->GetAndResetPerfStats(); + auto& shader_notify = QtCommon::system->GPU().ShaderNotify(); const int shaders_building = shader_notify.ShadersBuilding(); if (shaders_building > 0) { @@ -4741,7 +4718,7 @@ void GMainWindow::OnMouseActivity() { } void GMainWindow::OnCheckFirmwareDecryption() { - system->GetFileSystemController().CreateFactories(*vfs); + QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); if (!ContentManager::AreKeysPresent()) { QMessageBox::warning(this, tr("Derivation Components Missing"), tr("Encryption keys are missing.")); @@ -4786,11 +4763,11 @@ bool GMainWindow::OnCheckNcaVerification() { } bool GMainWindow::CheckFirmwarePresence() { - return FirmwareManager::CheckFirmwarePresence(*system.get()); + return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } void GMainWindow::SetFirmwareVersion() { - const auto pair = FirmwareManager::GetFirmwareVersion(*system.get()); + const auto pair = FirmwareManager::GetFirmwareVersion(*QtCommon::system.get()); const auto firmware_data = pair.first; const auto result = pair.second; @@ -4876,7 +4853,7 @@ bool GMainWindow::ConfirmClose() { UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) { return true; } - if (!system->GetExitLocked() && + if (!QtCommon::system->GetExitLocked() && UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) { return true; } @@ -4906,7 +4883,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { render_window->close(); multiplayer_state->Close(); - system->HIDCore().UnloadInputDevices(); + QtCommon::system->HIDCore().UnloadInputDevices(); Network::Shutdown(); QWidget::closeEvent(event); @@ -4977,12 +4954,12 @@ bool GMainWindow::ConfirmForceLockedExit() { } void GMainWindow::RequestGameExit() { - if (!system->IsPoweredOn()) { + if (!QtCommon::system->IsPoweredOn()) { return; } - system->SetExitRequested(true); - system->GetAppletManager().RequestExit(); + QtCommon::system->SetExitRequested(true); + QtCommon::system->GetAppletManager().RequestExit(); } void GMainWindow::filterBarSetChecked(bool state) { @@ -5092,7 +5069,7 @@ void GMainWindow::OnLanguageChanged(const QString& locale) { void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { #ifdef USE_DISCORD_PRESENCE if (state) { - discord_rpc = std::make_unique(*system); + discord_rpc = std::make_unique(*QtCommon::system); } else { discord_rpc = std::make_unique(); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index f523561628..0bc5913acc 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -71,7 +71,6 @@ enum class StartGameType { namespace Core { enum class SystemResultStatus : u32; -class System; } // namespace Core namespace Core::Frontend { @@ -479,7 +478,6 @@ private: std::unique_ptr ui; - std::unique_ptr system; std::unique_ptr discord_rpc; std::unique_ptr play_time_manager; std::shared_ptr input_subsystem; @@ -540,7 +538,6 @@ private: QString startup_icon_theme; // FS - std::shared_ptr vfs; std::unique_ptr provider; // Debugger panes diff --git a/src/yuzu/user_data_migration.h b/src/yuzu/user_data_migration.h index 3684d14916..a3ac2c15d3 100644 --- a/src/yuzu/user_data_migration.h +++ b/src/yuzu/user_data_migration.h @@ -10,6 +10,7 @@ #include #include "migration_worker.h" +// TODO(crueter): Quick implementation class UserDataMigrator { public: UserDataMigrator(QMainWindow* main_window); From 2d94767f9625630095a663200e6a13bfab1e9160 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 14:57:21 -0400 Subject: [PATCH 18/52] Fix license headers --- src/qt_common/qt_applet_util.cpp | 3 +++ src/qt_common/qt_applet_util.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/qt_common/qt_applet_util.cpp b/src/qt_common/qt_applet_util.cpp index 332f4796e8..1b0189392e 100644 --- a/src/qt_common/qt_applet_util.cpp +++ b/src/qt_common/qt_applet_util.cpp @@ -1 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_applet_util.h" diff --git a/src/qt_common/qt_applet_util.h b/src/qt_common/qt_applet_util.h index 9ceb4a2522..2b48d16698 100644 --- a/src/qt_common/qt_applet_util.h +++ b/src/qt_common/qt_applet_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_APPLET_UTIL_H #define QT_APPLET_UTIL_H From 8974aed013dae12150da80b163616495a1afc9dc Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:39:10 -0400 Subject: [PATCH 19/52] QProgressDialog abstractor, more moving Signed-off-by: crueter --- .ci/license-header.sh | 1 - .../org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 19 - .../features/settings/model/BooleanSetting.kt | 1 - .../settings/model/view/SettingsItem.kt | 7 - .../settings/ui/SettingsFragmentPresenter.kt | 1 - .../app/src/main/res/values/strings.xml | 3 - src/common/settings.h | 4 - .../fssystem/fssystem_bucket_tree.cpp | 4 +- .../fssystem_nca_file_system_driver.cpp | 133 +++---- src/qt_common/CMakeLists.txt | 9 +- src/qt_common/externals/CMakeLists.txt | 4 + src/qt_common/externals/cpmfile.json | 7 + src/qt_common/qt_common.cpp | 33 +- src/qt_common/qt_common.h | 14 +- src/qt_common/qt_content_util.cpp | 114 +++++- src/qt_common/qt_content_util.h | 11 +- src/qt_common/qt_frontend_util.cpp | 7 +- src/qt_common/qt_frontend_util.h | 93 ++++- src/qt_common/qt_game_util.cpp | 177 +++++++++ src/qt_common/qt_game_util.h | 24 ++ src/qt_common/qt_progress_dialog.cpp | 4 + src/qt_common/qt_progress_dialog.h | 47 +++ src/qt_common/shared_translation.cpp | 12 +- src/yuzu/game_list.cpp | 4 +- src/yuzu/game_list.h | 7 +- src/yuzu/main.cpp | 345 ++---------------- src/yuzu/main.h | 21 +- 27 files changed, 580 insertions(+), 526 deletions(-) create mode 100644 src/qt_common/qt_progress_dialog.cpp create mode 100644 src/qt_common/qt_progress_dialog.h diff --git a/.ci/license-header.sh b/.ci/license-header.sh index d98f42fc97..3d4929d1c1 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -15,7 +15,6 @@ FILES=`git diff --name-only $BASE` #FILES=$(git diff --name-only master) -echo $FILES echo "Done" check_header() { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 98f342c274..b383cc147f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -232,8 +232,6 @@ class GameAdapter(private val activity: AppCompatActivity) : binding.root.findNavController().navigate(action) } - val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - if (NativeLibrary.gameRequiresFirmware(game.programId) && !NativeLibrary.isFirmwareAvailable()) { MaterialAlertDialogBuilder(activity) .setTitle(R.string.loader_requires_firmware) @@ -248,23 +246,6 @@ class GameAdapter(private val activity: AppCompatActivity) : } .setNegativeButton(android.R.string.cancel) { _, _ -> } .show() - } else if (BooleanSetting.DISABLE_NCA_VERIFICATION.getBoolean(false) && !preferences.getBoolean( - Settings.PREF_HIDE_NCA_POPUP, false)) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.nca_verification_disabled) - .setMessage(activity.getString(R.string.nca_verification_disabled_description)) - .setPositiveButton(android.R.string.ok) { _, _ -> - launch() - } - .setNeutralButton(R.string.dont_show_again) { _, _ -> - preferences.edit { - putBoolean(Settings.PREF_HIDE_NCA_POPUP, true) - } - - launch() - } - .setNegativeButton(android.R.string.cancel) { _, _ -> } - .show() } else { launch() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 6d4bfd97ac..3c5b9003de 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -35,7 +35,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_SAMPLE_SHADING("sample_shading"), PICTURE_IN_PICTURE("picture_in_picture"), USE_CUSTOM_RTC("custom_rtc_enabled"), - DISABLE_NCA_VERIFICATION("disable_nca_verification"), BLACK_BACKGROUNDS("black_backgrounds"), JOYSTICK_REL_CENTER("joystick_rel_center"), DPAD_SLIDE("dpad_slide"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 883d8efaef..1f2ba81a73 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -297,13 +297,6 @@ abstract class SettingsItem( descriptionId = R.string.use_custom_rtc_description ) ) - put( - SwitchSetting( - BooleanSetting.DISABLE_NCA_VERIFICATION, - titleId = R.string.disable_nca_verification, - descriptionId = R.string.disable_nca_verification_description - ) - ) put( StringInputSetting( StringSetting.WEB_TOKEN, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 630bcb0d74..14d62ceec3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -210,7 +210,6 @@ class SettingsFragmentPresenter( add(IntSetting.LANGUAGE_INDEX.key) add(BooleanSetting.USE_CUSTOM_RTC.key) add(LongSetting.CUSTOM_RTC.key) - add(BooleanSetting.DISABLE_NCA_VERIFICATION.key) add(HeaderSetting(R.string.network)) add(StringSetting.WEB_TOKEN.key) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 2c7923d5a3..6e428a1f7f 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -784,9 +784,6 @@ Game Requires Firmware dump and install firmware, or press "OK" to launch anyways.]]> - NCA Verification Disabled - This is required to run new games and updates, but may cause instability or crashes if NCA files are corrupt, modified, or tampered with. If unsure, re-enable verification in Advanced Settings -> System, and use firmware versions of 19.0.1 or below. - Searching for game... Game not found for Title ID: %1$s diff --git a/src/common/settings.h b/src/common/settings.h index 9d448a2b38..fafd765804 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -626,10 +626,6 @@ struct Values { true, true, &rng_seed_enabled}; Setting device_name{ linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true}; - SwitchableSetting disable_nca_verification{linkage, true, "disable_nca_verification", - Category::System, Specialization::Default}; - Setting hide_nca_verification_popup{ - linkage, false, "hide_nca_verification_popup", Category::System, Specialization::Default}; Setting current_user{linkage, 0, "current_user", Category::System}; diff --git a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp index 615a624f4f..71ba458cef 100644 --- a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp +++ b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp @@ -238,9 +238,7 @@ void BucketTree::Initialize(size_t node_size, s64 end_offset) { ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); ASSERT(Common::IsPowerOfTwo(node_size)); - if (!Settings::values.disable_nca_verification.GetValue()) { - ASSERT(end_offset > 0); - } + ASSERT(end_offset > 0); ASSERT(!this->IsInitialized()); m_node_size = node_size; diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index 4cfa5c58f8..4e624ad3f4 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -1296,91 +1299,65 @@ Result NcaFileSystemDriver::CreateIntegrityVerificationStorageImpl( ASSERT(base_storage != nullptr); ASSERT(layer_info_offset >= 0); - if (!Settings::values.disable_nca_verification.GetValue()) { - // Define storage types. - using VerificationStorage = HierarchicalIntegrityVerificationStorage; - using StorageInfo = VerificationStorage::HierarchicalStorageInformation; + // Define storage types. + using VerificationStorage = HierarchicalIntegrityVerificationStorage; + using StorageInfo = VerificationStorage::HierarchicalStorageInformation; - // Validate the meta info. - HierarchicalIntegrityVerificationInformation level_hash_info; - std::memcpy(std::addressof(level_hash_info), std::addressof(meta_info.level_hash_info), - sizeof(level_hash_info)); + // Validate the meta info. + HierarchicalIntegrityVerificationInformation level_hash_info; + std::memcpy(std::addressof(level_hash_info), + std::addressof(meta_info.level_hash_info), + sizeof(level_hash_info)); - R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - // Get the base storage size. - s64 base_storage_size = base_storage->GetSize(); + // Get the base storage size. + s64 base_storage_size = base_storage->GetSize(); - // Create storage info. - StorageInfo storage_info; - for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { - const auto& layer_info = level_hash_info.info[i]; - R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, - ResultNcaBaseStorageOutOfRangeD); - - storage_info[i + 1] = std::make_shared( - base_storage, layer_info.size, layer_info_offset + layer_info.offset); - } - - // Set the last layer info. - const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; - const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); - R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, + // Create storage info. + StorageInfo storage_info; + for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { + const auto& layer_info = level_hash_info.info[i]; + R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, ResultNcaBaseStorageOutOfRangeD); - if (layer_info_offset > 0) { - R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, - ResultRomNcaInvalidIntegrityLayerInfoOffset); - } - storage_info[level_hash_info.max_layers - 1] = std::make_shared( - std::move(base_storage), layer_info.size, last_layer_info_offset); - // Make the integrity romfs storage. - auto integrity_storage = std::make_shared(); - R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); - - // Initialize the integrity storage. - R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info, - max_data_cache_entries, max_hash_cache_entries, - buffer_level)); - - // Set the output. - *out = std::move(integrity_storage); - R_SUCCEED(); - } else { - // Read IVFC layout - HierarchicalIntegrityVerificationInformation lhi{}; - std::memcpy(std::addressof(lhi), std::addressof(meta_info.level_hash_info), sizeof(lhi)); - - R_UNLESS(IntegrityMinLayerCount <= lhi.max_layers, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - R_UNLESS(lhi.max_layers <= IntegrityMaxLayerCount, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - - const auto& data_li = lhi.info[lhi.max_layers - 2]; - - const s64 base_size = base_storage->GetSize(); - - // Compute the data layer window - const s64 data_off = (layer_info_offset > 0) ? 0LL : data_li.offset.Get(); - R_UNLESS(data_off + data_li.size <= base_size, ResultNcaBaseStorageOutOfRangeD); - if (layer_info_offset > 0) { - R_UNLESS(data_off + data_li.size <= layer_info_offset, - ResultRomNcaInvalidIntegrityLayerInfoOffset); - } - - // TODO: Passthrough (temporary compatibility: integrity disabled) - auto data_view = std::make_shared(base_storage, data_li.size, data_off); - R_UNLESS(data_view != nullptr, ResultAllocationMemoryFailedAllocateShared); - - auto passthrough = std::make_shared(std::move(data_view)); - R_UNLESS(passthrough != nullptr, ResultAllocationMemoryFailedAllocateShared); - - *out = std::move(passthrough); - R_SUCCEED(); + storage_info[i + 1] = std::make_shared(base_storage, + layer_info.size, + layer_info_offset + layer_info.offset); } + + // Set the last layer info. + const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; + const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); + R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, + ResultNcaBaseStorageOutOfRangeD); + if (layer_info_offset > 0) { + R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, + ResultRomNcaInvalidIntegrityLayerInfoOffset); + } + storage_info[level_hash_info.max_layers - 1] + = std::make_shared(std::move(base_storage), + layer_info.size, + last_layer_info_offset); + + // Make the integrity romfs storage. + auto integrity_storage = std::make_shared(); + R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); + + // Initialize the integrity storage. + R_TRY(integrity_storage->Initialize(level_hash_info, + meta_info.master_hash, + storage_info, + max_data_cache_entries, + max_hash_cache_entries, + buffer_level)); + + // Set the output. + *out = std::move(integrity_storage); + R_SUCCEED(); } Result NcaFileSystemDriver::CreateRegionSwitchStorage(VirtualFile* out, diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 1acf8344a1..9d292da401 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,10 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -22,6 +26,8 @@ add_library(qt_common STATIC qt_content_util.h qt_content_util.cpp qt_rom_util.h qt_rom_util.cpp qt_applet_util.h qt_applet_util.cpp + qt_progress_dialog.h qt_progress_dialog.cpp + ) create_target_directory_groups(qt_common) @@ -33,7 +39,8 @@ endif() add_subdirectory(externals) -target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip frozen::frozen) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/externals/CMakeLists.txt b/src/qt_common/externals/CMakeLists.txt index 50594a741f..189a52c0a6 100644 --- a/src/qt_common/externals/CMakeLists.txt +++ b/src/qt_common/externals/CMakeLists.txt @@ -14,3 +14,7 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON) # QuaZip AddJsonPackage(quazip) + +# frozen +# TODO(crueter): Qt String Lookup +AddJsonPackage(frozen) diff --git a/src/qt_common/externals/cpmfile.json b/src/qt_common/externals/cpmfile.json index e3590d0f7f..0b464b95b2 100644 --- a/src/qt_common/externals/cpmfile.json +++ b/src/qt_common/externals/cpmfile.json @@ -8,5 +8,12 @@ "options": [ "QUAZIP_INSTALL OFF" ] + }, + "frozen": { + "package": "frozen", + "repo": "serge-sans-paille/frozen", + "sha": "61dce5ae18", + "hash": "1ae3d073e659c1f24b2cdd76379c90d6af9e06bc707d285a4fafce05f7a4c9e592ff208c94a9ae0f0d07620b3c6cec191f126b03d70ad4dfa496a86ed5658a6d", + "bundled": true } } diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 9c20f1e6d9..6be241c740 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_common.h" +#include "common/fs/fs.h" #include #include @@ -22,9 +23,15 @@ namespace QtCommon { -QObject *rootObject = nullptr; +#ifdef YUZU_QT_WIDGETS +QWidget* rootObject = nullptr; +#else +QObject* rootObject = nullptr; +#endif + std::unique_ptr system = nullptr; std::shared_ptr vfs = nullptr; +std::unique_ptr provider = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -81,11 +88,35 @@ const QString tr(const std::string& str) return QGuiApplication::tr(str.c_str()); } +#ifdef YUZU_QT_WIDGETS +void Init(QWidget* root) +#else void Init(QObject* root) +#endif { system = std::make_unique(); rootObject = root; vfs = std::make_unique(); + provider = std::make_unique(); +} + +std::filesystem::path GetEdenCommand() { + std::filesystem::path command; + + QString appimage = QString::fromLocal8Bit(getenv("APPIMAGE")); + if (!appimage.isEmpty()) { + command = std::filesystem::path{appimage.toStdString()}; + } else { + const QStringList args = QGuiApplication::arguments(); + command = args[0].toStdString(); + } + + // If relative path, make it an absolute path + if (command.c_str()[0] == '.') { + command = Common::FS::GetCurrentDir() / command; + } + + return command; } } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 5f9b5d7de9..a2700427ab 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,18 +4,25 @@ #ifndef QT_COMMON_H #define QT_COMMON_H -#include #include #include "core/core.h" +#include "core/file_sys/registered_cache.h" #include +#include #include namespace QtCommon { +#ifdef YUZU_QT_WIDGETS +extern QWidget *rootObject; +#else extern QObject *rootObject; +#endif + extern std::unique_ptr system; extern std::shared_ptr vfs; +extern std::unique_ptr provider; typedef std::function QtProgressCallback; @@ -23,10 +30,15 @@ Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); +#ifdef YUZU_QT_WIDGETS +void Init(QWidget *root); +#else void Init(QObject *root); +#endif const QString tr(const char *str); const QString tr(const std::string &str); +std::filesystem::path GetEdenCommand(); } // namespace QtCommon #endif diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 5f8ca14504..e4625aa423 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -6,6 +6,7 @@ #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_progress_dialog.h" #include "qt_frontend_util.h" #include @@ -31,24 +32,34 @@ bool CheckGameFirmware(u64 program_id, QObject* parent) return true; } -FirmwareInstallResult InstallFirmware(const QString& location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem* vfs) +void InstallFirmware(const QString& location, bool recursive) { - static constexpr const char* failedTitle = "Firmware Install Failed"; - static constexpr const char* successTitle = "Firmware Install Failed"; - static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + QtCommon::Frontend::QtProgressDialog progress(tr("Installing Firmware..."), + tr("Cancel"), + 0, + 100, + rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + progress.show(); + // Declare progress callback. + auto callback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Succeeded"; QMessageBox::Icon icon; FirmwareInstallResult result; const auto ShowMessage = [&]() { QtCommon::Frontend::ShowMessage(icon, failedTitle, - GetFirmwareInstallResultString(result), - buttons, - rootObject); + GetFirmwareInstallResultString(result)); }; LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); @@ -57,7 +68,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, // there.) std::filesystem::path firmware_source_path = location.toStdString(); if (!Common::FS::IsDir(firmware_source_path)) { - return FirmwareInstallResult::NoOp; + return; } std::vector out; @@ -86,7 +97,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::NoNCAs; icon = QMessageBox::Warning; ShowMessage(); - return result; + return; } // Locate and erase the content of nand/system/Content/registered/*.nca, if any. @@ -96,7 +107,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedDelete; icon = QMessageBox::Critical; ShowMessage(); - return result; + return; } LOG_INFO(Frontend, @@ -127,7 +138,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedCorrupted; icon = QMessageBox::Warning; ShowMessage(); - return result; + return; } } @@ -135,12 +146,34 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedCopy; icon = QMessageBox::Critical; ShowMessage(); - return result; + return; } // Re-scan VFS for the newly placed firmware files. system->GetFileSystemController().CreateFactories(*vfs); + auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(90 + static_cast((processed_size * 10) / total_size)); + return progress.wasCanceled(); + }; + + auto results = ContentManager::VerifyInstalledContents(*QtCommon::system, + *QtCommon::provider, + VerifyFirmwareCallback, + true); + + if (results.size() > 0) { + const auto failed_names = QString::fromStdString( + fmt::format("{}", fmt::join(results, "\n"))); + progress.close(); + QtCommon::Frontend::Critical(tr("Firmware integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1") + .arg(failed_names)); + return; + } + + progress.close(); + const auto pair = FirmwareManager::GetFirmwareVersion(*system); const auto firmware_data = pair.first; const std::string display_version(firmware_data.display_version.data()); @@ -149,9 +182,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, QtCommon::Frontend::Information(rootObject, tr(successTitle), tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version)), - buttons); - return result; + .arg(QString::fromStdString(display_version))); } QString UnzipFirmwareToTmp(const QString& location) @@ -179,8 +210,23 @@ QString UnzipFirmwareToTmp(const QString& location) } // Content // -void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) +void VerifyGameContents(const std::string& game_path) { + QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), + tr("Cancel"), + 0, + 100, + rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + + const auto callback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); switch (result) { @@ -234,4 +280,34 @@ void InstallKeys() } } +void VerifyInstalledContents() { + // Initialize a progress dialog. + QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, QtCommon::rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + + // Declare progress callback. + auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + + const std::vector result = + ContentManager::VerifyInstalledContents(*QtCommon::system, *QtCommon::provider, QtProgressCallback); + progress.close(); + + if (result.empty()) { + QtCommon::Frontend::Information(tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + } else { + const auto failed_names = + QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + QtCommon::Frontend::Critical( + tr("Integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1").arg(failed_names)); + } +} + } // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b401bdf1e3..b572c1c4a3 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -6,8 +6,6 @@ #include #include "common/common_types.h" -#include "core/core.h" -#include "qt_common/qt_common.h" namespace QtCommon::Content { @@ -37,11 +35,7 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul return FIRMWARE_RESULTS.at(static_cast(result)); } -FirmwareInstallResult InstallFirmware( - const QString &location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem *vfs); +void InstallFirmware(const QString &location, bool recursive); QString UnzipFirmwareToTmp(const QString &location); @@ -49,6 +43,7 @@ QString UnzipFirmwareToTmp(const QString &location); void InstallKeys(); // Content // -void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); +void VerifyGameContents(const std::string &game_path); +void VerifyInstalledContents(); } #endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index d357c11338..d519669ad5 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -10,11 +10,8 @@ namespace QtCommon::Frontend { -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons, - QObject *parent) +StandardButton ShowMessage( + Icon icon, const QString &title, const QString &text, StandardButtons buttons, QObject *parent) { #ifdef YUZU_QT_WIDGETS QMessageBox *box = new QMessageBox(icon, title, text, buttons, (QWidget *) parent); diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 7f43286430..f86b9e1357 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -5,12 +5,12 @@ #define QT_FRONTEND_UTIL_H #include -#include #include "qt_common/qt_common.h" #ifdef YUZU_QT_WIDGETS #include #include +#include #endif /** @@ -23,6 +23,11 @@ Q_NAMESPACE #ifdef YUZU_QT_WIDGETS using Options = QFileDialog::Options; using Option = QFileDialog::Option; + +using StandardButton = QMessageBox::StandardButton; +using StandardButtons = QMessageBox::StandardButtons; + +using Icon = QMessageBox::Icon; #else enum Option { ShowDirsOnly = 0x00000001, @@ -36,44 +41,96 @@ enum Option { Q_ENUM_NS(Option) Q_DECLARE_FLAGS(Options, Option) Q_FLAG_NS(Options) + +enum StandardButton { + // keep this in sync with QDialogButtonBox::StandardButton and QPlatformDialogHelper::StandardButton + NoButton = 0x00000000, + Ok = 0x00000400, + Save = 0x00000800, + SaveAll = 0x00001000, + Open = 0x00002000, + Yes = 0x00004000, + YesToAll = 0x00008000, + No = 0x00010000, + NoToAll = 0x00020000, + Abort = 0x00040000, + Retry = 0x00080000, + Ignore = 0x00100000, + Close = 0x00200000, + Cancel = 0x00400000, + Discard = 0x00800000, + Help = 0x01000000, + Apply = 0x02000000, + Reset = 0x04000000, + RestoreDefaults = 0x08000000, + + FirstButton = Ok, // internal + LastButton = RestoreDefaults, // internal + + YesAll = YesToAll, // obsolete + NoAll = NoToAll, // obsolete + + Default = 0x00000100, // obsolete + Escape = 0x00000200, // obsolete + FlagMask = 0x00000300, // obsolete + ButtonMask = ~FlagMask // obsolete +}; +Q_ENUM_NS(StandardButton) + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +typedef StandardButton Button; +#endif +Q_DECLARE_FLAGS(StandardButtons, StandardButton) +Q_FLAG_NS(StandardButtons) + +enum Icon { + // keep this in sync with QMessageDialogOptions::StandardIcon + NoIcon = 0, + Information = 1, + Warning = 2, + Critical = 3, + Question = 4 +}; +Q_ENUM_NS(Icon) + #endif // TODO(crueter) widgets-less impl, choices et al. -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, +StandardButton ShowMessage(Icon icon, const QString &title, const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + StandardButtons buttons = StandardButton::NoButton, QObject *parent = nullptr); #define UTIL_OVERRIDES(level) \ - inline QMessageBox::StandardButton level(QObject *parent, \ + inline StandardButton level(QObject *parent, \ const QString &title, \ const QString &text, \ - QMessageBox::StandardButtons buttons = QMessageBox::Ok) \ + StandardButtons buttons = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, title, text, buttons, parent); \ + return ShowMessage(Icon::level, title, text, buttons, parent); \ } \ - inline QMessageBox::StandardButton level(QObject *parent, \ + inline StandardButton level(QObject *parent, \ const char *title, \ const char *text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, parent); \ + return ShowMessage(Icon::level, tr(title), tr(text), buttons, parent); \ } \ - inline QMessageBox::StandardButton level(const char *title, \ + inline StandardButton level(const char *title, \ const char *text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, rootObject); \ + return ShowMessage(Icon::level, tr(title), tr(text), buttons, rootObject); \ } \ - inline QMessageBox::StandardButton level(const QString title, \ + inline StandardButton level(const QString title, \ const QString &text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, title, text, buttons, rootObject); \ + return ShowMessage(Icon::level, title, text, buttons, rootObject); \ } UTIL_OVERRIDES(Information) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 488eb8c971..292eefa224 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -5,12 +5,15 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "core/file_sys/savedata_factory.h" +#include "core/hle/service/am/am_types.h" #include "frontend_common/content_manager.h" #include "qt_common.h" #include "qt_common/uisettings.h" #include "qt_frontend_util.h" +#include "yuzu/util/util.h" #include +#include #include #ifdef _WIN32 @@ -397,4 +400,178 @@ void ResetMetadata() } } +// Uhhh // + +// Messages in pre-defined message boxes for less code spaghetti +inline constexpr bool CreateShortcutMessagesGUI(ShortcutMessages imsg, const QString& game_title) +{ + int result = 0; + QMessageBox::StandardButtons buttons; + switch (imsg) { + case ShortcutMessages::Fullscreen: + buttons = QMessageBox::Yes | QMessageBox::No; + result + = QtCommon::Frontend::Information(tr("Create Shortcut"), + tr("Do you want to launch the game in fullscreen?"), + buttons); + return result == QMessageBox::Yes; + case ShortcutMessages::Success: + QtCommon::Frontend::Information(tr("Shortcut Created"), + tr("Successfully created a shortcut to %1").arg(game_title)); + return false; + case ShortcutMessages::Volatile: + buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; + result = QtCommon::Frontend::Warning( + tr("Shortcut may be Volatile!"), + tr("This will create a shortcut to the current AppImage. This may " + "not work well if you update. Continue?"), + buttons); + return result == QMessageBox::Ok; + default: + buttons = QMessageBox::Ok; + QtCommon::Frontend::Critical(tr("Failed to Create Shortcut"), + tr("Failed to create a shortcut to %1").arg(game_title), + buttons); + return false; + } +} + +void CreateShortcut(const std::string& game_path, + const u64 program_id, + const std::string& game_title_, + const ShortcutTarget &target, + std::string arguments_, + const bool needs_title) +{ + // Get path to Eden executable + std::filesystem::path command = GetEdenCommand(); + + // Shortcut path + std::filesystem::path shortcut_path = GetShortcutPath(target); + + if (!std::filesystem::exists(shortcut_path)) { + CreateShortcutMessagesGUI(ShortcutMessages::Failed, + QString::fromStdString(shortcut_path.generic_string())); + LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string()); + return; + } + + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + const auto loader = + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + + std::string game_title{game_title_}; + + // Delete illegal characters from title + if (needs_title) { + game_title = fmt::format("{:016X}", program_id); + if (control.first != nullptr) { + game_title = control.first->GetApplicationName(); + } else { + loader->ReadTitle(game_title); + } + } + + const std::string illegal_chars = "<>:\"/\\|?*."; + for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { + if (illegal_chars.find(*it) != std::string::npos) { + game_title.erase(it.base() - 1); + } + } + + const QString qgame_title = QString::fromStdString(game_title); + + // Get icon from game file + std::vector icon_image_file{}; + if (control.second != nullptr) { + icon_image_file = control.second->ReadAllBytes(); + } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { + LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); + } + + QImage icon_data = + QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); + std::filesystem::path out_icon_path; + if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (!SaveIconToFile(out_icon_path, icon_data)) { + LOG_ERROR(Frontend, "Could not write icon to file"); + } + } else { + QtCommon::Frontend::Critical( + tr("Create Icon"), + tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") + .arg(QString::fromStdString(out_icon_path.string()))); + } + +#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) + // Special case for AppImages + // Warn once if we are making a shortcut to a volatile AppImage + if (command.string().ends_with(".AppImage") && !UISettings::values.shortcut_already_warned) { + if (!CreateShortcutMessagesGUI(ShortcutMessages::Volatile, qgame_title)) { + return; + } + UISettings::values.shortcut_already_warned = true; + } +#endif + + // Create shortcut + std::string arguments{arguments_}; + if (CreateShortcutMessagesGUI(ShortcutMessages::Fullscreen, qgame_title)) { + arguments = "-f " + arguments; + } + const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); + const std::string categories = "Game;Emulator;Qt;"; + const std::string keywords = "Switch;Nintendo;"; + + if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + arguments, categories, keywords, game_title)) { + CreateShortcutMessagesGUI(ShortcutMessages::Success, + qgame_title); + return; + } + CreateShortcutMessagesGUI(ShortcutMessages::Failed, + qgame_title); +} + +constexpr std::string GetShortcutPath(ShortcutTarget target) { + { + std::string shortcut_path{}; + if (target == ShortcutTarget::Desktop) { + shortcut_path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + .toStdString(); + } else if (target == ShortcutTarget::Applications) { + shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + .toStdString(); + } + + return shortcut_path; + } +} + +void CreateHomeMenuShortcut(ShortcutTarget target) { + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + QtCommon::Frontend::Warning(tr("No firmware available"), + tr("Please install firmware to use the home menu.")); + return; + } + + auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + if (!qlaunch_nca) { + QtCommon::Frontend::Warning(tr("Home Menu Applet"), + tr("Home Menu is not available. Please reinstall firmware.")); + return; + } + + auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + const auto game_path = qlaunch_applet_nca->GetFullPath(); + + // TODO(crueter): Make this use the Eden icon + CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); +} + + } // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 9861910833..2872734390 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -5,6 +5,7 @@ #define QT_GAME_UTIL_H #include +#include #include "common/fs/path_util.h" #include @@ -24,6 +25,18 @@ enum class GameListRemoveTarget { CacheStorage, }; +enum class ShortcutTarget { + Desktop, + Applications, +}; + +enum class ShortcutMessages{ + Fullscreen = 0, + Success = 1, + Volatile = 2, + Failed = 3 +}; + bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, const std::filesystem::path& icon_path, @@ -57,6 +70,17 @@ void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); // Metadata // void ResetMetadata(); +// Shortcuts // +void CreateShortcut(const std::string& game_path, + const u64 program_id, + const std::string& game_title_, + const ShortcutTarget& target, + std::string arguments_, + const bool needs_title); + +constexpr std::string GetShortcutPath(ShortcutTarget target); +void CreateHomeMenuShortcut(ShortcutTarget target); + } #endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_progress_dialog.cpp b/src/qt_common/qt_progress_dialog.cpp new file mode 100644 index 0000000000..b4bf74c8bd --- /dev/null +++ b/src/qt_common/qt_progress_dialog.cpp @@ -0,0 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "qt_progress_dialog.h" diff --git a/src/qt_common/qt_progress_dialog.h b/src/qt_common/qt_progress_dialog.h new file mode 100644 index 0000000000..17f6817ffa --- /dev/null +++ b/src/qt_common/qt_progress_dialog.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef QT_PROGRESS_DIALOG_H +#define QT_PROGRESS_DIALOG_H + +#include + +#ifdef YUZU_QT_WIDGETS +#include +#endif + +namespace QtCommon::Frontend { +#ifdef YUZU_QT_WIDGETS + +using QtProgressDialog = QProgressDialog; + +// TODO(crueter): QML impl +#else +class QtProgressDialog +{ +public: + QtProgressDialog(const QString &labelText, + const QString &cancelButtonText, + int minimum, + int maximum, + QObject *parent = nullptr, + Qt::WindowFlags f = Qt::WindowFlags()); + + bool wasCanceled() const; + void setWindowModality(Qt::WindowModality modality); + void setMinimumDuration(int durationMs); + void setAutoClose(bool autoClose); + void setAutoReset(bool autoReset); + +public slots: + void setLabelText(QString &text); + void setRange(int min, int max); + void setValue(int progress); + bool close(); + + void show(); +}; +#endif // YUZU_QT_WIDGETS + +} +#endif // QT_PROGRESS_DIALOG_H diff --git a/src/qt_common/shared_translation.cpp b/src/qt_common/shared_translation.cpp index 81ec35b6d8..8f31e07154 100644 --- a/src/qt_common/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -29,10 +29,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) #define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) - // A setting can be ignored by giving it a blank name + // A setting can be ignored by giving it a blank name - // Applets - INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); + // Applets + INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); INSERT(Settings, error_applet_mode, tr("Error"), QString()); @@ -407,12 +407,6 @@ std::unique_ptr InitializeTranslations(QObject* parent) "their resolution, details and supported controllers and depending on this setting.\n" "Setting to Handheld can help improve performance for low end systems.")); INSERT(Settings, current_user, QString(), QString()); - INSERT(Settings, disable_nca_verification, tr("Disable NCA Verification"), - tr("Disables integrity verification of NCA content archives." - "\nThis may improve loading speed but risks data corruption or invalid files going " - "undetected.\n" - "Is necessary to make games and updates work that needs firmware 20+.")); - INSERT(Settings, hide_nca_verification_popup, QString(), QString()); // Controls diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 7c89730651..fa61cdfb1f 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -650,10 +650,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri // TODO: Implement shortcut creation for macOS #if !defined(__APPLE__) connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() { - emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop); + emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Desktop); }); connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { - emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); + emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Applications); }); #endif connect(properties, &QAction::triggered, diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 367d047c40..94e7b2dc42 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -52,11 +52,6 @@ enum class DumpRomFSTarget { SDMC, }; -enum class GameListShortcutTarget { - Desktop, - Applications, -}; - class GameList : public QWidget { Q_OBJECT @@ -113,7 +108,7 @@ signals: void VerifyIntegrityRequested(const std::string& game_path); void CopyTIDRequested(u64 program_id); void CreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target); + const QtCommon::Game::ShortcutTarget target); void NavigateToGamedbEntryRequested(u64 program_id, const CompatibilityList& compatibility_list); void OpenPerGameGeneralRequested(const std::string& file); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 728ed2068c..0d7a08d63d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1,21 +1,22 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#include "core/hle/service/am/applet_manager.h" +#include "core/loader/nca.h" +#include "core/tools/renderdoc.h" +#include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" +#include "qt_common/qt_content_util.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/qt_meta.h" +#include "qt_common/qt_path_util.h" +#include "qt_common/qt_progress_dialog.h" #include #include #include #include #include #include -#include "core/hle/service/am/applet_manager.h" -#include "core/loader/nca.h" -#include "core/tools/renderdoc.h" -#include "frontend_common/firmware_manager.h" -#include "qt_common/qt_common.h" -#include "qt_common/qt_game_util.h" -#include "qt_common/qt_path_util.h" -#include "qt_common/qt_meta.h" -#include "qt_common/qt_content_util.h" #ifdef __APPLE__ #include // for chdir @@ -398,8 +399,7 @@ inline static bool isDarkMode() { GMainWindow::GMainWindow(bool has_broken_vulkan) : ui{std::make_unique()}, - input_subsystem{std::make_shared()}, user_data_migrator{this}, - provider{std::make_unique()} { + input_subsystem{std::make_shared()}, user_data_migrator{this} { QtCommon::Init(this); Common::FS::CreateEdenPaths(); @@ -543,7 +543,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) QtCommon::system->SetContentProvider(std::make_unique()); QtCommon::system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, - provider.get()); + QtCommon::provider.get()); QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); // Remove cached contents generated during the previous session @@ -1091,7 +1091,7 @@ void GMainWindow::InitializeWidgets() { render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *QtCommon::system); render_window->hide(); - game_list = new GameList(QtCommon::vfs, provider.get(), *play_time_manager, *QtCommon::system, this); + game_list = new GameList(QtCommon::vfs, QtCommon::provider.get(), *play_time_manager, *QtCommon::system, this); ui->horizontalLayout->addWidget(game_list); game_list_placeholder = new GameListPlaceholder(this); @@ -1913,10 +1913,6 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa return false; } - if (!OnCheckNcaVerification()) { - return false; - } - /** Exec */ const Core::SystemResultStatus result{ QtCommon::system->Load(*render_window, filename.toStdString(), params)}; @@ -2023,7 +2019,7 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { u64 program_id = 0; const auto res2 = loader->ReadProgramId(program_id); if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) { - provider->AddEntry(FileSys::TitleType::Application, + QtCommon::provider->AddEntry(FileSys::TitleType::Application, FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id, file); } else if (res2 == Loader::ResultStatus::Success && @@ -2033,7 +2029,7 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { : FileSys::XCI{file}.GetSecurePartitionNSP(); for (const auto& title : nsp->GetNCAs()) { for (const auto& entry : title.second) { - provider->AddEntry(entry.first.first, entry.first.second, title.first, + QtCommon::provider->AddEntry(entry.first.first, entry.first.second, title.first, entry.second->GetBaseFile()); } } @@ -2761,18 +2757,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa // END void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - - const auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - QtCommon::Content::VerifyGameContents(game_path, QtProgressCallback); + QtCommon::Content::VerifyGameContents(game_path); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -2793,44 +2778,12 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QUrl(QStringLiteral("https://eden-emulator.github.io/game/") + directory)); } -// Messages in pre-defined message boxes for less code spaghetti -// TODO(crueter): Still need to decide what to do re: message boxes w/ qml -bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { - int result = 0; - QMessageBox::StandardButtons buttons; - switch (imsg) { - case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES: - buttons = QMessageBox::Yes | QMessageBox::No; - result = - QMessageBox::information(parent, tr("Create Shortcut"), - tr("Do you want to launch the game in fullscreen?"), buttons); - return result == QMessageBox::Yes; - case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: - QMessageBox::information(parent, tr("Create Shortcut"), - tr("Successfully created a shortcut to %1").arg(game_title)); - return false; - case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: - buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; - result = - QMessageBox::warning(this, tr("Create Shortcut"), - tr("This will create a shortcut to the current AppImage. This may " - "not work well if you update. Continue?"), - buttons); - return result == QMessageBox::Ok; - default: - buttons = QMessageBox::Ok; - QMessageBox::critical(parent, tr("Create Shortcut"), - tr("Failed to create a shortcut to %1").arg(game_title), buttons); - return false; - } -} - void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target) { + const QtCommon::Game::ShortcutTarget target) { // Create shortcut std::string arguments = fmt::format("-g \"{:s}\"", game_path); - CreateShortcut(game_path, program_id, "", target, arguments, true); + QtCommon::Game::CreateShortcut(game_path, program_id, "", target, arguments, true); } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { @@ -3884,74 +3837,11 @@ void GMainWindow::OnOpenLogFolder() } void GMainWindow::OnVerifyInstalledContents() { - // Initialize a progress dialog. - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - - // Declare progress callback. - auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - const std::vector result = - ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, QtProgressCallback); - progress.close(); - - if (result.empty()) { - QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); - } else { - const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); - QMessageBox::critical( - this, tr("Integrity verification failed!"), - tr("Verification failed for the following files:\n\n%1").arg(failed_names)); - } + QtCommon::Content::VerifyInstalledContents(); } void GMainWindow::InstallFirmware(const QString& location, bool recursive) { - QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - progress.show(); - - // Declare progress callback. - auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, QtCommon::vfs.get()); - - progress.close(); - - if (result != QtCommon::Content::FirmwareInstallResult::Success) return; - - auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(90 + static_cast((processed_size * 10) / total_size)); - return progress.wasCanceled(); - }; - - auto results = - ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, VerifyFirmwareCallback, true); - - if (results.size() > 0) { - const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(results, "\n"))); - progress.close(); - QMessageBox::critical( - this, tr("Firmware integrity verification failed!"), - tr("Verification failed for the following files:\n\n%1").arg(failed_names)); - return; - } - - progress.close(); + QtCommon::Content::InstallFirmware(location, recursive); OnCheckFirmwareDecryption(); } @@ -4190,8 +4080,6 @@ void GMainWindow::OnHomeMenu() { break; } - // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh - constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); @@ -4233,164 +4121,11 @@ void GMainWindow::OnInitialSetup() { } void GMainWindow::OnCreateHomeMenuDesktopShortcut() { - OnCreateHomeMenuShortcut(GameListShortcutTarget::Desktop); + QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Desktop); } void GMainWindow::OnCreateHomeMenuApplicationMenuShortcut() { - OnCreateHomeMenuShortcut(GameListShortcutTarget::Applications); -} - -std::filesystem::path GMainWindow::GetEdenCommand() { - std::filesystem::path command; - - QString appimage = QString::fromLocal8Bit(getenv("APPIMAGE")); - if (!appimage.isEmpty()) { - command = std::filesystem::path{appimage.toStdString()}; - } else { - const QStringList args = QApplication::arguments(); - command = args[0].toStdString(); - } - - // If relative path, make it an absolute path - if (command.c_str()[0] == '.') { - command = Common::FS::GetCurrentDir() / command; - } - - return command; -} - -std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target) { - std::filesystem::path shortcut_path{}; - if (target == GameListShortcutTarget::Desktop) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); - } else if (target == GameListShortcutTarget::Applications) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); - } - - return shortcut_path; -} - -// TODO(crueter): Migrate -void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { - // Get path to Eden executable - std::filesystem::path command = GetEdenCommand(); - - // Shortcut path - std::filesystem::path shortcut_path = GetShortcutPath(target); - - if (!std::filesystem::exists(shortcut_path)) { - GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, - QString::fromStdString(shortcut_path.generic_string())); - LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string()); - return; - } - - const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), - QtCommon::system->GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - const auto loader = - Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); - - std::string game_title{game_title_}; - - // Delete illegal characters from title - if (needs_title) { - game_title = fmt::format("{:016X}", program_id); - if (control.first != nullptr) { - game_title = control.first->GetApplicationName(); - } else { - loader->ReadTitle(game_title); - } - } - - const std::string illegal_chars = "<>:\"/\\|?*."; - for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { - if (illegal_chars.find(*it) != std::string::npos) { - game_title.erase(it.base() - 1); - } - } - - const QString qgame_title = QString::fromStdString(game_title); - - // Get icon from game file - std::vector icon_image_file{}; - if (control.second != nullptr) { - icon_image_file = control.second->ReadAllBytes(); - } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { - LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); - } - - QImage icon_data = - QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); - std::filesystem::path out_icon_path; - if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { - if (!SaveIconToFile(out_icon_path, icon_data)) { - LOG_ERROR(Frontend, "Could not write icon to file"); - } - } else { - QMessageBox::critical( - this, tr("Create Icon"), - tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(out_icon_path.string())), - QMessageBox::StandardButton::Ok); - } - -#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) - // Special case for AppImages - // Warn once if we are making a shortcut to a volatile AppImage - if (command.string().ends_with(".AppImage") && !UISettings::values.shortcut_already_warned) { - if (!GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, qgame_title)) { - return; - } - UISettings::values.shortcut_already_warned = true; - } -#endif - - // Create shortcut - std::string arguments{arguments_}; - if (GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qgame_title)) { - arguments = "-f " + arguments; - } - const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); - const std::string categories = "Game;Emulator;Qt;"; - const std::string keywords = "Switch;Nintendo;"; - - if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, - arguments, categories, keywords, game_title)) { - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, - qgame_title); - return; - } - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, - qgame_title); -} - -void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { - constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); - if (!bis_system) { - QMessageBox::warning(this, tr("No firmware available"), - tr("Please install firmware to use the home menu.")); - return; - } - - auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); - if (!qlaunch_nca) { - QMessageBox::warning(this, tr("Home Menu Applet"), - tr("Home Menu is not available. Please reinstall firmware.")); - return; - } - - auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); - const auto game_path = qlaunch_applet_nca->GetFullPath(); - - // TODO(crueter): Make this use the Eden icon - CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); + QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Applications); } void GMainWindow::OnCaptureScreenshot() { @@ -4718,7 +4453,6 @@ void GMainWindow::OnMouseActivity() { } void GMainWindow::OnCheckFirmwareDecryption() { - QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); if (!ContentManager::AreKeysPresent()) { QMessageBox::warning(this, tr("Derivation Components Missing"), tr("Encryption keys are missing.")); @@ -4727,41 +4461,6 @@ void GMainWindow::OnCheckFirmwareDecryption() { UpdateMenuState(); } -bool GMainWindow::OnCheckNcaVerification() { - if (!Settings::values.disable_nca_verification.GetValue()) - return true; - - const bool currently_hidden = Settings::values.hide_nca_verification_popup.GetValue(); - LOG_INFO(Frontend, "NCA Verification is disabled. Popup State={}", currently_hidden); - if (currently_hidden) - return true; - - QMessageBox msgbox(this); - msgbox.setWindowTitle(tr("NCA Verification Disabled")); - msgbox.setText(tr("NCA Verification is disabled.\n" - "This is required to run new games and updates.\n" - "Running without verification can cause instability or crashes if NCA files " - "are corrupt, modified, or tampered.\n" - "If unsure, re-enable verification in Eden's Settings and use firmware " - "version 19.0.1 or below.")); - msgbox.setIcon(QMessageBox::Warning); - msgbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - msgbox.setDefaultButton(QMessageBox::Ok); - - QCheckBox* cb = new QCheckBox(tr("Don't show again"), &msgbox); - cb->setChecked(currently_hidden); - msgbox.setCheckBox(cb); - - int result = msgbox.exec(); - - const bool hide = cb->isChecked(); - if (hide != currently_hidden) { - Settings::values.hide_nca_verification_popup.SetValue(hide); - } - - return result == static_cast(QMessageBox::Ok); -} - bool GMainWindow::CheckFirmwarePresence() { return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 0bc5913acc..e3922759b0 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -54,7 +54,6 @@ class QSlider; class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; -enum class GameListShortcutTarget; enum class DumpRomFSTarget; class GameListPlaceholder; @@ -161,13 +160,6 @@ class GMainWindow : public QMainWindow { /// Max number of recently loaded items to keep track of static const int max_recent_files_item = 10; - enum { - CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, - CREATE_SHORTCUT_MSGBOX_SUCCESS, - CREATE_SHORTCUT_MSGBOX_ERROR, - CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, - }; - public: void filterBarSetChecked(bool state); void UpdateUITheme(); @@ -177,7 +169,7 @@ public: bool DropAction(QDropEvent* event); void AcceptDropEvent(QDropEvent* event); - std::filesystem::path GetShortcutPath(GameListShortcutTarget target); + std::filesystem::path GetShortcutPath(QtCommon::Game::ShortcutTarget target); signals: @@ -358,8 +350,9 @@ private slots: void OnGameListCopyTID(u64 program_id); void OnGameListNavigateToGamedbEntry(u64 program_id, const CompatibilityList& compatibility_list); - void OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target); + void OnGameListCreateShortcut(u64 program_id, + const std::string& game_path, + const QtCommon::Game::ShortcutTarget target); void OnGameListOpenDirectory(const QString& directory); void OnGameListAddDirectory(); void OnGameListShowList(bool show); @@ -416,7 +409,6 @@ private slots: void OnInitialSetup(); void OnCreateHomeMenuDesktopShortcut(); void OnCreateHomeMenuApplicationMenuShortcut(); - void OnCreateHomeMenuShortcut(GameListShortcutTarget target); void OnCaptureScreenshot(); void OnCheckFirmwareDecryption(); void OnLanguageChanged(const QString& locale); @@ -537,9 +529,6 @@ private: QString startup_icon_theme; - // FS - std::unique_ptr provider; - // Debugger panes WaitTreeWidget* waitTreeWidget; ControllerDialog* controller_dialog; @@ -586,7 +575,7 @@ private: void CreateShortcut(const std::string& game_path, const u64 program_id, const std::string& game_title, - GameListShortcutTarget target, + QtCommon::Game::ShortcutTarget target, std::string arguments, const bool needs_title); From b326f2e3e0440208d99e2851522beb339a3b2044 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:47:34 -0400 Subject: [PATCH 20/52] fix headers Signed-off-by: crueter --- .../fssystem/fssystem_nca_file_system_driver.cpp | 3 --- src/yuzu/main.cpp | 12 ++---------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index 4e624ad3f4..37fb71e9e3 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,9 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0d7a08d63d..9480fed5b3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -10,11 +10,8 @@ #include "qt_common/qt_game_util.h" #include "qt_common/qt_meta.h" #include "qt_common/qt_path_util.h" -#include "qt_common/qt_progress_dialog.h" #include #include -#include -#include #include #include @@ -43,21 +40,16 @@ #include "configuration/configure_input.h" #include "configuration/configure_per_game.h" #include "configuration/configure_tas.h" -#include "core/core_timing.h" #include "core/file_sys/romfs_factory.h" -#include "core/file_sys/vfs/vfs.h" -#include "core/file_sys/vfs/vfs_real.h" #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general.h" #include "core/frontend/applets/mii_edit.h" #include "core/frontend/applets/software_keyboard.h" -#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/frontend/applets.h" -#include "core/hle/service/set/system_settings_server.h" #include "frontend_common/content_manager.h" -#include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" +#include "hid_core/frontend/emulated_controller.h" #include "yuzu/multiplayer/state.h" #include "yuzu/util/controller_navigation.h" @@ -139,6 +131,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/file_sys/savedata_factory.h" #include "core/file_sys/submission_package.h" #include "core/hle/kernel/k_process.h" +#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/sm/sm.h" @@ -166,7 +159,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/discord.h" #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" -#include "yuzu/hotkeys.h" #include "yuzu/install_dialog.h" #include "yuzu/loading_screen.h" #include "yuzu/main.h" From c70d9140a48e121326f278f8e6da550242a62432 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:49:10 -0400 Subject: [PATCH 21/52] Fix cpm-fetch Signed-off-by: crueter --- docs/CPM.md | 2 +- tools/cpm-fetch-all.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CPM.md b/docs/CPM.md index 2afcdaf164..bce224da40 100644 --- a/docs/CPM.md +++ b/docs/CPM.md @@ -245,6 +245,6 @@ include(CPMUtil) Currently, `cpm-fetch.sh` defines the following directories for cpmfiles (max depth of 2, so subdirs are caught as well): -`externals src/yuzu src/dynarmic .` +`externals src/qt_common src/dynarmic .` Whenever you add a new cpmfile, update the script accordingly \ No newline at end of file diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh index eac0f861a4..66f55df94d 100755 --- a/tools/cpm-fetch-all.sh +++ b/tools/cpm-fetch-all.sh @@ -6,6 +6,6 @@ # SPDX-FileCopyrightText: 2025 crueter # SPDX-License-Identifier: GPL-3.0-or-later -LIBS=$(find . externals src/yuzu/externals src/dynarmic -maxdepth 2 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") +LIBS=$(find . externals src/qt_common src/dynarmic -maxdepth 2 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") tools/cpm-fetch.sh $LIBS \ No newline at end of file From 63961f3741b49ff7dd4133cc9ec8a57fdbca6cea Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:51:44 -0400 Subject: [PATCH 22/52] fix cpm-fetch (again) Signed-off-by: crueter --- tools/cpm-fetch.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cpm-fetch.sh b/tools/cpm-fetch.sh index 5620996433..996cf76a97 100755 --- a/tools/cpm-fetch.sh +++ b/tools/cpm-fetch.sh @@ -105,7 +105,8 @@ ci_package() { for package in $@ do # prepare for cancer - JSON=$(find . externals src/yuzu/externals externals/ffmpeg src/dynarmic/externals externals/nx_tzdb -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) + # TODO(crueter): Fetch json once? + JSON=$(find . externals src/qt_common src/dynarmic -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) [ -z "$JSON" ] && echo "No cpmfile definition for $package" && continue From ae31504772b8d1b10b294eb9f8ebde90abc0dc57 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 12:09:12 -0400 Subject: [PATCH 23/52] fix msvc Signed-off-by: crueter --- src/qt_common/qt_game_util.cpp | 2 +- src/qt_common/qt_game_util.h | 3 +-- src/yuzu/main.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 292eefa224..3b667b7700 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -357,7 +357,7 @@ void RemoveCustomConfiguration(u64 program_id, const std::string& game_path) } } -void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs) +void RemoveCacheStorage(u64 program_id) { const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); auto vfs_nand_dir = vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 2872734390..0a21208659 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -7,7 +7,6 @@ #include #include #include "common/fs/path_util.h" -#include namespace QtCommon::Game { @@ -65,7 +64,7 @@ void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); void RemoveVulkanDriverPipelineCache(u64 program_id); void RemoveAllTransferableShaderCaches(u64 program_id); void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); -void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); +void RemoveCacheStorage(u64 program_id); // Metadata // void ResetMetadata(); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9480fed5b3..a411270ca8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2616,7 +2616,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListR QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; case QtCommon::Game::GameListRemoveTarget::CacheStorage: - QtCommon::Game::RemoveCacheStorage(program_id, QtCommon::vfs.get()); + QtCommon::Game::RemoveCacheStorage(program_id); break; } } From a572ee58d3c77df201c9af2eeeeab9395f56b47b Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 12:28:59 -0400 Subject: [PATCH 24/52] fix windows Signed-off-by: crueter --- src/yuzu/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a411270ca8..d7d4e94ab7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -113,6 +113,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/scm_rev.h" #include "common/scope_exit.h" #ifdef _WIN32 +#include "core/core_timing.h" #include "common/windows/timer_resolution.h" #endif #ifdef ARCHITECTURE_x86_64 @@ -1470,7 +1471,7 @@ void GMainWindow::InitializeHotkeys() { connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); }); - connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [this] { + connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [] { if (Settings::values.enable_renderdoc_hotkey) { QtCommon::system->GetRenderdocAPI().ToggleCapture(); } @@ -2140,7 +2141,7 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::string title_version; const auto res = QtCommon::system->GetGameName(title_name); - const auto metadata = [this, title_id] { + const auto metadata = [title_id] { const FileSys::PatchManager pm(title_id, QtCommon::system->GetFileSystemController(), QtCommon::system->GetContentProvider()); return pm.GetControlMetadata(); @@ -2371,7 +2372,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target std::filesystem::path path; QString open_target; - const auto [user_save_size, device_save_size] = [this, &game_path, &program_id] { + const auto [user_save_size, device_save_size] = [&game_path, &program_id] { const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata().first; @@ -2958,7 +2959,7 @@ void GMainWindow::OnMenuInstallToNAND() { } return false; }; - future = QtConcurrent::run([this, &file, progress_callback] { + future = QtConcurrent::run([&file, progress_callback] { return ContentManager::InstallNSP(*QtCommon::system, *QtCommon::vfs, file.toStdString(), progress_callback); }); From 6d7820cf01664586e8c560899671f0fadd6e2bfe Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 13:31:32 -0400 Subject: [PATCH 25/52] fix windows dir opening Signed-off-by: crueter --- src/qt_common/qt_game_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 3b667b7700..5d0b4d8ae7 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -165,7 +165,7 @@ bool MakeShortcutIcoPath(const u64 program_id, void OpenEdenFolder(const Common::FS::EdenPath& path) { - QDesktopServices::openUrl(QUrl(QString::fromStdString(Common::FS::GetEdenPathString(path)))); + QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(Common::FS::GetEdenPathString(path)))); } void OpenRootDataFolder() From d207df959a29cc4758c5328a3cdc96d909a96c92 Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 15 Sep 2025 04:22:15 +0200 Subject: [PATCH 26/52] [cmake, core] refactor: update mbedtls and make YUZU_USE_CPM better (#485) update mbedtls functors to support mbedtls3 signatures moved some vulkan stuff from externals to root, yuzu_use_cpm manages them now needs testing: - all key/derivation related things - nca verification - game loading/updates/stuff Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/485 Reviewed-by: MaranBr --- CMakeLists.txt | 36 +++++++-- CMakeModules/Findmbedtls.cmake | 17 ----- cpmfile.json | 36 +++++++++ externals/CMakeLists.txt | 76 ++++--------------- externals/cpmfile.json | 42 ++-------- externals/libusb/CMakeLists.txt | 12 ++- src/core/CMakeLists.txt | 2 +- src/core/crypto/aes_util.h | 2 +- src/core/crypto/key_manager.cpp | 2 +- src/core/crypto/partition_data_manager.cpp | 4 +- src/core/file_sys/registered_cache.cpp | 10 +-- src/core/file_sys/xts_archive.cpp | 2 +- .../bcat/delivery_cache_directory_service.cpp | 2 +- src/core/hle/service/ro/ro.cpp | 2 +- src/core/loader/nca.cpp | 6 +- src/dedicated_room/CMakeLists.txt | 2 +- 16 files changed, 114 insertions(+), 139 deletions(-) delete mode 100644 CMakeModules/Findmbedtls.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a9e15cfbd..fdf8900775 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,8 +159,6 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF) option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" ${EXT_DEFAULT}) -option(YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan Utility Headers from externals" ${EXT_DEFAULT}) -option(YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS "Use SPIRV-Tools from externals" ${EXT_DEFAULT}) option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) @@ -172,8 +170,6 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) CMAKE_DEPENDENT_OPTION(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF "ENABLE_QT" OFF) -option(ENABLE_MICROPROFILE "Enables microprofile capabilities" OFF) - option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}") option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ${EXT_DEFAULT}) @@ -455,6 +451,28 @@ if (YUZU_USE_CPM) ) endif() endif() + + # VulkanUtilityHeaders - pulls in headers and utility libs + AddJsonPackage(vulkan-utility-headers) + + # small hack + if (NOT VulkanUtilityLibraries_ADDED) + find_package(VulkanHeaders 1.3.274 REQUIRED) + endif() + + # SPIRV Headers + AddJsonPackage(spirv-headers) + + # SPIRV Tools + AddJsonPackage(spirv-tools) + + if (SPIRV-Tools_ADDED) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) + target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link) + endif() + + # mbedtls + AddJsonPackage(mbedtls) else() # Enforce the search mode of non-required packages for better and shorter failure messages find_package(fmt 8 REQUIRED) @@ -467,7 +485,13 @@ else() find_package(Opus 1.3 MODULE REQUIRED) find_package(ZLIB 1.2 REQUIRED) find_package(zstd 1.5 REQUIRED MODULE) - find_package(Boost 1.79.0 REQUIRED headers context system fiber) + find_package(Boost 1.57.0 REQUIRED context system fiber) + find_package(MbedTLS 3) + + find_package(VulkanUtilityLibraries REQUIRED) + find_package(VulkanHeaders 1.3.274 REQUIRED) + find_package(SPIRV-Tools MODULE REQUIRED) + find_package(SPIRV-Headers 1.3.274 REQUIRED) if (YUZU_TESTS) find_package(Catch2 3.0.1 REQUIRED) @@ -594,10 +618,8 @@ endfunction() add_subdirectory(externals) # pass targets from externals -find_package(VulkanUtilityLibraries) find_package(libusb) find_package(VulkanMemoryAllocator) -find_package(SPIRV-Tools) if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) find_package(xbyak) diff --git a/CMakeModules/Findmbedtls.cmake b/CMakeModules/Findmbedtls.cmake deleted file mode 100644 index f5ebf1abdc..0000000000 --- a/CMakeModules/Findmbedtls.cmake +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-FileCopyrightText: 2025 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -include(FindPackageHandleStandardArgs) - -find_package(PkgConfig QUIET) -pkg_search_module(mbedtls QUIET IMPORTED_TARGET mbedtls) -find_package_handle_standard_args(mbedtls - REQUIRED_VARS mbedtls_LINK_LIBRARIES - VERSION_VAR mbedtls_VERSION -) - -pkg_search_module(mbedcrypto QUIET IMPORTED_TARGET mbedcrypto) -find_package_handle_standard_args(mbedcrypto - REQUIRED_VARS mbedcrypto_LINK_LIBRARIES - VERSION_VAR mbedcrypto_VERSION -) diff --git a/cpmfile.json b/cpmfile.json index e071e0a8b8..887e958533 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -91,6 +91,42 @@ "OPUS_PRESUME_NEON ON" ] }, + "vulkan-utility-headers": { + "package": "VulkanUtilityLibraries", + "repo": "scripts/VulkanUtilityHeaders", + "tag": "1.4.326", + "artifact": "VulkanUtilityHeaders.tar.zst", + "git_host": "git.crueter.xyz", + "hash": "5924629755cb1605c4aa4eee20ef7957a9dd8d61e4df548be656d98054f2730c4109693c1bd35811f401f4705d2ccff9fc849be32b0d8480bc3f73541a5e0964" + }, + "spirv-tools": { + "package": "SPIRV-Tools", + "repo": "KhronosGroup/SPIRV-Tools", + "sha": "40eb301f32", + "hash": "58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa", + "find_args": "MODULE", + "options": [ + "SPIRV_SKIP_EXECUTABLES ON" + ] + }, + "spirv-headers": { + "package": "SPIRV-Headers", + "repo": "KhronosGroup/SPIRV-Headers", + "sha": "4e209d3d7e", + "hash": "f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4", + "options": [ + "SPIRV_WERROR OFF" + ] + }, + "mbedtls": { + "package": "MbedTLS", + "repo": "Mbed-TLS/mbedtls", + "tag": "mbedtls-%VERSION%", + "hash": "6671fb8fcaa832e5b115dfdce8f78baa6a4aea71f5c89a640583634cdee27aefe3bf4be075744da91f7c3ae5ea4e0c765c8fc3937b5cfd9ea73d87ef496524da", + "version": "3", + "git_version": "3.6.4", + "artifact": "%TAG%.tar.bz2" + }, "cubeb": { "repo": "mozilla/cubeb", "sha": "fa02160712", diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 9f89cfc1f5..aba5451b6d 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -54,36 +54,27 @@ endif() # Glad add_subdirectory(glad) -# mbedtls -AddJsonPackage(mbedtls) - -if (mbedtls_ADDED) - target_include_directories(mbedtls PUBLIC ${mbedtls_SOURCE_DIR}/include) - - if (NOT MSVC) - target_compile_options(mbedcrypto PRIVATE - -Wno-unused-but-set-variable - -Wno-string-concatenation - ) - elseif(CXX_CLANG) - foreach(TARGET mbedtls mbedcrypto mbedx509) - target_compile_options(${TARGET} PRIVATE - -w - ) - endforeach() - endif() -endif() - # libusb if (ENABLE_LIBUSB) add_subdirectory(libusb) endif() -# Sirit -# TODO(crueter): spirv-tools doesn't work w/ system -set(SPIRV_WERROR OFF) -AddJsonPackage(spirv-headers) +# VMA +AddJsonPackage(vulkan-memory-allocator) +if (VulkanMemoryAllocator_ADDED) + if (CXX_CLANG) + target_compile_options(VulkanMemoryAllocator INTERFACE + -Wno-unused-variable + ) + elseif(MSVC) + target_compile_options(VulkanMemoryAllocator INTERFACE + /wd4189 + ) + endif() +endif() + +# Sirit AddJsonPackage(sirit) if(MSVC AND USE_CCACHE AND sirit_ADDED) @@ -117,46 +108,9 @@ if (YUZU_USE_BUNDLED_FFMPEG) set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE) endif() -# VulkanUtilityHeaders - pulls in headers and utility libs -AddJsonPackage( - NAME vulkan-utility-headers - BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES} -) - -# small hack -if (NOT VulkanUtilityLibraries_ADDED) - find_package(VulkanHeaders 1.3.274 REQUIRED) -endif() - -# SPIRV Tools -AddJsonPackage( - NAME spirv-tools - BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS} -) - -if (SPIRV-Tools_ADDED) - add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) - target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link) -endif() - # TZDB (Time Zone Database) add_subdirectory(nx_tzdb) -# VMA -AddJsonPackage(vulkan-memory-allocator) - -if (VulkanMemoryAllocator_ADDED) - if (CXX_CLANG) - target_compile_options(VulkanMemoryAllocator INTERFACE - -Wno-unused-variable - ) - elseif(MSVC) - target_compile_options(VulkanMemoryAllocator INTERFACE - /wd4189 - ) - endif() -endif() - if (NOT TARGET LLVM::Demangle) add_library(demangle demangle/ItaniumDemangle.cpp) target_include_directories(demangle PUBLIC ./demangle) diff --git a/externals/cpmfile.json b/externals/cpmfile.json index 65f50ffdfc..283da76743 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -1,15 +1,10 @@ { - "mbedtls": { - "repo": "eden-emulator/mbedtls", - "sha": "ce4f81f4a9", - "hash": "f2e7f887651b28745e508149214d409fd7cfdb92cb94b4146b47ff1e0fc09e47143f203ac18e34c2c1814b5bd031d04c74828676c0d4342920a2ddb7fd35e9a5", - "find_args": "MODULE" - }, - "spirv-headers": { - "package": "SPIRV-Headers", - "repo": "KhronosGroup/SPIRV-Headers", - "sha": "4e209d3d7e", - "hash": "f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4" + "vulkan-memory-allocator": { + "package": "VulkanMemoryAllocator", + "repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator", + "sha": "1076b348ab", + "hash": "a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772", + "find_args": "CONFIG" }, "sirit": { "repo": "eden-emulator/sirit", @@ -35,31 +30,6 @@ "CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF" ] }, - "vulkan-utility-headers": { - "package": "VulkanUtilityLibraries", - "repo": "scripts/VulkanUtilityHeaders", - "tag": "1.4.326", - "artifact": "VulkanUtilityHeaders.tar.zst", - "git_host": "git.crueter.xyz", - "hash": "5924629755cb1605c4aa4eee20ef7957a9dd8d61e4df548be656d98054f2730c4109693c1bd35811f401f4705d2ccff9fc849be32b0d8480bc3f73541a5e0964" - }, - "vulkan-memory-allocator": { - "package": "VulkanMemoryAllocator", - "repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator", - "sha": "1076b348ab", - "hash": "a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772", - "find_args": "CONFIG" - }, - "spirv-tools": { - "package": "SPIRV-Tools", - "repo": "KhronosGroup/SPIRV-Tools", - "sha": "40eb301f32", - "hash": "58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa", - "find_args": "MODULE", - "options": [ - "SPIRV_SKIP_EXECUTABLES ON" - ] - }, "xbyak_sun": { "package": "xbyak", "repo": "herumi/xbyak", diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt index 0a20ca94b8..cfa9a02a2a 100644 --- a/externals/libusb/CMakeLists.txt +++ b/externals/libusb/CMakeLists.txt @@ -3,7 +3,17 @@ include(CPMUtil) -AddJsonPackage(libusb) +if (PLATFORM_SUN OR PLATFORM_OPENBSD OR PLATFORM_FREEBSD) + set(libusb_bundled ON) +else() + set(libusb_bundled OFF) +endif() + +# TODO(crueter): Fix on *BSD/Solaris +AddJsonPackage( + NAME libusb + BUNDLED_PACKAGE ${libusb_bundled} +) if (NOT libusb_ADDED) return() diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1e8e4ec07a..89c97eb1aa 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1200,7 +1200,7 @@ else() target_link_libraries(core PUBLIC Boost::headers) endif() -target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API mbedtls mbedcrypto) +target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto MbedTLS::mbedtls) if (MINGW) target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) endif() diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h index c2fd587a73..0a2a4e464c 100644 --- a/src/core/crypto/aes_util.h +++ b/src/core/crypto/aes_util.h @@ -16,7 +16,7 @@ struct CipherContext; enum class Mode { CTR = 11, ECB = 2, - XTS = 70, + XTS = 74, }; enum class Op { diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 04b75d5e8f..6d0b32ba70 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -539,7 +539,7 @@ static std::array MGF1(const std::array& seed) { while (out.size() < target_size) { out.resize(out.size() + 0x20); seed_exp[in_size + 3] = static_cast(i); - mbedtls_sha256_ret(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0); + mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0); ++i; } diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index 4b45e72c43..905b8139ef 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -178,7 +178,7 @@ std::array FindKeyFromHex(const std::vector& binary, std::array temp{}; for (size_t i = 0; i < binary.size() - key_size; ++i) { - mbedtls_sha256_ret(binary.data() + i, key_size, temp.data(), 0); + mbedtls_sha256(binary.data() + i, key_size, temp.data(), 0); if (temp != hash) continue; @@ -206,7 +206,7 @@ static std::array FindEncryptedMasterKeyFromHex(const std::vector< AESCipher cipher(key, Mode::ECB); for (size_t i = 0; i < binary.size() - 0x10; ++i) { cipher.Transcode(binary.data() + i, dec_temp.size(), dec_temp.data(), Op::Decrypt); - mbedtls_sha256_ret(dec_temp.data(), dec_temp.size(), temp.data(), 0); + mbedtls_sha256(dec_temp.data(), dec_temp.size(), temp.data(), 0); for (size_t k = 0; k < out.size(); ++k) { if (temp == master_key_hashes[k]) { diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index cb2089e9b3..45390500cc 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -64,7 +64,7 @@ static std::string GetRelativePathFromNcaID(const std::array& nca_id, bo } Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0); + mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); const auto format_str = fmt::runtime(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca"); @@ -146,7 +146,7 @@ bool PlaceholderCache::Create(const NcaID& id, u64 size) const { } Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0); + mbedtls_sha256(id.data(), id.size(), hash.data(), 0); const auto dirname = fmt::format("000000{:02X}", hash[0]); const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); @@ -170,7 +170,7 @@ bool PlaceholderCache::Delete(const NcaID& id) const { } Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0); + mbedtls_sha256(id.data(), id.size(), hash.data(), 0); const auto dirname = fmt::format("000000{:02X}", hash[0]); const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); @@ -665,7 +665,7 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, const OptionalHeader opt_header{0, 0}; ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}}; const auto& data = nca.GetBaseFile()->ReadBytes(0x100000); - mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0); + mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); std::memcpy(&c_rec.nca_id, &c_rec.hash, 16); const CNMT new_cnmt(header, opt_header, {c_rec}, {}); if (!RawInstallYuzuMeta(new_cnmt)) { @@ -776,7 +776,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti id = *override_id; } else { const auto& data = in->ReadBytes(0x100000); - mbedtls_sha256_ret(data.data(), data.size(), hash.data(), 0); + mbedtls_sha256(data.data(), data.size(), hash.data(), 0); memcpy(id.data(), hash.data(), 16); } diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index fd5342021c..c1912b2bda 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -68,7 +68,7 @@ NAX::NAX(VirtualFile file_, std::array nca_id) : header(std::make_unique()), file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} { Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0); + mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0], Common::HexToString(nca_id, false))); } diff --git a/src/core/hle/service/bcat/delivery_cache_directory_service.cpp b/src/core/hle/service/bcat/delivery_cache_directory_service.cpp index fea373a607..31693cfc33 100644 --- a/src/core/hle/service/bcat/delivery_cache_directory_service.cpp +++ b/src/core/hle/service/bcat/delivery_cache_directory_service.cpp @@ -15,7 +15,7 @@ namespace Service::BCAT { static BcatDigest DigestFile(const FileSys::VirtualFile& file) { BcatDigest out{}; const auto bytes = file->ReadAllBytes(); - mbedtls_md5_ret(bytes.data(), bytes.size(), out.data()); + mbedtls_md5(bytes.data(), bytes.size(), out.data()); return out; } diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index 3d3ad2d62c..600d0ec4fd 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp @@ -178,7 +178,7 @@ struct ProcessContext { std::vector nro_data(size); m_process->GetMemory().ReadBlock(base_address, nro_data.data(), size); - mbedtls_sha256_ret(nro_data.data(), size, hash.data(), 0); + mbedtls_sha256(nro_data.data(), size, hash.data(), 0); } for (size_t i = 0; i < MaxNrrInfos; i++) { diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 9a82dae144..0a9d9dc6f8 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -150,7 +150,7 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function // Initialize sha256 verification context. mbedtls_sha256_context ctx; mbedtls_sha256_init(&ctx); - mbedtls_sha256_starts_ret(&ctx, 0); + mbedtls_sha256_starts(&ctx, 0); // Ensure we maintain a clean state on exit. SCOPE_EXIT { @@ -168,7 +168,7 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function const size_t read_size = file->Read(buffer.data(), intended_read_size, processed_size); // Update the hash function with the buffer contents. - mbedtls_sha256_update_ret(&ctx, buffer.data(), read_size); + mbedtls_sha256_update(&ctx, buffer.data(), read_size); // Update counters. processed_size += read_size; @@ -181,7 +181,7 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function // Finalize context and compute the output hash. std::array output_hash; - mbedtls_sha256_finish_ret(&ctx, output_hash.data()); + mbedtls_sha256_finish(&ctx, output_hash.data()); // Compare to expected. if (std::memcmp(input_hash.data(), output_hash.data(), NcaSha256HalfHashLength) != 0) { diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index e5934c941a..5166329156 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -20,7 +20,7 @@ if (ENABLE_WEB_SERVICE) target_link_libraries(yuzu-room PRIVATE web_service) endif() -target_link_libraries(yuzu-room PRIVATE mbedtls mbedcrypto) +target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto MbedTLS::mbedtls) if (MSVC) target_link_libraries(yuzu-room PRIVATE getopt) endif() From 4c5d03f5defedd6decf2dfbbaca93a518e6d0adc Mon Sep 17 00:00:00 2001 From: Nixyn Date: Mon, 15 Sep 2025 06:26:06 +0200 Subject: [PATCH 27/52] [android / GameUI] Add grid compact layout and fix ugly borders on grid layout (#401) Tis PR adds a new layout for the Game Adapter with shorter cards and fixes the ugly borders in Game Adapter's Grid layout. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/401 Reviewed-by: crueter Reviewed-by: MaranBr Co-authored-by: Nixyn Co-committed-by: Nixyn --- .../org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 46 ++++++++++- .../org/yuzu/yuzu_emu/ui/GamesFragment.kt | 13 +++ .../res/drawable/gradient_overlay_bottom.xml | 9 ++ .../src/main/res/layout/card_game_grid.xml | 15 ++-- .../res/layout/card_game_grid_compact.xml | 82 +++++++++++++++++++ .../app/src/main/res/menu/menu_game_views.xml | 3 + .../app/src/main/res/values/strings.xml | 1 + 7 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml create mode 100644 src/android/app/src/main/res/layout/card_game_grid_compact.xml diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 98f342c274..0a2cb41745 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -36,17 +36,18 @@ import androidx.core.net.toUri import androidx.core.content.edit import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.yuzu.yuzu_emu.NativeLibrary +import org.yuzu.yuzu_emu.databinding.CardGameGridCompactBinding import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.Settings -import org.yuzu.yuzu_emu.utils.NativeConfig class GameAdapter(private val activity: AppCompatActivity) : AbstractDiffAdapter(exact = false) { companion object { const val VIEW_TYPE_GRID = 0 - const val VIEW_TYPE_LIST = 1 - const val VIEW_TYPE_CAROUSEL = 2 + const val VIEW_TYPE_GRID_COMPACT = 1 + const val VIEW_TYPE_LIST = 2 + const val VIEW_TYPE_CAROUSEL = 3 } private var viewType = 0 @@ -80,6 +81,7 @@ class GameAdapter(private val activity: AppCompatActivity) : listBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT listBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT } + VIEW_TYPE_GRID -> { val gridBinding = holder.binding as CardGameGridBinding gridBinding.cardGameGrid.scaleX = 1f @@ -89,6 +91,17 @@ class GameAdapter(private val activity: AppCompatActivity) : gridBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT gridBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT } + + VIEW_TYPE_GRID_COMPACT -> { + val gridCompactBinding = holder.binding as CardGameGridCompactBinding + gridCompactBinding.cardGameGridCompact.scaleX = 1f + gridCompactBinding.cardGameGridCompact.scaleY = 1f + gridCompactBinding.cardGameGridCompact.alpha = 1f + // Reset layout params to XML defaults (same as normal grid) + gridCompactBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT + gridCompactBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT + } + VIEW_TYPE_CAROUSEL -> { val carouselBinding = holder.binding as CardGameCarouselBinding // soothens transient flickering @@ -105,16 +118,25 @@ class GameAdapter(private val activity: AppCompatActivity) : parent, false ) + VIEW_TYPE_GRID -> CardGameGridBinding.inflate( LayoutInflater.from(parent.context), parent, false ) + + VIEW_TYPE_GRID_COMPACT -> CardGameGridCompactBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + VIEW_TYPE_CAROUSEL -> CardGameCarouselBinding.inflate( LayoutInflater.from(parent.context), parent, false ) + else -> throw IllegalArgumentException("Invalid view type") } return GameViewHolder(binding, viewType) @@ -130,6 +152,7 @@ class GameAdapter(private val activity: AppCompatActivity) : VIEW_TYPE_LIST -> bindListView(model) VIEW_TYPE_GRID -> bindGridView(model) VIEW_TYPE_CAROUSEL -> bindCarouselView(model) + VIEW_TYPE_GRID_COMPACT -> bindGridCompactView(model) } } @@ -168,6 +191,23 @@ class GameAdapter(private val activity: AppCompatActivity) : gridBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT } + private fun bindGridCompactView(model: Game) { + val gridCompactBinding = binding as CardGameGridCompactBinding + + gridCompactBinding.imageGameScreenCompact.scaleType = ImageView.ScaleType.CENTER_CROP + GameIconUtils.loadGameIcon(model, gridCompactBinding.imageGameScreenCompact) + + gridCompactBinding.textGameTitleCompact.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") + + gridCompactBinding.textGameTitleCompact.marquee() + gridCompactBinding.cardGameGridCompact.setOnClickListener { onClick(model) } + gridCompactBinding.cardGameGridCompact.setOnLongClickListener { onLongClick(model) } + + // Reset layout params to XML defaults (same as normal grid) + gridCompactBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT + gridCompactBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT + } + private fun bindCarouselView(model: Game) { val carouselBinding = binding as CardGameCarouselBinding diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt index 03fa1a3a2e..80055628e1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt @@ -194,6 +194,10 @@ class GamesFragment : Fragment() { val columns = resources.getInteger(R.integer.game_columns_grid) GridLayoutManager(context, columns) } + GameAdapter.VIEW_TYPE_GRID_COMPACT -> { + val columns = resources.getInteger(R.integer.game_columns_grid) + GridLayoutManager(context, columns) + } GameAdapter.VIEW_TYPE_LIST -> { val columns = resources.getInteger(R.integer.game_columns_list) GridLayoutManager(context, columns) @@ -300,6 +304,7 @@ class GamesFragment : Fragment() { val currentViewType = getCurrentViewType() when (currentViewType) { GameAdapter.VIEW_TYPE_LIST -> popup.menu.findItem(R.id.view_list).isChecked = true + GameAdapter.VIEW_TYPE_GRID_COMPACT -> popup.menu.findItem(R.id.view_grid_compact).isChecked = true GameAdapter.VIEW_TYPE_GRID -> popup.menu.findItem(R.id.view_grid).isChecked = true GameAdapter.VIEW_TYPE_CAROUSEL -> popup.menu.findItem(R.id.view_carousel).isChecked = true } @@ -314,6 +319,14 @@ class GamesFragment : Fragment() { true } + R.id.view_grid_compact -> { + if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) onPause() + setCurrentViewType(GameAdapter.VIEW_TYPE_GRID_COMPACT) + applyGridGamesBinding() + item.isChecked = true + true + } + R.id.view_list -> { if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) onPause() setCurrentViewType(GameAdapter.VIEW_TYPE_LIST) diff --git a/src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml b/src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml new file mode 100644 index 0000000000..f74cfa0d05 --- /dev/null +++ b/src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml @@ -0,0 +1,9 @@ + + + + diff --git a/src/android/app/src/main/res/layout/card_game_grid.xml b/src/android/app/src/main/res/layout/card_game_grid.xml index 3e0bf6005c..f03a77c4f1 100644 --- a/src/android/app/src/main/res/layout/card_game_grid.xml +++ b/src/android/app/src/main/res/layout/card_game_grid.xml @@ -5,27 +5,32 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="false" - android:focusableInTouchMode="false"> + android:focusableInTouchMode="false" + android:padding="4dp"> + app:cardCornerRadius="16dp" + android:foreground="@color/eden_border_gradient_start"> + android:paddingTop="14dp" + android:paddingLeft="6dp" + android:paddingRight="6dp" + android:paddingBottom="6dp"> + + + + + + + + + + + + + + + + + + + + + diff --git a/src/android/app/src/main/res/menu/menu_game_views.xml b/src/android/app/src/main/res/menu/menu_game_views.xml index 241cdcb4b5..11bf3e695e 100644 --- a/src/android/app/src/main/res/menu/menu_game_views.xml +++ b/src/android/app/src/main/res/menu/menu_game_views.xml @@ -4,6 +4,9 @@ + Alphabetical
List Grid + Compact Grid Carousel Screenshot for %1$s Folder From d2541dde756cdfb2a5ce6e7a6b2f242e7b86741b Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 16:31:36 -0400 Subject: [PATCH 28/52] qt_common init Signed-off-by: crueter --- ffmpeg.patch | 40 ++++++++++++++++ src/CMakeLists.txt | 1 + src/qt_common/CMakeLists.txt | 23 +++++++++ src/{yuzu => qt_common}/qt_common.cpp | 25 ++++++++-- src/qt_common/qt_common.h | 47 +++++++++++++++++++ .../configuration => qt_common}/qt_config.cpp | 0 .../configuration => qt_common}/qt_config.h | 0 .../shared_translation.cpp | 10 ++-- .../shared_translation.h | 9 ++-- src/{yuzu => qt_common}/uisettings.cpp | 2 +- src/{yuzu => qt_common}/uisettings.h | 2 +- src/yuzu/CMakeLists.txt | 13 ++--- src/yuzu/bootmanager.cpp | 9 ++-- src/yuzu/configuration/configure_audio.cpp | 4 +- src/yuzu/configuration/configure_cpu.h | 2 +- src/yuzu/configuration/configure_debug.cpp | 2 +- src/yuzu/configuration/configure_dialog.cpp | 2 +- src/yuzu/configuration/configure_dialog.h | 2 +- .../configuration/configure_filesystem.cpp | 28 +++++------ src/yuzu/configuration/configure_general.cpp | 2 +- src/yuzu/configuration/configure_graphics.cpp | 4 +- src/yuzu/configuration/configure_graphics.h | 2 +- .../configure_graphics_advanced.cpp | 2 +- .../configure_graphics_extensions.cpp | 2 +- src/yuzu/configuration/configure_hotkeys.cpp | 2 +- .../configuration/configure_input_per_game.h | 2 +- .../configuration/configure_input_player.cpp | 2 +- src/yuzu/configuration/configure_per_game.cpp | 2 +- src/yuzu/configuration/configure_per_game.h | 4 +- .../configure_per_game_addons.cpp | 2 +- src/yuzu/configuration/configure_ringcon.cpp | 2 +- src/yuzu/configuration/configure_tas.cpp | 2 +- src/yuzu/configuration/configure_ui.cpp | 2 +- src/yuzu/configuration/configure_web.cpp | 2 +- src/yuzu/configuration/input_profiles.h | 2 +- src/yuzu/configuration/shared_widget.cpp | 2 +- src/yuzu/configuration/shared_widget.h | 2 +- src/yuzu/debugger/console.cpp | 2 +- src/yuzu/debugger/wait_tree.cpp | 2 +- src/yuzu/game_list.cpp | 15 ++---- src/yuzu/game_list.h | 5 +- src/yuzu/game_list_p.h | 2 +- src/yuzu/game_list_worker.cpp | 30 ++++-------- src/yuzu/game_list_worker.h | 7 +-- src/yuzu/hotkeys.cpp | 2 +- src/yuzu/install_dialog.cpp | 2 +- src/yuzu/main.cpp | 27 ++++++----- src/yuzu/main.h | 2 +- src/yuzu/multiplayer/direct_connect.cpp | 2 +- src/yuzu/multiplayer/host_room.cpp | 2 +- src/yuzu/multiplayer/lobby.cpp | 2 +- src/yuzu/multiplayer/state.cpp | 2 +- src/yuzu/play_time_manager.cpp | 1 - src/yuzu/play_time_manager.h | 3 +- src/yuzu/qt_common.h | 15 ------ src/yuzu/vk_device_info.cpp | 2 +- 56 files changed, 233 insertions(+), 153 deletions(-) create mode 100644 ffmpeg.patch create mode 100644 src/qt_common/CMakeLists.txt rename src/{yuzu => qt_common}/qt_common.cpp (80%) create mode 100644 src/qt_common/qt_common.h rename src/{yuzu/configuration => qt_common}/qt_config.cpp (100%) rename src/{yuzu/configuration => qt_common}/qt_config.h (100%) rename src/{yuzu/configuration => qt_common}/shared_translation.cpp (99%) rename src/{yuzu/configuration => qt_common}/shared_translation.h (94%) rename src/{yuzu => qt_common}/uisettings.cpp (99%) rename src/{yuzu => qt_common}/uisettings.h (99%) delete mode 100644 src/yuzu/qt_common.h diff --git a/ffmpeg.patch b/ffmpeg.patch new file mode 100644 index 0000000000..58fa9dff61 --- /dev/null +++ b/ffmpeg.patch @@ -0,0 +1,40 @@ +diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt +index 54c852f831..ff35c8dc2c 100644 +--- a/externals/ffmpeg/CMakeLists.txt ++++ b/externals/ffmpeg/CMakeLists.txt +@@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID) + set(FFmpeg_HWACCEL_INCLUDE_DIRS) + set(FFmpeg_HWACCEL_LDFLAGS) + +- # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so +- if(PLATFORM_SUN) +- list(APPEND FFmpeg_HWACCEL_LIBRARIES +- X11 +- "/usr/lib/xorg/amd64/libdrm.so") +- else() +- pkg_check_modules(LIBDRM libdrm REQUIRED) +- list(APPEND FFmpeg_HWACCEL_LIBRARIES +- ${LIBDRM_LIBRARIES}) +- list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS +- ${LIBDRM_INCLUDE_DIRS}) ++ if (NOT APPLE) ++ # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so ++ if(PLATFORM_SUN) ++ list(APPEND FFmpeg_HWACCEL_LIBRARIES ++ X11 ++ "/usr/lib/xorg/amd64/libdrm.so") ++ else() ++ pkg_check_modules(LIBDRM libdrm REQUIRED) ++ list(APPEND FFmpeg_HWACCEL_LIBRARIES ++ ${LIBDRM_LIBRARIES}) ++ list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ++ ${LIBDRM_INCLUDE_DIRS}) ++ endif() ++ list(APPEND FFmpeg_HWACCEL_FLAGS ++ --enable-libdrm) + endif() +- list(APPEND FFmpeg_HWACCEL_FLAGS +- --enable-libdrm) + + if(LIBVA_FOUND) + find_package(X11 REQUIRED) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb66e55964..0032b20029 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ if (YUZU_ROOM_STANDALONE) endif() if (ENABLE_QT) + add_subdirectory(qt_common) add_subdirectory(yuzu) endif() diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt new file mode 100644 index 0000000000..be1a8ebbd0 --- /dev/null +++ b/src/qt_common/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2023 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +add_library(qt_common STATIC + qt_common.h + qt_common.cpp + + uisettings.cpp + uisettings.h + + qt_config.cpp + qt_config.h + + shared_translation.cpp + shared_translation.h +) + +create_target_directory_groups(qt_common) +target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni) + +if (NOT WIN32) + target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) +endif() diff --git a/src/yuzu/qt_common.cpp b/src/qt_common/qt_common.cpp similarity index 80% rename from src/yuzu/qt_common.cpp rename to src/qt_common/qt_common.cpp index 413402165c..29379c1d54 100644 --- a/src/yuzu/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,12 +1,13 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +#include "qt_common.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "uisettings.h" #include #include #include #include "common/logging/log.h" #include "core/frontend/emu_window.h" -#include "yuzu/qt_common.h" #if !defined(WIN32) && !defined(__APPLE__) #include @@ -15,6 +16,21 @@ #endif namespace QtCommon { + +MetadataResult ResetMetadata() +{ + if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) + / "game_list/")) { + return Empty; + } else if (Common::FS::RemoveDirRecursively( + Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { + return Success; + UISettings::values.is_game_list_reload_pending.exchange(true); + } else { + return Failure; + } +} + Core::Frontend::WindowSystemType GetWindowSystemType() { // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); @@ -57,4 +73,5 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -} // namespace QtCommon + +} diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h new file mode 100644 index 0000000000..3c7dddfc1f --- /dev/null +++ b/src/qt_common/qt_common.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef QT_COMMON_H +#define QT_COMMON_H + +#include + +#include +#include + +namespace QtCommon { + +static constexpr std::array METADATA_RESULTS = { + "The operation completed successfully.", + "The metadata cache couldn't be deleted. It might be in use or non-existent.", + "The metadata cache is already empty.", +}; + +enum MetadataResult { + Success, + Failure, + Empty, +}; +/** + * @brief ResetMetadata Reset game list metadata. + * @return A result code. + */ +MetadataResult ResetMetadata(); + +/** + * \brief Get a string representation of a result from ResetMetadata. + * \param result The result code. + * \return A string representation of the passed result code. + */ +inline constexpr const char *GetResetMetadataResultString(MetadataResult result) +{ + return METADATA_RESULTS.at(static_cast(result)); +} + +Core::Frontend::WindowSystemType GetWindowSystemType(); + +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); + + +} // namespace QtCommon +#endif diff --git a/src/yuzu/configuration/qt_config.cpp b/src/qt_common/qt_config.cpp similarity index 100% rename from src/yuzu/configuration/qt_config.cpp rename to src/qt_common/qt_config.cpp diff --git a/src/yuzu/configuration/qt_config.h b/src/qt_common/qt_config.h similarity index 100% rename from src/yuzu/configuration/qt_config.h rename to src/qt_common/qt_config.h diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/qt_common/shared_translation.cpp similarity index 99% rename from src/yuzu/configuration/shared_translation.cpp rename to src/qt_common/shared_translation.cpp index 1137145659..018af56c67 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -7,23 +7,21 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "yuzu/configuration/shared_translation.h" +#include "shared_translation.h" #include -#include #include "common/settings.h" #include "common/settings_enums.h" #include "common/settings_setting.h" #include "common/time_zone.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include #include -#include #include namespace ConfigurationShared { -std::unique_ptr InitializeTranslations(QWidget* parent) +std::unique_ptr InitializeTranslations(QObject* parent) { std::unique_ptr translations = std::make_unique(); const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; @@ -473,7 +471,7 @@ std::unique_ptr InitializeTranslations(QWidget* parent) return translations; } -std::unique_ptr ComboboxEnumeration(QWidget* parent) +std::unique_ptr ComboboxEnumeration(QObject* parent) { std::unique_ptr translations = std::make_unique(); const auto& tr = [&](const char* text, const char* context = "") { diff --git a/src/yuzu/configuration/shared_translation.h b/src/qt_common/shared_translation.h similarity index 94% rename from src/yuzu/configuration/shared_translation.h rename to src/qt_common/shared_translation.h index 574b1e2c78..48a2cb5205 100644 --- a/src/yuzu/configuration/shared_translation.h +++ b/src/qt_common/shared_translation.h @@ -11,23 +11,20 @@ #include #include -#include #include #include #include #include "common/common_types.h" -#include "common/settings.h" - -class QWidget; +#include "common/settings_enums.h" namespace ConfigurationShared { using TranslationMap = std::map>; using ComboboxTranslations = std::vector>; using ComboboxTranslationMap = std::map; -std::unique_ptr InitializeTranslations(QWidget* parent); +std::unique_ptr InitializeTranslations(QObject *parent); -std::unique_ptr ComboboxEnumeration(QWidget* parent); +std::unique_ptr ComboboxEnumeration(QObject* parent); static const std::map anti_aliasing_texts_map = { {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, diff --git a/src/yuzu/uisettings.cpp b/src/qt_common/uisettings.cpp similarity index 99% rename from src/yuzu/uisettings.cpp rename to src/qt_common/uisettings.cpp index 6da5424775..a17f3c0a4a 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/qt_common/uisettings.cpp @@ -7,7 +7,7 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifndef CANNOT_EXPLICITLY_INSTANTIATE namespace Settings { diff --git a/src/yuzu/uisettings.h b/src/qt_common/uisettings.h similarity index 99% rename from src/yuzu/uisettings.h rename to src/qt_common/uisettings.h index 3322b31ca3..4981d98dbf 100644 --- a/src/yuzu/uisettings.h +++ b/src/qt_common/uisettings.h @@ -17,7 +17,7 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/settings_enums.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" using Settings::Category; using Settings::ConfirmStop; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index d663f6c282..9e052b385d 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -150,12 +150,8 @@ add_executable(yuzu configuration/configure_web.ui configuration/input_profiles.cpp configuration/input_profiles.h - configuration/shared_translation.cpp - configuration/shared_translation.h configuration/shared_widget.cpp configuration/shared_widget.h - configuration/qt_config.cpp - configuration/qt_config.h debugger/console.cpp debugger/console.h debugger/controller.cpp @@ -205,12 +201,8 @@ add_executable(yuzu play_time_manager.cpp play_time_manager.h precompiled_headers.h - qt_common.cpp - qt_common.h startup_checks.cpp startup_checks.h - uisettings.cpp - uisettings.h util/clickable_label.cpp util/clickable_label.h util/controller_navigation.cpp @@ -396,14 +388,17 @@ elseif(WIN32) endif() endif() -target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core) target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json) +target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common) target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) if (NOT WIN32) target_include_directories(yuzu PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) endif() + +target_link_libraries(yuzu PRIVATE Vulkan::Headers) + if (UNIX AND NOT APPLE) target_link_libraries(yuzu PRIVATE Qt6::DBus) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 63e7a74003..7b5f2a314f 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -12,7 +12,7 @@ #include #include "common/settings_enums.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA #include #include @@ -58,7 +58,7 @@ #include "video_core/renderer_base.h" #include "yuzu/bootmanager.h" #include "yuzu/main.h" -#include "yuzu/qt_common.h" +#include "qt_common/qt_common.h" class QObject; class QPaintEngine; @@ -234,7 +234,7 @@ class DummyContext : public Core::Frontend::GraphicsContext {}; class RenderWidget : public QWidget { public: - explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { + explicit RenderWidget(GRenderWindow* parent) : QWidget(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); if (QtCommon::GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { @@ -247,9 +247,6 @@ public: QPaintEngine* paintEngine() const override { return nullptr; } - -private: - GRenderWindow* render_window; }; struct OpenGLRenderWidget : public RenderWidget { diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index c235b0fca4..8d11920d31 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -16,9 +16,9 @@ #include "ui_configure_audio.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_audio.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureAudio::ConfigureAudio(const Core::System& system_, std::shared_ptr> group_, diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 098e0e397b..16cf74af33 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -7,7 +7,7 @@ #include #include #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" class QComboBox; diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 733c419c4b..18f629f639 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -15,7 +15,7 @@ #include "ui_configure_debug.h" #include "yuzu/configuration/configure_debug.h" #include "yuzu/debugger/console.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent) : QScrollArea(parent), ui{std::make_unique()}, system{system_} { diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 987b1462db..4e128106e7 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -27,7 +27,7 @@ #include "yuzu/configuration/configure_ui.h" #include "yuzu/configuration/configure_web.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, InputCommon::InputSubsystem* input_subsystem, diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 0b6b285678..bf96035752 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -8,7 +8,7 @@ #include #include "configuration/shared_widget.h" #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/vk_device_info.h" namespace Core { diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index f25f14708b..392155d2a3 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -1,14 +1,15 @@ // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "yuzu/configuration/configure_filesystem.h" #include #include #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/settings.h" +#include "qt_common/qt_common.h" +#include "qt_common/uisettings.h" #include "ui_configure_filesystem.h" -#include "yuzu/configuration/configure_filesystem.h" -#include "yuzu/uisettings.h" ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { @@ -126,19 +127,16 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) } void ConfigureFilesystem::ResetMetadata() { - if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / - "game_list/")) { - QMessageBox::information(this, tr("Reset Metadata Cache"), - tr("The metadata cache is already empty.")); - } else if (Common::FS::RemoveDirRecursively( - Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - QMessageBox::information(this, tr("Reset Metadata Cache"), - tr("The operation completed successfully.")); - UISettings::values.is_game_list_reload_pending.exchange(true); - } else { - QMessageBox::warning( - this, tr("Reset Metadata Cache"), - tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); + auto result = QtCommon::ResetMetadata(); + const QString resultMessage = tr(QtCommon::GetResetMetadataResultString(result)); + const QString title = tr("Reset Metadata Cache"); + + switch (result) { + case QtCommon::Failure: + QMessageBox::warning(this, title, resultMessage); + break; + default: + QMessageBox::information(this, title, resultMessage); } } diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 918fa15d4d..352ae8ab85 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -11,7 +11,7 @@ #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_general.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureGeneral::ConfigureGeneral(const Core::System& system_, std::shared_ptr> group_, diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 16846878f9..e1e68b917a 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -40,8 +40,8 @@ #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/qt_common.h" -#include "yuzu/uisettings.h" +#include "qt_common/qt_common.h" +#include "qt_common/uisettings.h" #include "yuzu/vk_device_info.h" static const std::vector default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR, diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index b92b4496ba..9f7ece5714 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -15,7 +15,7 @@ #include #include "common/common_types.h" #include "common/settings_enums.h" -#include "configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 4db18673d4..921cb83b08 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -9,7 +9,7 @@ #include "ui_configure_graphics_advanced.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics_advanced.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( diff --git a/src/yuzu/configuration/configure_graphics_extensions.cpp b/src/yuzu/configuration/configure_graphics_extensions.cpp index 322fa9ea08..c4c7fbb31f 100644 --- a/src/yuzu/configuration/configure_graphics_extensions.cpp +++ b/src/yuzu/configuration/configure_graphics_extensions.cpp @@ -11,7 +11,7 @@ #include "ui_configure_graphics_extensions.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics_extensions.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" ConfigureGraphicsExtensions::ConfigureGraphicsExtensions( diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 3f68de12d8..53f7401ef4 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -13,7 +13,7 @@ #include "ui_configure_hotkeys.h" #include "yuzu/configuration/configure_hotkeys.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/sequence_dialog/sequence_dialog.h" constexpr int name_column = 0; diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 4420e856cb..1323d101d3 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -9,7 +9,7 @@ #include "ui_configure_input_per_game.h" #include "yuzu/configuration/input_profiles.h" -#include "yuzu/configuration/qt_config.h" +#include "qt_common/qt_config.h" class QComboBox; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index d0dc0ff44c..6afa8320a2 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -14,7 +14,7 @@ #include #include "common/assert.h" #include "common/param_package.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 031a8d4c2d..545c37a2c9 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -38,7 +38,7 @@ #include "yuzu/configuration/configure_per_game.h" #include "yuzu/configuration/configure_per_game_addons.h" #include "yuzu/configuration/configure_system.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/util.h" #include "yuzu/vk_device_info.h" diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index e0f4e5cd67..a756b561a8 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -15,8 +15,8 @@ #include "frontend_common/config.h" #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/qt_config.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/qt_config.h" +#include "qt_common/shared_translation.h" namespace Core { class System; diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 078f2e8288..90c94cb923 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -21,7 +21,7 @@ #include "ui_configure_per_game_addons.h" #include "yuzu/configuration/configure_input.h" #include "yuzu/configuration/configure_per_game_addons.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* parent) : QWidget(parent), ui{std::make_unique()}, system{system_} { diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index f7249be97e..7e7877aaf6 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -8,7 +8,7 @@ #include #include -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "input_common/drivers/keyboard.h" diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 773658bf22..290e825fe6 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -8,7 +8,7 @@ #include "common/settings.h" #include "ui_configure_tas.h" #include "yuzu/configuration/configure_tas.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureTasDialog::ConfigureTasDialog(QWidget* parent) : QDialog(parent), ui(std::make_unique()) { diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 8dafee628b..ac6d6e34aa 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -27,7 +27,7 @@ #include "core/core.h" #include "core/frontend/framebuffer_layout.h" #include "ui_configure_ui.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace { constexpr std::array default_game_icon_sizes{ diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index d62b5b0853..15a0029901 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -17,7 +17,7 @@ #include #include "common/settings.h" #include "ui_configure_web.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureWeb::ConfigureWeb(QWidget* parent) : QWidget(parent) diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 023ec74a63..64dcf0e603 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -6,7 +6,7 @@ #include #include -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" namespace Core { class System; diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index e23d86dc69..02b354b0a5 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -42,7 +42,7 @@ #include "common/logging/log.h" #include "common/settings.h" #include "common/settings_common.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" namespace ConfigurationShared { diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index 5c67d83542..a793347ce5 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -11,7 +11,7 @@ #include #include #include -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" class QCheckBox; class QComboBox; diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp index 1c1342ff18..40b2fddbc9 100644 --- a/src/yuzu/debugger/console.cpp +++ b/src/yuzu/debugger/console.cpp @@ -9,7 +9,7 @@ #include "common/logging/backend.h" #include "yuzu/debugger/console.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace Debugger { void ToggleConsole() { diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 9f9e21bc28..f32f6348a5 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -5,7 +5,7 @@ #include #include "yuzu/debugger/wait_tree.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "core/arm/debug.h" #include "core/core.h" diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 1ecef4af92..0d89dc892e 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -24,7 +24,7 @@ #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" #include "yuzu/main.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/controller_navigation.h" GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) @@ -820,7 +820,7 @@ QStandardItemModel* GameList::GetModel() const { return item_model; } -void GameList::PopulateAsync(QVector& game_dirs, const bool cached) +void GameList::PopulateAsync(QVector& game_dirs) { tree_view->setEnabled(false); @@ -843,8 +843,7 @@ void GameList::PopulateAsync(QVector& game_dirs, const bool game_dirs, compatibility_list, play_time_manager, - system, - cached); + system); // Get events from the worker as data becomes available connect(current_worker.get(), &GameListWorker::DataAvailable, this, &GameList::WorkerEvent, @@ -873,14 +872,6 @@ const QStringList GameList::supported_file_extensions = { QStringLiteral("nso"), QStringLiteral("nro"), QStringLiteral("nca"), QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; -void GameList::ForceRefreshGameDirectory() -{ - if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { - LOG_INFO(Frontend, "Force-reloading game list per user request."); - PopulateAsync(UISettings::values.game_dirs, false); - } -} - void GameList::RefreshGameDirectory() { if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 7c492bc19f..328432138c 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -20,7 +20,7 @@ #include "common/common_types.h" #include "core/core.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -97,7 +97,7 @@ public: bool IsEmpty() const; void LoadCompatibilityList(); - void PopulateAsync(QVector& game_dirs, const bool cached = true); + void PopulateAsync(QVector& game_dirs); void SaveInterfaceLayout(); void LoadInterfaceLayout(); @@ -110,7 +110,6 @@ public: static const QStringList supported_file_extensions; public slots: - void ForceRefreshGameDirectory(); void RefreshGameDirectory(); signals: diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index c330b574f9..b3e05b8b34 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -19,7 +19,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "yuzu/play_time_manager.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/util.h" enum class GameListItemType { diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 60109769bf..267faa7182 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -27,7 +27,7 @@ #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace { @@ -199,8 +199,7 @@ QList MakeGameListEntry(const std::string& path, u64 program_id, const CompatibilityList& compatibility_list, const PlayTime::PlayTimeManager& play_time_manager, - const FileSys::PatchManager& patch, - const bool cached) + const FileSys::PatchManager& patch) { const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); @@ -224,14 +223,10 @@ QList MakeGameListEntry(const std::string& path, QString patch_versions; - if (cached) { - patch_versions = GetGameListCachedObject( - fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { - return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); - }); - } else { - patch_versions = FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); - } + patch_versions = GetGameListCachedObject( + fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { + return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); + }); list.insert(2, new GameListItem(patch_versions)); @@ -244,15 +239,13 @@ GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_, QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_, - const bool cached_) + Core::System& system_) : vfs{std::move(vfs_)} , provider{provider_} , game_dirs{game_dirs_} , compatibility_list{compatibility_list_} , play_time_manager{play_time_manager_} , system{system_} - , cached{cached_} { // We want the game list to manage our lifetime. setAutoDelete(false); @@ -355,8 +348,7 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { program_id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent([=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); } } @@ -439,8 +431,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); @@ -463,8 +454,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa program_id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 0afd7c7849..5c5fbb251f 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -15,7 +15,7 @@ #include "common/thread.h" #include "core/file_sys/registered_cache.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -45,8 +45,7 @@ public: QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_, - const bool cached = true); + Core::System& system_); ~GameListWorker() override; /// Starts the processing of directory tree information. @@ -95,6 +94,4 @@ private: Common::Event processing_completed; Core::System& system; - - const bool cached; }; diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 1931dcd1f6..e9d0b4e23f 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -8,7 +8,7 @@ #include "hid_core/frontend/emulated_controller.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" HotkeyRegistry::HotkeyRegistry() = default; HotkeyRegistry::~HotkeyRegistry() = default; diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp index 673bbaa836..0e8e785ae9 100644 --- a/src/yuzu/install_dialog.cpp +++ b/src/yuzu/install_dialog.cpp @@ -8,7 +8,7 @@ #include #include #include "yuzu/install_dialog.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) { file_list = new QListWidget(this); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e23e9a6a48..34423589cc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -11,6 +11,7 @@ #include "core/loader/nca.h" #include "core/tools/renderdoc.h" #include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" #include @@ -156,7 +157,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/compatibility_list.h" #include "yuzu/configuration/configure_dialog.h" #include "yuzu/configuration/configure_input_per_game.h" -#include "yuzu/configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "yuzu/debugger/console.h" #include "yuzu/debugger/controller.h" #include "yuzu/debugger/wait_tree.h" @@ -170,7 +171,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/main.h" #include "yuzu/play_time_manager.h" #include "yuzu/startup_checks.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/clickable_label.h" #include "yuzu/vk_device_info.h" @@ -559,7 +560,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) game_list->LoadCompatibilityList(); // force reload on first load to ensure add-ons get updated - game_list->PopulateAsync(UISettings::values.game_dirs, false); + game_list->PopulateAsync(UISettings::values.game_dirs); // make sure menubar has the arrow cursor instead of inheriting from this ui->menubar->setCursor(QCursor()); @@ -4609,9 +4610,11 @@ void GMainWindow::OnToggleStatusBar() { statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); } -void GMainWindow::OnGameListRefresh() { - // force reload add-ons etc - game_list->ForceRefreshGameDirectory(); +void GMainWindow::OnGameListRefresh() +{ + // Resets metadata cache and reloads + QtCommon::ResetMetadata(); + game_list->RefreshGameDirectory(); SetFirmwareVersion(); } @@ -4620,7 +4623,7 @@ void GMainWindow::OnAlbum() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Album applet.")); + tr("Please install firmware to use the Album applet.")); return; } @@ -4643,7 +4646,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Cabinet applet.")); + tr("Please install firmware to use the Cabinet applet.")); return; } @@ -4667,7 +4670,7 @@ void GMainWindow::OnMiiEdit() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Mii editor.")); + tr("Please install firmware to use the Mii editor.")); return; } @@ -4690,7 +4693,7 @@ void GMainWindow::OnOpenControllerMenu() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Controller Menu.")); + tr("Please install firmware to use the Controller Menu.")); return; } @@ -4745,6 +4748,8 @@ void GMainWindow::OnHomeMenu() { break; } + // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); @@ -4767,7 +4772,7 @@ void GMainWindow::OnInitialSetup() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use Starter.")); + tr("Please install firmware to use Starter.")); return; } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7857788fcf..b20f601381 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -17,7 +17,7 @@ #include #include "common/common_types.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" #include "user_data_migration.h" diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index 30f37c2b4a..deac3b9e59 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp @@ -21,7 +21,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" enum class ConnectionType : u8 { TraversalServer, IP }; diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index d8e63da600..4dd3958550 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -25,7 +25,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifdef ENABLE_WEB_SERVICE #include "web_service/verify_user_jwt.h" #endif diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index ed6ba6a15c..84723041df 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -22,7 +22,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifdef ENABLE_WEB_SERVICE #include "web_service/web_backend.h" #endif diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index d5529712b0..2eed3cba63 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -19,7 +19,7 @@ #include "yuzu/multiplayer/lobby.h" #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/clickable_label.h" MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model_, diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp index 8317386816..d9579706ca 100644 --- a/src/yuzu/play_time_manager.cpp +++ b/src/yuzu/play_time_manager.cpp @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/alignment.h" #include "common/fs/file.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/yuzu/play_time_manager.h b/src/yuzu/play_time_manager.h index 1714b91313..ea7d9debc3 100644 --- a/src/yuzu/play_time_manager.h +++ b/src/yuzu/play_time_manager.h @@ -9,8 +9,9 @@ #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/polyfill_thread.h" +#include +// TODO(crueter): Extract this into frontend_common namespace Service::Account { class ProfileManager; } diff --git a/src/yuzu/qt_common.h b/src/yuzu/qt_common.h deleted file mode 100644 index 9c63f08f34..0000000000 --- a/src/yuzu/qt_common.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include "core/frontend/emu_window.h" - -namespace QtCommon { - -Core::Frontend::WindowSystemType GetWindowSystemType(); - -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); - -} // namespace QtCommon diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index ab0d39c256..65838f7d42 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -4,7 +4,7 @@ #include #include -#include "yuzu/qt_common.h" +#include "qt_common/qt_common.h" #include "common/dynamic_library.h" #include "common/logging/log.h" From 2e61d8618e667f7798638dd3c3eb93738cf3dbf3 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:05:57 -0400 Subject: [PATCH 29/52] move fw install Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 105 +++++++++++++++-- src/qt_common/qt_common.h | 35 +++++- .../configuration/configure_filesystem.cpp | 2 +- src/yuzu/main.cpp | 110 ++++-------------- 4 files changed, 155 insertions(+), 97 deletions(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 29379c1d54..260255c62e 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,6 +1,7 @@ #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/hle/service/filesystem/filesystem.h" #include "uisettings.h" #include @@ -21,17 +22,18 @@ MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list/")) { - return Empty; + return MetadataResult::Empty; } else if (Common::FS::RemoveDirRecursively( Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return Success; + return MetadataResult::Success; UISettings::values.is_game_list_reload_pending.exchange(true); } else { - return Failure; + return MetadataResult::Failure; } } -Core::Frontend::WindowSystemType GetWindowSystemType() { +Core::Frontend::WindowSystemType GetWindowSystemType() +{ // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); if (platform_name == QStringLiteral("windows")) @@ -51,7 +53,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType() { return Core::Frontend::WindowSystemType::Windows; } // namespace Core::Frontend::WindowSystemType -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) +{ Core::Frontend::EmuWindow::WindowSystemInfo wsi; wsi.type = GetWindowSystemType(); @@ -59,8 +62,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) // Our Win32 Qt external doesn't have the private API. wsi.render_surface = reinterpret_cast(window->winId()); #elif defined(__APPLE__) - wsi.render_surface = reinterpret_cast(objc_msgSend)( - reinterpret_cast(window->winId()), sel_registerName("layer")); + wsi.render_surface = reinterpret_cast( + objc_msgSend)(reinterpret_cast(window->winId()), sel_registerName("layer")); #else QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); wsi.display_connection = pni->nativeResourceForWindow("display", window); @@ -74,4 +77,92 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } +FirmwareInstallResult InstallFirmware(const QString& location, + bool recursive, + std::function QtProgressCallback, + Core::System* system, + FileSys::VfsFilesystem* vfs) +{ + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector out; + const Common::FS::DirEntryCallable callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") { + out.emplace_back(entry.path()); + } + + return true; + }; + + QtProgressCallback(100, 10); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + return FirmwareInstallResult::NoNCAs; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + return FirmwareInstallResult::FailedDelete; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + QtProgressCallback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), + FileSys::OpenMode::Read); + auto firmware_dst_vfile = firmware_vdir + ->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, + "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), + firmware_src_path.filename().string()); + success = false; + } + + if (QtProgressCallback(100, + 20 + + static_cast(((i) / static_cast(out.size())) + * 70.0))) { + return FirmwareInstallResult::FailedCorrupted; + } + } + + if (!success) { + return FirmwareInstallResult::FailedCopy; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + return FirmwareInstallResult::Success; +} + } diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 3c7dddfc1f..31adcf05c7 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -7,8 +7,11 @@ #include #include +#include "core/core.h" #include +#include + namespace QtCommon { static constexpr std::array METADATA_RESULTS = { @@ -17,7 +20,7 @@ static constexpr std::array METADATA_RESULTS = { "The metadata cache is already empty.", }; -enum MetadataResult { +enum class MetadataResult { Success, Failure, Empty, @@ -38,6 +41,36 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } +static constexpr std::array FIRMWARE_RESULTS = { + "", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware." +}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware(const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 392155d2a3..5459dc0377 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -132,7 +132,7 @@ void ConfigureFilesystem::ResetMetadata() { const QString title = tr("Reset Metadata Cache"); switch (result) { - case QtCommon::Failure: + case QtCommon::MetadataResult::Failure: QMessageBox::warning(this, title, resultMessage); break; default: diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 34423589cc..b0aaa953a9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4356,106 +4356,40 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); + const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); - // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in - // there.) - std::filesystem::path firmware_source_path = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - progress.close(); + progress.close(); + + QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); + + switch (result) { + case QtCommon::FirmwareInstallResult::NoNCAs: + case QtCommon::FirmwareInstallResult::FailedCorrupted: + box->setIcon(QMessageBox::Icon::Warning); + box->exec(); return; - } - - std::vector out; - const Common::FS::DirEntryCallable callback = - [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") { - out.emplace_back(entry.path()); - } - - return true; - }; - - QtProgressCallback(100, 10); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback, - Common::FS::DirEntryFilter::File); - } else { - Common::FS::IterateDirEntries(firmware_source_path, callback, - Common::FS::DirEntryFilter::File); - } - - if (out.size() <= 0) { - progress.close(); - QMessageBox::warning(this, tr("Firmware install failed"), - tr("Unable to locate potential firmware NCA files")); + case QtCommon::FirmwareInstallResult::FailedCopy: + case QtCommon::FirmwareInstallResult::FailedDelete: + box->setIcon(QMessageBox::Icon::Critical); + box->exec(); return; + default: + box->deleteLater(); + break; } - // Locate and erase the content of nand/system/Content/registered/*.nca, if any. - auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - progress.close(); - QMessageBox::critical(this, tr("Firmware install failed"), - tr("Failed to delete one or more firmware file.")); - return; - } - - LOG_INFO(Frontend, - "Cleaned nand/system/Content/registered folder in preparation for new firmware."); - - QtProgressCallback(100, 20); - - auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); - - bool success = true; - int i = 0; - for (const auto& firmware_src_path : out) { - i++; - auto firmware_src_vfile = - vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read); - auto firmware_dst_vfile = - firmware_vdir->CreateFileRelative(firmware_src_path.filename().string()); - - if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { - LOG_ERROR(Frontend, "Failed to copy firmware file {} to {} in registered folder!", - firmware_src_path.generic_string(), firmware_src_path.filename().string()); - success = false; - } - - if (QtProgressCallback( - 100, 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - progress.close(); - QMessageBox::warning( - this, tr("Firmware install failed"), - tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "Restart Eden or re-install firmware.")); - return; - } - } - - if (!success) { - progress.close(); - QMessageBox::critical(this, tr("Firmware install failed"), - tr("One or more firmware files failed to copy into NAND.")); - return; - } - - // Re-scan VFS for the newly placed firmware files. - system->GetFileSystemController().CreateFactories(*vfs); - auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); return progress.wasCanceled(); }; - auto result = - ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + auto results = + ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); - if (result.size() > 0) { + if (results.size() > 0) { const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + QString::fromStdString(fmt::format("{}", fmt::join(results, "\n"))); progress.close(); QMessageBox::critical( this, tr("Firmware integrity verification failed!"), From 6f2d1d8eabc9cf2da8a0f0ee4feca9ecdd6150c4 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:12:24 -0400 Subject: [PATCH 30/52] Fix license headers Signed-off-by: crueter --- .ci/license-header.sh | 12 +++++++++--- src/qt_common/qt_common.cpp | 3 +++ src/qt_common/qt_config.cpp | 3 +++ src/qt_common/qt_config.h | 3 +++ src/yuzu/configuration/configure_audio.cpp | 3 +++ src/yuzu/configuration/configure_cpu.h | 3 +++ src/yuzu/configuration/configure_dialog.cpp | 3 +++ src/yuzu/configuration/configure_dialog.h | 3 +++ src/yuzu/configuration/configure_filesystem.cpp | 3 +++ src/yuzu/configuration/configure_general.cpp | 3 +++ src/yuzu/configuration/configure_graphics.cpp | 3 +++ src/yuzu/configuration/configure_graphics.h | 3 +++ .../configuration/configure_graphics_advanced.cpp | 3 +++ .../configuration/configure_graphics_extensions.cpp | 3 +++ src/yuzu/configuration/configure_hotkeys.cpp | 3 +++ src/yuzu/configuration/configure_input_per_game.h | 3 +++ src/yuzu/configuration/configure_per_game.cpp | 3 +++ src/yuzu/configuration/configure_per_game.h | 3 +++ src/yuzu/configuration/configure_per_game_addons.cpp | 3 +++ src/yuzu/configuration/configure_ringcon.cpp | 3 +++ src/yuzu/configuration/configure_tas.cpp | 3 +++ src/yuzu/configuration/input_profiles.h | 3 +++ src/yuzu/configuration/shared_widget.cpp | 3 +++ src/yuzu/configuration/shared_widget.h | 3 +++ src/yuzu/debugger/console.cpp | 3 +++ src/yuzu/debugger/wait_tree.cpp | 3 +++ src/yuzu/game_list_p.h | 3 +++ src/yuzu/game_list_worker.cpp | 3 +++ src/yuzu/game_list_worker.h | 3 +++ src/yuzu/hotkeys.cpp | 3 +++ src/yuzu/install_dialog.cpp | 3 +++ src/yuzu/multiplayer/state.cpp | 3 +++ src/yuzu/play_time_manager.cpp | 3 +++ src/yuzu/play_time_manager.h | 3 +++ src/yuzu/vk_device_info.cpp | 3 +++ 35 files changed, 111 insertions(+), 3 deletions(-) diff --git a/.ci/license-header.sh b/.ci/license-header.sh index fecffaa7d3..f1e16abbe6 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -5,13 +5,19 @@ HEADER_HASH="$(cat "$PWD/.ci/license/header-hash.txt")" echo "Getting branch changes" -BRANCH=`git rev-parse --abbrev-ref HEAD` -COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"` -RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" +# BRANCH=`git rev-parse --abbrev-ref HEAD` +# COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"` +# RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" +# FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` + +CURRENT=`git rev-parse --short=10 HEAD` +BASE=`git merge-base master $CURRENT` +RANGE="$CURRENT^..$BASE" FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` #FILES=$(git diff --name-only master) +echo $FILES echo "Done" check_header() { diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 260255c62e..4a27566107 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/qt_common/qt_config.cpp b/src/qt_common/qt_config.cpp index ae5b330e23..f787873cf6 100644 --- a/src/qt_common/qt_config.cpp +++ b/src/qt_common/qt_config.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/qt_common/qt_config.h b/src/qt_common/qt_config.h index dc2dceb4d7..a8c80dd273 100644 --- a/src/qt_common/qt_config.h +++ b/src/qt_common/qt_config.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 8d11920d31..a7ebae91f8 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 16cf74af33..bbc6096f9b 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 4e128106e7..0816782282 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index bf96035752..c1e148fc8e 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 5459dc0377..d02e6dec2b 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 352ae8ab85..18c2c9cb77 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index e1e68b917a..cd806e5ef8 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 9f7ece5714..38d97aae80 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 921cb83b08..e07ad8c466 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_graphics_extensions.cpp b/src/yuzu/configuration/configure_graphics_extensions.cpp index c4c7fbb31f..f165e703d9 100644 --- a/src/yuzu/configuration/configure_graphics_extensions.cpp +++ b/src/yuzu/configuration/configure_graphics_extensions.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 53f7401ef4..a5c1ee009a 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2017 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 1323d101d3..dcd6dd841b 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 545c37a2c9..b51ede0de8 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index a756b561a8..83afc27f3d 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 90c94cb923..ed4cbc1147 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 7e7877aaf6..795ad1a85e 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 290e825fe6..898a1a3e59 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 64dcf0e603..dba5ce1318 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index 02b354b0a5..e30ecc4848 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index a793347ce5..9e718098a3 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp index 40b2fddbc9..8fb22db192 100644 --- a/src/yuzu/debugger/console.cpp +++ b/src/yuzu/debugger/console.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index f32f6348a5..feb814b25e 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index b3e05b8b34..5a3b5829f5 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 267faa7182..538c7ab822 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 5c5fbb251f..f5d5f6341b 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index e9d0b4e23f..31932e6f43 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp index 0e8e785ae9..e6f1392ce0 100644 --- a/src/yuzu/install_dialog.cpp +++ b/src/yuzu/install_dialog.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index 2eed3cba63..8ff1d991ec 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp index d9579706ca..6d06bc7614 100644 --- a/src/yuzu/play_time_manager.cpp +++ b/src/yuzu/play_time_manager.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/play_time_manager.h b/src/yuzu/play_time_manager.h index ea7d9debc3..cd81bdb061 100644 --- a/src/yuzu/play_time_manager.h +++ b/src/yuzu/play_time_manager.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index 65838f7d42..d961d550a1 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later From efa3a44ac1140c16ac49dd70924a37c5ead9a2cc Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:56:58 -0400 Subject: [PATCH 31/52] debug: log user/save id Signed-off-by: crueter --- src/core/file_sys/savedata_factory.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 106922e04f..0591517727 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -126,6 +126,10 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, std::string out = GetSaveDataSpaceIdPath(space); + LOG_INFO(Common_Filesystem, "Save ID: {:016X}", save_id); + LOG_INFO(Common_Filesystem, "User ID[1]: {:016X}", user_id[1]); + LOG_INFO(Common_Filesystem, "User ID[0]: {:016X}", user_id[0]); + switch (type) { case SaveDataType::System: return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); From edadf5e8c8d025ee3145ddc991d3040706248f5c Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 18:17:20 -0400 Subject: [PATCH 32/52] explicitly check write status for dir Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 4a27566107..abeae4c3a1 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -123,7 +123,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { return FirmwareInstallResult::FailedDelete; } From b2967171ea1ab6a391736919cf82951895fbb671 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 23:23:14 -0400 Subject: [PATCH 33/52] more common funcs Signed-off-by: crueter --- .ci/license-header.sh | 6 +- src/core/file_sys/savedata_factory.cpp | 3 + src/qt_common/CMakeLists.txt | 4 +- src/qt_common/qt_common.cpp | 43 ++++- src/qt_common/qt_common.h | 4 +- src/qt_common/qt_game_util.cpp | 171 +++++++++++++++++ src/qt_common/qt_game_util.h | 41 +++++ src/qt_common/qt_path_util.cpp | 20 ++ src/qt_common/qt_path_util.h | 7 + src/yuzu/main.cpp | 243 +++++-------------------- src/yuzu/main.h | 9 - 11 files changed, 331 insertions(+), 220 deletions(-) create mode 100644 src/qt_common/qt_game_util.cpp create mode 100644 src/qt_common/qt_game_util.h create mode 100644 src/qt_common/qt_path_util.cpp create mode 100644 src/qt_common/qt_path_util.h diff --git a/.ci/license-header.sh b/.ci/license-header.sh index f1e16abbe6..d98f42fc97 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -10,10 +10,8 @@ echo "Getting branch changes" # RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" # FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` -CURRENT=`git rev-parse --short=10 HEAD` -BASE=`git merge-base master $CURRENT` -RANGE="$CURRENT^..$BASE" -FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` +BASE=`git merge-base master HEAD` +FILES=`git diff --name-only $BASE` #FILES=$(git diff --name-only master) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 0591517727..edf51e74de 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index be1a8ebbd0..d6ef427ba6 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -13,10 +13,12 @@ add_library(qt_common STATIC shared_translation.cpp shared_translation.h + qt_path_util.h qt_path_util.cpp + qt_game_util.h qt_game_util.cpp ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni) +target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index abeae4c3a1..0cd4c86b4a 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -15,6 +15,11 @@ #if !defined(WIN32) && !defined(__APPLE__) #include + +#include + +#include + #elif defined(__APPLE__) #include #endif @@ -80,11 +85,12 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -FirmwareInstallResult InstallFirmware(const QString& location, - bool recursive, - std::function QtProgressCallback, - Core::System* system, - FileSys::VfsFilesystem* vfs) +FirmwareInstallResult InstallFirmware( + const QString& location, + bool recursive, + std::function QtProgressCallback, + Core::System* system, + FileSys::VfsFilesystem* vfs) { LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); @@ -123,7 +129,8 @@ FirmwareInstallResult InstallFirmware(const QString& location, // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + if (sysnand_content_vdir->IsWritable() + && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { return FirmwareInstallResult::FailedDelete; } @@ -168,4 +175,28 @@ FirmwareInstallResult InstallFirmware(const QString& location, return FirmwareInstallResult::Success; } +QString UnzipFirmwareToTmp(const QString& location) +{ + namespace fs = std::filesystem; + fs::path tmp{fs::temp_directory_path()}; + + if (!fs::create_directories(tmp / "eden" / "firmware")) { + return ""; + } + + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + return ""; + } + + return qCacheDir; } + +} // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 31adcf05c7..b3ca99e65a 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -62,10 +62,12 @@ enum class FirmwareInstallResult { FirmwareInstallResult InstallFirmware(const QString &location, bool recursive, - std::function QtProgressCallback, + std::function QtProgressCallback, Core::System *system, FileSys::VfsFilesystem *vfs); +QString UnzipFirmwareToTmp(const QString &location); + inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) { return FIRMWARE_RESULTS.at(static_cast(result)); diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp new file mode 100644 index 0000000000..9aba4e393c --- /dev/null +++ b/src/qt_common/qt_game_util.cpp @@ -0,0 +1,171 @@ +#include "qt_game_util.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" + +#include +#include +#include "fmt/ostream.h" +#include + +#ifdef _WIN32 +#include +#endif + +namespace QtCommon { + +bool CreateShortcutLink(const std::filesystem::path& shortcut_path, + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, const std::string& categories, + const std::string& keywords, const std::string& name) try { +#ifdef _WIN32 // Windows + HRESULT hr = CoInitialize(nullptr); + if (FAILED(hr)) { + LOG_ERROR(Frontend, "CoInitialize failed"); + return false; + } + SCOPE_EXIT { + CoUninitialize(); + }; + IShellLinkW* ps1 = nullptr; + IPersistFile* persist_file = nullptr; + SCOPE_EXIT { + if (persist_file != nullptr) { + persist_file->Release(); + } + if (ps1 != nullptr) { + ps1->Release(); + } + }; + HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + reinterpret_cast(&ps1)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); + return false; + } + hres = ps1->SetPath(command.c_str()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set path"); + return false; + } + if (!arguments.empty()) { + hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set arguments"); + return false; + } + } + if (!comment.empty()) { + hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set description"); + return false; + } + } + if (std::filesystem::is_regular_file(icon_path)) { + hres = ps1->SetIconLocation(icon_path.c_str(), 0); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set icon location"); + return false; + } + } + hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast(&persist_file)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); + return false; + } + hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to save shortcut"); + return false; + } + return true; +#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Any desktop NIX + std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); + std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); + if (!shortcut_stream.is_open()) { + LOG_ERROR(Frontend, "Failed to create shortcut"); + return false; + } + // TODO: Migrate fmt::print to std::print in futures STD C++ 23. + fmt::print(shortcut_stream, "[Desktop Entry]\n"); + fmt::print(shortcut_stream, "Type=Application\n"); + fmt::print(shortcut_stream, "Version=1.0\n"); + fmt::print(shortcut_stream, "Name={}\n", name); + if (!comment.empty()) { + fmt::print(shortcut_stream, "Comment={}\n", comment); + } + if (std::filesystem::is_regular_file(icon_path)) { + fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); + } + fmt::print(shortcut_stream, "TryExec={}\n", command.string()); + fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); + if (!categories.empty()) { + fmt::print(shortcut_stream, "Categories={}\n", categories); + } + if (!keywords.empty()) { + fmt::print(shortcut_stream, "Keywords={}\n", keywords); + } + return true; +#else // Unsupported platform + return false; +#endif +} + catch (const std::exception& e) { + LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); + return false; +} + +bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, + std::filesystem::path& out_icon_path) { + // Get path to Yuzu icons directory & icon extension + std::string ico_extension = "png"; +#if defined(_WIN32) + out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); + ico_extension = "ico"; +#elif defined(__linux__) || defined(__FreeBSD__) + out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; +#endif + // Create icons directory if it doesn't exist + if (!Common::FS::CreateDirs(out_icon_path)) { + out_icon_path.clear(); + return false; + } + + // Create icon file path + out_icon_path /= (program_id == 0 ? fmt::format("eden-{}.{}", game_file_name, ico_extension) + : fmt::format("eden-{:016X}.{}", program_id, ico_extension)); + return true; +} + +void OpenRootDataFolder() { + QDesktopServices::openUrl(QUrl( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); +} + +void OpenNANDFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); +} + +void OpenSDMCFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); +} + +void OpenModFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); +} + +void OpenLogFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); +} + +} diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h new file mode 100644 index 0000000000..98d17027c4 --- /dev/null +++ b/src/qt_common/qt_game_util.h @@ -0,0 +1,41 @@ +#ifndef QT_GAME_UTIL_H +#define QT_GAME_UTIL_H + +#include "frontend_common/content_manager.h" +#include + +namespace QtCommon { + +static constexpr std::array GAME_VERIFICATION_RESULTS = { + "The operation completed successfully.", + "File contents may be corrupt or missing..", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "File contents could not be checked for validity." +}; + +inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result) +{ + return GAME_VERIFICATION_RESULTS.at(static_cast(result)); +} + +bool CreateShortcutLink(const std::filesystem::path& shortcut_path, + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, + const std::string& categories, + const std::string& keywords, + const std::string& name); + +bool MakeShortcutIcoPath(const u64 program_id, + const std::string_view game_file_name, + std::filesystem::path& out_icon_path); + +void OpenRootDataFolder(); +void OpenNANDFolder(); +void OpenSDMCFolder(); +void OpenModFolder(); +void OpenLogFolder(); +} + +#endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp new file mode 100644 index 0000000000..2ca2f6bf72 --- /dev/null +++ b/src/qt_common/qt_path_util.cpp @@ -0,0 +1,20 @@ +#include "qt_path_util.h" +#include +#include +#include +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include + +bool QtCommon::PathUtil::OpenShaderCache(u64 program_id) +{ + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; + if (!Common::FS::CreateDirs(shader_cache_folder_path)) { + return false; + } + + const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; + const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); + return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); +} diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h new file mode 100644 index 0000000000..6fafad7ed9 --- /dev/null +++ b/src/qt_common/qt_path_util.h @@ -0,0 +1,7 @@ +#ifndef QT_PATH_UTIL_H +#define QT_PATH_UTIL_H + +#include "common/common_types.h" +namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); } + +#endif // QT_PATH_UTIL_H diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b0aaa953a9..88f3a3d743 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -12,6 +12,8 @@ #include "core/tools/renderdoc.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/qt_path_util.h" #include @@ -1166,7 +1168,7 @@ void GMainWindow::InitializeWidgets() { loading_screen = new LoadingScreen(this); loading_screen->hide(); ui->horizontalLayout->addWidget(loading_screen); - connect(loading_screen, &LoadingScreen::Hidden, [&] { + connect(loading_screen, &LoadingScreen::Hidden, this, [&] { loading_screen->Clear(); if (emulation_running) { render_window->show(); @@ -2613,16 +2615,9 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; - if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), - tr("Failed to create the shader cache directory for this title.")); - return; + if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { + QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); } - const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; - const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); - QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, @@ -2687,6 +2682,7 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& return true; } +// TODO(crueter): All this can be transfered to qt_common QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { switch (type) { case InstalledEntryType::Game: @@ -3043,12 +3039,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } } +// END void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { - const auto NotImplemented = [this] { - QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"), - tr("File contents were not checked for validity.")); - }; - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(100); @@ -3061,18 +3053,20 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { }; const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback); + const QString resultString = tr(QtCommon::GetGameVerificationResultString(result)); progress.close(); switch (result) { case ContentManager::GameVerificationResult::Success: QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); + resultString); break; case ContentManager::GameVerificationResult::Failed: QMessageBox::critical(this, tr("Integrity verification failed!"), - tr("File contents may be corrupt.")); + resultString); break; case ContentManager::GameVerificationResult::NotImplemented: - NotImplemented(); + QMessageBox::warning(this, tr("Integrity verification couldn't be performed"), + resultString); } } @@ -3094,109 +3088,8 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QUrl(QStringLiteral("https://eden-emulator.github.io/game/") + directory)); } -bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, - const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { -#ifdef _WIN32 // Windows - HRESULT hr = CoInitialize(nullptr); - if (FAILED(hr)) { - LOG_ERROR(Frontend, "CoInitialize failed"); - return false; - } - SCOPE_EXIT { - CoUninitialize(); - }; - IShellLinkW* ps1 = nullptr; - IPersistFile* persist_file = nullptr; - SCOPE_EXIT { - if (persist_file != nullptr) { - persist_file->Release(); - } - if (ps1 != nullptr) { - ps1->Release(); - } - }; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - reinterpret_cast(&ps1)); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); - return false; - } - hres = ps1->SetPath(command.c_str()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set path"); - return false; - } - if (!arguments.empty()) { - hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set arguments"); - return false; - } - } - if (!comment.empty()) { - hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set description"); - return false; - } - } - if (std::filesystem::is_regular_file(icon_path)) { - hres = ps1->SetIconLocation(icon_path.c_str(), 0); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set icon location"); - return false; - } - } - hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast(&persist_file)); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); - return false; - } - hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to save shortcut"); - return false; - } - return true; -#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Any desktop NIX - std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); - std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); - if (!shortcut_stream.is_open()) { - LOG_ERROR(Frontend, "Failed to create shortcut"); - return false; - } - // TODO: Migrate fmt::print to std::print in futures STD C++ 23. - fmt::print(shortcut_stream, "[Desktop Entry]\n"); - fmt::print(shortcut_stream, "Type=Application\n"); - fmt::print(shortcut_stream, "Version=1.0\n"); - fmt::print(shortcut_stream, "Name={}\n", name); - if (!comment.empty()) { - fmt::print(shortcut_stream, "Comment={}\n", comment); - } - if (std::filesystem::is_regular_file(icon_path)) { - fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); - } - fmt::print(shortcut_stream, "TryExec={}\n", command.string()); - fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); - if (!categories.empty()) { - fmt::print(shortcut_stream, "Categories={}\n", categories); - } - if (!keywords.empty()) { - fmt::print(shortcut_stream, "Keywords={}\n", keywords); - } - return true; -#else // Unsupported platform - return false; -#endif -} catch (const std::exception& e) { - LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); - return false; -} // Messages in pre-defined message boxes for less code spaghetti +// TODO(crueter): Still need to decide what to do re: message boxes w/ qml bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { int result = 0; QMessageBox::StandardButtons buttons; @@ -3227,33 +3120,6 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt } } -bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path) { - // Get path to Yuzu icons directory & icon extension - std::string ico_extension = "png"; -#if defined(_WIN32) - out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); - ico_extension = "ico"; -#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) - out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; -#endif - // Create icons directory if it doesn't exist - if (!Common::FS::CreateDirs(out_icon_path)) { - QMessageBox::critical( - this, tr("Create Icon"), - tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(out_icon_path.string())), - QMessageBox::StandardButton::Ok); - out_icon_path.clear(); - return false; - } - - // Create icon file path - out_icon_path /= (program_id == 0 ? fmt::format("eden-{}.{}", game_file_name, ico_extension) - : fmt::format("eden-{:016X}.{}", program_id, ico_extension)); - return true; -} - void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { // Create shortcut @@ -4288,28 +4154,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } void GMainWindow::OnOpenRootDataFolder() { - QDesktopServices::openUrl( - QUrl(QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); + QtCommon::OpenRootDataFolder(); } -void GMainWindow::OnOpenNANDFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); +void GMainWindow::OnOpenNANDFolder() +{ + QtCommon::OpenNANDFolder(); } -void GMainWindow::OnOpenSDMCFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); +void GMainWindow::OnOpenSDMCFolder() +{ + QtCommon::OpenSDMCFolder(); } -void GMainWindow::OnOpenModFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); +void GMainWindow::OnOpenModFolder() +{ + QtCommon::OpenModFolder(); } -void GMainWindow::OnOpenLogFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); +void GMainWindow::OnOpenLogFolder() +{ + QtCommon::OpenLogFolder(); } void GMainWindow::OnVerifyInstalledContents() { @@ -4444,32 +4309,14 @@ void GMainWindow::OnInstallFirmwareFromZIP() { return; } - namespace fs = std::filesystem; - fs::path tmp{std::filesystem::temp_directory_path()}; + const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location); - if (!std::filesystem::create_directories(tmp / "eden" / "firmware")) { - goto unzipFailed; - } - - { - tmp /= "eden"; - tmp /= "firmware"; - - QString qCacheDir = QString::fromStdString(tmp.string()); - - QFile zip(firmware_zip_location); - - QStringList result = JlCompress::extractDir(&zip, qCacheDir); - if (result.isEmpty()) { - goto unzipFailed; - } - - // In this case, it has to be done recursively, since sometimes people - // will pack it into a subdirectory after dumping + // In this case, it has to be done recursively, since sometimes people + // will pack it into a subdirectory after dumping + if (!qCacheDir.isEmpty()) { InstallFirmware(qCacheDir, true); - std::error_code ec; - std::filesystem::remove_all(tmp, ec); + std::filesystem::remove_all(std::filesystem::temp_directory_path() / "eden" / "firmware", ec); if (ec) { QMessageBox::warning(this, tr("Firmware cleanup failed"), @@ -4478,14 +4325,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() { "again.\nOS reported error: %1") .arg(QString::fromStdString(ec.message()))); } - - return; } -unzipFailed: - QMessageBox::critical( - this, tr("Firmware unzip failed"), - tr("Check write permissions in the system temp directory and try again.")); - return; } void GMainWindow::OnInstallDecryptionKeys() { @@ -4764,10 +4604,8 @@ std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target return shortcut_path; } -void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program_id, - const std::string& game_title_, GameListShortcutTarget target, - std::string arguments_, const bool needs_title) { - // Get path to yuzu executable +void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { + // Get path to Eden executable std::filesystem::path command = GetEdenCommand(); // Shortcut path @@ -4819,10 +4657,16 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); std::filesystem::path out_icon_path; - if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } + } else { + QMessageBox::critical( + this, tr("Create Icon"), + tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") + .arg(QString::fromStdString(out_icon_path.string())), + QMessageBox::StandardButton::Ok); } #if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) @@ -4843,12 +4687,12 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qgame_title)) { arguments = "-f " + arguments; } - const std::string comment = fmt::format("Start {:s} with the eden Emulator", game_title); + const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments, - categories, keywords, game_title)) { + if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, qgame_title); return; @@ -4876,6 +4720,7 @@ void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); const auto game_path = qlaunch_applet_nca->GetFullPath(); + // TODO(crueter): Make this use the Eden icon CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b20f601381..8d00fef4f8 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -478,15 +478,6 @@ private: QString GetTasStateDescription() const; bool CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title); - bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path); - bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, const std::string& arguments, - const std::string& categories, const std::string& keywords, - const std::string& name); - - bool OnCheckNcaVerification(); /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog From 6c5d6ac23708240585796524369135eb5c2597b0 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 23:28:13 -0400 Subject: [PATCH 34/52] Fix license headers --- src/qt_common/qt_game_util.cpp | 3 +++ src/qt_common/qt_game_util.h | 3 +++ src/qt_common/qt_path_util.cpp | 3 +++ src/qt_common/qt_path_util.h | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 9aba4e393c..9264c782d1 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_game_util.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 98d17027c4..3d27839672 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 2ca2f6bf72..6875d01dea 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_path_util.h" #include #include diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h index 6fafad7ed9..7f399c4bb4 100644 --- a/src/qt_common/qt_path_util.h +++ b/src/qt_common/qt_path_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_PATH_UTIL_H #define QT_PATH_UTIL_H From 0d28d07b77240e13b8c032d163e2b02887df6244 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 01:21:18 -0400 Subject: [PATCH 35/52] thank you Qt Creator, very cool Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 7 ++----- src/qt_common/qt_game_util.cpp | 10 +++++++--- src/yuzu/main.cpp | 3 --- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 0cd4c86b4a..54c79c93e1 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -9,17 +9,14 @@ #include #include -#include #include "common/logging/log.h" #include "core/frontend/emu_window.h" -#if !defined(WIN32) && !defined(__APPLE__) -#include - #include - #include +#if !defined(WIN32) && !defined(__APPLE__) +#include #elif defined(__APPLE__) #include #endif diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 9264c782d1..add9d46a39 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -7,11 +7,15 @@ #include #include -#include "fmt/ostream.h" -#include #ifdef _WIN32 -#include + #include + #include + #include "common/scope_exit.h" + #include "common/string_util.h" +#else + #include "fmt/ostream.h" + #include #endif namespace QtCommon { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 88f3a3d743..86e0755ce8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -15,8 +15,6 @@ #include "qt_common/qt_game_util.h" #include "qt_common/qt_path_util.h" -#include - #ifdef __APPLE__ #include // for chdir #endif @@ -121,7 +119,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/scm_rev.h" #include "common/scope_exit.h" #ifdef _WIN32 -#include #include "common/windows/timer_resolution.h" #endif #ifdef ARCHITECTURE_x86_64 From caaef71d9d7d4c93ed29df1870e5f3703e37c928 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 21:10:17 -0400 Subject: [PATCH 36/52] [qt] frontend abstraction and message box early handling Signed-off-by: crueter --- src/CMakeLists.txt | 1 + src/frontend_common/firmware_manager.h | 5 ++- src/qt_common/CMakeLists.txt | 6 ++- src/qt_common/qt_common.cpp | 59 ++++++++++++++++++++++---- src/qt_common/qt_common.h | 34 +++++++-------- src/qt_common/qt_frontend_util.cpp | 25 +++++++++++ src/qt_common/qt_frontend_util.h | 29 +++++++++++++ src/yuzu/main.cpp | 24 +++-------- 8 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 src/qt_common/qt_frontend_util.cpp create mode 100644 src/qt_common/qt_frontend_util.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0032b20029..184b049d06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ if (YUZU_ROOM_STANDALONE) endif() if (ENABLE_QT) + add_definitions(-DYUZU_QT_WIDGETS) add_subdirectory(qt_common) add_subdirectory(yuzu) endif() diff --git a/src/frontend_common/firmware_manager.h b/src/frontend_common/firmware_manager.h index 20f3b41478..23fce59eb3 100644 --- a/src/frontend_common/firmware_manager.h +++ b/src/frontend_common/firmware_manager.h @@ -7,6 +7,7 @@ #include "common/common_types.h" #include "core/core.h" #include "core/file_sys/nca_metadata.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/registered_cache.h" #include "core/hle/service/filesystem/filesystem.h" #include @@ -143,6 +144,8 @@ inline std::pair GetFirmwareVersion return {firmware_data, result}; } + +// TODO(crueter): GET AS STRING } -#endif // FIRMWARE_MANAGER_H +#endif diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index d6ef427ba6..0c9bb54b11 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) + add_library(qt_common STATIC qt_common.h qt_common.cpp @@ -15,10 +17,12 @@ add_library(qt_common STATIC shared_translation.h qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp + qt_frontend_util.h qt_frontend_util.cpp ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 54c79c93e1..c7b75a196d 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -5,6 +5,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "core/hle/service/filesystem/filesystem.h" +#include "frontend_common/firmware_manager.h" #include "uisettings.h" #include @@ -13,6 +14,10 @@ #include "core/frontend/emu_window.h" #include + +#include +#include "qt_frontend_util.h" + #include #if !defined(WIN32) && !defined(__APPLE__) @@ -22,7 +27,6 @@ #endif namespace QtCommon { - MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) @@ -87,8 +91,24 @@ FirmwareInstallResult InstallFirmware( bool recursive, std::function QtProgressCallback, Core::System* system, - FileSys::VfsFilesystem* vfs) + FileSys::VfsFilesystem* vfs, + QWidget* parent) { + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + parent); + }; + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in @@ -121,14 +141,20 @@ FirmwareInstallResult InstallFirmware( } if (out.size() <= 0) { - return FirmwareInstallResult::NoNCAs; + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - return FirmwareInstallResult::FailedDelete; + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } LOG_INFO(Frontend, @@ -159,17 +185,35 @@ FirmwareInstallResult InstallFirmware( 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - return FirmwareInstallResult::FailedCorrupted; + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } } if (!success) { - return FirmwareInstallResult::FailedCopy; + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } // Re-scan VFS for the newly placed firmware files. system->GetFileSystemController().CreateFactories(*vfs); - return FirmwareInstallResult::Success; + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::ShowMessage(QMessageBox::Information, + qApp->tr(successTitle), + qApp->tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons, + parent); + return result; } QString UnzipFirmwareToTmp(const QString& location) @@ -195,5 +239,4 @@ QString UnzipFirmwareToTmp(const QString& location) return qCacheDir; } - } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index b3ca99e65a..ef9b5577f1 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -13,7 +13,6 @@ #include namespace QtCommon { - static constexpr std::array METADATA_RESULTS = { "The operation completed successfully.", "The metadata cache couldn't be deleted. It might be in use or non-existent.", @@ -41,15 +40,14 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } -static constexpr std::array FIRMWARE_RESULTS = { - "", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware." -}; +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; enum class FirmwareInstallResult { Success, @@ -60,11 +58,13 @@ enum class FirmwareInstallResult { FailedCorrupted, }; -FirmwareInstallResult InstallFirmware(const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs); +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs, + QWidget *parent = nullptr); QString UnzipFirmwareToTmp(const QString &location); @@ -75,8 +75,6 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul Core::Frontend::WindowSystemType GetWindowSystemType(); -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); - - +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); } // namespace QtCommon #endif diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp new file mode 100644 index 0000000000..6cbe82e000 --- /dev/null +++ b/src/qt_common/qt_frontend_util.cpp @@ -0,0 +1,25 @@ +#include "qt_frontend_util.h" + +namespace QtCommon::Frontend { +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ +#ifdef YUZU_QT_WIDGETS + QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + return static_cast(box->exec()); +#endif +} + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ + return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); +} + +} // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h new file mode 100644 index 0000000000..8508e29f18 --- /dev/null +++ b/src/qt_common/qt_frontend_util.h @@ -0,0 +1,29 @@ +#ifndef QT_FRONTEND_UTIL_H +#define QT_FRONTEND_UTIL_H + +#include +#include + +#ifdef YUZU_QT_WIDGETS +#include +#endif + +/** + * manages common functionality e.g. message boxes and such for Qt/QML + */ +namespace QtCommon::Frontend { +Q_NAMESPACE + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); +} // namespace QtCommon::Frontend +#endif // QT_FRONTEND_UTIL_H diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 86e0755ce8..19110781bf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2611,6 +2611,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } +// TODO(crueter): Transfer ts to showmessage void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); @@ -2680,6 +2681,8 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& } // TODO(crueter): All this can be transfered to qt_common +// Aldoe I need to decide re: message boxes for QML +// translations_common? strings_common? qt_strings? who knows QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { switch (type) { case InstalledEntryType::Game: @@ -4218,28 +4221,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); - const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); progress.close(); - QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); - - switch (result) { - case QtCommon::FirmwareInstallResult::NoNCAs: - case QtCommon::FirmwareInstallResult::FailedCorrupted: - box->setIcon(QMessageBox::Icon::Warning); - box->exec(); - return; - case QtCommon::FirmwareInstallResult::FailedCopy: - case QtCommon::FirmwareInstallResult::FailedDelete: - box->setIcon(QMessageBox::Icon::Critical); - box->exec(); - return; - default: - box->deleteLater(); - break; - } + if (result != QtCommon::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); From fe362c9e00a70a7ca5d03071a980d481501fbc4d Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 21:12:22 -0400 Subject: [PATCH 37/52] Fix license headers --- src/qt_common/qt_frontend_util.cpp | 3 +++ src/qt_common/qt_frontend_util.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 6cbe82e000..9a05c89928 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_frontend_util.h" namespace QtCommon::Frontend { diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 8508e29f18..8a38c033bf 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_FRONTEND_UTIL_H #define QT_FRONTEND_UTIL_H From 4c02ca7a5fc427bcb0f448c1ff272c4e3b3f8b85 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 7 Aug 2025 20:45:16 -0400 Subject: [PATCH 38/52] [qt_common] update translations Signed-off-by: crueter --- src/qt_common/qt_frontend_util.cpp | 2 + src/qt_common/qt_game_util.cpp | 20 ++--- src/qt_common/qt_game_util.h | 4 +- src/qt_common/shared_translation.cpp | 110 +++++++++++++-------------- 4 files changed, 70 insertions(+), 66 deletions(-) diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 9a05c89928..bcb662239b 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -14,6 +14,8 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); return static_cast(box->exec()); #endif + // TODO(crueter): If Qt Widgets is disabled... + // need a way to reference icon/buttons too } QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index add9d46a39..a870c2ab27 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -146,33 +146,33 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_ return true; } -void OpenRootDataFolder() { +void OpenEdenFolder(const Common::FS::EdenPath& path) { QDesktopServices::openUrl(QUrl( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); + QString::fromStdString(Common::FS::GetEdenPathString(path)))); +} + +void OpenRootDataFolder() { + OpenEdenFolder(Common::FS::EdenPath::EdenDir); } void OpenNANDFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); + OpenEdenFolder(Common::FS::EdenPath::NANDDir); } void OpenSDMCFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); + OpenEdenFolder(Common::FS::EdenPath::SDMCDir); } void OpenModFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); + OpenEdenFolder(Common::FS::EdenPath::LoadDir); } void OpenLogFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); + OpenEdenFolder(Common::FS::EdenPath::LogDir); } } diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 3d27839672..12916d8a98 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -4,6 +4,7 @@ #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H +#include "common/fs/path_util.h" #include "frontend_common/content_manager.h" #include @@ -12,7 +13,7 @@ namespace QtCommon { static constexpr std::array GAME_VERIFICATION_RESULTS = { "The operation completed successfully.", "File contents may be corrupt or missing..", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Firmware installation cancelled, firmware may be in a bad state or corrupted. " "File contents could not be checked for validity." }; @@ -34,6 +35,7 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, std::filesystem::path& out_icon_path); +void OpenEdenFolder(const Common::FS::EdenPath &path); void OpenRootDataFolder(); void OpenNANDFolder(); void OpenSDMCFolder(); diff --git a/src/qt_common/shared_translation.cpp b/src/qt_common/shared_translation.cpp index 018af56c67..81ec35b6d8 100644 --- a/src/qt_common/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -29,10 +29,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) #define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) - // A setting can be ignored by giving it a blank name + // A setting can be ignored by giving it a blank name - // Applets - INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); + // Applets + INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); INSERT(Settings, error_applet_mode, tr("Error"), QString()); @@ -648,58 +648,58 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) translations->insert( {Settings::EnumMetadata::Index(), { - {static_cast(Settings::TimeZone::Auto), - tr("Auto (%1)", "Auto select time zone") - .arg(QString::fromStdString( - Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, - {static_cast(Settings::TimeZone::Default), - tr("Default (%1)", "Default time zone") - .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, - PAIR(TimeZone, Cet, tr("CET")), - PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), - PAIR(TimeZone, Cuba, tr("Cuba")), - PAIR(TimeZone, Eet, tr("EET")), - PAIR(TimeZone, Egypt, tr("Egypt")), - PAIR(TimeZone, Eire, tr("Eire")), - PAIR(TimeZone, Est, tr("EST")), - PAIR(TimeZone, Est5Edt, tr("EST5EDT")), - PAIR(TimeZone, Gb, tr("GB")), - PAIR(TimeZone, GbEire, tr("GB-Eire")), - PAIR(TimeZone, Gmt, tr("GMT")), - PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), - PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), - PAIR(TimeZone, GmtZero, tr("GMT0")), - PAIR(TimeZone, Greenwich, tr("Greenwich")), - PAIR(TimeZone, Hongkong, tr("Hongkong")), - PAIR(TimeZone, Hst, tr("HST")), - PAIR(TimeZone, Iceland, tr("Iceland")), - PAIR(TimeZone, Iran, tr("Iran")), - PAIR(TimeZone, Israel, tr("Israel")), - PAIR(TimeZone, Jamaica, tr("Jamaica")), - PAIR(TimeZone, Japan, tr("Japan")), - PAIR(TimeZone, Kwajalein, tr("Kwajalein")), - PAIR(TimeZone, Libya, tr("Libya")), - PAIR(TimeZone, Met, tr("MET")), - PAIR(TimeZone, Mst, tr("MST")), - PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), - PAIR(TimeZone, Navajo, tr("Navajo")), - PAIR(TimeZone, Nz, tr("NZ")), - PAIR(TimeZone, NzChat, tr("NZ-CHAT")), - PAIR(TimeZone, Poland, tr("Poland")), - PAIR(TimeZone, Portugal, tr("Portugal")), - PAIR(TimeZone, Prc, tr("PRC")), - PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), - PAIR(TimeZone, Roc, tr("ROC")), - PAIR(TimeZone, Rok, tr("ROK")), - PAIR(TimeZone, Singapore, tr("Singapore")), - PAIR(TimeZone, Turkey, tr("Turkey")), - PAIR(TimeZone, Uct, tr("UCT")), - PAIR(TimeZone, Universal, tr("Universal")), - PAIR(TimeZone, Utc, tr("UTC")), - PAIR(TimeZone, WSu, tr("W-SU")), - PAIR(TimeZone, Wet, tr("WET")), - PAIR(TimeZone, Zulu, tr("Zulu")), - }}); + {static_cast(Settings::TimeZone::Auto), + tr("Auto (%1)", "Auto select time zone") + .arg(QString::fromStdString( + Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, + {static_cast(Settings::TimeZone::Default), + tr("Default (%1)", "Default time zone") + .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, + PAIR(TimeZone, Cet, tr("CET")), + PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), + PAIR(TimeZone, Cuba, tr("Cuba")), + PAIR(TimeZone, Eet, tr("EET")), + PAIR(TimeZone, Egypt, tr("Egypt")), + PAIR(TimeZone, Eire, tr("Eire")), + PAIR(TimeZone, Est, tr("EST")), + PAIR(TimeZone, Est5Edt, tr("EST5EDT")), + PAIR(TimeZone, Gb, tr("GB")), + PAIR(TimeZone, GbEire, tr("GB-Eire")), + PAIR(TimeZone, Gmt, tr("GMT")), + PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), + PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), + PAIR(TimeZone, GmtZero, tr("GMT0")), + PAIR(TimeZone, Greenwich, tr("Greenwich")), + PAIR(TimeZone, Hongkong, tr("Hongkong")), + PAIR(TimeZone, Hst, tr("HST")), + PAIR(TimeZone, Iceland, tr("Iceland")), + PAIR(TimeZone, Iran, tr("Iran")), + PAIR(TimeZone, Israel, tr("Israel")), + PAIR(TimeZone, Jamaica, tr("Jamaica")), + PAIR(TimeZone, Japan, tr("Japan")), + PAIR(TimeZone, Kwajalein, tr("Kwajalein")), + PAIR(TimeZone, Libya, tr("Libya")), + PAIR(TimeZone, Met, tr("MET")), + PAIR(TimeZone, Mst, tr("MST")), + PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), + PAIR(TimeZone, Navajo, tr("Navajo")), + PAIR(TimeZone, Nz, tr("NZ")), + PAIR(TimeZone, NzChat, tr("NZ-CHAT")), + PAIR(TimeZone, Poland, tr("Poland")), + PAIR(TimeZone, Portugal, tr("Portugal")), + PAIR(TimeZone, Prc, tr("PRC")), + PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), + PAIR(TimeZone, Roc, tr("ROC")), + PAIR(TimeZone, Rok, tr("ROK")), + PAIR(TimeZone, Singapore, tr("Singapore")), + PAIR(TimeZone, Turkey, tr("Turkey")), + PAIR(TimeZone, Uct, tr("UCT")), + PAIR(TimeZone, Universal, tr("Universal")), + PAIR(TimeZone, Utc, tr("UTC")), + PAIR(TimeZone, WSu, tr("W-SU")), + PAIR(TimeZone, Wet, tr("WET")), + PAIR(TimeZone, Zulu, tr("Zulu")), + }}); translations->insert({Settings::EnumMetadata::Index(), { PAIR(AudioMode, Mono, tr("Mono")), From e18628eb6c688080897119f29d5a98646f5eb1df Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:48:13 -0400 Subject: [PATCH 39/52] [qt_common] reorg, move more stuff out of main Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 5 + src/qt_common/qt_common.cpp | 175 +------- src/qt_common/qt_common.h | 76 +--- src/qt_common/qt_content_util.cpp | 202 +++++++++ src/qt_common/qt_content_util.h | 48 +++ src/qt_common/qt_frontend_util.cpp | 73 +++- src/qt_common/qt_frontend_util.h | 44 +- src/qt_common/qt_game_util.cpp | 270 ++++++++++-- src/qt_common/qt_game_util.h | 40 +- src/qt_common/qt_meta.cpp | 72 ++++ src/qt_common/qt_meta.h | 12 + src/qt_common/qt_path_util.cpp | 9 +- src/qt_common/qt_path_util.h | 4 +- src/qt_common/qt_rom_util.cpp | 75 ++++ src/qt_common/qt_rom_util.h | 17 + .../configuration/configure_filesystem.cpp | 13 +- src/yuzu/game_list.cpp | 25 +- src/yuzu/game_list.h | 19 +- src/yuzu/main.cpp | 403 +++--------------- src/yuzu/main.h | 21 +- 20 files changed, 923 insertions(+), 680 deletions(-) create mode 100644 src/qt_common/qt_content_util.cpp create mode 100644 src/qt_common/qt_content_util.h create mode 100644 src/qt_common/qt_meta.cpp create mode 100644 src/qt_common/qt_meta.h create mode 100644 src/qt_common/qt_rom_util.cpp create mode 100644 src/qt_common/qt_rom_util.h diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 0c9bb54b11..da6c9b0481 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -18,11 +19,15 @@ add_library(qt_common STATIC qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp qt_frontend_util.h qt_frontend_util.cpp + qt_meta.h qt_meta.cpp + qt_content_util.h qt_content_util.cpp + qt_rom_util.h qt_rom_util.cpp ) create_target_directory_groups(qt_common) target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) target_link_libraries(qt_common PRIVATE Qt6::Core) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index c7b75a196d..6f8808ca32 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -2,11 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_common.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "frontend_common/firmware_manager.h" -#include "uisettings.h" #include #include @@ -16,7 +11,6 @@ #include #include -#include "qt_frontend_util.h" #include @@ -27,19 +21,9 @@ #endif namespace QtCommon { -MetadataResult ResetMetadata() -{ - if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) - / "game_list/")) { - return MetadataResult::Empty; - } else if (Common::FS::RemoveDirRecursively( - Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return MetadataResult::Success; - UISettings::values.is_game_list_reload_pending.exchange(true); - } else { - return MetadataResult::Failure; - } -} + +QObject *rootObject = nullptr; +Core::System *system = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -86,157 +70,14 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -FirmwareInstallResult InstallFirmware( - const QString& location, - bool recursive, - std::function QtProgressCallback, - Core::System* system, - FileSys::VfsFilesystem* vfs, - QWidget* parent) +const QString tr(const char* str) { - static constexpr const char* failedTitle = "Firmware Install Failed"; - static constexpr const char* successTitle = "Firmware Install Failed"; - static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; - - QMessageBox::Icon icon; - FirmwareInstallResult result; - - const auto ShowMessage = [&]() { - QtCommon::Frontend::ShowMessage(icon, - failedTitle, - GetFirmwareInstallResultString(result), - buttons, - parent); - }; - - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); - - // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in - // there.) - std::filesystem::path firmware_source_path = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - return FirmwareInstallResult::NoOp; - } - - std::vector out; - const Common::FS::DirEntryCallable callback = - [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") { - out.emplace_back(entry.path()); - } - - return true; - }; - - QtProgressCallback(100, 10); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } else { - Common::FS::IterateDirEntries(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } - - if (out.size() <= 0) { - result = FirmwareInstallResult::NoNCAs; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - - // Locate and erase the content of nand/system/Content/registered/*.nca, if any. - auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (sysnand_content_vdir->IsWritable() - && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - result = FirmwareInstallResult::FailedDelete; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - LOG_INFO(Frontend, - "Cleaned nand/system/Content/registered folder in preparation for new firmware."); - - QtProgressCallback(100, 20); - - auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); - - bool success = true; - int i = 0; - for (const auto& firmware_src_path : out) { - i++; - auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), - FileSys::OpenMode::Read); - auto firmware_dst_vfile = firmware_vdir - ->CreateFileRelative(firmware_src_path.filename().string()); - - if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { - LOG_ERROR(Frontend, - "Failed to copy firmware file {} to {} in registered folder!", - firmware_src_path.generic_string(), - firmware_src_path.filename().string()); - success = false; - } - - if (QtProgressCallback(100, - 20 - + static_cast(((i) / static_cast(out.size())) - * 70.0))) { - result = FirmwareInstallResult::FailedCorrupted; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - } - - if (!success) { - result = FirmwareInstallResult::FailedCopy; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - // Re-scan VFS for the newly placed firmware files. - system->GetFileSystemController().CreateFactories(*vfs); - - const auto pair = FirmwareManager::GetFirmwareVersion(*system); - const auto firmware_data = pair.first; - const std::string display_version(firmware_data.display_version.data()); - - result = FirmwareInstallResult::Success; - QtCommon::Frontend::ShowMessage(QMessageBox::Information, - qApp->tr(successTitle), - qApp->tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version)), - buttons, - parent); - return result; + return QGuiApplication::tr(str); } -QString UnzipFirmwareToTmp(const QString& location) +const QString tr(const std::string& str) { - namespace fs = std::filesystem; - fs::path tmp{fs::temp_directory_path()}; - - if (!fs::create_directories(tmp / "eden" / "firmware")) { - return ""; - } - - tmp /= "eden"; - tmp /= "firmware"; - - QString qCacheDir = QString::fromStdString(tmp.string()); - - QFile zip(location); - - QStringList result = JlCompress::extractDir(&zip, qCacheDir); - if (result.isEmpty()) { - return ""; - } - - return qCacheDir; + return QGuiApplication::tr(str.c_str()); } + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index ef9b5577f1..cf52cedc32 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,8 +4,6 @@ #ifndef QT_COMMON_H #define QT_COMMON_H -#include - #include #include "core/core.h" #include @@ -13,68 +11,28 @@ #include namespace QtCommon { -static constexpr std::array METADATA_RESULTS = { - "The operation completed successfully.", - "The metadata cache couldn't be deleted. It might be in use or non-existent.", - "The metadata cache is already empty.", -}; -enum class MetadataResult { - Success, - Failure, - Empty, -}; -/** - * @brief ResetMetadata Reset game list metadata. - * @return A result code. - */ -MetadataResult ResetMetadata(); +extern QObject *rootObject; +extern Core::System *system; -/** - * \brief Get a string representation of a result from ResetMetadata. - * \param result The result code. - * \return A string representation of the passed result code. - */ -inline constexpr const char *GetResetMetadataResultString(MetadataResult result) -{ - return METADATA_RESULTS.at(static_cast(result)); -} - -static constexpr std::array FIRMWARE_RESULTS - = {"Successfully installed firmware version %1", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware."}; - -enum class FirmwareInstallResult { - Success, - NoOp, - NoNCAs, - FailedDelete, - FailedCopy, - FailedCorrupted, -}; - -FirmwareInstallResult InstallFirmware( - const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs, - QWidget *parent = nullptr); - -QString UnzipFirmwareToTmp(const QString &location); - -inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) -{ - return FIRMWARE_RESULTS.at(static_cast(result)); -} +typedef std::function QtProgressCallback; Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); + +static inline void SetRootObject(QObject *parent) +{ + rootObject = parent; +} + +static inline void SetSystem(Core::System *newSystem) +{ + system = newSystem; +} + +const QString tr(const char *str); +const QString tr(const std::string &str); + } // namespace QtCommon #endif diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp new file mode 100644 index 0000000000..81ec7c9cea --- /dev/null +++ b/src/qt_common/qt_content_util.cpp @@ -0,0 +1,202 @@ +#include "qt_content_util.h" +#include "common/fs/fs.h" +#include "frontend_common/content_manager.h" +#include "frontend_common/firmware_manager.h" +#include "qt_common/qt_game_util.h" +#include "qt_frontend_util.h" + +#include + +namespace QtCommon::Content { + +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent) +{ + if (FirmwareManager::GameRequiresFirmware(program_id) + && !FirmwareManager::CheckFirmwarePresence(system)) { + auto result = QtCommon::Frontend::ShowMessage( + QMessageBox::Warning, + "Game Requires Firmware", + "The game you are trying to launch requires firmware to boot or to get past the " + "opening menu. Please " + "dump and install firmware, or press \"OK\" to launch anyways.", + QMessageBox::Ok | QMessageBox::Cancel, + parent); + + return result == QMessageBox::Ok; + } + + return true; +} + +FirmwareInstallResult InstallFirmware( + const QString& location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem* vfs) +{ + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + rootObject); + }; + + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector out; + const Common::FS::DirEntryCallable dir_callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") { + out.emplace_back(entry.path()); + } + + return true; + }; + + callback(100, 10); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (sysnand_content_vdir->IsWritable() + && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + callback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), + FileSys::OpenMode::Read); + auto firmware_dst_vfile = firmware_vdir + ->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, + "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), + firmware_src_path.filename().string()); + success = false; + } + + if (callback(100, 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + } + + if (!success) { + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::Information(rootObject, + tr(successTitle), + tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons); + return result; +} + +QString UnzipFirmwareToTmp(const QString& location) +{ + namespace fs = std::filesystem; + fs::path tmp{fs::temp_directory_path()}; + + if (!fs::create_directories(tmp / "eden" / "firmware")) { + return ""; + } + + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + return ""; + } + + return qCacheDir; +} + +// Content // +void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) { + const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); + + switch (result) { + case ContentManager::GameVerificationResult::Success: + QtCommon::Frontend::Information(rootObject, tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + break; + case ContentManager::GameVerificationResult::Failed: + QtCommon::Frontend::Critical(rootObject, tr("Integrity verification failed!"), + tr("File contents may be corrupt or missing.")); + break; + case ContentManager::GameVerificationResult::NotImplemented: + QtCommon::Frontend::Warning( + rootObject, + tr("Integrity verification couldn't be performed"), + tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " + "File contents could not be checked for validity.")); + } +} + + +} diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h new file mode 100644 index 0000000000..9a1a4e5bc2 --- /dev/null +++ b/src/qt_common/qt_content_util.h @@ -0,0 +1,48 @@ +#ifndef QT_CONTENT_UTIL_H +#define QT_CONTENT_UTIL_H + +#include +#include "common/common_types.h" +#include "core/core.h" +#include "qt_common/qt_common.h" + +namespace QtCommon::Content { + +// +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent); + +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem *vfs); + +QString UnzipFirmwareToTmp(const QString &location); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + +// Content // +void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); +} +#endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index bcb662239b..6b96a26a21 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -4,27 +4,84 @@ #include "qt_frontend_util.h" namespace QtCommon::Frontend { + QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, - QWidget *parent) + QObject *parent) { #ifdef YUZU_QT_WIDGETS - QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + QMessageBox *box = new QMessageBox(icon, title, text, buttons, (QWidget *) parent); return static_cast(box->exec()); #endif // TODO(crueter): If Qt Widgets is disabled... // need a way to reference icon/buttons too } -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons, - QWidget *parent) +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) { - return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); + return ShowMessage(QMessageBox::Information, title, text, buttons, parent); } +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, title, text, buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, title, text, buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, title, text, buttons, parent); +} + +QMessageBox::StandardButton Information(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Information, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, parent->tr(title), parent->tr(text), buttons, parent); +} + + } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 8a38c033bf..a91a0db07b 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -17,16 +17,52 @@ namespace QtCommon::Frontend { Q_NAMESPACE +// TODO(crueter) widgets-less impl, choices et al. QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QObject *parent = nullptr); -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Information(QObject *parent, const char *title, const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index a870c2ab27..488eb8c971 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -4,40 +4,50 @@ #include "qt_game_util.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/file_sys/savedata_factory.h" +#include "frontend_common/content_manager.h" +#include "qt_common.h" +#include "qt_common/uisettings.h" +#include "qt_frontend_util.h" #include #include #ifdef _WIN32 - #include - #include - #include "common/scope_exit.h" - #include "common/string_util.h" +#include "common/scope_exit.h" +#include "common/string_util.h" +#include +#include #else - #include "fmt/ostream.h" - #include +#include "fmt/ostream.h" +#include #endif -namespace QtCommon { +namespace QtCommon::Game { bool CreateShortcutLink(const std::filesystem::path& shortcut_path, - const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, + const std::string& categories, + const std::string& keywords, + const std::string& name) +try { #ifdef _WIN32 // Windows HRESULT hr = CoInitialize(nullptr); if (FAILED(hr)) { LOG_ERROR(Frontend, "CoInitialize failed"); return false; } - SCOPE_EXIT { + SCOPE_EXIT + { CoUninitialize(); }; IShellLinkW* ps1 = nullptr; IPersistFile* persist_file = nullptr; - SCOPE_EXIT { + SCOPE_EXIT + { if (persist_file != nullptr) { persist_file->Release(); } @@ -45,7 +55,10 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, ps1->Release(); } }; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + HRESULT hres = CoCreateInstance(CLSID_ShellLink, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IShellLinkW, reinterpret_cast(&ps1)); if (FAILED(hres)) { LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); @@ -115,17 +128,18 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, fmt::print(shortcut_stream, "Keywords={}\n", keywords); } return true; -#else // Unsupported platform +#else // Unsupported platform return false; #endif -} - catch (const std::exception& e) { +} catch (const std::exception& e) { LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); return false; } -bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path) { +bool MakeShortcutIcoPath(const u64 program_id, + const std::string_view game_file_name, + std::filesystem::path& out_icon_path) +{ // Get path to Yuzu icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) @@ -146,12 +160,13 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_ return true; } -void OpenEdenFolder(const Common::FS::EdenPath& path) { - QDesktopServices::openUrl(QUrl( - QString::fromStdString(Common::FS::GetEdenPathString(path)))); +void OpenEdenFolder(const Common::FS::EdenPath& path) +{ + QDesktopServices::openUrl(QUrl(QString::fromStdString(Common::FS::GetEdenPathString(path)))); } -void OpenRootDataFolder() { +void OpenRootDataFolder() +{ OpenEdenFolder(Common::FS::EdenPath::EdenDir); } @@ -175,4 +190,211 @@ void OpenLogFolder() OpenEdenFolder(Common::FS::EdenPath::LogDir); } +static QString GetGameListErrorRemoving(QtCommon::Game::InstalledEntryType type) +{ + switch (type) { + case QtCommon::Game::InstalledEntryType::Game: + return tr("Error Removing Contents"); + case QtCommon::Game::InstalledEntryType::Update: + return tr("Error Removing Update"); + case QtCommon::Game::InstalledEntryType::AddOnContent: + return tr("Error Removing DLC"); + default: + return QStringLiteral("Error Removing "); + } } + +// Game Content // +void RemoveBaseContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveBaseContent(system->GetFileSystemController(), + program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed base game."); + } else { + QtCommon::Frontend::Warning( + rootObject, + GetGameListErrorRemoving(type), + tr("The base game is not installed in the NAND and cannot be removed.")); + } +} + +void RemoveUpdateContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed update."); + } else { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There is no update installed for this title.")); + } +} + +void RemoveAddOnContent(u64 program_id, InstalledEntryType type) +{ + const size_t count = ContentManager::RemoveAllDLC(*system, program_id); + if (count == 0) { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There are no DLCs installed for this title.")); + return; + } + + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed %1 installed DLC.").arg(count)); +} + +// Global Content // + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) +{ + const auto target_file_name = [target] { + switch (target) { + case GameListRemoveTarget::GlShaderCache: + return "opengl.bin"; + case GameListRemoveTarget::VkShaderCache: + return "vulkan.bin"; + default: + return ""; + } + }(); + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader cache.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("Failed to remove the transferable shader cache.")); + } +} + +void RemoveVulkanDriverPipelineCache(u64 program_id) +{ + static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; + + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + return; + } + if (!Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Vulkan Driver Pipeline Cache"), + tr("Failed to remove the driver pipeline cache.")); + } +} + +void RemoveAllTransferableShaderCaches(u64 program_id) +{ + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); + + if (!Common::FS::Exists(program_shader_cache_dir)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader caches.")); + } else { + QtCommon::Frontend::Warning( + rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("Failed to remove the transferable shader cache directory.")); + } +} + +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path) +{ + const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); + const auto config_file_name = program_id == 0 + ? Common::FS::PathToUTF8String(file_path.filename()) + .append(".ini") + : fmt::format("{:016X}.ini", program_id); + const auto custom_config_file_path = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) + / "custom" / config_file_name; + + if (!Common::FS::Exists(custom_config_file_path)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("A custom configuration for this title does not exist.")); + return; + } + + if (Common::FS::RemoveFile(custom_config_file_path)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the custom game configuration.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("Failed to remove the custom game configuration.")); + } +} + +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs) +{ + const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); + auto vfs_nand_dir = vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), + FileSys::OpenMode::Read); + + const auto cache_storage_path + = FileSys::SaveDataFactory::GetFullPath({}, + vfs_nand_dir, + FileSys::SaveDataSpaceId::User, + FileSys::SaveDataType::Cache, + 0 /* program_id */, + {}, + 0); + + const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); + + // Not an error if it wasn't cleared. + Common::FS::RemoveDirRecursively(path); +} + +// Metadata // +void ResetMetadata() +{ + const QString title = tr("Reset Metadata Cache"); + + if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) + / "game_list/")) { + QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty.")); + } else if (Common::FS::RemoveDirRecursively( + Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { + QtCommon::Frontend::Information(rootObject, + title, + tr("The operation completed successfully.")); + UISettings::values.is_game_list_reload_pending.exchange(true); + } else { + QtCommon::Frontend::Warning( + rootObject, + title, + tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); + } +} + +} // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 12916d8a98..9861910833 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -4,23 +4,25 @@ #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H +#include #include "common/fs/path_util.h" -#include "frontend_common/content_manager.h" -#include +#include -namespace QtCommon { +namespace QtCommon::Game { -static constexpr std::array GAME_VERIFICATION_RESULTS = { - "The operation completed successfully.", - "File contents may be corrupt or missing..", - "Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "File contents could not be checked for validity." +enum class InstalledEntryType { + Game, + Update, + AddOnContent, }; -inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result) -{ - return GAME_VERIFICATION_RESULTS.at(static_cast(result)); -} +enum class GameListRemoveTarget { + GlShaderCache, + VkShaderCache, + AllShaderCache, + CustomConfiguration, + CacheStorage, +}; bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, @@ -41,6 +43,20 @@ void OpenNANDFolder(); void OpenSDMCFolder(); void OpenModFolder(); void OpenLogFolder(); + +void RemoveBaseContent(u64 program_id, InstalledEntryType type); +void RemoveUpdateContent(u64 program_id, InstalledEntryType type); +void RemoveAddOnContent(u64 program_id, InstalledEntryType type); + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); +void RemoveVulkanDriverPipelineCache(u64 program_id); +void RemoveAllTransferableShaderCaches(u64 program_id); +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); + +// Metadata // +void ResetMetadata(); + } #endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_meta.cpp b/src/qt_common/qt_meta.cpp new file mode 100644 index 0000000000..c972c0fe45 --- /dev/null +++ b/src/qt_common/qt_meta.cpp @@ -0,0 +1,72 @@ +#include "qt_meta.h" +#include "common/common_types.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" + +namespace QtCommon::Meta { + +void RegisterMetaTypes() +{ + // Register integral and floating point types + qRegisterMetaType("u8"); + qRegisterMetaType("u16"); + qRegisterMetaType("u32"); + qRegisterMetaType("u64"); + qRegisterMetaType("u128"); + qRegisterMetaType("s8"); + qRegisterMetaType("s16"); + qRegisterMetaType("s32"); + qRegisterMetaType("s64"); + qRegisterMetaType("f32"); + qRegisterMetaType("f64"); + + // Register string types + qRegisterMetaType("std::string"); + qRegisterMetaType("std::wstring"); + qRegisterMetaType("std::u8string"); + qRegisterMetaType("std::u16string"); + qRegisterMetaType("std::u32string"); + qRegisterMetaType("std::string_view"); + qRegisterMetaType("std::wstring_view"); + qRegisterMetaType("std::u8string_view"); + qRegisterMetaType("std::u16string_view"); + qRegisterMetaType("std::u32string_view"); + + // Register applet types + + // Cabinet Applet + qRegisterMetaType("Core::Frontend::CabinetParameters"); + qRegisterMetaType>( + "std::shared_ptr"); + + // Controller Applet + qRegisterMetaType("Core::Frontend::ControllerParameters"); + + // Profile Select Applet + qRegisterMetaType( + "Core::Frontend::ProfileSelectParameters"); + + // Software Keyboard Applet + qRegisterMetaType( + "Core::Frontend::KeyboardInitializeParameters"); + qRegisterMetaType( + "Core::Frontend::InlineAppearParameters"); + qRegisterMetaType("Core::Frontend::InlineTextParameters"); + qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdTextCheckResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdReplyType"); + + // Web Browser Applet + qRegisterMetaType("Service::AM::Frontend::WebExitReason"); + + // Register loader types + qRegisterMetaType("Core::SystemResultStatus"); +} + +} diff --git a/src/qt_common/qt_meta.h b/src/qt_common/qt_meta.h new file mode 100644 index 0000000000..36cafba2bf --- /dev/null +++ b/src/qt_common/qt_meta.h @@ -0,0 +1,12 @@ +#ifndef QT_META_H +#define QT_META_H + +#include + +namespace QtCommon::Meta { + +// +void RegisterMetaTypes(); + +} +#endif // QT_META_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 6875d01dea..761e6e8405 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -7,17 +7,22 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "qt_common/qt_frontend_util.h" #include -bool QtCommon::PathUtil::OpenShaderCache(u64 program_id) +namespace QtCommon::Path { + +bool OpenShaderCache(u64 program_id, QObject *parent) { const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - return false; + QtCommon::Frontend::ShowMessage(QMessageBox::Warning, "Error Opening Shader Cache", "Failed to create or open shader cache for this title, ensure your app data directory has write permissions.", QMessageBox::Ok, parent); } const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } + +} diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h index 7f399c4bb4..855b06caa9 100644 --- a/src/qt_common/qt_path_util.h +++ b/src/qt_common/qt_path_util.h @@ -5,6 +5,8 @@ #define QT_PATH_UTIL_H #include "common/common_types.h" -namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); } +#include + +namespace QtCommon::Path { bool OpenShaderCache(u64 program_id, QObject *parent); } #endif // QT_PATH_UTIL_H diff --git a/src/qt_common/qt_rom_util.cpp b/src/qt_common/qt_rom_util.cpp new file mode 100644 index 0000000000..e707d1e471 --- /dev/null +++ b/src/qt_common/qt_rom_util.cpp @@ -0,0 +1,75 @@ +#include "qt_rom_util.h" + +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full) +{ + // TODO(crueter) + // if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) + // return false; + // if (dialog.wasCanceled()) + // return false; + + // std::vector buffer(CopyBufferSize); + // auto last_timestamp = std::chrono::steady_clock::now(); + + // const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file, + // const FileSys::VirtualFile& dest_file) { + // if (src_file == nullptr || dest_file == nullptr) { + // return false; + // } + // if (!dest_file->Resize(src_file->GetSize())) { + // return false; + // } + + // for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) { + // if (dialog.wasCanceled()) { + // dest_file->Resize(0); + // return false; + // } + + // using namespace std::literals::chrono_literals; + // const auto new_timestamp = std::chrono::steady_clock::now(); + + // if ((new_timestamp - last_timestamp) > 33ms) { + // last_timestamp = new_timestamp; + // dialog.setValue( + // static_cast(std::min(read_size, total_size) * 100 / total_size)); + // QCoreApplication::processEvents(); + // } + + // const auto read = src_file->Read(buffer.data(), buffer.size(), i); + // dest_file->Write(buffer.data(), read, i); + + // read_size += read; + // } + + // return true; + // }; + + // if (full) { + // for (const auto& file : src->GetFiles()) { + // const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); + // if (!QtRawCopy(file, out)) + // return false; + // } + // } + + // for (const auto& dir : src->GetSubdirectories()) { + // const auto out = dest->CreateSubdirectory(dir->GetName()); + // if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full)) + // return false; + // } + + // return true; + return true; +} + +} diff --git a/src/qt_common/qt_rom_util.h b/src/qt_common/qt_rom_util.h new file mode 100644 index 0000000000..52ebb1e8d0 --- /dev/null +++ b/src/qt_common/qt_rom_util.h @@ -0,0 +1,17 @@ +#ifndef QT_ROM_UTIL_H +#define QT_ROM_UTIL_H + +#include "qt_common/qt_common.h" +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full); + +} +#endif // QT_ROM_UTIL_H diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index d02e6dec2b..d461bd2cc9 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -11,6 +11,7 @@ #include "common/fs/path_util.h" #include "common/settings.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" #include "qt_common/uisettings.h" #include "ui_configure_filesystem.h" @@ -130,17 +131,7 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) } void ConfigureFilesystem::ResetMetadata() { - auto result = QtCommon::ResetMetadata(); - const QString resultMessage = tr(QtCommon::GetResetMetadataResultString(result)); - const QString title = tr("Reset Metadata Cache"); - - switch (result) { - case QtCommon::MetadataResult::Failure: - QMessageBox::warning(this, title, resultMessage); - break; - default: - QMessageBox::information(this, title, resultMessage); - } + QtCommon::Game::ResetMetadata(); } void ConfigureFilesystem::UpdateEnabledControls() { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 0d89dc892e..7c89730651 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include +#include "yuzu/game_list.h" #include #include #include @@ -13,19 +13,20 @@ #include #include #include -#include #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" -#include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" #include "yuzu/main.h" -#include "qt_common/uisettings.h" #include "yuzu/util/controller_navigation.h" +#include +#include GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) : QObject(parent), gamelist{gamelist_} {} @@ -608,30 +609,30 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(open_transferable_shader_cache, &QAction::triggered, [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); connect(remove_all_content, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Game); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Game); }); connect(remove_update, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Update); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Update); }); connect(remove_dlc, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::AddOnContent); }); connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::GlShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::GlShaderCache, path); }); connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::VkShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::VkShaderCache, path); }); connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::AllShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::AllShaderCache, path); }); connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CustomConfiguration, path); }); connect(remove_play_time_data, &QAction::triggered, [this, program_id]() { emit RemovePlayTimeRequested(program_id); }); connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CacheStorage, path); }); connect(dump_romfs, &QAction::triggered, [this, program_id, path]() { emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 328432138c..367d047c40 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -21,6 +21,7 @@ #include "common/common_types.h" #include "core/core.h" #include "qt_common/uisettings.h" +#include "qt_common/qt_game_util.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -46,14 +47,6 @@ enum class GameListOpenTarget { ModData, }; -enum class GameListRemoveTarget { - GlShaderCache, - VkShaderCache, - AllShaderCache, - CustomConfiguration, - CacheStorage, -}; - enum class DumpRomFSTarget { Normal, SDMC, @@ -64,12 +57,6 @@ enum class GameListShortcutTarget { Applications, }; -enum class InstalledEntryType { - Game, - Update, - AddOnContent, -}; - class GameList : public QWidget { Q_OBJECT @@ -118,8 +105,8 @@ signals: void OpenFolderRequested(u64 program_id, GameListOpenTarget target, const std::string& game_path); void OpenTransferableShaderCacheRequested(u64 program_id); - void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); - void RemoveFileRequested(u64 program_id, GameListRemoveTarget target, + void RemoveInstalledEntryRequested(u64 program_id, QtCommon::Game::InstalledEntryType type); + void RemoveFileRequested(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void RemovePlayTimeRequested(u64 program_id); void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 19110781bf..7db448af01 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -14,6 +14,8 @@ #include "qt_common/qt_common.h" #include "qt_common/qt_game_util.h" #include "qt_common/qt_path_util.h" +#include "qt_common/qt_meta.h" +#include "qt_common/qt_content_util.h" #ifdef __APPLE__ #include // for chdir @@ -299,14 +301,6 @@ enum class CalloutFlag : uint32_t { DRDDeprecation = 0x2, }; -/** - * Some games perform worse or straight-up don't work with updates, - * so this tracks which games are bad in this regard. - */ -constexpr std::array bad_update_games{ - 0x0100F2C0115B6000 // Tears of the Kingdom -}; - const int GMainWindow::max_recent_files_item; static void RemoveCachedContents() { @@ -389,6 +383,7 @@ static void OverrideWindowsFont() { #endif #ifndef _WIN32 +// TODO(crueter): carboxyl does this, is it needed in qml? inline static bool isDarkMode() { #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) const auto scheme = QGuiApplication::styleHints()->colorScheme(); @@ -407,6 +402,9 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) input_subsystem{std::make_shared()}, user_data_migrator{this}, vfs{std::make_shared()}, provider{std::make_unique()} { + QtCommon::SetSystem(system.get()); + QtCommon::SetRootObject(this); + Common::FS::CreateEdenPaths(); this->config = std::make_unique(); @@ -463,7 +461,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) Network::Init(); - RegisterMetaTypes(); + QtCommon::Meta::RegisterMetaTypes(); InitializeWidgets(); InitializeDebugWidgets(); @@ -734,65 +732,6 @@ GMainWindow::~GMainWindow() { #endif } -void GMainWindow::RegisterMetaTypes() { - // Register integral and floating point types - qRegisterMetaType("u8"); - qRegisterMetaType("u16"); - qRegisterMetaType("u32"); - qRegisterMetaType("u64"); - qRegisterMetaType("u128"); - qRegisterMetaType("s8"); - qRegisterMetaType("s16"); - qRegisterMetaType("s32"); - qRegisterMetaType("s64"); - qRegisterMetaType("f32"); - qRegisterMetaType("f64"); - - // Register string types - qRegisterMetaType("std::string"); - qRegisterMetaType("std::wstring"); - qRegisterMetaType("std::u8string"); - qRegisterMetaType("std::u16string"); - qRegisterMetaType("std::u32string"); - qRegisterMetaType("std::string_view"); - qRegisterMetaType("std::wstring_view"); - qRegisterMetaType("std::u8string_view"); - qRegisterMetaType("std::u16string_view"); - qRegisterMetaType("std::u32string_view"); - - // Register applet types - - // Cabinet Applet - qRegisterMetaType("Core::Frontend::CabinetParameters"); - qRegisterMetaType>( - "std::shared_ptr"); - - // Controller Applet - qRegisterMetaType("Core::Frontend::ControllerParameters"); - - // Profile Select Applet - qRegisterMetaType( - "Core::Frontend::ProfileSelectParameters"); - - // Software Keyboard Applet - qRegisterMetaType( - "Core::Frontend::KeyboardInitializeParameters"); - qRegisterMetaType( - "Core::Frontend::InlineAppearParameters"); - qRegisterMetaType("Core::Frontend::InlineTextParameters"); - qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdTextCheckResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdReplyType"); - - // Web Browser Applet - qRegisterMetaType("Service::AM::Frontend::WebExitReason"); - - // Register loader types - qRegisterMetaType("Core::SystemResultStatus"); -} - void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr nfp_device) { cabinet_applet = @@ -1634,8 +1573,9 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory); connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); - connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, - &GMainWindow::OnTransferableShaderCacheOpenFile); + connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, [this](u64 program_id) { + QtCommon::Path::OpenShaderCache(program_id, this); + }); connect(game_list, &GameList::RemoveInstalledEntryRequested, this, &GMainWindow::OnGameListRemoveInstalledEntry); connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile); @@ -1970,74 +1910,10 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa nullptr, // Net Connect }); - /** Game Updates check */ + /** firmware check */ - // yuzu's configuration doesn't actually support lists so this is a bit hacky - QSettings settings; - QStringList currentIgnored = settings.value("ignoredBadUpdates", {}).toStringList(); - - if (std::find(bad_update_games.begin(), bad_update_games.end(), params.program_id) != - bad_update_games.end() && - !currentIgnored.contains(QString::number(params.program_id))) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Updates Warning")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch is known to have performance or booting " - "issues when updates are applied. Please try increasing the memory layout to " - "6GB or 8GB if any issues occur.

Press \"OK\" to continue launching, or " - "\"Cancel\" to cancel the launch.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - QCheckBox* dontShowAgain = new QCheckBox(msg); - dontShowAgain->setText(tr("Don't show again for this game")); - msg->setCheckBox(dontShowAgain); - - int result = msg->exec(); - - // wtf - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - if (dontShowAgain->isChecked()) { - currentIgnored << QString::number(params.program_id); - settings.setValue("ignoredBadUpdates", currentIgnored); - settings.sync(); - } - break; - } - } - - if (FirmwareManager::GameRequiresFirmware(params.program_id) && - !FirmwareManager::CheckFirmwarePresence(*system)) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Requires Firmware")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch requires firmware to boot or to get past the " - "opening menu. Please " - "dump and install firmware, or press \"OK\" to launch anyways.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - int exec_result = msg->exec(); - - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)exec_result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - break; - } + if (!QtCommon::Content::CheckGameFirmware(params.program_id, *system, this)) { + return false; } if (!OnCheckNcaVerification()) { @@ -2459,6 +2335,7 @@ void GMainWindow::ShutdownGame() { return; } + // TODO(crueter): make this common as well (frontend_common?) play_time_manager->Stop(); OnShutdownBegin(); OnEmulationStopTimeExpired(); @@ -2503,6 +2380,7 @@ void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { BootGame(game_path, params); } +// TODO(crueter): Common profile selector void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path) { std::filesystem::path path; @@ -2611,13 +2489,6 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } -// TODO(crueter): Transfer ts to showmessage -void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { - if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { - QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); - } -} - static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest, bool full) { @@ -2683,26 +2554,14 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& // TODO(crueter): All this can be transfered to qt_common // Aldoe I need to decide re: message boxes for QML // translations_common? strings_common? qt_strings? who knows -QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { - switch (type) { - case InstalledEntryType::Game: - return tr("Error Removing Contents"); - case InstalledEntryType::Update: - return tr("Error Removing Update"); - case InstalledEntryType::AddOnContent: - return tr("Error Removing DLC"); - default: - return QStringLiteral("Error Removing "); - } -} -void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) { +void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type) { const QString entry_question = [type] { switch (type) { - case InstalledEntryType::Game: + case QtCommon::Game::InstalledEntryType::Game: return tr("Remove Installed Game Contents?"); - case InstalledEntryType::Update: + case QtCommon::Game::InstalledEntryType::Update: return tr("Remove Installed Game Update?"); - case InstalledEntryType::AddOnContent: + case QtCommon::Game::InstalledEntryType::AddOnContent: return tr("Remove Installed Game DLC?"); default: return QStringLiteral("Remove Installed Game ?"); @@ -2714,18 +2573,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT return; } + // TODO(crueter): move this to QtCommon (populate async?) switch (type) { - case InstalledEntryType::Game: - RemoveBaseContent(program_id, type); + case QtCommon::Game::InstalledEntryType::Game: + QtCommon::Game::RemoveBaseContent(program_id, type); [[fallthrough]]; - case InstalledEntryType::Update: - RemoveUpdateContent(program_id, type); - if (type != InstalledEntryType::Game) { + case QtCommon::Game::InstalledEntryType::Update: + QtCommon::Game::RemoveUpdateContent(program_id, type); + if (type != QtCommon::Game::InstalledEntryType::Game) { break; } [[fallthrough]]; - case InstalledEntryType::AddOnContent: - RemoveAddOnContent(program_id, type); + case QtCommon::Game::InstalledEntryType::AddOnContent: + QtCommon::Game::RemoveAddOnContent(program_id, type); break; } Common::FS::RemoveDirRecursively(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / @@ -2733,55 +2593,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { - const auto res = - ContentManager::RemoveBaseContent(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed base game.")); - } else { - QMessageBox::warning( - this, GetGameListErrorRemoving(type), - tr("The base game is not installed in the NAND and cannot be removed.")); - } -} - -void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { - const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed update.")); - } else { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There is no update installed for this title.")); - } -} - -void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { - const size_t count = ContentManager::RemoveAllDLC(*system, program_id); - if (count == 0) { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There are no DLC installed for this title.")); - return; - } - - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed %1 installed DLC.").arg(count)); -} - -void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, +void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path) { const QString question = [target] { switch (target) { - case GameListRemoveTarget::GlShaderCache: + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: return tr("Delete OpenGL Transferable Shader Cache?"); - case GameListRemoveTarget::VkShaderCache: + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: return tr("Delete Vulkan Transferable Shader Cache?"); - case GameListRemoveTarget::AllShaderCache: + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: return tr("Delete All Transferable Shader Caches?"); - case GameListRemoveTarget::CustomConfiguration: + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: return tr("Remove Custom Game Configuration?"); - case GameListRemoveTarget::CacheStorage: + case QtCommon::Game::GameListRemoveTarget::CacheStorage: return tr("Remove Cache Storage?"); default: return QString{}; @@ -2794,20 +2618,20 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ } switch (target) { - case GameListRemoveTarget::VkShaderCache: - RemoveVulkanDriverPipelineCache(program_id); + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: + QtCommon::Game::RemoveVulkanDriverPipelineCache(program_id); [[fallthrough]]; - case GameListRemoveTarget::GlShaderCache: - RemoveTransferableShaderCache(program_id, target); + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: + QtCommon::Game::RemoveTransferableShaderCache(program_id, target); break; - case GameListRemoveTarget::AllShaderCache: - RemoveAllTransferableShaderCaches(program_id); + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: + QtCommon::Game::RemoveAllTransferableShaderCaches(program_id); break; - case GameListRemoveTarget::CustomConfiguration: - RemoveCustomConfiguration(program_id, game_path); + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: + QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; - case GameListRemoveTarget::CacheStorage: - RemoveCacheStorage(program_id); + case QtCommon::Game::GameListRemoveTarget::CacheStorage: + QtCommon::Game::RemoveCacheStorage(program_id, vfs.get()); break; } } @@ -2823,107 +2647,6 @@ void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) { game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) { - const auto target_file_name = [target] { - switch (target) { - case GameListRemoveTarget::GlShaderCache: - return "opengl.bin"; - case GameListRemoveTarget::VkShaderCache: - return "vulkan.bin"; - default: - return ""; - } - }(); - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveFile(target_file)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader cache.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("Failed to remove the transferable shader cache.")); - } -} - -void GMainWindow::RemoveVulkanDriverPipelineCache(u64 program_id) { - static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; - - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - return; - } - if (!Common::FS::RemoveFile(target_file)) { - QMessageBox::warning(this, tr("Error Removing Vulkan Driver Pipeline Cache"), - tr("Failed to remove the driver pipeline cache.")); - } -} - -void GMainWindow::RemoveAllTransferableShaderCaches(u64 program_id) { - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); - - if (!Common::FS::Exists(program_shader_cache_dir)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader caches.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("Failed to remove the transferable shader cache directory.")); - } -} - -void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& game_path) { - const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); - const auto config_file_name = - program_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()).append(".ini") - : fmt::format("{:016X}.ini", program_id); - const auto custom_config_file_path = - Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "custom" / config_file_name; - - if (!Common::FS::Exists(custom_config_file_path)) { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("A custom configuration for this title does not exist.")); - return; - } - - if (Common::FS::RemoveFile(custom_config_file_path)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the custom game configuration.")); - } else { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("Failed to remove the custom game configuration.")); - } -} - -void GMainWindow::RemoveCacheStorage(u64 program_id) { - const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); - auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); - - const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( - {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache, - 0 /* program_id */, {}, 0); - - const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); - - // Not an error if it wasn't cleared. - Common::FS::RemoveDirRecursively(path); -} - void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target) { const auto failed = [this] { @@ -3052,22 +2775,7 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { return progress.wasCanceled(); }; - const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback); - const QString resultString = tr(QtCommon::GetGameVerificationResultString(result)); - progress.close(); - switch (result) { - case ContentManager::GameVerificationResult::Success: - QMessageBox::information(this, tr("Integrity verification succeeded!"), - resultString); - break; - case ContentManager::GameVerificationResult::Failed: - QMessageBox::critical(this, tr("Integrity verification failed!"), - resultString); - break; - case ContentManager::GameVerificationResult::NotImplemented: - QMessageBox::warning(this, tr("Integrity verification couldn't be performed"), - resultString); - } + QtCommon::Content::VerifyGameContents(game_path, QtProgressCallback); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -4103,6 +3811,7 @@ void GMainWindow::OnLoadAmiibo() { LoadAmiibo(filename); } +// TODO(crueter): does this need to be ported to QML? bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { @@ -4154,27 +3863,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } void GMainWindow::OnOpenRootDataFolder() { - QtCommon::OpenRootDataFolder(); + QtCommon::Game::OpenRootDataFolder(); } void GMainWindow::OnOpenNANDFolder() { - QtCommon::OpenNANDFolder(); + QtCommon::Game::OpenNANDFolder(); } void GMainWindow::OnOpenSDMCFolder() { - QtCommon::OpenSDMCFolder(); + QtCommon::Game::OpenSDMCFolder(); } void GMainWindow::OnOpenModFolder() { - QtCommon::OpenModFolder(); + QtCommon::Game::OpenModFolder(); } void GMainWindow::OnOpenLogFolder() { - QtCommon::OpenLogFolder(); + QtCommon::Game::OpenLogFolder(); } void GMainWindow::OnVerifyInstalledContents() { @@ -4221,11 +3930,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); + auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, vfs.get()); progress.close(); - if (result != QtCommon::FirmwareInstallResult::Success) return; + if (result != QtCommon::Content::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); @@ -4292,7 +4001,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() { return; } - const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location); + const QString qCacheDir = QtCommon::Content::UnzipFirmwareToTmp(firmware_zip_location); // In this case, it has to be done recursively, since sometimes people // will pack it into a subdirectory after dumping @@ -4370,7 +4079,7 @@ void GMainWindow::OnToggleStatusBar() { void GMainWindow::OnGameListRefresh() { // Resets metadata cache and reloads - QtCommon::ResetMetadata(); + QtCommon::Game::ResetMetadata(); game_list->RefreshGameDirectory(); SetFirmwareVersion(); } @@ -4640,7 +4349,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); std::filesystem::path out_icon_path; - if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } @@ -4674,7 +4383,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, qgame_title); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8d00fef4f8..f523561628 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -17,9 +17,10 @@ #include #include "common/common_types.h" -#include "qt_common/qt_config.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" +#include "qt_common/qt_config.h" +#include "qt_common/qt_game_util.h" #include "user_data_migration.h" #include "yuzu/compatibility_list.h" #include "yuzu/hotkeys.h" @@ -53,10 +54,8 @@ class QSlider; class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; -enum class GameListRemoveTarget; enum class GameListShortcutTarget; enum class DumpRomFSTarget; -enum class InstalledEntryType; class GameListPlaceholder; class QtAmiiboSettingsDialog; @@ -258,8 +257,6 @@ private: void LinkActionShortcut(QAction* action, const QString& action_name, const bool tas_allowed = false); - void RegisterMetaTypes(); - void InitializeWidgets(); void InitializeDebugWidgets(); void InitializeRecentFileMenuActions(); @@ -353,9 +350,8 @@ private slots: void OnGameListLoadFile(QString game_path, u64 program_id); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path); - void OnTransferableShaderCacheOpenFile(u64 program_id); - void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); - void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, + void OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type); + void OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void OnGameListRemovePlayTimeData(u64 program_id); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target); @@ -436,16 +432,7 @@ private slots: #endif private: - QString GetGameListErrorRemoving(InstalledEntryType type) const; - void RemoveBaseContent(u64 program_id, InstalledEntryType type); - void RemoveUpdateContent(u64 program_id, InstalledEntryType type); - void RemoveAddOnContent(u64 program_id, InstalledEntryType type); - void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); - void RemoveVulkanDriverPipelineCache(u64 program_id); - void RemoveAllTransferableShaderCaches(u64 program_id); - void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemovePlayTimeData(u64 program_id); - void RemoveCacheStorage(u64 program_id); bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, u64* selected_title_id, u8* selected_content_record_type); ContentManager::InstallResult InstallNCA(const QString& filename); From 7a12441d250e7f60797cf0f0320f2d871566da62 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:50:05 -0400 Subject: [PATCH 40/52] Fix license headers Signed-off-by: crueter --- ffmpeg.patch | 40 ------------------------------- src/qt_common/qt_content_util.cpp | 3 +++ src/qt_common/qt_content_util.h | 3 +++ src/qt_common/qt_meta.cpp | 3 +++ src/qt_common/qt_meta.h | 3 +++ src/qt_common/qt_rom_util.cpp | 3 +++ src/qt_common/qt_rom_util.h | 3 +++ 7 files changed, 18 insertions(+), 40 deletions(-) delete mode 100644 ffmpeg.patch diff --git a/ffmpeg.patch b/ffmpeg.patch deleted file mode 100644 index 58fa9dff61..0000000000 --- a/ffmpeg.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt -index 54c852f831..ff35c8dc2c 100644 ---- a/externals/ffmpeg/CMakeLists.txt -+++ b/externals/ffmpeg/CMakeLists.txt -@@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID) - set(FFmpeg_HWACCEL_INCLUDE_DIRS) - set(FFmpeg_HWACCEL_LDFLAGS) - -- # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -- if(PLATFORM_SUN) -- list(APPEND FFmpeg_HWACCEL_LIBRARIES -- X11 -- "/usr/lib/xorg/amd64/libdrm.so") -- else() -- pkg_check_modules(LIBDRM libdrm REQUIRED) -- list(APPEND FFmpeg_HWACCEL_LIBRARIES -- ${LIBDRM_LIBRARIES}) -- list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS -- ${LIBDRM_INCLUDE_DIRS}) -+ if (NOT APPLE) -+ # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -+ if(PLATFORM_SUN) -+ list(APPEND FFmpeg_HWACCEL_LIBRARIES -+ X11 -+ "/usr/lib/xorg/amd64/libdrm.so") -+ else() -+ pkg_check_modules(LIBDRM libdrm REQUIRED) -+ list(APPEND FFmpeg_HWACCEL_LIBRARIES -+ ${LIBDRM_LIBRARIES}) -+ list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS -+ ${LIBDRM_INCLUDE_DIRS}) -+ endif() -+ list(APPEND FFmpeg_HWACCEL_FLAGS -+ --enable-libdrm) - endif() -- list(APPEND FFmpeg_HWACCEL_FLAGS -- --enable-libdrm) - - if(LIBVA_FOUND) - find_package(X11 REQUIRED) diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 81ec7c9cea..9c3ae6e115 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_content_util.h" #include "common/fs/fs.h" #include "frontend_common/content_manager.h" diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index 9a1a4e5bc2..b7073d2d35 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_CONTENT_UTIL_H #define QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_meta.cpp b/src/qt_common/qt_meta.cpp index c972c0fe45..67ae659771 100644 --- a/src/qt_common/qt_meta.cpp +++ b/src/qt_common/qt_meta.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_meta.h" #include "common/common_types.h" #include "core/core.h" diff --git a/src/qt_common/qt_meta.h b/src/qt_common/qt_meta.h index 36cafba2bf..c0a37db983 100644 --- a/src/qt_common/qt_meta.h +++ b/src/qt_common/qt_meta.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_META_H #define QT_META_H diff --git a/src/qt_common/qt_rom_util.cpp b/src/qt_common/qt_rom_util.cpp index e707d1e471..08ccb05a97 100644 --- a/src/qt_common/qt_rom_util.cpp +++ b/src/qt_common/qt_rom_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_rom_util.h" #include diff --git a/src/qt_common/qt_rom_util.h b/src/qt_common/qt_rom_util.h index 52ebb1e8d0..f76b09753d 100644 --- a/src/qt_common/qt_rom_util.h +++ b/src/qt_common/qt_rom_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_ROM_UTIL_H #define QT_ROM_UTIL_H From d3fcee21d097a4bbe084275df80066b0ee366fe8 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:54:46 -0400 Subject: [PATCH 41/52] cleanup Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index da6c9b0481..add8e59311 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,7 +1,6 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later -find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -25,9 +24,13 @@ add_library(qt_common STATIC ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) -target_link_libraries(qt_common PRIVATE Qt6::Core) -target_link_libraries(qt_common PRIVATE Qt6::Core) + +# TODO(crueter) +if (ENABLE_QT) + target_link_libraries(qt_common PRIVATE Qt6::Widgets) +endif() + +target_link_libraries(qt_common PUBLIC core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) From be4d1f73588a0b17747b6b35231df4a24efdee50 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:08:30 -0400 Subject: [PATCH 42/52] fix win Signed-off-by: crueter --- src/qt_common/qt_content_util.cpp | 5 ++--- src/qt_common/qt_content_util.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 9c3ae6e115..5ad361a527 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -5,17 +5,16 @@ #include "common/fs/fs.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" -#include "qt_common/qt_game_util.h" #include "qt_frontend_util.h" #include namespace QtCommon::Content { -bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent) +bool CheckGameFirmware(u64 program_id, QObject *parent) { if (FirmwareManager::GameRequiresFirmware(program_id) - && !FirmwareManager::CheckFirmwarePresence(system)) { + && !FirmwareManager::CheckFirmwarePresence(*system)) { auto result = QtCommon::Frontend::ShowMessage( QMessageBox::Warning, "Game Requires Firmware", diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b7073d2d35..529b887146 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -12,7 +12,7 @@ namespace QtCommon::Content { // -bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent); +bool CheckGameFirmware(u64 program_id, QObject *parent); static constexpr std::array FIRMWARE_RESULTS = {"Successfully installed firmware version %1", From 8fb655a2420a2e9a3b7aa216b398b0309803d5f2 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:30:19 -0400 Subject: [PATCH 43/52] fix Signed-off-by: crueter --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7db448af01..30ea8702be 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1912,7 +1912,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa /** firmware check */ - if (!QtCommon::Content::CheckGameFirmware(params.program_id, *system, this)) { + if (!QtCommon::Content::CheckGameFirmware(params.program_id, this)) { return false; } From 07d00fba163ee4b8c22867c3ddee575119c8e6cc Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 14:56:25 -0400 Subject: [PATCH 44/52] better handling for sys/vfs/rootobject Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 5 +- .../externals/CMakeLists.txt | 0 .../externals/cpmfile.json | 0 src/qt_common/qt_applet_util.cpp | 1 + src/qt_common/qt_applet_util.h | 8 + src/qt_common/qt_common.cpp | 10 +- src/qt_common/qt_common.h | 14 +- src/qt_common/qt_content_util.cpp | 51 ++- src/qt_common/qt_content_util.h | 11 +- src/qt_common/qt_frontend_util.cpp | 75 +---- src/qt_common/qt_frontend_util.h | 97 +++--- src/yuzu/CMakeLists.txt | 4 - src/yuzu/main.cpp | 297 ++++++++---------- src/yuzu/main.h | 3 - src/yuzu/user_data_migration.h | 1 + 15 files changed, 286 insertions(+), 291 deletions(-) rename src/{yuzu => qt_common}/externals/CMakeLists.txt (100%) rename src/{yuzu => qt_common}/externals/cpmfile.json (100%) create mode 100644 src/qt_common/qt_applet_util.cpp create mode 100644 src/qt_common/qt_applet_util.h diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index add8e59311..1acf8344a1 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(qt_common STATIC qt_meta.h qt_meta.cpp qt_content_util.h qt_content_util.cpp qt_rom_util.h qt_rom_util.cpp + qt_applet_util.h qt_applet_util.cpp ) create_target_directory_groups(qt_common) @@ -30,7 +31,9 @@ if (ENABLE_QT) target_link_libraries(qt_common PRIVATE Qt6::Widgets) endif() -target_link_libraries(qt_common PUBLIC core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) +add_subdirectory(externals) + +target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/yuzu/externals/CMakeLists.txt b/src/qt_common/externals/CMakeLists.txt similarity index 100% rename from src/yuzu/externals/CMakeLists.txt rename to src/qt_common/externals/CMakeLists.txt diff --git a/src/yuzu/externals/cpmfile.json b/src/qt_common/externals/cpmfile.json similarity index 100% rename from src/yuzu/externals/cpmfile.json rename to src/qt_common/externals/cpmfile.json diff --git a/src/qt_common/qt_applet_util.cpp b/src/qt_common/qt_applet_util.cpp new file mode 100644 index 0000000000..332f4796e8 --- /dev/null +++ b/src/qt_common/qt_applet_util.cpp @@ -0,0 +1 @@ +#include "qt_applet_util.h" diff --git a/src/qt_common/qt_applet_util.h b/src/qt_common/qt_applet_util.h new file mode 100644 index 0000000000..9ceb4a2522 --- /dev/null +++ b/src/qt_common/qt_applet_util.h @@ -0,0 +1,8 @@ +#ifndef QT_APPLET_UTIL_H +#define QT_APPLET_UTIL_H + +// TODO +namespace QtCommon::Applets { + +} +#endif // QT_APPLET_UTIL_H diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 6f8808ca32..9c20f1e6d9 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -23,7 +23,8 @@ namespace QtCommon { QObject *rootObject = nullptr; -Core::System *system = nullptr; +std::unique_ptr system = nullptr; +std::shared_ptr vfs = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -80,4 +81,11 @@ const QString tr(const std::string& str) return QGuiApplication::tr(str.c_str()); } +void Init(QObject* root) +{ + system = std::make_unique(); + rootObject = root; + vfs = std::make_unique(); +} + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index cf52cedc32..5f9b5d7de9 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,6 +4,7 @@ #ifndef QT_COMMON_H #define QT_COMMON_H +#include #include #include "core/core.h" #include @@ -13,7 +14,8 @@ namespace QtCommon { extern QObject *rootObject; -extern Core::System *system; +extern std::unique_ptr system; +extern std::shared_ptr vfs; typedef std::function QtProgressCallback; @@ -21,15 +23,7 @@ Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); -static inline void SetRootObject(QObject *parent) -{ - rootObject = parent; -} - -static inline void SetSystem(Core::System *newSystem) -{ - system = newSystem; -} +void Init(QObject *root); const QString tr(const char *str); const QString tr(const std::string &str); diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 5ad361a527..5f8ca14504 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -5,13 +5,14 @@ #include "common/fs/fs.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" #include "qt_frontend_util.h" #include namespace QtCommon::Content { -bool CheckGameFirmware(u64 program_id, QObject *parent) +bool CheckGameFirmware(u64 program_id, QObject* parent) { if (FirmwareManager::GameRequiresFirmware(program_id) && !FirmwareManager::CheckFirmwarePresence(*system)) { @@ -30,11 +31,10 @@ bool CheckGameFirmware(u64 program_id, QObject *parent) return true; } -FirmwareInstallResult InstallFirmware( - const QString& location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem* vfs) +FirmwareInstallResult InstallFirmware(const QString& location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem* vfs) { static constexpr const char* failedTitle = "Firmware Install Failed"; static constexpr const char* successTitle = "Firmware Install Failed"; @@ -179,16 +179,19 @@ QString UnzipFirmwareToTmp(const QString& location) } // Content // -void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) { +void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) +{ const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); switch (result) { case ContentManager::GameVerificationResult::Success: - QtCommon::Frontend::Information(rootObject, tr("Integrity verification succeeded!"), + QtCommon::Frontend::Information(rootObject, + tr("Integrity verification succeeded!"), tr("The operation completed successfully.")); break; case ContentManager::GameVerificationResult::Failed: - QtCommon::Frontend::Critical(rootObject, tr("Integrity verification failed!"), + QtCommon::Frontend::Critical(rootObject, + tr("Integrity verification failed!"), tr("File contents may be corrupt or missing.")); break; case ContentManager::GameVerificationResult::NotImplemented: @@ -200,5 +203,35 @@ void VerifyGameContents(const std::string& game_path, QtProgressCallback callbac } } +void InstallKeys() +{ + const QString key_source_location + = QtCommon::Frontend::GetOpenFileName(tr("Select Dumped Keys Location"), + {}, + QStringLiteral("Decryption Keys (*.keys)"), + {}, + QtCommon::Frontend::Option::ReadOnly); + if (key_source_location.isEmpty()) { + return; + } + + FirmwareManager::KeyInstallResult result = FirmwareManager::InstallKeys(key_source_location + .toStdString(), + "keys"); + + system->GetFileSystemController().CreateFactories(*QtCommon::vfs); + + switch (result) { + case FirmwareManager::KeyInstallResult::Success: + QtCommon::Frontend::Information(tr("Decryption Keys install succeeded"), + tr("Decryption Keys were successfully installed")); + break; + default: + QtCommon::Frontend::Critical(tr("Decryption Keys install failed"), + tr(FirmwareManager::GetKeyInstallResultString(result))); + break; + } } + +} // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index 529b887146..b401bdf1e3 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -32,6 +32,11 @@ enum class FirmwareInstallResult { FailedCorrupted, }; +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + FirmwareInstallResult InstallFirmware( const QString &location, bool recursive, @@ -40,10 +45,8 @@ FirmwareInstallResult InstallFirmware( QString UnzipFirmwareToTmp(const QString &location); -inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) -{ - return FIRMWARE_RESULTS.at(static_cast(result)); -} +// Keys // +void InstallKeys(); // Content // void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 6b96a26a21..d357c11338 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -2,6 +2,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_frontend_util.h" +#include "qt_common/qt_common.h" + +#ifdef YUZU_QT_WIDGETS +#include +#endif namespace QtCommon::Frontend { @@ -19,69 +24,15 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, // need a way to reference icon/buttons too } -QMessageBox::StandardButton Information(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) +const QString GetOpenFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter, + Options options) { - return ShowMessage(QMessageBox::Information, title, text, buttons, parent); +#ifdef YUZU_QT_WIDGETS + return QFileDialog::getOpenFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options); +#endif } -QMessageBox::StandardButton Warning(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Warning, title, text, buttons, parent); -} - -QMessageBox::StandardButton Critical(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Critical, title, text, buttons, parent); -} - -QMessageBox::StandardButton Question(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Question, title, text, buttons, parent); -} - -QMessageBox::StandardButton Information(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Information, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Warning(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Warning, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Critical(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Critical, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Question(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Question, parent->tr(title), parent->tr(text), buttons, parent); -} - - } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index a91a0db07b..7f43286430 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -6,8 +6,10 @@ #include #include +#include "qt_common/qt_common.h" #ifdef YUZU_QT_WIDGETS +#include #include #endif @@ -15,8 +17,27 @@ * manages common functionality e.g. message boxes and such for Qt/QML */ namespace QtCommon::Frontend { + Q_NAMESPACE +#ifdef YUZU_QT_WIDGETS +using Options = QFileDialog::Options; +using Option = QFileDialog::Option; +#else +enum Option { + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseNativeDialog = 0x00000008, + ReadOnly = 0x00000010, + HideNameFilterDetails = 0x00000020, + DontUseCustomDirectoryIcons = 0x00000040 +}; +Q_ENUM_NS(Option) +Q_DECLARE_FLAGS(Options, Option) +Q_FLAG_NS(Options) +#endif + // TODO(crueter) widgets-less impl, choices et al. QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, @@ -24,45 +45,47 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, QObject *parent = nullptr); -QMessageBox::StandardButton Information(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +#define UTIL_OVERRIDES(level) \ + inline QMessageBox::StandardButton level(QObject *parent, \ + const QString &title, \ + const QString &text, \ + QMessageBox::StandardButtons buttons = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, title, text, buttons, parent); \ + } \ + inline QMessageBox::StandardButton level(QObject *parent, \ + const char *title, \ + const char *text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, parent); \ + } \ + inline QMessageBox::StandardButton level(const char *title, \ + const char *text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, rootObject); \ + } \ + inline QMessageBox::StandardButton level(const QString title, \ + const QString &text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, title, text, buttons, rootObject); \ + } -QMessageBox::StandardButton Warning(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +UTIL_OVERRIDES(Information) +UTIL_OVERRIDES(Warning) +UTIL_OVERRIDES(Critical) +UTIL_OVERRIDES(Question) -QMessageBox::StandardButton Critical(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Question(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Information(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Warning(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Critical(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Question(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +const QString GetOpenFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter = nullptr, + Options options = Options()); } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 9e052b385d..8a1d760c50 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -496,8 +496,4 @@ if (YUZU_ROOM) target_link_libraries(yuzu PRIVATE yuzu-room) endif() -# Extra deps -add_subdirectory(externals) -target_link_libraries(yuzu PRIVATE QuaZip::QuaZip) - create_target_directory_groups(yuzu) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 30ea8702be..728ed2068c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -70,9 +70,8 @@ // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows // defines. -static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper( - const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) { - return vfs->CreateDirectory(path, mode); +static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(const std::string& path, FileSys::OpenMode mode) { + return QtCommon::vfs->CreateDirectory(path, mode); } static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::VirtualDir& dir, @@ -398,12 +397,10 @@ inline static bool isDarkMode() { #endif // _WIN32 GMainWindow::GMainWindow(bool has_broken_vulkan) - : ui{std::make_unique()}, system{std::make_unique()}, + : ui{std::make_unique()}, input_subsystem{std::make_shared()}, user_data_migrator{this}, - vfs{std::make_shared()}, provider{std::make_unique()} { - QtCommon::SetSystem(system.get()); - QtCommon::SetRootObject(this); + QtCommon::Init(this); Common::FS::CreateEdenPaths(); this->config = std::make_unique(); @@ -435,7 +432,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) UISettings::RestoreWindowState(config); - system->Initialize(); + QtCommon::system->Initialize(); Common::Log::Initialize(); Common::Log::Start(); @@ -457,7 +454,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); discord_rpc->Update(); - play_time_manager = std::make_unique(system->GetProfileManager()); + play_time_manager = std::make_unique(QtCommon::system->GetProfileManager()); Network::Init(); @@ -474,7 +471,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) ConnectMenuEvents(); ConnectWidgetEvents(); - system->HIDCore().ReloadInputDevices(); + QtCommon::system->HIDCore().ReloadInputDevices(); controller_dialog->refreshConfiguration(); const auto branch_name = std::string(Common::g_scm_branch); @@ -518,7 +515,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) std::chrono::duration_cast>( Common::Windows::SetCurrentTimerResolutionToMaximum()) .count()); - system->CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution()); + QtCommon::system->CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution()); #endif UpdateWindowTitle(); @@ -544,10 +541,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) } #endif - system->SetContentProvider(std::make_unique()); - system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, + QtCommon::system->SetContentProvider(std::make_unique()); + QtCommon::system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); - system->GetFileSystemController().CreateFactories(*vfs); + QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); // Remove cached contents generated during the previous session RemoveCachedContents(); @@ -661,7 +658,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) if (!argument_ok) { // try to look it up by username, only finds the first username that matches. const std::string user_arg_str = args[user_arg_idx].toStdString(); - const auto user_idx = system->GetProfileManager().GetUserIndex(user_arg_str); + const auto user_idx = QtCommon::system->GetProfileManager().GetUserIndex(user_arg_str); if (user_idx == std::nullopt) { LOG_ERROR(Frontend, "Invalid user argument"); @@ -671,7 +668,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) selected_user = user_idx.value(); } - if (!system->GetProfileManager().UserExistsIndex(selected_user)) { + if (!QtCommon::system->GetProfileManager().UserExistsIndex(selected_user)) { LOG_ERROR(Frontend, "Selected user doesn't exist"); continue; } @@ -762,7 +759,7 @@ void GMainWindow::AmiiboSettingsRequestExit() { void GMainWindow::ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters) { controller_applet = - new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); + new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *QtCommon::system); SCOPE_EXIT { controller_applet->deleteLater(); controller_applet = nullptr; @@ -775,8 +772,8 @@ void GMainWindow::ControllerSelectorReconfigureControllers( bool is_success = controller_applet->exec() != QDialog::Rejected; // Don't forget to apply settings. - system->HIDCore().DisableAllControllerConfiguration(); - system->ApplySettings(); + QtCommon::system->HIDCore().DisableAllControllerConfiguration(); + QtCommon::system->ApplySettings(); config->SaveAllValues(); UpdateStatusButtons(); @@ -792,7 +789,7 @@ void GMainWindow::ControllerSelectorRequestExit() { void GMainWindow::ProfileSelectorSelectProfile( const Core::Frontend::ProfileSelectParameters& parameters) { - profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); + profile_select_applet = new QtProfileSelectionDialog(*QtCommon::system, this, parameters); SCOPE_EXIT { profile_select_applet->deleteLater(); profile_select_applet = nullptr; @@ -807,7 +804,7 @@ void GMainWindow::ProfileSelectorSelectProfile( return; } - const auto uuid = system->GetProfileManager().GetUser( + const auto uuid = QtCommon::system->GetProfileManager().GetUser( static_cast(profile_select_applet->GetIndex())); if (!uuid.has_value()) { emit ProfileSelectorFinishedSelection(std::nullopt); @@ -830,7 +827,7 @@ void GMainWindow::SoftwareKeyboardInitialize( return; } - software_keyboard = new QtSoftwareKeyboardDialog(render_window, *system, is_inline, + software_keyboard = new QtSoftwareKeyboardDialog(render_window, *QtCommon::system, is_inline, std::move(initialize_parameters)); if (is_inline) { @@ -947,7 +944,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, return; } - web_applet = new QtNXWebEngineView(this, *system, input_subsystem.get()); + web_applet = new QtNXWebEngineView(this, *QtCommon::system, input_subsystem.get()); ui->action_Pause->setEnabled(false); ui->action_Restart->setEnabled(false); @@ -1091,10 +1088,10 @@ void GMainWindow::InitializeWidgets() { #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING ui->action_Report_Compatibility->setVisible(true); #endif - render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *system); + render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *QtCommon::system); render_window->hide(); - game_list = new GameList(vfs, provider.get(), *play_time_manager, *system, this); + game_list = new GameList(QtCommon::vfs, provider.get(), *play_time_manager, *QtCommon::system, this); ui->horizontalLayout->addWidget(game_list); game_list_placeholder = new GameListPlaceholder(this); @@ -1113,7 +1110,7 @@ void GMainWindow::InitializeWidgets() { }); multiplayer_state = new MultiplayerState(this, game_list->GetModel(), ui->action_Leave_Room, - ui->action_Show_Room, *system); + ui->action_Show_Room, *QtCommon::system); multiplayer_state->setVisible(false); // Create status bar @@ -1367,12 +1364,12 @@ void GMainWindow::InitializeWidgets() { void GMainWindow::InitializeDebugWidgets() { QMenu* debug_menu = ui->menu_View_Debugging; - waitTreeWidget = new WaitTreeWidget(*system, this); + waitTreeWidget = new WaitTreeWidget(*QtCommon::system, this); addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this); + controller_dialog = new ControllerDialog(QtCommon::system->HIDCore(), input_subsystem, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); @@ -1412,7 +1409,7 @@ void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name this->addAction(action); - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = hotkey_registry.GetControllerHotkey(main_window, action_name.toStdString(), controller); connect( @@ -1457,7 +1454,7 @@ void GMainWindow::InitializeHotkeys() { const auto connect_shortcut = [&](const QString& action_name, const Fn& function) { const auto* hotkey = hotkey_registry.GetHotkey(main_window.toStdString(), action_name.toStdString(), this); - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = hotkey_registry.GetControllerHotkey( main_window.toStdString(), action_name.toStdString(), controller); connect(hotkey, &QShortcut::activated, this, function); @@ -1483,7 +1480,7 @@ void GMainWindow::InitializeHotkeys() { }); connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [this] { if (Settings::values.enable_renderdoc_hotkey) { - system->GetRenderdocAPI().ToggleCapture(); + QtCommon::system->GetRenderdocAPI().ToggleCapture(); } }); connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { @@ -1889,13 +1886,13 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa return false; } - system->SetFilesystem(vfs); + QtCommon::system->SetFilesystem(QtCommon::vfs); if (params.launch_type == Service::AM::LaunchType::FrontendInitiated) { - system->GetUserChannel().clear(); + QtCommon::system->GetUserChannel().clear(); } - system->SetFrontendAppletSet({ + QtCommon::system->SetFrontendAppletSet({ std::make_unique(*this), // Amiibo Settings (UISettings::values.controller_applet_disabled.GetValue() == true) ? nullptr @@ -1922,13 +1919,13 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa /** Exec */ const Core::SystemResultStatus result{ - system->Load(*render_window, filename.toStdString(), params)}; + QtCommon::system->Load(*render_window, filename.toStdString(), params)}; const auto drd_callout = (UISettings::values.callout_flags.GetValue() & static_cast(CalloutFlag::DRDDeprecation)) == 0; if (result == Core::SystemResultStatus::Success && - system->GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && + QtCommon::system->GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && drd_callout) { UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() | static_cast(CalloutFlag::DRDDeprecation); @@ -1993,7 +1990,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa bool GMainWindow::SelectAndSetCurrentUser( const Core::Frontend::ProfileSelectParameters& parameters) { - QtProfileSelectionDialog dialog(*system, this, parameters); + QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2008,12 +2005,12 @@ bool GMainWindow::SelectAndSetCurrentUser( void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { // Ensure all NCAs are registered before launching the game - const auto file = vfs->OpenFile(filepath, FileSys::OpenMode::Read); + const auto file = QtCommon::vfs->OpenFile(filepath, FileSys::OpenMode::Read); if (!file) { return; } - auto loader = Loader::GetLoader(*system, file); + auto loader = Loader::GetLoader(*QtCommon::system, file); if (!loader) { return; } @@ -2062,8 +2059,8 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP last_filename_booted = filename; ConfigureFilesystemProvider(filename.toStdString()); - const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); - const auto loader = Loader::GetLoader(*system, v_file, params.program_id, params.program_index); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, filename.toUtf8().constData()); + const auto loader = Loader::GetLoader(*QtCommon::system, v_file, params.program_id, params.program_index); if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && type == StartGameType::Normal) { @@ -2074,8 +2071,8 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); QtConfig per_game_config(config_file_name, Config::ConfigType::PerGameConfig); - system->HIDCore().ReloadInputDevices(); - system->ApplySettings(); + QtCommon::system->HIDCore().ReloadInputDevices(); + QtCommon::system->ApplySettings(); } Settings::LogSettings(); @@ -2101,19 +2098,19 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP return; } - system->SetShuttingDown(false); + QtCommon::system->SetShuttingDown(false); game_list->setDisabled(true); // Create and start the emulation thread - emu_thread = std::make_unique(*system); + emu_thread = std::make_unique(*QtCommon::system); emit EmulationStarting(emu_thread.get()); emu_thread->start(); // Register an ExecuteProgram callback such that Core can execute a sub-program - system->RegisterExecuteProgramCallback( + QtCommon::system->RegisterExecuteProgramCallback( [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); - system->RegisterExitCallback([this] { + QtCommon::system->RegisterExitCallback([this] { emu_thread->ForceStop(); render_window->Exit(); }); @@ -2153,11 +2150,11 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::string title_name; std::string title_version; - const auto res = system->GetGameName(title_name); + const auto res = QtCommon::system->GetGameName(title_name); const auto metadata = [this, title_id] { - const FileSys::PatchManager pm(title_id, system->GetFileSystemController(), - system->GetContentProvider()); + const FileSys::PatchManager pm(title_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()); return pm.GetControlMetadata(); }(); if (metadata.first != nullptr) { @@ -2169,16 +2166,16 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::filesystem::path{Common::U16StringFromBuffer(filename.utf16(), filename.size())} .filename()); } - const bool is_64bit = system->Kernel().ApplicationProcess()->Is64Bit(); + const bool is_64bit = QtCommon::system->Kernel().ApplicationProcess()->Is64Bit(); const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); title_name = tr("%1 %2", "%1 is the title name. %2 indicates if the title is 64-bit or 32-bit") .arg(QString::fromStdString(title_name), instruction_set_suffix) .toStdString(); LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); - const auto gpu_vendor = system->GPU().Renderer().GetDeviceVendor(); + const auto gpu_vendor = QtCommon::system->GPU().Renderer().GetDeviceVendor(); UpdateWindowTitle(title_name, title_version, gpu_vendor); - loading_screen->Prepare(system->GetAppLoader()); + loading_screen->Prepare(QtCommon::system->GetAppLoader()); loading_screen->show(); emulation_running = true; @@ -2206,11 +2203,11 @@ bool GMainWindow::OnShutdownBegin() { // Disable unlimited frame rate Settings::values.use_speed_limit.SetValue(true); - if (system->IsShuttingDown()) { + if (QtCommon::system->IsShuttingDown()) { return false; } - system->SetShuttingDown(true); + QtCommon::system->SetShuttingDown(true); discord_rpc->Pause(); RequestGameExit(); @@ -2221,9 +2218,9 @@ bool GMainWindow::OnShutdownBegin() { int shutdown_time = 1000; - if (system->DebuggerEnabled()) { + if (QtCommon::system->DebuggerEnabled()) { shutdown_time = 0; - } else if (system->GetExitLocked()) { + } else if (QtCommon::system->GetExitLocked()) { shutdown_time = 5000; } @@ -2241,7 +2238,7 @@ bool GMainWindow::OnShutdownBegin() { } void GMainWindow::OnShutdownBeginDialog() { - shutdown_dialog = new OverlayDialog(this, *system, QString{}, tr("Closing software..."), + shutdown_dialog = new OverlayDialog(this, *QtCommon::system, QString{}, tr("Closing software..."), QString{}, QString{}, Qt::AlignHCenter | Qt::AlignVCenter); shutdown_dialog->open(); } @@ -2293,10 +2290,10 @@ void GMainWindow::OnEmulationStopped() { OnTasStateChanged(); render_window->FinalizeCamera(); - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None); // Enable all controllers - system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); + QtCommon::system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); render_window->removeEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, false); @@ -2325,8 +2322,8 @@ void GMainWindow::OnEmulationStopped() { // Enable game list game_list->setEnabled(true); - Settings::RestoreGlobalState(system->IsPoweredOn()); - system->HIDCore().ReloadInputDevices(); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); + QtCommon::system->HIDCore().ReloadInputDevices(); UpdateStatusButtons(); } @@ -2387,15 +2384,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QString open_target; const auto [user_save_size, device_save_size] = [this, &game_path, &program_id] { - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata().first; if (control != nullptr) { return std::make_pair(control->GetDefaultNormalSaveSize(), control->GetDeviceSaveDataSize()); } else { - const auto file = Core::GetGameFileFromPath(vfs, game_path); - const auto loader = Loader::GetLoader(*system, file); + const auto file = Core::GetGameFileFromPath(QtCommon::vfs, game_path); + const auto loader = Loader::GetLoader(*QtCommon::system, file); FileSys::NACP nacp{}; loader->ReadControlData(nacp); @@ -2414,7 +2411,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target open_target = tr("Save Data"); const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); + QtCommon::vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); if (has_user_save) { // User save data @@ -2425,7 +2422,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target .display_options = {}, .purpose = Service::AM::Frontend::UserSelectionPurpose::General, }; - QtProfileSelectionDialog dialog(*system, this, parameters); + QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2443,7 +2440,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } const auto user_id = - system->GetProfileManager().GetUser(static_cast(index)); + QtCommon::system->GetProfileManager().GetUser(static_cast(index)); ASSERT(user_id); const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( @@ -2631,7 +2628,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListR QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; case QtCommon::Game::GameListRemoveTarget::CacheStorage: - QtCommon::Game::RemoveCacheStorage(program_id, vfs.get()); + QtCommon::Game::RemoveCacheStorage(program_id, QtCommon::vfs.get()); break; } } @@ -2656,7 +2653,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa }; const auto loader = - Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); if (loader == nullptr) { failed(); return; @@ -2665,7 +2662,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa FileSys::VirtualFile packed_update_raw{}; loader->ReadUpdateRaw(packed_update_raw); - const auto& installed = system->GetContentProvider(); + const auto& installed = QtCommon::system->GetContentProvider(); u64 title_id{}; u8 raw_type{}; @@ -2697,14 +2694,14 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir); - const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed}; + const FileSys::PatchManager pm{title_id, QtCommon::system->GetFileSystemController(), installed}; auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false); - const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::OpenMode::ReadWrite); + const auto out = VfsFilesystemCreateDirectoryWrapper(path, FileSys::OpenMode::ReadWrite); if (out == nullptr) { failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); return; } @@ -2718,7 +2715,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa selections, 0, false, &ok); if (!ok) { failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); return; } @@ -2758,7 +2755,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } else { progress.close(); failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); } } @@ -2888,8 +2885,8 @@ void GMainWindow::OnGameListShowList(bool show) { void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { u64 title_id{}; - const auto v_file = Core::GetGameFileFromPath(vfs, file); - const auto loader = Loader::GetLoader(*system, v_file); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, file); + const auto loader = Loader::GetLoader(*QtCommon::system, v_file); if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { QMessageBox::information(this, tr("Properties"), @@ -3017,7 +3014,7 @@ void GMainWindow::OnMenuInstallToNAND() { return false; }; future = QtConcurrent::run([this, &file, progress_callback] { - return ContentManager::InstallNSP(*system, *vfs, file.toStdString(), + return ContentManager::InstallNSP(*QtCommon::system, *QtCommon::vfs, file.toStdString(), progress_callback); }); @@ -3109,7 +3106,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { } const bool is_application = index >= static_cast(FileSys::TitleType::Application); - const auto& fs_controller = system->GetFileSystemController(); + const auto& fs_controller = QtCommon::system->GetFileSystemController(); auto* registered_cache = is_application ? fs_controller.GetUserNANDContents() : fs_controller.GetSystemNANDContents(); @@ -3120,7 +3117,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { } return false; }; - return ContentManager::InstallNCA(*vfs, filename.toStdString(), *registered_cache, + return ContentManager::InstallNCA(*QtCommon::vfs, filename.toStdString(), *registered_cache, static_cast(index), progress_callback); } @@ -3149,7 +3146,7 @@ void GMainWindow::OnStartGame() { UpdateMenuState(); OnTasStateChanged(); - play_time_manager->SetProgramId(system->GetApplicationProcessProgramID()); + play_time_manager->SetProgramId(QtCommon::system->GetApplicationProcessProgramID()); play_time_manager->Start(); discord_rpc->Update(); @@ -3160,7 +3157,7 @@ void GMainWindow::OnStartGame() { } void GMainWindow::OnRestartGame() { - if (!system->IsPoweredOn()) { + if (!QtCommon::system->IsPoweredOn()) { return; } @@ -3208,7 +3205,7 @@ void GMainWindow::OnStopGame() { bool GMainWindow::ConfirmShutdownGame() { if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Always) { - if (system->GetExitLocked()) { + if (QtCommon::system->GetExitLocked()) { if (!ConfirmForceLockedExit()) { return false; } @@ -3220,7 +3217,7 @@ bool GMainWindow::ConfirmShutdownGame() { } else { if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game && - system->GetExitLocked()) { + QtCommon::system->GetExitLocked()) { if (!ConfirmForceLockedExit()) { return false; } @@ -3247,12 +3244,12 @@ void GMainWindow::OnExit() { } void GMainWindow::OnSaveConfig() { - system->ApplySettings(); + QtCommon::system->ApplySettings(); config->SaveAllValues(); } void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { - error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, + error_applet = new OverlayDialog(render_window, *QtCommon::system, error_code, error_text, QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); SCOPE_EXIT { error_applet->deleteLater(); @@ -3481,7 +3478,7 @@ void GMainWindow::OnConfigure() { Settings::SetConfiguringGlobal(true); ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), - vk_device_records, *system, + vk_device_records, *QtCommon::system, !multiplayer_state->IsHostingPublicRoom()); connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, &GMainWindow::OnLanguageChanged); @@ -3582,7 +3579,7 @@ void GMainWindow::OnConfigure() { UpdateStatusButtons(); controller_dialog->refreshConfiguration(); - system->ApplySettings(); + QtCommon::system->ApplySettings(); } void GMainWindow::OnConfigureTas() { @@ -3590,7 +3587,7 @@ void GMainWindow::OnConfigureTas() { const auto result = dialog.exec(); if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { - Settings::RestoreGlobalState(system->IsPoweredOn()); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); return; } else if (result == QDialog::Accepted) { dialog.ApplyConfiguration(); @@ -3604,7 +3601,7 @@ void GMainWindow::OnTasStartStop() { } // Disable system buttons to prevent TAS from executing a hotkey - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); controller->ResetSystemButtons(); input_subsystem->GetTas()->StartStop(); @@ -3620,7 +3617,7 @@ void GMainWindow::OnTasRecord() { } // Disable system buttons to prevent TAS from recording a hotkey - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); controller->ResetSystemButtons(); const bool is_recording = input_subsystem->GetTas()->Record(); @@ -3642,8 +3639,8 @@ void GMainWindow::OnTasReset() { void GMainWindow::OnToggleDockedMode() { const bool is_docked = Settings::IsDockedMode(); - auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + auto* player_1 = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* handheld = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); if (!is_docked && handheld->IsConnected()) { QMessageBox::warning(this, tr("Invalid config detected"), @@ -3658,7 +3655,7 @@ void GMainWindow::OnToggleDockedMode() { Settings::values.use_docked_mode.SetValue(is_docked ? Settings::ConsoleMode::Handheld : Settings::ConsoleMode::Docked); UpdateDockedButton(); - OnDockedModeChanged(is_docked, !is_docked, *system); + OnDockedModeChanged(is_docked, !is_docked, *QtCommon::system); } void GMainWindow::OnToggleGpuAccuracy() { @@ -3675,7 +3672,7 @@ void GMainWindow::OnToggleGpuAccuracy() { } } - system->ApplySettings(); + QtCommon::system->ApplySettings(); UpdateGPUAccuracyButton(); } @@ -3740,20 +3737,20 @@ void GMainWindow::OnToggleGraphicsAPI() { } void GMainWindow::OnConfigurePerGame() { - const u64 title_id = system->GetApplicationProcessProgramID(); + const u64 title_id = QtCommon::system->GetApplicationProcessProgramID(); OpenPerGameConfiguration(title_id, current_game_path.toStdString()); } void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) { - const auto v_file = Core::GetGameFileFromPath(vfs, file_name); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, file_name); Settings::SetConfiguringGlobal(false); - ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *system); + ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *QtCommon::system); dialog.LoadFromFile(v_file); const auto result = dialog.exec(); if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { - Settings::RestoreGlobalState(system->IsPoweredOn()); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); return; } else if (result == QDialog::Accepted) { dialog.ApplyConfiguration(); @@ -3765,9 +3762,9 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file } // Do not cause the global config to write local settings into the config file - const bool is_powered_on = system->IsPoweredOn(); + const bool is_powered_on = QtCommon::system->IsPoweredOn(); Settings::RestoreGlobalState(is_powered_on); - system->HIDCore().ReloadInputDevices(); + QtCommon::system->HIDCore().ReloadInputDevices(); UISettings::values.configuration_applied = false; @@ -3822,7 +3819,7 @@ bool GMainWindow::question(QWidget* parent, const QString& title, const QString& box_dialog->setDefaultButton(defaultButton); ControllerNavigation* controller_navigation = - new ControllerNavigation(system->HIDCore(), box_dialog); + new ControllerNavigation(QtCommon::system->HIDCore(), box_dialog); connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, [box_dialog](Qt::Key key) { QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); @@ -3901,7 +3898,7 @@ void GMainWindow::OnVerifyInstalledContents() { }; const std::vector result = - ContentManager::VerifyInstalledContents(*system, *provider, QtProgressCallback); + ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, QtProgressCallback); progress.close(); if (result.empty()) { @@ -3930,7 +3927,7 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, vfs.get()); + auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, QtCommon::vfs.get()); progress.close(); @@ -3942,7 +3939,7 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { }; auto results = - ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, VerifyFirmwareCallback, true); if (results.size() > 0) { const auto failed_names = @@ -4026,30 +4023,9 @@ void GMainWindow::OnInstallDecryptionKeys() { return; } - const QString key_source_location = QFileDialog::getOpenFileName( - this, tr("Select Dumped Keys Location"), {}, QStringLiteral("Decryption Keys (*.keys)"), {}, - QFileDialog::ReadOnly); - if (key_source_location.isEmpty()) { - return; - } + QtCommon::Content::InstallKeys(); - FirmwareManager::KeyInstallResult result = - FirmwareManager::InstallKeys(key_source_location.toStdString(), "keys"); - - system->GetFileSystemController().CreateFactories(*vfs); game_list->PopulateAsync(UISettings::values.game_dirs); - - switch (result) { - case FirmwareManager::KeyInstallResult::Success: - QMessageBox::information(this, tr("Decryption Keys install succeeded"), - tr("Decryption Keys were successfully installed")); - break; - default: - QMessageBox::critical(this, tr("Decryption Keys install failed"), - tr(FirmwareManager::GetKeyInstallResultString(result))); - break; - } - OnCheckFirmwareDecryption(); } @@ -4086,7 +4062,7 @@ void GMainWindow::OnGameListRefresh() void GMainWindow::OnAlbum() { constexpr u64 AlbumId = static_cast(Service::AM::AppletProgramId::PhotoViewer); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Album applet.")); @@ -4100,7 +4076,7 @@ void GMainWindow::OnAlbum() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer); const auto filename = QString::fromStdString(album_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4109,7 +4085,7 @@ void GMainWindow::OnAlbum() { void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { constexpr u64 CabinetId = static_cast(Service::AM::AppletProgramId::Cabinet); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Cabinet applet.")); @@ -4123,8 +4099,8 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet); - system->GetFrontendAppletHolder().SetCabinetMode(mode); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet); + QtCommon::system->GetFrontendAppletHolder().SetCabinetMode(mode); const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4133,7 +4109,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { void GMainWindow::OnMiiEdit() { constexpr u64 MiiEditId = static_cast(Service::AM::AppletProgramId::MiiEdit); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Mii editor.")); @@ -4147,7 +4123,7 @@ void GMainWindow::OnMiiEdit() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit); const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4156,7 +4132,7 @@ void GMainWindow::OnMiiEdit() { void GMainWindow::OnOpenControllerMenu() { constexpr u64 ControllerAppletId = static_cast(Service::AM::AppletProgramId::Controller); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Controller Menu.")); @@ -4171,7 +4147,7 @@ void GMainWindow::OnOpenControllerMenu() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller); const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4180,7 +4156,7 @@ void GMainWindow::OnOpenControllerMenu() { } void GMainWindow::OnHomeMenu() { - auto result = FirmwareManager::VerifyFirmware(*system.get()); + auto result = FirmwareManager::VerifyFirmware(*QtCommon::system.get()); switch (result) { case FirmwareManager::ErrorFirmwareMissing: @@ -4217,7 +4193,7 @@ void GMainWindow::OnHomeMenu() { // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); if (!qlaunch_applet_nca) { @@ -4226,7 +4202,7 @@ void GMainWindow::OnHomeMenu() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch); const auto filename = QString::fromStdString((qlaunch_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4235,7 +4211,7 @@ void GMainWindow::OnHomeMenu() { void GMainWindow::OnInitialSetup() { constexpr u64 Starter = static_cast(Service::AM::AppletProgramId::Starter); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use Starter.")); @@ -4249,7 +4225,7 @@ void GMainWindow::OnInitialSetup() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Starter); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Starter); const auto filename = QString::fromStdString((qlaunch_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4296,6 +4272,7 @@ std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target return shortcut_path; } +// TODO(crueter): Migrate void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { // Get path to Eden executable std::filesystem::path command = GetEdenCommand(); @@ -4311,11 +4288,11 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program return; } - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata(); const auto loader = - Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); std::string game_title{game_title_}; @@ -4395,7 +4372,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the home menu.")); @@ -4421,7 +4398,7 @@ void GMainWindow::OnCaptureScreenshot() { return; } - const u64 title_id = system->GetApplicationProcessProgramID(); + const u64 title_id = QtCommon::system->GetApplicationProcessProgramID(); const auto screenshot_path = QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::ScreenshotsDir)); const auto date = @@ -4583,7 +4560,7 @@ void GMainWindow::OnTasStateChanged() { } void GMainWindow::UpdateStatusBar() { - if (emu_thread == nullptr || !system->IsPoweredOn()) { + if (emu_thread == nullptr || !QtCommon::system->IsPoweredOn()) { status_bar_update_timer.stop(); return; } @@ -4594,8 +4571,8 @@ void GMainWindow::UpdateStatusBar() { tas_label->clear(); } - auto results = system->GetAndResetPerfStats(); - auto& shader_notify = system->GPU().ShaderNotify(); + auto results = QtCommon::system->GetAndResetPerfStats(); + auto& shader_notify = QtCommon::system->GPU().ShaderNotify(); const int shaders_building = shader_notify.ShadersBuilding(); if (shaders_building > 0) { @@ -4741,7 +4718,7 @@ void GMainWindow::OnMouseActivity() { } void GMainWindow::OnCheckFirmwareDecryption() { - system->GetFileSystemController().CreateFactories(*vfs); + QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); if (!ContentManager::AreKeysPresent()) { QMessageBox::warning(this, tr("Derivation Components Missing"), tr("Encryption keys are missing.")); @@ -4786,11 +4763,11 @@ bool GMainWindow::OnCheckNcaVerification() { } bool GMainWindow::CheckFirmwarePresence() { - return FirmwareManager::CheckFirmwarePresence(*system.get()); + return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } void GMainWindow::SetFirmwareVersion() { - const auto pair = FirmwareManager::GetFirmwareVersion(*system.get()); + const auto pair = FirmwareManager::GetFirmwareVersion(*QtCommon::system.get()); const auto firmware_data = pair.first; const auto result = pair.second; @@ -4876,7 +4853,7 @@ bool GMainWindow::ConfirmClose() { UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) { return true; } - if (!system->GetExitLocked() && + if (!QtCommon::system->GetExitLocked() && UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) { return true; } @@ -4906,7 +4883,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { render_window->close(); multiplayer_state->Close(); - system->HIDCore().UnloadInputDevices(); + QtCommon::system->HIDCore().UnloadInputDevices(); Network::Shutdown(); QWidget::closeEvent(event); @@ -4977,12 +4954,12 @@ bool GMainWindow::ConfirmForceLockedExit() { } void GMainWindow::RequestGameExit() { - if (!system->IsPoweredOn()) { + if (!QtCommon::system->IsPoweredOn()) { return; } - system->SetExitRequested(true); - system->GetAppletManager().RequestExit(); + QtCommon::system->SetExitRequested(true); + QtCommon::system->GetAppletManager().RequestExit(); } void GMainWindow::filterBarSetChecked(bool state) { @@ -5092,7 +5069,7 @@ void GMainWindow::OnLanguageChanged(const QString& locale) { void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { #ifdef USE_DISCORD_PRESENCE if (state) { - discord_rpc = std::make_unique(*system); + discord_rpc = std::make_unique(*QtCommon::system); } else { discord_rpc = std::make_unique(); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index f523561628..0bc5913acc 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -71,7 +71,6 @@ enum class StartGameType { namespace Core { enum class SystemResultStatus : u32; -class System; } // namespace Core namespace Core::Frontend { @@ -479,7 +478,6 @@ private: std::unique_ptr ui; - std::unique_ptr system; std::unique_ptr discord_rpc; std::unique_ptr play_time_manager; std::shared_ptr input_subsystem; @@ -540,7 +538,6 @@ private: QString startup_icon_theme; // FS - std::shared_ptr vfs; std::unique_ptr provider; // Debugger panes diff --git a/src/yuzu/user_data_migration.h b/src/yuzu/user_data_migration.h index 3684d14916..a3ac2c15d3 100644 --- a/src/yuzu/user_data_migration.h +++ b/src/yuzu/user_data_migration.h @@ -10,6 +10,7 @@ #include #include "migration_worker.h" +// TODO(crueter): Quick implementation class UserDataMigrator { public: UserDataMigrator(QMainWindow* main_window); From a4b288a6899f17f6922f1f9d730dd25b5a08554d Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 14:57:21 -0400 Subject: [PATCH 45/52] Fix license headers --- src/qt_common/qt_applet_util.cpp | 3 +++ src/qt_common/qt_applet_util.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/qt_common/qt_applet_util.cpp b/src/qt_common/qt_applet_util.cpp index 332f4796e8..1b0189392e 100644 --- a/src/qt_common/qt_applet_util.cpp +++ b/src/qt_common/qt_applet_util.cpp @@ -1 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_applet_util.h" diff --git a/src/qt_common/qt_applet_util.h b/src/qt_common/qt_applet_util.h index 9ceb4a2522..2b48d16698 100644 --- a/src/qt_common/qt_applet_util.h +++ b/src/qt_common/qt_applet_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_APPLET_UTIL_H #define QT_APPLET_UTIL_H From a2614a924147a38d9ccdf880721fad3d693c2e67 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:39:10 -0400 Subject: [PATCH 46/52] QProgressDialog abstractor, more moving Signed-off-by: crueter --- .ci/license-header.sh | 1 - .../org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 19 - .../features/settings/model/BooleanSetting.kt | 1 - .../settings/model/view/SettingsItem.kt | 7 - .../settings/ui/SettingsFragmentPresenter.kt | 1 - .../app/src/main/res/values/strings.xml | 3 - src/common/settings.h | 4 - .../fssystem/fssystem_bucket_tree.cpp | 4 +- .../fssystem_nca_file_system_driver.cpp | 133 +++---- src/qt_common/CMakeLists.txt | 9 +- src/qt_common/externals/CMakeLists.txt | 4 + src/qt_common/externals/cpmfile.json | 7 + src/qt_common/qt_common.cpp | 33 +- src/qt_common/qt_common.h | 14 +- src/qt_common/qt_content_util.cpp | 114 +++++- src/qt_common/qt_content_util.h | 11 +- src/qt_common/qt_frontend_util.cpp | 7 +- src/qt_common/qt_frontend_util.h | 93 ++++- src/qt_common/qt_game_util.cpp | 177 +++++++++ src/qt_common/qt_game_util.h | 24 ++ src/qt_common/qt_progress_dialog.cpp | 4 + src/qt_common/qt_progress_dialog.h | 47 +++ src/qt_common/shared_translation.cpp | 12 +- src/yuzu/game_list.cpp | 4 +- src/yuzu/game_list.h | 7 +- src/yuzu/main.cpp | 345 ++---------------- src/yuzu/main.h | 21 +- 27 files changed, 580 insertions(+), 526 deletions(-) create mode 100644 src/qt_common/qt_progress_dialog.cpp create mode 100644 src/qt_common/qt_progress_dialog.h diff --git a/.ci/license-header.sh b/.ci/license-header.sh index d98f42fc97..3d4929d1c1 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -15,7 +15,6 @@ FILES=`git diff --name-only $BASE` #FILES=$(git diff --name-only master) -echo $FILES echo "Done" check_header() { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 0a2cb41745..9ea2a9ee17 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -272,8 +272,6 @@ class GameAdapter(private val activity: AppCompatActivity) : binding.root.findNavController().navigate(action) } - val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - if (NativeLibrary.gameRequiresFirmware(game.programId) && !NativeLibrary.isFirmwareAvailable()) { MaterialAlertDialogBuilder(activity) .setTitle(R.string.loader_requires_firmware) @@ -288,23 +286,6 @@ class GameAdapter(private val activity: AppCompatActivity) : } .setNegativeButton(android.R.string.cancel) { _, _ -> } .show() - } else if (BooleanSetting.DISABLE_NCA_VERIFICATION.getBoolean(false) && !preferences.getBoolean( - Settings.PREF_HIDE_NCA_POPUP, false)) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.nca_verification_disabled) - .setMessage(activity.getString(R.string.nca_verification_disabled_description)) - .setPositiveButton(android.R.string.ok) { _, _ -> - launch() - } - .setNeutralButton(R.string.dont_show_again) { _, _ -> - preferences.edit { - putBoolean(Settings.PREF_HIDE_NCA_POPUP, true) - } - - launch() - } - .setNegativeButton(android.R.string.cancel) { _, _ -> } - .show() } else { launch() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 6d4bfd97ac..3c5b9003de 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -35,7 +35,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_SAMPLE_SHADING("sample_shading"), PICTURE_IN_PICTURE("picture_in_picture"), USE_CUSTOM_RTC("custom_rtc_enabled"), - DISABLE_NCA_VERIFICATION("disable_nca_verification"), BLACK_BACKGROUNDS("black_backgrounds"), JOYSTICK_REL_CENTER("joystick_rel_center"), DPAD_SLIDE("dpad_slide"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 883d8efaef..1f2ba81a73 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -297,13 +297,6 @@ abstract class SettingsItem( descriptionId = R.string.use_custom_rtc_description ) ) - put( - SwitchSetting( - BooleanSetting.DISABLE_NCA_VERIFICATION, - titleId = R.string.disable_nca_verification, - descriptionId = R.string.disable_nca_verification_description - ) - ) put( StringInputSetting( StringSetting.WEB_TOKEN, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 630bcb0d74..14d62ceec3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -210,7 +210,6 @@ class SettingsFragmentPresenter( add(IntSetting.LANGUAGE_INDEX.key) add(BooleanSetting.USE_CUSTOM_RTC.key) add(LongSetting.CUSTOM_RTC.key) - add(BooleanSetting.DISABLE_NCA_VERIFICATION.key) add(HeaderSetting(R.string.network)) add(StringSetting.WEB_TOKEN.key) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 20c6e85b6c..b1ed0e31fb 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -785,9 +785,6 @@ Game Requires Firmware dump and install firmware, or press "OK" to launch anyways.]]> - NCA Verification Disabled - This is required to run new games and updates, but may cause instability or crashes if NCA files are corrupt, modified, or tampered with. If unsure, re-enable verification in Advanced Settings -> System, and use firmware versions of 19.0.1 or below. - Searching for game... Game not found for Title ID: %1$s diff --git a/src/common/settings.h b/src/common/settings.h index 9d448a2b38..fafd765804 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -626,10 +626,6 @@ struct Values { true, true, &rng_seed_enabled}; Setting device_name{ linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true}; - SwitchableSetting disable_nca_verification{linkage, true, "disable_nca_verification", - Category::System, Specialization::Default}; - Setting hide_nca_verification_popup{ - linkage, false, "hide_nca_verification_popup", Category::System, Specialization::Default}; Setting current_user{linkage, 0, "current_user", Category::System}; diff --git a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp index 615a624f4f..71ba458cef 100644 --- a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp +++ b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp @@ -238,9 +238,7 @@ void BucketTree::Initialize(size_t node_size, s64 end_offset) { ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); ASSERT(Common::IsPowerOfTwo(node_size)); - if (!Settings::values.disable_nca_verification.GetValue()) { - ASSERT(end_offset > 0); - } + ASSERT(end_offset > 0); ASSERT(!this->IsInitialized()); m_node_size = node_size; diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index 4cfa5c58f8..4e624ad3f4 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -1296,91 +1299,65 @@ Result NcaFileSystemDriver::CreateIntegrityVerificationStorageImpl( ASSERT(base_storage != nullptr); ASSERT(layer_info_offset >= 0); - if (!Settings::values.disable_nca_verification.GetValue()) { - // Define storage types. - using VerificationStorage = HierarchicalIntegrityVerificationStorage; - using StorageInfo = VerificationStorage::HierarchicalStorageInformation; + // Define storage types. + using VerificationStorage = HierarchicalIntegrityVerificationStorage; + using StorageInfo = VerificationStorage::HierarchicalStorageInformation; - // Validate the meta info. - HierarchicalIntegrityVerificationInformation level_hash_info; - std::memcpy(std::addressof(level_hash_info), std::addressof(meta_info.level_hash_info), - sizeof(level_hash_info)); + // Validate the meta info. + HierarchicalIntegrityVerificationInformation level_hash_info; + std::memcpy(std::addressof(level_hash_info), + std::addressof(meta_info.level_hash_info), + sizeof(level_hash_info)); - R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - // Get the base storage size. - s64 base_storage_size = base_storage->GetSize(); + // Get the base storage size. + s64 base_storage_size = base_storage->GetSize(); - // Create storage info. - StorageInfo storage_info; - for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { - const auto& layer_info = level_hash_info.info[i]; - R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, - ResultNcaBaseStorageOutOfRangeD); - - storage_info[i + 1] = std::make_shared( - base_storage, layer_info.size, layer_info_offset + layer_info.offset); - } - - // Set the last layer info. - const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; - const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); - R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, + // Create storage info. + StorageInfo storage_info; + for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { + const auto& layer_info = level_hash_info.info[i]; + R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, ResultNcaBaseStorageOutOfRangeD); - if (layer_info_offset > 0) { - R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, - ResultRomNcaInvalidIntegrityLayerInfoOffset); - } - storage_info[level_hash_info.max_layers - 1] = std::make_shared( - std::move(base_storage), layer_info.size, last_layer_info_offset); - // Make the integrity romfs storage. - auto integrity_storage = std::make_shared(); - R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); - - // Initialize the integrity storage. - R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info, - max_data_cache_entries, max_hash_cache_entries, - buffer_level)); - - // Set the output. - *out = std::move(integrity_storage); - R_SUCCEED(); - } else { - // Read IVFC layout - HierarchicalIntegrityVerificationInformation lhi{}; - std::memcpy(std::addressof(lhi), std::addressof(meta_info.level_hash_info), sizeof(lhi)); - - R_UNLESS(IntegrityMinLayerCount <= lhi.max_layers, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - R_UNLESS(lhi.max_layers <= IntegrityMaxLayerCount, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - - const auto& data_li = lhi.info[lhi.max_layers - 2]; - - const s64 base_size = base_storage->GetSize(); - - // Compute the data layer window - const s64 data_off = (layer_info_offset > 0) ? 0LL : data_li.offset.Get(); - R_UNLESS(data_off + data_li.size <= base_size, ResultNcaBaseStorageOutOfRangeD); - if (layer_info_offset > 0) { - R_UNLESS(data_off + data_li.size <= layer_info_offset, - ResultRomNcaInvalidIntegrityLayerInfoOffset); - } - - // TODO: Passthrough (temporary compatibility: integrity disabled) - auto data_view = std::make_shared(base_storage, data_li.size, data_off); - R_UNLESS(data_view != nullptr, ResultAllocationMemoryFailedAllocateShared); - - auto passthrough = std::make_shared(std::move(data_view)); - R_UNLESS(passthrough != nullptr, ResultAllocationMemoryFailedAllocateShared); - - *out = std::move(passthrough); - R_SUCCEED(); + storage_info[i + 1] = std::make_shared(base_storage, + layer_info.size, + layer_info_offset + layer_info.offset); } + + // Set the last layer info. + const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; + const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); + R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, + ResultNcaBaseStorageOutOfRangeD); + if (layer_info_offset > 0) { + R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, + ResultRomNcaInvalidIntegrityLayerInfoOffset); + } + storage_info[level_hash_info.max_layers - 1] + = std::make_shared(std::move(base_storage), + layer_info.size, + last_layer_info_offset); + + // Make the integrity romfs storage. + auto integrity_storage = std::make_shared(); + R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); + + // Initialize the integrity storage. + R_TRY(integrity_storage->Initialize(level_hash_info, + meta_info.master_hash, + storage_info, + max_data_cache_entries, + max_hash_cache_entries, + buffer_level)); + + // Set the output. + *out = std::move(integrity_storage); + R_SUCCEED(); } Result NcaFileSystemDriver::CreateRegionSwitchStorage(VirtualFile* out, diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 1acf8344a1..9d292da401 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,10 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -22,6 +26,8 @@ add_library(qt_common STATIC qt_content_util.h qt_content_util.cpp qt_rom_util.h qt_rom_util.cpp qt_applet_util.h qt_applet_util.cpp + qt_progress_dialog.h qt_progress_dialog.cpp + ) create_target_directory_groups(qt_common) @@ -33,7 +39,8 @@ endif() add_subdirectory(externals) -target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip frozen::frozen) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/externals/CMakeLists.txt b/src/qt_common/externals/CMakeLists.txt index 50594a741f..189a52c0a6 100644 --- a/src/qt_common/externals/CMakeLists.txt +++ b/src/qt_common/externals/CMakeLists.txt @@ -14,3 +14,7 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON) # QuaZip AddJsonPackage(quazip) + +# frozen +# TODO(crueter): Qt String Lookup +AddJsonPackage(frozen) diff --git a/src/qt_common/externals/cpmfile.json b/src/qt_common/externals/cpmfile.json index e3590d0f7f..0b464b95b2 100644 --- a/src/qt_common/externals/cpmfile.json +++ b/src/qt_common/externals/cpmfile.json @@ -8,5 +8,12 @@ "options": [ "QUAZIP_INSTALL OFF" ] + }, + "frozen": { + "package": "frozen", + "repo": "serge-sans-paille/frozen", + "sha": "61dce5ae18", + "hash": "1ae3d073e659c1f24b2cdd76379c90d6af9e06bc707d285a4fafce05f7a4c9e592ff208c94a9ae0f0d07620b3c6cec191f126b03d70ad4dfa496a86ed5658a6d", + "bundled": true } } diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 9c20f1e6d9..6be241c740 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_common.h" +#include "common/fs/fs.h" #include #include @@ -22,9 +23,15 @@ namespace QtCommon { -QObject *rootObject = nullptr; +#ifdef YUZU_QT_WIDGETS +QWidget* rootObject = nullptr; +#else +QObject* rootObject = nullptr; +#endif + std::unique_ptr system = nullptr; std::shared_ptr vfs = nullptr; +std::unique_ptr provider = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -81,11 +88,35 @@ const QString tr(const std::string& str) return QGuiApplication::tr(str.c_str()); } +#ifdef YUZU_QT_WIDGETS +void Init(QWidget* root) +#else void Init(QObject* root) +#endif { system = std::make_unique(); rootObject = root; vfs = std::make_unique(); + provider = std::make_unique(); +} + +std::filesystem::path GetEdenCommand() { + std::filesystem::path command; + + QString appimage = QString::fromLocal8Bit(getenv("APPIMAGE")); + if (!appimage.isEmpty()) { + command = std::filesystem::path{appimage.toStdString()}; + } else { + const QStringList args = QGuiApplication::arguments(); + command = args[0].toStdString(); + } + + // If relative path, make it an absolute path + if (command.c_str()[0] == '.') { + command = Common::FS::GetCurrentDir() / command; + } + + return command; } } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 5f9b5d7de9..a2700427ab 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,18 +4,25 @@ #ifndef QT_COMMON_H #define QT_COMMON_H -#include #include #include "core/core.h" +#include "core/file_sys/registered_cache.h" #include +#include #include namespace QtCommon { +#ifdef YUZU_QT_WIDGETS +extern QWidget *rootObject; +#else extern QObject *rootObject; +#endif + extern std::unique_ptr system; extern std::shared_ptr vfs; +extern std::unique_ptr provider; typedef std::function QtProgressCallback; @@ -23,10 +30,15 @@ Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); +#ifdef YUZU_QT_WIDGETS +void Init(QWidget *root); +#else void Init(QObject *root); +#endif const QString tr(const char *str); const QString tr(const std::string &str); +std::filesystem::path GetEdenCommand(); } // namespace QtCommon #endif diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 5f8ca14504..e4625aa423 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -6,6 +6,7 @@ #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_progress_dialog.h" #include "qt_frontend_util.h" #include @@ -31,24 +32,34 @@ bool CheckGameFirmware(u64 program_id, QObject* parent) return true; } -FirmwareInstallResult InstallFirmware(const QString& location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem* vfs) +void InstallFirmware(const QString& location, bool recursive) { - static constexpr const char* failedTitle = "Firmware Install Failed"; - static constexpr const char* successTitle = "Firmware Install Failed"; - static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + QtCommon::Frontend::QtProgressDialog progress(tr("Installing Firmware..."), + tr("Cancel"), + 0, + 100, + rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + progress.show(); + // Declare progress callback. + auto callback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Succeeded"; QMessageBox::Icon icon; FirmwareInstallResult result; const auto ShowMessage = [&]() { QtCommon::Frontend::ShowMessage(icon, failedTitle, - GetFirmwareInstallResultString(result), - buttons, - rootObject); + GetFirmwareInstallResultString(result)); }; LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); @@ -57,7 +68,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, // there.) std::filesystem::path firmware_source_path = location.toStdString(); if (!Common::FS::IsDir(firmware_source_path)) { - return FirmwareInstallResult::NoOp; + return; } std::vector out; @@ -86,7 +97,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::NoNCAs; icon = QMessageBox::Warning; ShowMessage(); - return result; + return; } // Locate and erase the content of nand/system/Content/registered/*.nca, if any. @@ -96,7 +107,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedDelete; icon = QMessageBox::Critical; ShowMessage(); - return result; + return; } LOG_INFO(Frontend, @@ -127,7 +138,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedCorrupted; icon = QMessageBox::Warning; ShowMessage(); - return result; + return; } } @@ -135,12 +146,34 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedCopy; icon = QMessageBox::Critical; ShowMessage(); - return result; + return; } // Re-scan VFS for the newly placed firmware files. system->GetFileSystemController().CreateFactories(*vfs); + auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(90 + static_cast((processed_size * 10) / total_size)); + return progress.wasCanceled(); + }; + + auto results = ContentManager::VerifyInstalledContents(*QtCommon::system, + *QtCommon::provider, + VerifyFirmwareCallback, + true); + + if (results.size() > 0) { + const auto failed_names = QString::fromStdString( + fmt::format("{}", fmt::join(results, "\n"))); + progress.close(); + QtCommon::Frontend::Critical(tr("Firmware integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1") + .arg(failed_names)); + return; + } + + progress.close(); + const auto pair = FirmwareManager::GetFirmwareVersion(*system); const auto firmware_data = pair.first; const std::string display_version(firmware_data.display_version.data()); @@ -149,9 +182,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, QtCommon::Frontend::Information(rootObject, tr(successTitle), tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version)), - buttons); - return result; + .arg(QString::fromStdString(display_version))); } QString UnzipFirmwareToTmp(const QString& location) @@ -179,8 +210,23 @@ QString UnzipFirmwareToTmp(const QString& location) } // Content // -void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) +void VerifyGameContents(const std::string& game_path) { + QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), + tr("Cancel"), + 0, + 100, + rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + + const auto callback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); switch (result) { @@ -234,4 +280,34 @@ void InstallKeys() } } +void VerifyInstalledContents() { + // Initialize a progress dialog. + QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, QtCommon::rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + + // Declare progress callback. + auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + + const std::vector result = + ContentManager::VerifyInstalledContents(*QtCommon::system, *QtCommon::provider, QtProgressCallback); + progress.close(); + + if (result.empty()) { + QtCommon::Frontend::Information(tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + } else { + const auto failed_names = + QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + QtCommon::Frontend::Critical( + tr("Integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1").arg(failed_names)); + } +} + } // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b401bdf1e3..b572c1c4a3 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -6,8 +6,6 @@ #include #include "common/common_types.h" -#include "core/core.h" -#include "qt_common/qt_common.h" namespace QtCommon::Content { @@ -37,11 +35,7 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul return FIRMWARE_RESULTS.at(static_cast(result)); } -FirmwareInstallResult InstallFirmware( - const QString &location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem *vfs); +void InstallFirmware(const QString &location, bool recursive); QString UnzipFirmwareToTmp(const QString &location); @@ -49,6 +43,7 @@ QString UnzipFirmwareToTmp(const QString &location); void InstallKeys(); // Content // -void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); +void VerifyGameContents(const std::string &game_path); +void VerifyInstalledContents(); } #endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index d357c11338..d519669ad5 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -10,11 +10,8 @@ namespace QtCommon::Frontend { -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons, - QObject *parent) +StandardButton ShowMessage( + Icon icon, const QString &title, const QString &text, StandardButtons buttons, QObject *parent) { #ifdef YUZU_QT_WIDGETS QMessageBox *box = new QMessageBox(icon, title, text, buttons, (QWidget *) parent); diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 7f43286430..f86b9e1357 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -5,12 +5,12 @@ #define QT_FRONTEND_UTIL_H #include -#include #include "qt_common/qt_common.h" #ifdef YUZU_QT_WIDGETS #include #include +#include #endif /** @@ -23,6 +23,11 @@ Q_NAMESPACE #ifdef YUZU_QT_WIDGETS using Options = QFileDialog::Options; using Option = QFileDialog::Option; + +using StandardButton = QMessageBox::StandardButton; +using StandardButtons = QMessageBox::StandardButtons; + +using Icon = QMessageBox::Icon; #else enum Option { ShowDirsOnly = 0x00000001, @@ -36,44 +41,96 @@ enum Option { Q_ENUM_NS(Option) Q_DECLARE_FLAGS(Options, Option) Q_FLAG_NS(Options) + +enum StandardButton { + // keep this in sync with QDialogButtonBox::StandardButton and QPlatformDialogHelper::StandardButton + NoButton = 0x00000000, + Ok = 0x00000400, + Save = 0x00000800, + SaveAll = 0x00001000, + Open = 0x00002000, + Yes = 0x00004000, + YesToAll = 0x00008000, + No = 0x00010000, + NoToAll = 0x00020000, + Abort = 0x00040000, + Retry = 0x00080000, + Ignore = 0x00100000, + Close = 0x00200000, + Cancel = 0x00400000, + Discard = 0x00800000, + Help = 0x01000000, + Apply = 0x02000000, + Reset = 0x04000000, + RestoreDefaults = 0x08000000, + + FirstButton = Ok, // internal + LastButton = RestoreDefaults, // internal + + YesAll = YesToAll, // obsolete + NoAll = NoToAll, // obsolete + + Default = 0x00000100, // obsolete + Escape = 0x00000200, // obsolete + FlagMask = 0x00000300, // obsolete + ButtonMask = ~FlagMask // obsolete +}; +Q_ENUM_NS(StandardButton) + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +typedef StandardButton Button; +#endif +Q_DECLARE_FLAGS(StandardButtons, StandardButton) +Q_FLAG_NS(StandardButtons) + +enum Icon { + // keep this in sync with QMessageDialogOptions::StandardIcon + NoIcon = 0, + Information = 1, + Warning = 2, + Critical = 3, + Question = 4 +}; +Q_ENUM_NS(Icon) + #endif // TODO(crueter) widgets-less impl, choices et al. -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, +StandardButton ShowMessage(Icon icon, const QString &title, const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + StandardButtons buttons = StandardButton::NoButton, QObject *parent = nullptr); #define UTIL_OVERRIDES(level) \ - inline QMessageBox::StandardButton level(QObject *parent, \ + inline StandardButton level(QObject *parent, \ const QString &title, \ const QString &text, \ - QMessageBox::StandardButtons buttons = QMessageBox::Ok) \ + StandardButtons buttons = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, title, text, buttons, parent); \ + return ShowMessage(Icon::level, title, text, buttons, parent); \ } \ - inline QMessageBox::StandardButton level(QObject *parent, \ + inline StandardButton level(QObject *parent, \ const char *title, \ const char *text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, parent); \ + return ShowMessage(Icon::level, tr(title), tr(text), buttons, parent); \ } \ - inline QMessageBox::StandardButton level(const char *title, \ + inline StandardButton level(const char *title, \ const char *text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, rootObject); \ + return ShowMessage(Icon::level, tr(title), tr(text), buttons, rootObject); \ } \ - inline QMessageBox::StandardButton level(const QString title, \ + inline StandardButton level(const QString title, \ const QString &text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, title, text, buttons, rootObject); \ + return ShowMessage(Icon::level, title, text, buttons, rootObject); \ } UTIL_OVERRIDES(Information) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 488eb8c971..292eefa224 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -5,12 +5,15 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "core/file_sys/savedata_factory.h" +#include "core/hle/service/am/am_types.h" #include "frontend_common/content_manager.h" #include "qt_common.h" #include "qt_common/uisettings.h" #include "qt_frontend_util.h" +#include "yuzu/util/util.h" #include +#include #include #ifdef _WIN32 @@ -397,4 +400,178 @@ void ResetMetadata() } } +// Uhhh // + +// Messages in pre-defined message boxes for less code spaghetti +inline constexpr bool CreateShortcutMessagesGUI(ShortcutMessages imsg, const QString& game_title) +{ + int result = 0; + QMessageBox::StandardButtons buttons; + switch (imsg) { + case ShortcutMessages::Fullscreen: + buttons = QMessageBox::Yes | QMessageBox::No; + result + = QtCommon::Frontend::Information(tr("Create Shortcut"), + tr("Do you want to launch the game in fullscreen?"), + buttons); + return result == QMessageBox::Yes; + case ShortcutMessages::Success: + QtCommon::Frontend::Information(tr("Shortcut Created"), + tr("Successfully created a shortcut to %1").arg(game_title)); + return false; + case ShortcutMessages::Volatile: + buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; + result = QtCommon::Frontend::Warning( + tr("Shortcut may be Volatile!"), + tr("This will create a shortcut to the current AppImage. This may " + "not work well if you update. Continue?"), + buttons); + return result == QMessageBox::Ok; + default: + buttons = QMessageBox::Ok; + QtCommon::Frontend::Critical(tr("Failed to Create Shortcut"), + tr("Failed to create a shortcut to %1").arg(game_title), + buttons); + return false; + } +} + +void CreateShortcut(const std::string& game_path, + const u64 program_id, + const std::string& game_title_, + const ShortcutTarget &target, + std::string arguments_, + const bool needs_title) +{ + // Get path to Eden executable + std::filesystem::path command = GetEdenCommand(); + + // Shortcut path + std::filesystem::path shortcut_path = GetShortcutPath(target); + + if (!std::filesystem::exists(shortcut_path)) { + CreateShortcutMessagesGUI(ShortcutMessages::Failed, + QString::fromStdString(shortcut_path.generic_string())); + LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string()); + return; + } + + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + const auto loader = + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + + std::string game_title{game_title_}; + + // Delete illegal characters from title + if (needs_title) { + game_title = fmt::format("{:016X}", program_id); + if (control.first != nullptr) { + game_title = control.first->GetApplicationName(); + } else { + loader->ReadTitle(game_title); + } + } + + const std::string illegal_chars = "<>:\"/\\|?*."; + for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { + if (illegal_chars.find(*it) != std::string::npos) { + game_title.erase(it.base() - 1); + } + } + + const QString qgame_title = QString::fromStdString(game_title); + + // Get icon from game file + std::vector icon_image_file{}; + if (control.second != nullptr) { + icon_image_file = control.second->ReadAllBytes(); + } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { + LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); + } + + QImage icon_data = + QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); + std::filesystem::path out_icon_path; + if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (!SaveIconToFile(out_icon_path, icon_data)) { + LOG_ERROR(Frontend, "Could not write icon to file"); + } + } else { + QtCommon::Frontend::Critical( + tr("Create Icon"), + tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") + .arg(QString::fromStdString(out_icon_path.string()))); + } + +#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) + // Special case for AppImages + // Warn once if we are making a shortcut to a volatile AppImage + if (command.string().ends_with(".AppImage") && !UISettings::values.shortcut_already_warned) { + if (!CreateShortcutMessagesGUI(ShortcutMessages::Volatile, qgame_title)) { + return; + } + UISettings::values.shortcut_already_warned = true; + } +#endif + + // Create shortcut + std::string arguments{arguments_}; + if (CreateShortcutMessagesGUI(ShortcutMessages::Fullscreen, qgame_title)) { + arguments = "-f " + arguments; + } + const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); + const std::string categories = "Game;Emulator;Qt;"; + const std::string keywords = "Switch;Nintendo;"; + + if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + arguments, categories, keywords, game_title)) { + CreateShortcutMessagesGUI(ShortcutMessages::Success, + qgame_title); + return; + } + CreateShortcutMessagesGUI(ShortcutMessages::Failed, + qgame_title); +} + +constexpr std::string GetShortcutPath(ShortcutTarget target) { + { + std::string shortcut_path{}; + if (target == ShortcutTarget::Desktop) { + shortcut_path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + .toStdString(); + } else if (target == ShortcutTarget::Applications) { + shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + .toStdString(); + } + + return shortcut_path; + } +} + +void CreateHomeMenuShortcut(ShortcutTarget target) { + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + QtCommon::Frontend::Warning(tr("No firmware available"), + tr("Please install firmware to use the home menu.")); + return; + } + + auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + if (!qlaunch_nca) { + QtCommon::Frontend::Warning(tr("Home Menu Applet"), + tr("Home Menu is not available. Please reinstall firmware.")); + return; + } + + auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + const auto game_path = qlaunch_applet_nca->GetFullPath(); + + // TODO(crueter): Make this use the Eden icon + CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); +} + + } // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 9861910833..2872734390 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -5,6 +5,7 @@ #define QT_GAME_UTIL_H #include +#include #include "common/fs/path_util.h" #include @@ -24,6 +25,18 @@ enum class GameListRemoveTarget { CacheStorage, }; +enum class ShortcutTarget { + Desktop, + Applications, +}; + +enum class ShortcutMessages{ + Fullscreen = 0, + Success = 1, + Volatile = 2, + Failed = 3 +}; + bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, const std::filesystem::path& icon_path, @@ -57,6 +70,17 @@ void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); // Metadata // void ResetMetadata(); +// Shortcuts // +void CreateShortcut(const std::string& game_path, + const u64 program_id, + const std::string& game_title_, + const ShortcutTarget& target, + std::string arguments_, + const bool needs_title); + +constexpr std::string GetShortcutPath(ShortcutTarget target); +void CreateHomeMenuShortcut(ShortcutTarget target); + } #endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_progress_dialog.cpp b/src/qt_common/qt_progress_dialog.cpp new file mode 100644 index 0000000000..b4bf74c8bd --- /dev/null +++ b/src/qt_common/qt_progress_dialog.cpp @@ -0,0 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "qt_progress_dialog.h" diff --git a/src/qt_common/qt_progress_dialog.h b/src/qt_common/qt_progress_dialog.h new file mode 100644 index 0000000000..17f6817ffa --- /dev/null +++ b/src/qt_common/qt_progress_dialog.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef QT_PROGRESS_DIALOG_H +#define QT_PROGRESS_DIALOG_H + +#include + +#ifdef YUZU_QT_WIDGETS +#include +#endif + +namespace QtCommon::Frontend { +#ifdef YUZU_QT_WIDGETS + +using QtProgressDialog = QProgressDialog; + +// TODO(crueter): QML impl +#else +class QtProgressDialog +{ +public: + QtProgressDialog(const QString &labelText, + const QString &cancelButtonText, + int minimum, + int maximum, + QObject *parent = nullptr, + Qt::WindowFlags f = Qt::WindowFlags()); + + bool wasCanceled() const; + void setWindowModality(Qt::WindowModality modality); + void setMinimumDuration(int durationMs); + void setAutoClose(bool autoClose); + void setAutoReset(bool autoReset); + +public slots: + void setLabelText(QString &text); + void setRange(int min, int max); + void setValue(int progress); + bool close(); + + void show(); +}; +#endif // YUZU_QT_WIDGETS + +} +#endif // QT_PROGRESS_DIALOG_H diff --git a/src/qt_common/shared_translation.cpp b/src/qt_common/shared_translation.cpp index 81ec35b6d8..8f31e07154 100644 --- a/src/qt_common/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -29,10 +29,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) #define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) - // A setting can be ignored by giving it a blank name + // A setting can be ignored by giving it a blank name - // Applets - INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); + // Applets + INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); INSERT(Settings, error_applet_mode, tr("Error"), QString()); @@ -407,12 +407,6 @@ std::unique_ptr InitializeTranslations(QObject* parent) "their resolution, details and supported controllers and depending on this setting.\n" "Setting to Handheld can help improve performance for low end systems.")); INSERT(Settings, current_user, QString(), QString()); - INSERT(Settings, disable_nca_verification, tr("Disable NCA Verification"), - tr("Disables integrity verification of NCA content archives." - "\nThis may improve loading speed but risks data corruption or invalid files going " - "undetected.\n" - "Is necessary to make games and updates work that needs firmware 20+.")); - INSERT(Settings, hide_nca_verification_popup, QString(), QString()); // Controls diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 7c89730651..fa61cdfb1f 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -650,10 +650,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri // TODO: Implement shortcut creation for macOS #if !defined(__APPLE__) connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() { - emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop); + emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Desktop); }); connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { - emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); + emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Applications); }); #endif connect(properties, &QAction::triggered, diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 367d047c40..94e7b2dc42 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -52,11 +52,6 @@ enum class DumpRomFSTarget { SDMC, }; -enum class GameListShortcutTarget { - Desktop, - Applications, -}; - class GameList : public QWidget { Q_OBJECT @@ -113,7 +108,7 @@ signals: void VerifyIntegrityRequested(const std::string& game_path); void CopyTIDRequested(u64 program_id); void CreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target); + const QtCommon::Game::ShortcutTarget target); void NavigateToGamedbEntryRequested(u64 program_id, const CompatibilityList& compatibility_list); void OpenPerGameGeneralRequested(const std::string& file); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 728ed2068c..0d7a08d63d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1,21 +1,22 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#include "core/hle/service/am/applet_manager.h" +#include "core/loader/nca.h" +#include "core/tools/renderdoc.h" +#include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" +#include "qt_common/qt_content_util.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/qt_meta.h" +#include "qt_common/qt_path_util.h" +#include "qt_common/qt_progress_dialog.h" #include #include #include #include #include #include -#include "core/hle/service/am/applet_manager.h" -#include "core/loader/nca.h" -#include "core/tools/renderdoc.h" -#include "frontend_common/firmware_manager.h" -#include "qt_common/qt_common.h" -#include "qt_common/qt_game_util.h" -#include "qt_common/qt_path_util.h" -#include "qt_common/qt_meta.h" -#include "qt_common/qt_content_util.h" #ifdef __APPLE__ #include // for chdir @@ -398,8 +399,7 @@ inline static bool isDarkMode() { GMainWindow::GMainWindow(bool has_broken_vulkan) : ui{std::make_unique()}, - input_subsystem{std::make_shared()}, user_data_migrator{this}, - provider{std::make_unique()} { + input_subsystem{std::make_shared()}, user_data_migrator{this} { QtCommon::Init(this); Common::FS::CreateEdenPaths(); @@ -543,7 +543,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) QtCommon::system->SetContentProvider(std::make_unique()); QtCommon::system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, - provider.get()); + QtCommon::provider.get()); QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); // Remove cached contents generated during the previous session @@ -1091,7 +1091,7 @@ void GMainWindow::InitializeWidgets() { render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *QtCommon::system); render_window->hide(); - game_list = new GameList(QtCommon::vfs, provider.get(), *play_time_manager, *QtCommon::system, this); + game_list = new GameList(QtCommon::vfs, QtCommon::provider.get(), *play_time_manager, *QtCommon::system, this); ui->horizontalLayout->addWidget(game_list); game_list_placeholder = new GameListPlaceholder(this); @@ -1913,10 +1913,6 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa return false; } - if (!OnCheckNcaVerification()) { - return false; - } - /** Exec */ const Core::SystemResultStatus result{ QtCommon::system->Load(*render_window, filename.toStdString(), params)}; @@ -2023,7 +2019,7 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { u64 program_id = 0; const auto res2 = loader->ReadProgramId(program_id); if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) { - provider->AddEntry(FileSys::TitleType::Application, + QtCommon::provider->AddEntry(FileSys::TitleType::Application, FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id, file); } else if (res2 == Loader::ResultStatus::Success && @@ -2033,7 +2029,7 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { : FileSys::XCI{file}.GetSecurePartitionNSP(); for (const auto& title : nsp->GetNCAs()) { for (const auto& entry : title.second) { - provider->AddEntry(entry.first.first, entry.first.second, title.first, + QtCommon::provider->AddEntry(entry.first.first, entry.first.second, title.first, entry.second->GetBaseFile()); } } @@ -2761,18 +2757,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa // END void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - - const auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - QtCommon::Content::VerifyGameContents(game_path, QtProgressCallback); + QtCommon::Content::VerifyGameContents(game_path); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -2793,44 +2778,12 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QUrl(QStringLiteral("https://eden-emulator.github.io/game/") + directory)); } -// Messages in pre-defined message boxes for less code spaghetti -// TODO(crueter): Still need to decide what to do re: message boxes w/ qml -bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { - int result = 0; - QMessageBox::StandardButtons buttons; - switch (imsg) { - case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES: - buttons = QMessageBox::Yes | QMessageBox::No; - result = - QMessageBox::information(parent, tr("Create Shortcut"), - tr("Do you want to launch the game in fullscreen?"), buttons); - return result == QMessageBox::Yes; - case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: - QMessageBox::information(parent, tr("Create Shortcut"), - tr("Successfully created a shortcut to %1").arg(game_title)); - return false; - case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: - buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; - result = - QMessageBox::warning(this, tr("Create Shortcut"), - tr("This will create a shortcut to the current AppImage. This may " - "not work well if you update. Continue?"), - buttons); - return result == QMessageBox::Ok; - default: - buttons = QMessageBox::Ok; - QMessageBox::critical(parent, tr("Create Shortcut"), - tr("Failed to create a shortcut to %1").arg(game_title), buttons); - return false; - } -} - void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target) { + const QtCommon::Game::ShortcutTarget target) { // Create shortcut std::string arguments = fmt::format("-g \"{:s}\"", game_path); - CreateShortcut(game_path, program_id, "", target, arguments, true); + QtCommon::Game::CreateShortcut(game_path, program_id, "", target, arguments, true); } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { @@ -3884,74 +3837,11 @@ void GMainWindow::OnOpenLogFolder() } void GMainWindow::OnVerifyInstalledContents() { - // Initialize a progress dialog. - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - - // Declare progress callback. - auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - const std::vector result = - ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, QtProgressCallback); - progress.close(); - - if (result.empty()) { - QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); - } else { - const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); - QMessageBox::critical( - this, tr("Integrity verification failed!"), - tr("Verification failed for the following files:\n\n%1").arg(failed_names)); - } + QtCommon::Content::VerifyInstalledContents(); } void GMainWindow::InstallFirmware(const QString& location, bool recursive) { - QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - progress.show(); - - // Declare progress callback. - auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, QtCommon::vfs.get()); - - progress.close(); - - if (result != QtCommon::Content::FirmwareInstallResult::Success) return; - - auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(90 + static_cast((processed_size * 10) / total_size)); - return progress.wasCanceled(); - }; - - auto results = - ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, VerifyFirmwareCallback, true); - - if (results.size() > 0) { - const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(results, "\n"))); - progress.close(); - QMessageBox::critical( - this, tr("Firmware integrity verification failed!"), - tr("Verification failed for the following files:\n\n%1").arg(failed_names)); - return; - } - - progress.close(); + QtCommon::Content::InstallFirmware(location, recursive); OnCheckFirmwareDecryption(); } @@ -4190,8 +4080,6 @@ void GMainWindow::OnHomeMenu() { break; } - // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh - constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); @@ -4233,164 +4121,11 @@ void GMainWindow::OnInitialSetup() { } void GMainWindow::OnCreateHomeMenuDesktopShortcut() { - OnCreateHomeMenuShortcut(GameListShortcutTarget::Desktop); + QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Desktop); } void GMainWindow::OnCreateHomeMenuApplicationMenuShortcut() { - OnCreateHomeMenuShortcut(GameListShortcutTarget::Applications); -} - -std::filesystem::path GMainWindow::GetEdenCommand() { - std::filesystem::path command; - - QString appimage = QString::fromLocal8Bit(getenv("APPIMAGE")); - if (!appimage.isEmpty()) { - command = std::filesystem::path{appimage.toStdString()}; - } else { - const QStringList args = QApplication::arguments(); - command = args[0].toStdString(); - } - - // If relative path, make it an absolute path - if (command.c_str()[0] == '.') { - command = Common::FS::GetCurrentDir() / command; - } - - return command; -} - -std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target) { - std::filesystem::path shortcut_path{}; - if (target == GameListShortcutTarget::Desktop) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); - } else if (target == GameListShortcutTarget::Applications) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); - } - - return shortcut_path; -} - -// TODO(crueter): Migrate -void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { - // Get path to Eden executable - std::filesystem::path command = GetEdenCommand(); - - // Shortcut path - std::filesystem::path shortcut_path = GetShortcutPath(target); - - if (!std::filesystem::exists(shortcut_path)) { - GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, - QString::fromStdString(shortcut_path.generic_string())); - LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string()); - return; - } - - const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), - QtCommon::system->GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - const auto loader = - Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); - - std::string game_title{game_title_}; - - // Delete illegal characters from title - if (needs_title) { - game_title = fmt::format("{:016X}", program_id); - if (control.first != nullptr) { - game_title = control.first->GetApplicationName(); - } else { - loader->ReadTitle(game_title); - } - } - - const std::string illegal_chars = "<>:\"/\\|?*."; - for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { - if (illegal_chars.find(*it) != std::string::npos) { - game_title.erase(it.base() - 1); - } - } - - const QString qgame_title = QString::fromStdString(game_title); - - // Get icon from game file - std::vector icon_image_file{}; - if (control.second != nullptr) { - icon_image_file = control.second->ReadAllBytes(); - } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { - LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); - } - - QImage icon_data = - QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); - std::filesystem::path out_icon_path; - if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { - if (!SaveIconToFile(out_icon_path, icon_data)) { - LOG_ERROR(Frontend, "Could not write icon to file"); - } - } else { - QMessageBox::critical( - this, tr("Create Icon"), - tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(out_icon_path.string())), - QMessageBox::StandardButton::Ok); - } - -#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) - // Special case for AppImages - // Warn once if we are making a shortcut to a volatile AppImage - if (command.string().ends_with(".AppImage") && !UISettings::values.shortcut_already_warned) { - if (!GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, qgame_title)) { - return; - } - UISettings::values.shortcut_already_warned = true; - } -#endif - - // Create shortcut - std::string arguments{arguments_}; - if (GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qgame_title)) { - arguments = "-f " + arguments; - } - const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); - const std::string categories = "Game;Emulator;Qt;"; - const std::string keywords = "Switch;Nintendo;"; - - if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, - arguments, categories, keywords, game_title)) { - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, - qgame_title); - return; - } - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, - qgame_title); -} - -void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { - constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); - if (!bis_system) { - QMessageBox::warning(this, tr("No firmware available"), - tr("Please install firmware to use the home menu.")); - return; - } - - auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); - if (!qlaunch_nca) { - QMessageBox::warning(this, tr("Home Menu Applet"), - tr("Home Menu is not available. Please reinstall firmware.")); - return; - } - - auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); - const auto game_path = qlaunch_applet_nca->GetFullPath(); - - // TODO(crueter): Make this use the Eden icon - CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); + QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Applications); } void GMainWindow::OnCaptureScreenshot() { @@ -4718,7 +4453,6 @@ void GMainWindow::OnMouseActivity() { } void GMainWindow::OnCheckFirmwareDecryption() { - QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); if (!ContentManager::AreKeysPresent()) { QMessageBox::warning(this, tr("Derivation Components Missing"), tr("Encryption keys are missing.")); @@ -4727,41 +4461,6 @@ void GMainWindow::OnCheckFirmwareDecryption() { UpdateMenuState(); } -bool GMainWindow::OnCheckNcaVerification() { - if (!Settings::values.disable_nca_verification.GetValue()) - return true; - - const bool currently_hidden = Settings::values.hide_nca_verification_popup.GetValue(); - LOG_INFO(Frontend, "NCA Verification is disabled. Popup State={}", currently_hidden); - if (currently_hidden) - return true; - - QMessageBox msgbox(this); - msgbox.setWindowTitle(tr("NCA Verification Disabled")); - msgbox.setText(tr("NCA Verification is disabled.\n" - "This is required to run new games and updates.\n" - "Running without verification can cause instability or crashes if NCA files " - "are corrupt, modified, or tampered.\n" - "If unsure, re-enable verification in Eden's Settings and use firmware " - "version 19.0.1 or below.")); - msgbox.setIcon(QMessageBox::Warning); - msgbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - msgbox.setDefaultButton(QMessageBox::Ok); - - QCheckBox* cb = new QCheckBox(tr("Don't show again"), &msgbox); - cb->setChecked(currently_hidden); - msgbox.setCheckBox(cb); - - int result = msgbox.exec(); - - const bool hide = cb->isChecked(); - if (hide != currently_hidden) { - Settings::values.hide_nca_verification_popup.SetValue(hide); - } - - return result == static_cast(QMessageBox::Ok); -} - bool GMainWindow::CheckFirmwarePresence() { return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 0bc5913acc..e3922759b0 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -54,7 +54,6 @@ class QSlider; class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; -enum class GameListShortcutTarget; enum class DumpRomFSTarget; class GameListPlaceholder; @@ -161,13 +160,6 @@ class GMainWindow : public QMainWindow { /// Max number of recently loaded items to keep track of static const int max_recent_files_item = 10; - enum { - CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, - CREATE_SHORTCUT_MSGBOX_SUCCESS, - CREATE_SHORTCUT_MSGBOX_ERROR, - CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, - }; - public: void filterBarSetChecked(bool state); void UpdateUITheme(); @@ -177,7 +169,7 @@ public: bool DropAction(QDropEvent* event); void AcceptDropEvent(QDropEvent* event); - std::filesystem::path GetShortcutPath(GameListShortcutTarget target); + std::filesystem::path GetShortcutPath(QtCommon::Game::ShortcutTarget target); signals: @@ -358,8 +350,9 @@ private slots: void OnGameListCopyTID(u64 program_id); void OnGameListNavigateToGamedbEntry(u64 program_id, const CompatibilityList& compatibility_list); - void OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target); + void OnGameListCreateShortcut(u64 program_id, + const std::string& game_path, + const QtCommon::Game::ShortcutTarget target); void OnGameListOpenDirectory(const QString& directory); void OnGameListAddDirectory(); void OnGameListShowList(bool show); @@ -416,7 +409,6 @@ private slots: void OnInitialSetup(); void OnCreateHomeMenuDesktopShortcut(); void OnCreateHomeMenuApplicationMenuShortcut(); - void OnCreateHomeMenuShortcut(GameListShortcutTarget target); void OnCaptureScreenshot(); void OnCheckFirmwareDecryption(); void OnLanguageChanged(const QString& locale); @@ -537,9 +529,6 @@ private: QString startup_icon_theme; - // FS - std::unique_ptr provider; - // Debugger panes WaitTreeWidget* waitTreeWidget; ControllerDialog* controller_dialog; @@ -586,7 +575,7 @@ private: void CreateShortcut(const std::string& game_path, const u64 program_id, const std::string& game_title, - GameListShortcutTarget target, + QtCommon::Game::ShortcutTarget target, std::string arguments, const bool needs_title); From c6c3bff022021c7717c6d76ea3fc8c6f4aafeb94 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:47:34 -0400 Subject: [PATCH 47/52] fix headers Signed-off-by: crueter --- .../fssystem/fssystem_nca_file_system_driver.cpp | 3 --- src/yuzu/main.cpp | 12 ++---------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index 4e624ad3f4..37fb71e9e3 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,9 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0d7a08d63d..9480fed5b3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -10,11 +10,8 @@ #include "qt_common/qt_game_util.h" #include "qt_common/qt_meta.h" #include "qt_common/qt_path_util.h" -#include "qt_common/qt_progress_dialog.h" #include #include -#include -#include #include #include @@ -43,21 +40,16 @@ #include "configuration/configure_input.h" #include "configuration/configure_per_game.h" #include "configuration/configure_tas.h" -#include "core/core_timing.h" #include "core/file_sys/romfs_factory.h" -#include "core/file_sys/vfs/vfs.h" -#include "core/file_sys/vfs/vfs_real.h" #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general.h" #include "core/frontend/applets/mii_edit.h" #include "core/frontend/applets/software_keyboard.h" -#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/frontend/applets.h" -#include "core/hle/service/set/system_settings_server.h" #include "frontend_common/content_manager.h" -#include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" +#include "hid_core/frontend/emulated_controller.h" #include "yuzu/multiplayer/state.h" #include "yuzu/util/controller_navigation.h" @@ -139,6 +131,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/file_sys/savedata_factory.h" #include "core/file_sys/submission_package.h" #include "core/hle/kernel/k_process.h" +#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/sm/sm.h" @@ -166,7 +159,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/discord.h" #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" -#include "yuzu/hotkeys.h" #include "yuzu/install_dialog.h" #include "yuzu/loading_screen.h" #include "yuzu/main.h" From 8169b09749d51105d30a7e16bef6d7fb93db31b3 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:49:10 -0400 Subject: [PATCH 48/52] Fix cpm-fetch Signed-off-by: crueter --- docs/CPM.md | 2 +- tools/cpm-fetch-all.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CPM.md b/docs/CPM.md index 2afcdaf164..bce224da40 100644 --- a/docs/CPM.md +++ b/docs/CPM.md @@ -245,6 +245,6 @@ include(CPMUtil) Currently, `cpm-fetch.sh` defines the following directories for cpmfiles (max depth of 2, so subdirs are caught as well): -`externals src/yuzu src/dynarmic .` +`externals src/qt_common src/dynarmic .` Whenever you add a new cpmfile, update the script accordingly \ No newline at end of file diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh index eac0f861a4..66f55df94d 100755 --- a/tools/cpm-fetch-all.sh +++ b/tools/cpm-fetch-all.sh @@ -6,6 +6,6 @@ # SPDX-FileCopyrightText: 2025 crueter # SPDX-License-Identifier: GPL-3.0-or-later -LIBS=$(find . externals src/yuzu/externals src/dynarmic -maxdepth 2 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") +LIBS=$(find . externals src/qt_common src/dynarmic -maxdepth 2 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") tools/cpm-fetch.sh $LIBS \ No newline at end of file From 8ccc4192eb53c2af592c24109490a93102a4fe6c Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:51:44 -0400 Subject: [PATCH 49/52] fix cpm-fetch (again) Signed-off-by: crueter --- tools/cpm-fetch.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cpm-fetch.sh b/tools/cpm-fetch.sh index 5620996433..996cf76a97 100755 --- a/tools/cpm-fetch.sh +++ b/tools/cpm-fetch.sh @@ -105,7 +105,8 @@ ci_package() { for package in $@ do # prepare for cancer - JSON=$(find . externals src/yuzu/externals externals/ffmpeg src/dynarmic/externals externals/nx_tzdb -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) + # TODO(crueter): Fetch json once? + JSON=$(find . externals src/qt_common src/dynarmic -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) [ -z "$JSON" ] && echo "No cpmfile definition for $package" && continue From b91704c8244ffb4bd3443ce0d823564984224380 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 12:09:12 -0400 Subject: [PATCH 50/52] fix msvc Signed-off-by: crueter --- src/qt_common/qt_game_util.cpp | 2 +- src/qt_common/qt_game_util.h | 3 +-- src/yuzu/main.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 292eefa224..3b667b7700 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -357,7 +357,7 @@ void RemoveCustomConfiguration(u64 program_id, const std::string& game_path) } } -void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs) +void RemoveCacheStorage(u64 program_id) { const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); auto vfs_nand_dir = vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 2872734390..0a21208659 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -7,7 +7,6 @@ #include #include #include "common/fs/path_util.h" -#include namespace QtCommon::Game { @@ -65,7 +64,7 @@ void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); void RemoveVulkanDriverPipelineCache(u64 program_id); void RemoveAllTransferableShaderCaches(u64 program_id); void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); -void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); +void RemoveCacheStorage(u64 program_id); // Metadata // void ResetMetadata(); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9480fed5b3..a411270ca8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2616,7 +2616,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListR QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; case QtCommon::Game::GameListRemoveTarget::CacheStorage: - QtCommon::Game::RemoveCacheStorage(program_id, QtCommon::vfs.get()); + QtCommon::Game::RemoveCacheStorage(program_id); break; } } From 83e9f7b441a632e0ff8df162b898c09f30829f3a Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 12:28:59 -0400 Subject: [PATCH 51/52] fix windows Signed-off-by: crueter --- src/yuzu/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a411270ca8..d7d4e94ab7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -113,6 +113,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/scm_rev.h" #include "common/scope_exit.h" #ifdef _WIN32 +#include "core/core_timing.h" #include "common/windows/timer_resolution.h" #endif #ifdef ARCHITECTURE_x86_64 @@ -1470,7 +1471,7 @@ void GMainWindow::InitializeHotkeys() { connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); }); - connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [this] { + connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [] { if (Settings::values.enable_renderdoc_hotkey) { QtCommon::system->GetRenderdocAPI().ToggleCapture(); } @@ -2140,7 +2141,7 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::string title_version; const auto res = QtCommon::system->GetGameName(title_name); - const auto metadata = [this, title_id] { + const auto metadata = [title_id] { const FileSys::PatchManager pm(title_id, QtCommon::system->GetFileSystemController(), QtCommon::system->GetContentProvider()); return pm.GetControlMetadata(); @@ -2371,7 +2372,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target std::filesystem::path path; QString open_target; - const auto [user_save_size, device_save_size] = [this, &game_path, &program_id] { + const auto [user_save_size, device_save_size] = [&game_path, &program_id] { const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata().first; @@ -2958,7 +2959,7 @@ void GMainWindow::OnMenuInstallToNAND() { } return false; }; - future = QtConcurrent::run([this, &file, progress_callback] { + future = QtConcurrent::run([&file, progress_callback] { return ContentManager::InstallNSP(*QtCommon::system, *QtCommon::vfs, file.toStdString(), progress_callback); }); From 33a203159ba46aec20255ba3be381a89d7d2f060 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 13:31:32 -0400 Subject: [PATCH 52/52] fix windows dir opening Signed-off-by: crueter --- src/qt_common/qt_game_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 3b667b7700..5d0b4d8ae7 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -165,7 +165,7 @@ bool MakeShortcutIcoPath(const u64 program_id, void OpenEdenFolder(const Common::FS::EdenPath& path) { - QDesktopServices::openUrl(QUrl(QString::fromStdString(Common::FS::GetEdenPathString(path)))); + QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(Common::FS::GetEdenPathString(path)))); } void OpenRootDataFolder()