[qt_common] reorg, move more stuff out of main

Signed-off-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
crueter 2025-08-30 19:48:13 -04:00
parent 4c02ca7a5f
commit e18628eb6c
20 changed files with 923 additions and 680 deletions

View file

@ -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})

View file

@ -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 <QGuiApplication>
#include <QStringLiteral>
@ -16,7 +11,6 @@
#include <QFile>
#include <QMessageBox>
#include "qt_frontend_util.h"
#include <JlCompress.h>
@ -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<bool(std::size_t, std::size_t)> 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<std::filesystem::path> 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<int>(((i) / static_cast<float>(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

View file

@ -4,8 +4,6 @@
#ifndef QT_COMMON_H
#define QT_COMMON_H
#include <array>
#include <QWindow>
#include "core/core.h"
#include <core/frontend/emu_window.h>
@ -13,68 +11,28 @@
#include <core/file_sys/vfs/vfs_real.h>
namespace QtCommon {
static constexpr std::array<const char *, 3> 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<std::size_t>(result));
}
static constexpr std::array<const char *, 6> 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<bool(std::size_t, std::size_t)> 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<std::size_t>(result));
}
typedef std::function<bool(std::size_t, std::size_t)> 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

View file

@ -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 <JlCompress.h>
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 <a href='https://yuzu-mirror.github.io/help/quickstart'>"
"dump and install firmware</a>, 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<std::filesystem::path> 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<int>(((i) / static_cast<float>(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."));
}
}
}

View file

@ -0,0 +1,48 @@
#ifndef QT_CONTENT_UTIL_H
#define QT_CONTENT_UTIL_H
#include <QObject>
#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<const char *, 6> 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<std::size_t>(result));
}
// Content //
void VerifyGameContents(const std::string &game_path, QtProgressCallback callback);
}
#endif // QT_CONTENT_UTIL_H

View file

@ -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<QMessageBox::StandardButton>(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

View file

@ -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

View file

@ -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 <QDesktopServices>
#include <QUrl>
#ifdef _WIN32
#include <shlobj.h>
#include <windows.h>
#include "common/scope_exit.h"
#include "common/string_util.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
#include <shlobj.h>
#include <windows.h>
#else
#include "fmt/ostream.h"
#include <fstream>
#include "fmt/ostream.h"
#include <fstream>
#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<void**>(&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 <Invalid Type>");
}
}
// 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

View file

@ -4,23 +4,25 @@
#ifndef QT_GAME_UTIL_H
#define QT_GAME_UTIL_H
#include <QObject>
#include "common/fs/path_util.h"
#include "frontend_common/content_manager.h"
#include <array>
#include <core/file_sys/vfs/vfs.h>
namespace QtCommon {
namespace QtCommon::Game {
static constexpr std::array<const char *, 3> 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<std::size_t>(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

72
src/qt_common/qt_meta.cpp Normal file
View file

@ -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>("u8");
qRegisterMetaType<u16>("u16");
qRegisterMetaType<u32>("u32");
qRegisterMetaType<u64>("u64");
qRegisterMetaType<u128>("u128");
qRegisterMetaType<s8>("s8");
qRegisterMetaType<s16>("s16");
qRegisterMetaType<s32>("s32");
qRegisterMetaType<s64>("s64");
qRegisterMetaType<f32>("f32");
qRegisterMetaType<f64>("f64");
// Register string types
qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<std::wstring>("std::wstring");
qRegisterMetaType<std::u8string>("std::u8string");
qRegisterMetaType<std::u16string>("std::u16string");
qRegisterMetaType<std::u32string>("std::u32string");
qRegisterMetaType<std::string_view>("std::string_view");
qRegisterMetaType<std::wstring_view>("std::wstring_view");
qRegisterMetaType<std::u8string_view>("std::u8string_view");
qRegisterMetaType<std::u16string_view>("std::u16string_view");
qRegisterMetaType<std::u32string_view>("std::u32string_view");
// Register applet types
// Cabinet Applet
qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
qRegisterMetaType<std::shared_ptr<Service::NFC::NfcDevice>>(
"std::shared_ptr<Service::NFC::NfcDevice>");
// Controller Applet
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
// Profile Select Applet
qRegisterMetaType<Core::Frontend::ProfileSelectParameters>(
"Core::Frontend::ProfileSelectParameters");
// Software Keyboard Applet
qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>(
"Core::Frontend::KeyboardInitializeParameters");
qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
"Core::Frontend::InlineAppearParameters");
qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
qRegisterMetaType<Service::AM::Frontend::SwkbdResult>("Service::AM::Frontend::SwkbdResult");
qRegisterMetaType<Service::AM::Frontend::SwkbdTextCheckResult>(
"Service::AM::Frontend::SwkbdTextCheckResult");
qRegisterMetaType<Service::AM::Frontend::SwkbdReplyType>(
"Service::AM::Frontend::SwkbdReplyType");
// Web Browser Applet
qRegisterMetaType<Service::AM::Frontend::WebExitReason>("Service::AM::Frontend::WebExitReason");
// Register loader types
qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
}
}

12
src/qt_common/qt_meta.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef QT_META_H
#define QT_META_H
#include <QObject>
namespace QtCommon::Meta {
//
void RegisterMetaTypes();
}
#endif // QT_META_H

View file

@ -7,17 +7,22 @@
#include <QUrl>
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "qt_common/qt_frontend_util.h"
#include <fmt/format.h>
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));
}
}

View file

@ -5,6 +5,8 @@
#define QT_PATH_UTIL_H
#include "common/common_types.h"
namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); }
#include <QObject>
namespace QtCommon::Path { bool OpenShaderCache(u64 program_id, QObject *parent); }
#endif // QT_PATH_UTIL_H

View file

@ -0,0 +1,75 @@
#include "qt_rom_util.h"
#include <QCoreApplication>
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<u8> 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<int>(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;
}
}

View file

@ -0,0 +1,17 @@
#ifndef QT_ROM_UTIL_H
#define QT_ROM_UTIL_H
#include "qt_common/qt_common.h"
#include <cstddef>
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

View file

@ -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() {

View file

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <regex>
#include "yuzu/game_list.h"
#include <QApplication>
#include <QDir>
#include <QFileInfo>
@ -13,19 +13,20 @@
#include <QMenu>
#include <QThreadPool>
#include <QToolButton>
#include <fmt/ranges.h>
#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 <fmt/ranges.h>
#include <regex>
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);

View file

@ -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);

View file

@ -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 <unistd.h> // 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<u64, 1> 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<InputCommon::InputSubsystem>()}, user_data_migrator{this},
vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
provider{std::make_unique<FileSys::ManualContentProvider>()} {
QtCommon::SetSystem(system.get());
QtCommon::SetRootObject(this);
Common::FS::CreateEdenPaths();
this->config = std::make_unique<QtConfig>();
@ -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>("u8");
qRegisterMetaType<u16>("u16");
qRegisterMetaType<u32>("u32");
qRegisterMetaType<u64>("u64");
qRegisterMetaType<u128>("u128");
qRegisterMetaType<s8>("s8");
qRegisterMetaType<s16>("s16");
qRegisterMetaType<s32>("s32");
qRegisterMetaType<s64>("s64");
qRegisterMetaType<f32>("f32");
qRegisterMetaType<f64>("f64");
// Register string types
qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<std::wstring>("std::wstring");
qRegisterMetaType<std::u8string>("std::u8string");
qRegisterMetaType<std::u16string>("std::u16string");
qRegisterMetaType<std::u32string>("std::u32string");
qRegisterMetaType<std::string_view>("std::string_view");
qRegisterMetaType<std::wstring_view>("std::wstring_view");
qRegisterMetaType<std::u8string_view>("std::u8string_view");
qRegisterMetaType<std::u16string_view>("std::u16string_view");
qRegisterMetaType<std::u32string_view>("std::u32string_view");
// Register applet types
// Cabinet Applet
qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
qRegisterMetaType<std::shared_ptr<Service::NFC::NfcDevice>>(
"std::shared_ptr<Service::NFC::NfcDevice>");
// Controller Applet
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
// Profile Select Applet
qRegisterMetaType<Core::Frontend::ProfileSelectParameters>(
"Core::Frontend::ProfileSelectParameters");
// Software Keyboard Applet
qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>(
"Core::Frontend::KeyboardInitializeParameters");
qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
"Core::Frontend::InlineAppearParameters");
qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
qRegisterMetaType<Service::AM::Frontend::SwkbdResult>("Service::AM::Frontend::SwkbdResult");
qRegisterMetaType<Service::AM::Frontend::SwkbdTextCheckResult>(
"Service::AM::Frontend::SwkbdTextCheckResult");
qRegisterMetaType<Service::AM::Frontend::SwkbdReplyType>(
"Service::AM::Frontend::SwkbdReplyType");
// Web Browser Applet
qRegisterMetaType<Service::AM::Frontend::WebExitReason>("Service::AM::Frontend::WebExitReason");
// Register loader types
qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
}
void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
std::shared_ptr<Service::NFC::NfcDevice> 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.<br><br>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 <a href='https://yuzu-mirror.github.io/help/quickstart'>"
"dump and install firmware</a>, 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 <Invalid Type>");
}
}
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 <Invalid Type>?");
@ -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<int>((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<int>(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);

View file

@ -17,9 +17,10 @@
#include <QTranslator>
#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);