more common funcs
Signed-off-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
parent
edadf5e8c8
commit
b2967171ea
11 changed files with 331 additions and 220 deletions
|
@ -10,10 +10,8 @@ echo "Getting branch changes"
|
|||
# RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}"
|
||||
# FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r`
|
||||
|
||||
CURRENT=`git rev-parse --short=10 HEAD`
|
||||
BASE=`git merge-base master $CURRENT`
|
||||
RANGE="$CURRENT^..$BASE"
|
||||
FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r`
|
||||
BASE=`git merge-base master HEAD`
|
||||
FILES=`git diff --name-only $BASE`
|
||||
|
||||
#FILES=$(git diff --name-only master)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@ add_library(qt_common STATIC
|
|||
|
||||
shared_translation.cpp
|
||||
shared_translation.h
|
||||
qt_path_util.h qt_path_util.cpp
|
||||
qt_game_util.h qt_game_util.cpp
|
||||
)
|
||||
|
||||
create_target_directory_groups(qt_common)
|
||||
target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni)
|
||||
target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
|
||||
#if !defined(WIN32) && !defined(__APPLE__)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <JlCompress.h>
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <objc/message.h>
|
||||
#endif
|
||||
|
@ -80,9 +85,10 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
|||
return wsi;
|
||||
}
|
||||
|
||||
FirmwareInstallResult InstallFirmware(const QString& location,
|
||||
FirmwareInstallResult InstallFirmware(
|
||||
const QString& location,
|
||||
bool recursive,
|
||||
std::function<bool(size_t, size_t)> QtProgressCallback,
|
||||
std::function<bool(std::size_t, std::size_t)> QtProgressCallback,
|
||||
Core::System* system,
|
||||
FileSys::VfsFilesystem* vfs)
|
||||
{
|
||||
|
@ -123,7 +129,8 @@ FirmwareInstallResult InstallFirmware(const QString& location,
|
|||
|
||||
// Locate and erase the content of nand/system/Content/registered/*.nca, if any.
|
||||
auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory();
|
||||
if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) {
|
||||
if (sysnand_content_vdir->IsWritable()
|
||||
&& !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) {
|
||||
return FirmwareInstallResult::FailedDelete;
|
||||
}
|
||||
|
||||
|
@ -168,4 +175,28 @@ FirmwareInstallResult InstallFirmware(const QString& location,
|
|||
return FirmwareInstallResult::Success;
|
||||
}
|
||||
|
||||
QString UnzipFirmwareToTmp(const QString& location)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
fs::path tmp{fs::temp_directory_path()};
|
||||
|
||||
if (!fs::create_directories(tmp / "eden" / "firmware")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
tmp /= "eden";
|
||||
tmp /= "firmware";
|
||||
|
||||
QString qCacheDir = QString::fromStdString(tmp.string());
|
||||
|
||||
QFile zip(location);
|
||||
|
||||
QStringList result = JlCompress::extractDir(&zip, qCacheDir);
|
||||
if (result.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return qCacheDir;
|
||||
}
|
||||
|
||||
} // namespace QtCommon
|
||||
|
|
|
@ -62,10 +62,12 @@ enum class FirmwareInstallResult {
|
|||
|
||||
FirmwareInstallResult InstallFirmware(const QString &location,
|
||||
bool recursive,
|
||||
std::function<bool(size_t, size_t)> QtProgressCallback,
|
||||
std::function<bool(std::size_t, std::size_t)> QtProgressCallback,
|
||||
Core::System *system,
|
||||
FileSys::VfsFilesystem *vfs);
|
||||
|
||||
QString UnzipFirmwareToTmp(const QString &location);
|
||||
|
||||
inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result)
|
||||
{
|
||||
return FIRMWARE_RESULTS.at(static_cast<std::size_t>(result));
|
||||
|
|
171
src/qt_common/qt_game_util.cpp
Normal file
171
src/qt_common/qt_game_util.cpp
Normal file
|
@ -0,0 +1,171 @@
|
|||
#include "qt_game_util.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include "fmt/ostream.h"
|
||||
#include <fstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace QtCommon {
|
||||
|
||||
bool CreateShortcutLink(const std::filesystem::path& shortcut_path,
|
||||
const std::string& comment,
|
||||
const std::filesystem::path& icon_path,
|
||||
const std::filesystem::path& command,
|
||||
const std::string& arguments, const std::string& categories,
|
||||
const std::string& keywords, const std::string& name) try {
|
||||
#ifdef _WIN32 // Windows
|
||||
HRESULT hr = CoInitialize(nullptr);
|
||||
if (FAILED(hr)) {
|
||||
LOG_ERROR(Frontend, "CoInitialize failed");
|
||||
return false;
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
CoUninitialize();
|
||||
};
|
||||
IShellLinkW* ps1 = nullptr;
|
||||
IPersistFile* persist_file = nullptr;
|
||||
SCOPE_EXIT {
|
||||
if (persist_file != nullptr) {
|
||||
persist_file->Release();
|
||||
}
|
||||
if (ps1 != nullptr) {
|
||||
ps1->Release();
|
||||
}
|
||||
};
|
||||
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
|
||||
reinterpret_cast<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 OpenRootDataFolder() {
|
||||
QDesktopServices::openUrl(QUrl(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir))));
|
||||
}
|
||||
|
||||
void OpenNANDFolder()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir))));
|
||||
}
|
||||
|
||||
void OpenSDMCFolder()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir))));
|
||||
}
|
||||
|
||||
void OpenModFolder()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir))));
|
||||
}
|
||||
|
||||
void OpenLogFolder()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir))));
|
||||
}
|
||||
|
||||
}
|
41
src/qt_common/qt_game_util.h
Normal file
41
src/qt_common/qt_game_util.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef QT_GAME_UTIL_H
|
||||
#define QT_GAME_UTIL_H
|
||||
|
||||
#include "frontend_common/content_manager.h"
|
||||
#include <array>
|
||||
|
||||
namespace QtCommon {
|
||||
|
||||
static constexpr std::array<const char *, 3> GAME_VERIFICATION_RESULTS = {
|
||||
"The operation completed successfully.",
|
||||
"File contents may be corrupt or missing..",
|
||||
"Firmware installation cancelled, firmware may be in a bad state or corrupted."
|
||||
"File contents could not be checked for validity."
|
||||
};
|
||||
|
||||
inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result)
|
||||
{
|
||||
return GAME_VERIFICATION_RESULTS.at(static_cast<std::size_t>(result));
|
||||
}
|
||||
|
||||
bool CreateShortcutLink(const std::filesystem::path& shortcut_path,
|
||||
const std::string& comment,
|
||||
const std::filesystem::path& icon_path,
|
||||
const std::filesystem::path& command,
|
||||
const std::string& arguments,
|
||||
const std::string& categories,
|
||||
const std::string& keywords,
|
||||
const std::string& name);
|
||||
|
||||
bool MakeShortcutIcoPath(const u64 program_id,
|
||||
const std::string_view game_file_name,
|
||||
std::filesystem::path& out_icon_path);
|
||||
|
||||
void OpenRootDataFolder();
|
||||
void OpenNANDFolder();
|
||||
void OpenSDMCFolder();
|
||||
void OpenModFolder();
|
||||
void OpenLogFolder();
|
||||
}
|
||||
|
||||
#endif // QT_GAME_UTIL_H
|
20
src/qt_common/qt_path_util.cpp
Normal file
20
src/qt_common/qt_path_util.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "qt_path_util.h"
|
||||
#include <QDesktopServices>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
bool QtCommon::PathUtil::OpenShaderCache(u64 program_id)
|
||||
{
|
||||
const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
|
||||
const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
|
||||
if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)};
|
||||
const auto qt_shader_cache_path = QString::fromStdString(shader_path_string);
|
||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path));
|
||||
}
|
7
src/qt_common/qt_path_util.h
Normal file
7
src/qt_common/qt_path_util.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef QT_PATH_UTIL_H
|
||||
#define QT_PATH_UTIL_H
|
||||
|
||||
#include "common/common_types.h"
|
||||
namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); }
|
||||
|
||||
#endif // QT_PATH_UTIL_H
|
|
@ -12,6 +12,8 @@
|
|||
#include "core/tools/renderdoc.h"
|
||||
#include "frontend_common/firmware_manager.h"
|
||||
#include "qt_common/qt_common.h"
|
||||
#include "qt_common/qt_game_util.h"
|
||||
#include "qt_common/qt_path_util.h"
|
||||
|
||||
#include <JlCompress.h>
|
||||
|
||||
|
@ -1166,7 +1168,7 @@ void GMainWindow::InitializeWidgets() {
|
|||
loading_screen = new LoadingScreen(this);
|
||||
loading_screen->hide();
|
||||
ui->horizontalLayout->addWidget(loading_screen);
|
||||
connect(loading_screen, &LoadingScreen::Hidden, [&] {
|
||||
connect(loading_screen, &LoadingScreen::Hidden, this, [&] {
|
||||
loading_screen->Clear();
|
||||
if (emulation_running) {
|
||||
render_window->show();
|
||||
|
@ -2613,16 +2615,9 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
|
|||
}
|
||||
|
||||
void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
|
||||
const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
|
||||
const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
|
||||
if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
|
||||
QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"),
|
||||
tr("Failed to create the shader cache directory for this title."));
|
||||
return;
|
||||
if (!QtCommon::PathUtil::OpenShaderCache(program_id)) {
|
||||
QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions."));
|
||||
}
|
||||
const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)};
|
||||
const auto qt_shader_cache_path = QString::fromStdString(shader_path_string);
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path));
|
||||
}
|
||||
|
||||
static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog,
|
||||
|
@ -2687,6 +2682,7 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog&
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO(crueter): All this can be transfered to qt_common
|
||||
QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const {
|
||||
switch (type) {
|
||||
case InstalledEntryType::Game:
|
||||
|
@ -3043,12 +3039,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
|
|||
}
|
||||
}
|
||||
|
||||
// END
|
||||
void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) {
|
||||
const auto NotImplemented = [this] {
|
||||
QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"),
|
||||
tr("File contents were not checked for validity."));
|
||||
};
|
||||
|
||||
QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
progress.setMinimumDuration(100);
|
||||
|
@ -3061,18 +3053,20 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) {
|
|||
};
|
||||
|
||||
const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback);
|
||||
const QString resultString = tr(QtCommon::GetGameVerificationResultString(result));
|
||||
progress.close();
|
||||
switch (result) {
|
||||
case ContentManager::GameVerificationResult::Success:
|
||||
QMessageBox::information(this, tr("Integrity verification succeeded!"),
|
||||
tr("The operation completed successfully."));
|
||||
resultString);
|
||||
break;
|
||||
case ContentManager::GameVerificationResult::Failed:
|
||||
QMessageBox::critical(this, tr("Integrity verification failed!"),
|
||||
tr("File contents may be corrupt."));
|
||||
resultString);
|
||||
break;
|
||||
case ContentManager::GameVerificationResult::NotImplemented:
|
||||
NotImplemented();
|
||||
QMessageBox::warning(this, tr("Integrity verification couldn't be performed"),
|
||||
resultString);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3094,109 +3088,8 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
|
|||
QUrl(QStringLiteral("https://eden-emulator.github.io/game/") + directory));
|
||||
}
|
||||
|
||||
bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
|
||||
const std::string& comment,
|
||||
const std::filesystem::path& icon_path,
|
||||
const std::filesystem::path& command,
|
||||
const std::string& arguments, const std::string& categories,
|
||||
const std::string& keywords, const std::string& name) try {
|
||||
#ifdef _WIN32 // Windows
|
||||
HRESULT hr = CoInitialize(nullptr);
|
||||
if (FAILED(hr)) {
|
||||
LOG_ERROR(Frontend, "CoInitialize failed");
|
||||
return false;
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
CoUninitialize();
|
||||
};
|
||||
IShellLinkW* ps1 = nullptr;
|
||||
IPersistFile* persist_file = nullptr;
|
||||
SCOPE_EXIT {
|
||||
if (persist_file != nullptr) {
|
||||
persist_file->Release();
|
||||
}
|
||||
if (ps1 != nullptr) {
|
||||
ps1->Release();
|
||||
}
|
||||
};
|
||||
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
|
||||
reinterpret_cast<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;
|
||||
}
|
||||
// Messages in pre-defined message boxes for less code spaghetti
|
||||
// TODO(crueter): Still need to decide what to do re: message boxes w/ qml
|
||||
bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) {
|
||||
int result = 0;
|
||||
QMessageBox::StandardButtons buttons;
|
||||
|
@ -3227,33 +3120,6 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt
|
|||
}
|
||||
}
|
||||
|
||||
bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
|
||||
std::filesystem::path& out_icon_path) {
|
||||
// Get path to Yuzu icons directory & icon extension
|
||||
std::string ico_extension = "png";
|
||||
#if defined(_WIN32)
|
||||
out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir);
|
||||
ico_extension = "ico";
|
||||
#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__)
|
||||
out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256";
|
||||
#endif
|
||||
// Create icons directory if it doesn't exist
|
||||
if (!Common::FS::CreateDirs(out_icon_path)) {
|
||||
QMessageBox::critical(
|
||||
this, tr("Create Icon"),
|
||||
tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
|
||||
.arg(QString::fromStdString(out_icon_path.string())),
|
||||
QMessageBox::StandardButton::Ok);
|
||||
out_icon_path.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create icon file path
|
||||
out_icon_path /= (program_id == 0 ? fmt::format("eden-{}.{}", game_file_name, ico_extension)
|
||||
: fmt::format("eden-{:016X}.{}", program_id, ico_extension));
|
||||
return true;
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
|
||||
GameListShortcutTarget target) {
|
||||
// Create shortcut
|
||||
|
@ -4288,28 +4154,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) {
|
|||
}
|
||||
|
||||
void GMainWindow::OnOpenRootDataFolder() {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir))));
|
||||
QtCommon::OpenRootDataFolder();
|
||||
}
|
||||
|
||||
void GMainWindow::OnOpenNANDFolder() {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir))));
|
||||
void GMainWindow::OnOpenNANDFolder()
|
||||
{
|
||||
QtCommon::OpenNANDFolder();
|
||||
}
|
||||
|
||||
void GMainWindow::OnOpenSDMCFolder() {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir))));
|
||||
void GMainWindow::OnOpenSDMCFolder()
|
||||
{
|
||||
QtCommon::OpenSDMCFolder();
|
||||
}
|
||||
|
||||
void GMainWindow::OnOpenModFolder() {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir))));
|
||||
void GMainWindow::OnOpenModFolder()
|
||||
{
|
||||
QtCommon::OpenModFolder();
|
||||
}
|
||||
|
||||
void GMainWindow::OnOpenLogFolder() {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir))));
|
||||
void GMainWindow::OnOpenLogFolder()
|
||||
{
|
||||
QtCommon::OpenLogFolder();
|
||||
}
|
||||
|
||||
void GMainWindow::OnVerifyInstalledContents() {
|
||||
|
@ -4444,32 +4309,14 @@ void GMainWindow::OnInstallFirmwareFromZIP() {
|
|||
return;
|
||||
}
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
fs::path tmp{std::filesystem::temp_directory_path()};
|
||||
|
||||
if (!std::filesystem::create_directories(tmp / "eden" / "firmware")) {
|
||||
goto unzipFailed;
|
||||
}
|
||||
|
||||
{
|
||||
tmp /= "eden";
|
||||
tmp /= "firmware";
|
||||
|
||||
QString qCacheDir = QString::fromStdString(tmp.string());
|
||||
|
||||
QFile zip(firmware_zip_location);
|
||||
|
||||
QStringList result = JlCompress::extractDir(&zip, qCacheDir);
|
||||
if (result.isEmpty()) {
|
||||
goto unzipFailed;
|
||||
}
|
||||
const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location);
|
||||
|
||||
// In this case, it has to be done recursively, since sometimes people
|
||||
// will pack it into a subdirectory after dumping
|
||||
if (!qCacheDir.isEmpty()) {
|
||||
InstallFirmware(qCacheDir, true);
|
||||
|
||||
std::error_code ec;
|
||||
std::filesystem::remove_all(tmp, ec);
|
||||
std::filesystem::remove_all(std::filesystem::temp_directory_path() / "eden" / "firmware", ec);
|
||||
|
||||
if (ec) {
|
||||
QMessageBox::warning(this, tr("Firmware cleanup failed"),
|
||||
|
@ -4478,14 +4325,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() {
|
|||
"again.\nOS reported error: %1")
|
||||
.arg(QString::fromStdString(ec.message())));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
unzipFailed:
|
||||
QMessageBox::critical(
|
||||
this, tr("Firmware unzip failed"),
|
||||
tr("Check write permissions in the system temp directory and try again."));
|
||||
return;
|
||||
}
|
||||
|
||||
void GMainWindow::OnInstallDecryptionKeys() {
|
||||
|
@ -4764,10 +4604,8 @@ std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target
|
|||
return shortcut_path;
|
||||
}
|
||||
|
||||
void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program_id,
|
||||
const std::string& game_title_, GameListShortcutTarget target,
|
||||
std::string arguments_, const bool needs_title) {
|
||||
// Get path to yuzu executable
|
||||
void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) {
|
||||
// Get path to Eden executable
|
||||
std::filesystem::path command = GetEdenCommand();
|
||||
|
||||
// Shortcut path
|
||||
|
@ -4819,10 +4657,16 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program
|
|||
QImage icon_data =
|
||||
QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
|
||||
std::filesystem::path out_icon_path;
|
||||
if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
|
||||
if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
|
||||
if (!SaveIconToFile(out_icon_path, icon_data)) {
|
||||
LOG_ERROR(Frontend, "Could not write icon to file");
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(
|
||||
this, tr("Create Icon"),
|
||||
tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
|
||||
.arg(QString::fromStdString(out_icon_path.string())),
|
||||
QMessageBox::StandardButton::Ok);
|
||||
}
|
||||
|
||||
#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__)
|
||||
|
@ -4843,12 +4687,12 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program
|
|||
this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qgame_title)) {
|
||||
arguments = "-f " + arguments;
|
||||
}
|
||||
const std::string comment = fmt::format("Start {:s} with the eden Emulator", game_title);
|
||||
const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title);
|
||||
const std::string categories = "Game;Emulator;Qt;";
|
||||
const std::string keywords = "Switch;Nintendo;";
|
||||
|
||||
if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments,
|
||||
categories, keywords, game_title)) {
|
||||
if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command,
|
||||
arguments, categories, keywords, game_title)) {
|
||||
GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS,
|
||||
qgame_title);
|
||||
return;
|
||||
|
@ -4876,6 +4720,7 @@ void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) {
|
|||
auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
|
||||
const auto game_path = qlaunch_applet_nca->GetFullPath();
|
||||
|
||||
// TODO(crueter): Make this use the Eden icon
|
||||
CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false);
|
||||
}
|
||||
|
||||
|
|
|
@ -478,15 +478,6 @@ private:
|
|||
|
||||
QString GetTasStateDescription() const;
|
||||
bool CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title);
|
||||
bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
|
||||
std::filesystem::path& out_icon_path);
|
||||
bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment,
|
||||
const std::filesystem::path& icon_path,
|
||||
const std::filesystem::path& command, const std::string& arguments,
|
||||
const std::string& categories, const std::string& keywords,
|
||||
const std::string& name);
|
||||
|
||||
bool OnCheckNcaVerification();
|
||||
|
||||
/**
|
||||
* Mimic the behavior of QMessageBox::question but link controller navigation to the dialog
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue