Compare commits
25 commits
33a203159b
...
6d7820cf01
Author | SHA1 | Date | |
---|---|---|---|
6d7820cf01 | |||
a572ee58d3 | |||
ae31504772 | |||
63961f3741 | |||
c70d9140a4 | |||
b326f2e3e0 | |||
8974aed013 | |||
2d94767f96 | |||
c65f075638 | |||
4356e80e50 | |||
c45d9a71e8 | |||
fd7711aa5d | |||
c6a2d2acad | |||
ca349ad7b0 | |||
75f18095e0 | |||
092e645296 | |||
49670ebb0f | |||
115d0484a6 | |||
886b649a0d | |||
195bd7005e | |||
ae62ee3d27 | |||
cb5719ec0e | |||
3508208473 | |||
7a0712af1f | |||
11db0f0dbf |
88 changed files with 2235 additions and 1497 deletions
|
@ -5,10 +5,13 @@ 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]}"
|
||||
FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r`
|
||||
# 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`
|
||||
|
||||
BASE=`git merge-base master HEAD`
|
||||
FILES=`git diff --name-only $BASE`
|
||||
|
||||
#FILES=$(git diff --name-only master)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -234,6 +234,8 @@ if (YUZU_ROOM_STANDALONE)
|
|||
endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
add_definitions(-DYUZU_QT_WIDGETS)
|
||||
add_subdirectory(qt_common)
|
||||
add_subdirectory(yuzu)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -784,9 +784,6 @@
|
|||
<string name="loader_requires_firmware">Game Requires Firmware</string>
|
||||
<string name="loader_requires_firmware_description"><![CDATA[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.]]></string>
|
||||
|
||||
<string name="nca_verification_disabled">NCA Verification Disabled</string>
|
||||
<string name="nca_verification_disabled_description">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.</string>
|
||||
|
||||
<!-- Intent Launch strings -->
|
||||
<string name="searching_for_game">Searching for game...</string>
|
||||
<string name="game_not_found_for_title_id">Game not found for Title ID: %1$s</string>
|
||||
|
|
|
@ -626,10 +626,6 @@ struct Values {
|
|||
true, true, &rng_seed_enabled};
|
||||
Setting<std::string> device_name{
|
||||
linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true};
|
||||
SwitchableSetting<bool> disable_nca_verification{linkage, true, "disable_nca_verification",
|
||||
Category::System, Specialization::Default};
|
||||
Setting<bool> hide_nca_verification_popup{
|
||||
linkage, false, "hide_nca_verification_popup", Category::System, Specialization::Default};
|
||||
|
||||
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
|
@ -1296,91 +1296,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<s32>(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<OffsetVfsFile>(
|
||||
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<s32>(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<OffsetVfsFile>(
|
||||
std::move(base_storage), layer_info.size, last_layer_info_offset);
|
||||
|
||||
// Make the integrity romfs storage.
|
||||
auto integrity_storage = std::make_shared<IntegrityRomFsStorage>();
|
||||
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<OffsetVfsFile>(base_storage, data_li.size, data_off);
|
||||
R_UNLESS(data_view != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
|
||||
auto passthrough = std::make_shared<PassthroughStorage>(std::move(data_view));
|
||||
R_UNLESS(passthrough != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
|
||||
*out = std::move(passthrough);
|
||||
R_SUCCEED();
|
||||
storage_info[i + 1] = std::make_shared<OffsetVfsFile>(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<OffsetVfsFile>(std::move(base_storage),
|
||||
layer_info.size,
|
||||
last_layer_info_offset);
|
||||
|
||||
// Make the integrity romfs storage.
|
||||
auto integrity_storage = std::make_shared<IntegrityRomFsStorage>();
|
||||
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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -126,6 +129,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]);
|
||||
|
|
File diff suppressed because one or more lines are too long
47
src/qt_common/CMakeLists.txt
Normal file
47
src/qt_common/CMakeLists.txt
Normal file
|
@ -0,0 +1,47 @@
|
|||
# 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
|
||||
qt_common.h
|
||||
qt_common.cpp
|
||||
|
||||
uisettings.cpp
|
||||
uisettings.h
|
||||
|
||||
qt_config.cpp
|
||||
qt_config.h
|
||||
|
||||
shared_translation.cpp
|
||||
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
|
||||
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
|
||||
qt_progress_dialog.h qt_progress_dialog.cpp
|
||||
|
||||
)
|
||||
|
||||
create_target_directory_groups(qt_common)
|
||||
|
||||
# TODO(crueter)
|
||||
if (ENABLE_QT)
|
||||
target_link_libraries(qt_common PRIVATE Qt6::Widgets)
|
||||
endif()
|
||||
|
||||
add_subdirectory(externals)
|
||||
|
||||
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})
|
||||
endif()
|
|
@ -14,3 +14,7 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON)
|
|||
|
||||
# QuaZip
|
||||
AddJsonPackage(quazip)
|
||||
|
||||
# frozen
|
||||
# TODO(crueter): Qt String Lookup
|
||||
AddJsonPackage(frozen)
|
|
@ -8,5 +8,12 @@
|
|||
"options": [
|
||||
"QUAZIP_INSTALL OFF"
|
||||
]
|
||||
},
|
||||
"frozen": {
|
||||
"package": "frozen",
|
||||
"repo": "serge-sans-paille/frozen",
|
||||
"sha": "61dce5ae18",
|
||||
"hash": "1ae3d073e659c1f24b2cdd76379c90d6af9e06bc707d285a4fafce05f7a4c9e592ff208c94a9ae0f0d07620b3c6cec191f126b03d70ad4dfa496a86ed5658a6d",
|
||||
"bundled": true
|
||||
}
|
||||
}
|
4
src/qt_common/qt_applet_util.cpp
Normal file
4
src/qt_common/qt_applet_util.cpp
Normal file
|
@ -0,0 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "qt_applet_util.h"
|
11
src/qt_common/qt_applet_util.h
Normal file
11
src/qt_common/qt_applet_util.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
// 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
|
||||
|
||||
// TODO
|
||||
namespace QtCommon::Applets {
|
||||
|
||||
}
|
||||
#endif // QT_APPLET_UTIL_H
|
|
@ -1,12 +1,19 @@
|
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// 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 <QGuiApplication>
|
||||
#include <QStringLiteral>
|
||||
#include <QWindow>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "yuzu/qt_common.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <JlCompress.h>
|
||||
|
||||
#if !defined(WIN32) && !defined(__APPLE__)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
@ -15,7 +22,19 @@
|
|||
#endif
|
||||
|
||||
namespace QtCommon {
|
||||
Core::Frontend::WindowSystemType GetWindowSystemType() {
|
||||
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
QWidget* rootObject = nullptr;
|
||||
#else
|
||||
QObject* rootObject = nullptr;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Core::System> system = nullptr;
|
||||
std::shared_ptr<FileSys::RealVfsFilesystem> vfs = nullptr;
|
||||
std::unique_ptr<FileSys::ManualContentProvider> provider = nullptr;
|
||||
|
||||
Core::Frontend::WindowSystemType GetWindowSystemType()
|
||||
{
|
||||
// Determine WSI type based on Qt platform.
|
||||
QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("windows"))
|
||||
|
@ -35,7 +54,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();
|
||||
|
||||
|
@ -43,8 +63,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
|||
// Our Win32 Qt external doesn't have the private API.
|
||||
wsi.render_surface = reinterpret_cast<void*>(window->winId());
|
||||
#elif defined(__APPLE__)
|
||||
wsi.render_surface = reinterpret_cast<void* (*)(id, SEL)>(objc_msgSend)(
|
||||
reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
|
||||
wsi.render_surface = reinterpret_cast<void* (*) (id, SEL)>(
|
||||
objc_msgSend)(reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
||||
|
@ -57,4 +77,46 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
|||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
const QString tr(const char* str)
|
||||
{
|
||||
return QGuiApplication::tr(str);
|
||||
}
|
||||
|
||||
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<Core::System>();
|
||||
rootObject = root;
|
||||
vfs = std::make_unique<FileSys::RealVfsFilesystem>();
|
||||
provider = std::make_unique<FileSys::ManualContentProvider>();
|
||||
}
|
||||
|
||||
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
|
44
src/qt_common/qt_common.h
Normal file
44
src/qt_common/qt_common.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef QT_COMMON_H
|
||||
#define QT_COMMON_H
|
||||
|
||||
#include <QWindow>
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include <core/frontend/emu_window.h>
|
||||
#include <memory>
|
||||
|
||||
#include <core/file_sys/vfs/vfs_real.h>
|
||||
|
||||
namespace QtCommon {
|
||||
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
extern QWidget *rootObject;
|
||||
#else
|
||||
extern QObject *rootObject;
|
||||
#endif
|
||||
|
||||
extern std::unique_ptr<Core::System> system;
|
||||
extern std::shared_ptr<FileSys::RealVfsFilesystem> vfs;
|
||||
extern std::unique_ptr<FileSys::ManualContentProvider> provider;
|
||||
|
||||
typedef std::function<bool(std::size_t, std::size_t)> QtProgressCallback;
|
||||
|
||||
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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
313
src/qt_common/qt_content_util.cpp
Normal file
313
src/qt_common/qt_content_util.cpp
Normal file
|
@ -0,0 +1,313 @@
|
|||
// 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"
|
||||
#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 <JlCompress.h>
|
||||
|
||||
namespace QtCommon::Content {
|
||||
|
||||
bool CheckGameFirmware(u64 program_id, 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;
|
||||
}
|
||||
|
||||
void InstallFirmware(const QString& location, bool recursive)
|
||||
{
|
||||
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<int>((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));
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
result = FirmwareInstallResult::FailedCopy;
|
||||
icon = QMessageBox::Critical;
|
||||
ShowMessage();
|
||||
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<int>((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());
|
||||
|
||||
result = FirmwareInstallResult::Success;
|
||||
QtCommon::Frontend::Information(rootObject,
|
||||
tr(successTitle),
|
||||
tr(GetFirmwareInstallResultString(result))
|
||||
.arg(QString::fromStdString(display_version)));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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<int>((processed_size * 100) / total_size));
|
||||
return progress.wasCanceled();
|
||||
};
|
||||
|
||||
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."));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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<int>((processed_size * 100) / total_size));
|
||||
return progress.wasCanceled();
|
||||
};
|
||||
|
||||
const std::vector<std::string> 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
|
49
src/qt_common/qt_content_util.h
Normal file
49
src/qt_common/qt_content_util.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
// 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
|
||||
|
||||
#include <QObject>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace QtCommon::Content {
|
||||
|
||||
//
|
||||
bool CheckGameFirmware(u64 program_id, 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,
|
||||
};
|
||||
|
||||
inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result)
|
||||
{
|
||||
return FIRMWARE_RESULTS.at(static_cast<std::size_t>(result));
|
||||
}
|
||||
|
||||
void InstallFirmware(const QString &location, bool recursive);
|
||||
|
||||
QString UnzipFirmwareToTmp(const QString &location);
|
||||
|
||||
// Keys //
|
||||
void InstallKeys();
|
||||
|
||||
// Content //
|
||||
void VerifyGameContents(const std::string &game_path);
|
||||
void VerifyInstalledContents();
|
||||
}
|
||||
#endif // QT_CONTENT_UTIL_H
|
35
src/qt_common/qt_frontend_util.cpp
Normal file
35
src/qt_common/qt_frontend_util.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "qt_frontend_util.h"
|
||||
#include "qt_common/qt_common.h"
|
||||
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
#include <QFileDialog>
|
||||
#endif
|
||||
|
||||
namespace QtCommon::Frontend {
|
||||
|
||||
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);
|
||||
return static_cast<QMessageBox::StandardButton>(box->exec());
|
||||
#endif
|
||||
// TODO(crueter): If Qt Widgets is disabled...
|
||||
// need a way to reference icon/buttons too
|
||||
}
|
||||
|
||||
const QString GetOpenFileName(const QString &title,
|
||||
const QString &dir,
|
||||
const QString &filter,
|
||||
QString *selectedFilter,
|
||||
Options options)
|
||||
{
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
return QFileDialog::getOpenFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace QtCommon::Frontend
|
148
src/qt_common/qt_frontend_util.h
Normal file
148
src/qt_common/qt_frontend_util.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
// 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
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include "qt_common/qt_common.h"
|
||||
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
#include <QFileDialog>
|
||||
#include <QWidget>
|
||||
#include <QMessageBox>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
using StandardButton = QMessageBox::StandardButton;
|
||||
using StandardButtons = QMessageBox::StandardButtons;
|
||||
|
||||
using Icon = QMessageBox::Icon;
|
||||
#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)
|
||||
|
||||
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.
|
||||
StandardButton ShowMessage(Icon icon,
|
||||
const QString &title,
|
||||
const QString &text,
|
||||
StandardButtons buttons = StandardButton::NoButton,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
#define UTIL_OVERRIDES(level) \
|
||||
inline StandardButton level(QObject *parent, \
|
||||
const QString &title, \
|
||||
const QString &text, \
|
||||
StandardButtons buttons = StandardButton::Ok) \
|
||||
{ \
|
||||
return ShowMessage(Icon::level, title, text, buttons, parent); \
|
||||
} \
|
||||
inline StandardButton level(QObject *parent, \
|
||||
const char *title, \
|
||||
const char *text, \
|
||||
StandardButtons buttons \
|
||||
= StandardButton::Ok) \
|
||||
{ \
|
||||
return ShowMessage(Icon::level, tr(title), tr(text), buttons, parent); \
|
||||
} \
|
||||
inline StandardButton level(const char *title, \
|
||||
const char *text, \
|
||||
StandardButtons buttons \
|
||||
= StandardButton::Ok) \
|
||||
{ \
|
||||
return ShowMessage(Icon::level, tr(title), tr(text), buttons, rootObject); \
|
||||
} \
|
||||
inline StandardButton level(const QString title, \
|
||||
const QString &text, \
|
||||
StandardButtons buttons \
|
||||
= StandardButton::Ok) \
|
||||
{ \
|
||||
return ShowMessage(Icon::level, title, text, buttons, rootObject); \
|
||||
}
|
||||
|
||||
UTIL_OVERRIDES(Information)
|
||||
UTIL_OVERRIDES(Warning)
|
||||
UTIL_OVERRIDES(Critical)
|
||||
UTIL_OVERRIDES(Question)
|
||||
|
||||
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
|
577
src/qt_common/qt_game_util.cpp
Normal file
577
src/qt_common/qt_game_util.cpp
Normal file
|
@ -0,0 +1,577 @@
|
|||
// 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"
|
||||
#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 <QDesktopServices>
|
||||
#include <QStandardPaths>
|
||||
#include <QUrl>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/string_util.h"
|
||||
#include <shlobj.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include "fmt/ostream.h"
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
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 {
|
||||
#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<void**>(&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<void**>(&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 OpenEdenFolder(const Common::FS::EdenPath& path)
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(Common::FS::GetEdenPathString(path))));
|
||||
}
|
||||
|
||||
void OpenRootDataFolder()
|
||||
{
|
||||
OpenEdenFolder(Common::FS::EdenPath::EdenDir);
|
||||
}
|
||||
|
||||
void OpenNANDFolder()
|
||||
{
|
||||
OpenEdenFolder(Common::FS::EdenPath::NANDDir);
|
||||
}
|
||||
|
||||
void OpenSDMCFolder()
|
||||
{
|
||||
OpenEdenFolder(Common::FS::EdenPath::SDMCDir);
|
||||
}
|
||||
|
||||
void OpenModFolder()
|
||||
{
|
||||
OpenEdenFolder(Common::FS::EdenPath::LoadDir);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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."));
|
||||
}
|
||||
}
|
||||
|
||||
// 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<u8> 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<int>(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<u64>(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
|
85
src/qt_common/qt_game_util.h
Normal file
85
src/qt_common/qt_game_util.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
// 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
|
||||
|
||||
#include <QObject>
|
||||
#include <QStandardPaths>
|
||||
#include "common/fs/path_util.h"
|
||||
|
||||
namespace QtCommon::Game {
|
||||
|
||||
enum class InstalledEntryType {
|
||||
Game,
|
||||
Update,
|
||||
AddOnContent,
|
||||
};
|
||||
|
||||
enum class GameListRemoveTarget {
|
||||
GlShaderCache,
|
||||
VkShaderCache,
|
||||
AllShaderCache,
|
||||
CustomConfiguration,
|
||||
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,
|
||||
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 OpenEdenFolder(const Common::FS::EdenPath &path);
|
||||
void OpenRootDataFolder();
|
||||
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);
|
||||
|
||||
// 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
|
75
src/qt_common/qt_meta.cpp
Normal file
75
src/qt_common/qt_meta.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
// 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"
|
||||
#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");
|
||||
}
|
||||
|
||||
}
|
15
src/qt_common/qt_meta.h
Normal file
15
src/qt_common/qt_meta.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef QT_META_H
|
||||
#define QT_META_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace QtCommon::Meta {
|
||||
|
||||
//
|
||||
void RegisterMetaTypes();
|
||||
|
||||
}
|
||||
#endif // QT_META_H
|
28
src/qt_common/qt_path_util.cpp
Normal file
28
src/qt_common/qt_path_util.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "qt_path_util.h"
|
||||
#include <QDesktopServices>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "qt_common/qt_frontend_util.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
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)) {
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
12
src/qt_common/qt_path_util.h
Normal file
12
src/qt_common/qt_path_util.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
// 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
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace QtCommon::Path { bool OpenShaderCache(u64 program_id, QObject *parent); }
|
||||
|
||||
#endif // QT_PATH_UTIL_H
|
4
src/qt_common/qt_progress_dialog.cpp
Normal file
4
src/qt_common/qt_progress_dialog.cpp
Normal file
|
@ -0,0 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "qt_progress_dialog.h"
|
47
src/qt_common/qt_progress_dialog.h
Normal file
47
src/qt_common/qt_progress_dialog.h
Normal file
|
@ -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 <QWindow>
|
||||
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
#include <QProgressDialog>
|
||||
#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
|
78
src/qt_common/qt_rom_util.cpp
Normal file
78
src/qt_common/qt_rom_util.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
20
src/qt_common/qt_rom_util.h
Normal file
20
src/qt_common/qt_rom_util.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
// 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
|
||||
|
||||
#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
|
|
@ -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 <QCoreApplication>
|
||||
#include <QWidget>
|
||||
#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 <map>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace ConfigurationShared {
|
||||
|
||||
std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent)
|
||||
std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
||||
{
|
||||
std::unique_ptr<TranslationMap> translations = std::make_unique<TranslationMap>();
|
||||
const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); };
|
||||
|
@ -409,12 +407,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* 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
|
||||
|
||||
|
@ -473,7 +465,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent)
|
|||
return translations;
|
||||
}
|
||||
|
||||
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent)
|
||||
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
||||
{
|
||||
std::unique_ptr<ComboboxTranslationMap> translations = std::make_unique<ComboboxTranslationMap>();
|
||||
const auto& tr = [&](const char* text, const char* context = "") {
|
||||
|
@ -650,58 +642,58 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent)
|
|||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::TimeZone>::Index(),
|
||||
{
|
||||
{static_cast<u32>(Settings::TimeZone::Auto),
|
||||
tr("Auto (%1)", "Auto select time zone")
|
||||
.arg(QString::fromStdString(
|
||||
Settings::GetTimeZoneString(Settings::TimeZone::Auto)))},
|
||||
{static_cast<u32>(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<u32>(Settings::TimeZone::Auto),
|
||||
tr("Auto (%1)", "Auto select time zone")
|
||||
.arg(QString::fromStdString(
|
||||
Settings::GetTimeZoneString(Settings::TimeZone::Auto)))},
|
||||
{static_cast<u32>(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<Settings::AudioMode>::Index(),
|
||||
{
|
||||
PAIR(AudioMode, Mono, tr("Mono")),
|
|
@ -11,23 +11,20 @@
|
|||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <typeindex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
class QWidget;
|
||||
#include "common/settings_enums.h"
|
||||
|
||||
namespace ConfigurationShared {
|
||||
using TranslationMap = std::map<u32, std::pair<QString, QString>>;
|
||||
using ComboboxTranslations = std::vector<std::pair<u32, QString>>;
|
||||
using ComboboxTranslationMap = std::map<u32, ComboboxTranslations>;
|
||||
|
||||
std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent);
|
||||
std::unique_ptr<TranslationMap> InitializeTranslations(QObject *parent);
|
||||
|
||||
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent);
|
||||
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent);
|
||||
|
||||
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map = {
|
||||
{Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))},
|
|
@ -7,7 +7,7 @@
|
|||
#include <QSettings>
|
||||
#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 {
|
|
@ -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;
|
|
@ -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)
|
||||
|
||||
|
@ -501,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)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include <QtCore/qglobal.h>
|
||||
#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 <QCamera>
|
||||
#include <QCameraImageCapture>
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -16,9 +19,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<std::vector<ConfigurationShared::Tab*>> group_,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -7,7 +10,7 @@
|
|||
#include <vector>
|
||||
#include <QWidget>
|
||||
#include "yuzu/configuration/configuration_shared.h"
|
||||
#include "yuzu/configuration/shared_translation.h"
|
||||
#include "qt_common/shared_translation.h"
|
||||
|
||||
class QComboBox;
|
||||
|
||||
|
|
|
@ -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<Ui::ConfigureDebug>()}, system{system_} {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -27,7 +30,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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -8,7 +11,7 @@
|
|||
#include <QDialog>
|
||||
#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 {
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "yuzu/configuration/configure_filesystem.h"
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include "common/fs/fs.h"
|
||||
#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"
|
||||
#include "yuzu/configuration/configure_filesystem.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
|
||||
ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) {
|
||||
|
@ -126,20 +131,7 @@ 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."));
|
||||
}
|
||||
QtCommon::Game::ResetMetadata();
|
||||
}
|
||||
|
||||
void ConfigureFilesystem::UpdateEnabledControls() {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -11,7 +14,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<std::vector<ConfigurationShared::Tab*>> group_,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -40,8 +43,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<VkPresentModeKHR> default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -15,7 +18,7 @@
|
|||
#include <vulkan/vulkan_core.h>
|
||||
#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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -9,7 +12,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(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -11,7 +14,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(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -13,7 +16,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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -9,7 +12,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;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <QTimer>
|
||||
#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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -38,7 +41,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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -15,8 +18,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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -21,7 +24,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<Ui::ConfigurePerGameAddons>()}, system{system_} {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -8,7 +11,7 @@
|
|||
#include <QTimer>
|
||||
#include <fmt/ranges.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 "input_common/drivers/keyboard.h"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -8,7 +11,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<Ui::ConfigureTas>()) {
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include "common/settings.h"
|
||||
#include "ui_configure_web.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
#include "qt_common/uisettings.h"
|
||||
|
||||
ConfigureWeb::ConfigureWeb(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -6,7 +9,7 @@
|
|||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "configuration/qt_config.h"
|
||||
#include "qt_common/qt_config.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -42,7 +45,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 {
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -11,7 +14,7 @@
|
|||
#include <QStringLiteral>
|
||||
#include <QWidget>
|
||||
#include <qobjectdefs.h>
|
||||
#include "yuzu/configuration/shared_translation.h"
|
||||
#include "qt_common/shared_translation.h"
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -9,7 +12,7 @@
|
|||
|
||||
#include "common/logging/backend.h"
|
||||
#include "yuzu/debugger/console.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
#include "qt_common/uisettings.h"
|
||||
|
||||
namespace Debugger {
|
||||
void ToggleConsole() {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -5,7 +8,7 @@
|
|||
#include <fmt/ranges.h>
|
||||
|
||||
#include "yuzu/debugger/wait_tree.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
#include "qt_common/uisettings.h"
|
||||
|
||||
#include "core/arm/debug.h"
|
||||
#include "core/core.h"
|
||||
|
|
|
@ -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 "yuzu/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);
|
||||
|
@ -649,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,
|
||||
|
@ -820,7 +821,7 @@ QStandardItemModel* GameList::GetModel() const {
|
|||
return item_model;
|
||||
}
|
||||
|
||||
void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs, const bool cached)
|
||||
void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs)
|
||||
{
|
||||
tree_view->setEnabled(false);
|
||||
|
||||
|
@ -843,8 +844,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& 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 +873,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) {
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "uisettings.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,30 +47,11 @@ enum class GameListOpenTarget {
|
|||
ModData,
|
||||
};
|
||||
|
||||
enum class GameListRemoveTarget {
|
||||
GlShaderCache,
|
||||
VkShaderCache,
|
||||
AllShaderCache,
|
||||
CustomConfiguration,
|
||||
CacheStorage,
|
||||
};
|
||||
|
||||
enum class DumpRomFSTarget {
|
||||
Normal,
|
||||
SDMC,
|
||||
};
|
||||
|
||||
enum class GameListShortcutTarget {
|
||||
Desktop,
|
||||
Applications,
|
||||
};
|
||||
|
||||
enum class InstalledEntryType {
|
||||
Game,
|
||||
Update,
|
||||
AddOnContent,
|
||||
};
|
||||
|
||||
class GameList : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -97,7 +79,7 @@ public:
|
|||
bool IsEmpty() const;
|
||||
|
||||
void LoadCompatibilityList();
|
||||
void PopulateAsync(QVector<UISettings::GameDir>& game_dirs, const bool cached = true);
|
||||
void PopulateAsync(QVector<UISettings::GameDir>& game_dirs);
|
||||
|
||||
void SaveInterfaceLayout();
|
||||
void LoadInterfaceLayout();
|
||||
|
@ -110,7 +92,6 @@ public:
|
|||
static const QStringList supported_file_extensions;
|
||||
|
||||
public slots:
|
||||
void ForceRefreshGameDirectory();
|
||||
void RefreshGameDirectory();
|
||||
|
||||
signals:
|
||||
|
@ -119,15 +100,15 @@ 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);
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -19,7 +22,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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -27,7 +30,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 +202,7 @@ QList<QStandardItem*> 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 +226,10 @@ QList<QStandardItem*> 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 +242,13 @@ GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_,
|
|||
QVector<UISettings::GameDir>& 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 +351,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 +434,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 +457,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); });
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -15,7 +18,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 +48,7 @@ public:
|
|||
QVector<UISettings::GameDir>& 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 +97,4 @@ private:
|
|||
Common::Event processing_completed;
|
||||
|
||||
Core::System& system;
|
||||
|
||||
const bool cached;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -8,7 +11,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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -8,7 +11,7 @@
|
|||
#include <QListWidget>
|
||||
#include <QVBoxLayout>
|
||||
#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);
|
||||
|
|
1313
src/yuzu/main.cpp
1313
src/yuzu/main.cpp
File diff suppressed because it is too large
Load diff
|
@ -17,9 +17,10 @@
|
|||
#include <QTranslator>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "configuration/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,7 @@ 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;
|
||||
|
@ -72,7 +70,6 @@ enum class StartGameType {
|
|||
|
||||
namespace Core {
|
||||
enum class SystemResultStatus : u32;
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
@ -163,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();
|
||||
|
@ -179,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:
|
||||
|
||||
|
@ -258,8 +248,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 +341,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);
|
||||
|
@ -363,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);
|
||||
|
@ -421,7 +409,6 @@ private slots:
|
|||
void OnInitialSetup();
|
||||
void OnCreateHomeMenuDesktopShortcut();
|
||||
void OnCreateHomeMenuApplicationMenuShortcut();
|
||||
void OnCreateHomeMenuShortcut(GameListShortcutTarget target);
|
||||
void OnCaptureScreenshot();
|
||||
void OnCheckFirmwareDecryption();
|
||||
void OnLanguageChanged(const QString& locale);
|
||||
|
@ -436,16 +423,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);
|
||||
|
@ -478,15 +456,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
|
||||
|
@ -501,7 +470,6 @@ private:
|
|||
|
||||
std::unique_ptr<Ui::MainWindow> ui;
|
||||
|
||||
std::unique_ptr<Core::System> system;
|
||||
std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
|
||||
std::unique_ptr<PlayTime::PlayTimeManager> play_time_manager;
|
||||
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
|
||||
|
@ -561,10 +529,6 @@ private:
|
|||
|
||||
QString startup_icon_theme;
|
||||
|
||||
// FS
|
||||
std::shared_ptr<FileSys::VfsFilesystem> vfs;
|
||||
std::unique_ptr<FileSys::ManualContentProvider> provider;
|
||||
|
||||
// Debugger panes
|
||||
WaitTreeWidget* waitTreeWidget;
|
||||
ControllerDialog* controller_dialog;
|
||||
|
@ -611,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);
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -19,7 +22,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_,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// 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
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.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
|
||||
|
||||
|
@ -9,8 +12,9 @@
|
|||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include <common/polyfill_thread.h>
|
||||
|
||||
// TODO(crueter): Extract this into frontend_common
|
||||
namespace Service::Account {
|
||||
class ProfileManager;
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWindow>
|
||||
#include "core/frontend/emu_window.h"
|
||||
|
||||
namespace QtCommon {
|
||||
|
||||
Core::Frontend::WindowSystemType GetWindowSystemType();
|
||||
|
||||
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window);
|
||||
|
||||
} // namespace QtCommon
|
|
@ -10,6 +10,7 @@
|
|||
#include <QMainWindow>
|
||||
#include "migration_worker.h"
|
||||
|
||||
// TODO(crueter): Quick implementation
|
||||
class UserDataMigrator {
|
||||
public:
|
||||
UserDataMigrator(QMainWindow* main_window);
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
// 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
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "yuzu/qt_common.h"
|
||||
#include "qt_common/qt_common.h"
|
||||
|
||||
#include "common/dynamic_library.h"
|
||||
#include "common/logging/log.h"
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue