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