11 changed files with 331 additions and 220 deletions
-
6.ci/license-header.sh
-
3src/core/file_sys/savedata_factory.cpp
-
4src/qt_common/CMakeLists.txt
-
43src/qt_common/qt_common.cpp
-
4src/qt_common/qt_common.h
-
171src/qt_common/qt_game_util.cpp
-
41src/qt_common/qt_game_util.h
-
20src/qt_common/qt_path_util.cpp
-
7src/qt_common/qt_path_util.h
-
243src/yuzu/main.cpp
-
9src/yuzu/main.h
@ -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)))); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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 |
||||
@ -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)); |
||||
|
} |
||||
@ -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 |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue