From 3062a35eb1297067446156c43e9d0df2f684edff Mon Sep 17 00:00:00 2001 From: boludoz Date: Sun, 15 Oct 2023 02:02:22 -0300 Subject: [PATCH 01/24] Improved shortcut: add games in applist for Windows, question for start game at fullscreen & better unicode support for some Windows path funcs. --- src/common/fs/fs_util.cpp | 59 +++++ src/common/fs/fs_util.h | 22 +- src/common/fs/path_util.cpp | 87 ++++++- src/common/fs/path_util.h | 15 +- src/yuzu/game_list.cpp | 4 - src/yuzu/main.cpp | 504 ++++++++++++++++++++++-------------- src/yuzu/main.h | 22 +- src/yuzu/util/util.cpp | 17 +- src/yuzu/util/util.h | 14 +- 9 files changed, 522 insertions(+), 222 deletions(-) diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index 813a713c3..442f63728 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp @@ -36,4 +36,63 @@ std::string PathToUTF8String(const std::filesystem::path& path) { return ToUTF8String(path.u8string()); } +std::u8string U8FilenameSantizer(const std::u8string_view u8filename) { + std::u8string u8path_santized{u8filename.begin(), u8filename.end()}; + size_t eSizeSanitized = u8path_santized.size(); + + // Special case for ":", for example: 'Pepe: La secuela' --> 'Pepe - La + // secuela' or 'Pepe : La secuela' --> 'Pepe - La secuela' + for (size_t i = 0; i < eSizeSanitized; i++) { + switch (u8path_santized[i]) { + case u8':': + if (i == 0 || i == eSizeSanitized - 1) { + u8path_santized.replace(i, 1, u8"_"); + } else if (u8path_santized[i - 1] == u8' ') { + u8path_santized.replace(i, 1, u8"-"); + } else { + u8path_santized.replace(i, 1, u8" -"); + eSizeSanitized++; + } + break; + case u8'\\': + case u8'/': + case u8'*': + case u8'?': + case u8'\"': + case u8'<': + case u8'>': + case u8'|': + case u8'\0': + u8path_santized.replace(i, 1, u8"_"); + break; + default: + break; + } + } + + // Delete duplicated spaces || Delete duplicated dots (MacOS i think) + for (size_t i = 0; i < eSizeSanitized - 1; i++) { + if ((u8path_santized[i] == u8' ' && u8path_santized[i + 1] == u8' ') || + (u8path_santized[i] == u8'.' && u8path_santized[i + 1] == u8'.')) { + u8path_santized.erase(i, 1); + i--; + } + } + + // Delete all spaces and dots at the end (Windows almost) + while (u8path_santized.back() == u8' ' || u8path_santized.back() == u8'.') { + u8path_santized.pop_back(); + } + + if (u8path_santized.empty()) { + return u8""; + } + + return u8path_santized; +} + +std::string UTF8FilenameSantizer(const std::string_view filename) { + return ToUTF8String(U8FilenameSantizer(ToU8String(filename))); +} + } // namespace Common::FS diff --git a/src/common/fs/fs_util.h b/src/common/fs/fs_util.h index 2492a9f94..dbb4f5a9a 100644 --- a/src/common/fs/fs_util.h +++ b/src/common/fs/fs_util.h @@ -82,4 +82,24 @@ concept IsChar = std::same_as; */ [[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path); -} // namespace Common::FS +/** + * Fix filename (remove invalid characters) + * + * @param u8_string dirty encoded filename string + * + * @returns utf8_string santized filename string + * + */ +[[nodiscard]] std::u8string U8FilenameSantizer(const std::u8string_view u8filename); + +/** + * Fix filename (remove invalid characters) + * + * @param utf8_string dirty encoded filename string + * + * @returns utf8_string santized filename string + * + */ +[[nodiscard]] std::string UTF8FilenameSantizer(const std::string_view filename); + +} // namespace Common::FS \ No newline at end of file diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 0abd81a45..a461161ed 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -6,6 +6,7 @@ #include #include "common/fs/fs.h" +#include "common/string_util.h" #ifdef ANDROID #include "common/fs/fs_android.h" #endif @@ -14,7 +15,7 @@ #include "common/logging/log.h" #ifdef _WIN32 -#include // Used in GetExeDirectory() +#include // Used in GetExeDirectory() and GetWindowsDesktop() #else #include // Used in Get(Home/Data)Directory() #include // Used in GetHomeDirectory() @@ -250,30 +251,39 @@ void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) { #ifdef _WIN32 fs::path GetExeDirectory() { - wchar_t exe_path[MAX_PATH]; + WCHAR exe_path[MAX_PATH]; - if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH) == 0) { + if (SUCCEEDED(GetModuleFileNameW(nullptr, exe_path, MAX_PATH))) { + std::wstring wideExePath(exe_path); + + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideExePath)}.parent_path(); + } else { LOG_ERROR(Common_Filesystem, - "Failed to get the path to the executable of the current process"); + "[GetExeDirectory] Failed to get the path to the executable of the current " + "process"); } - return fs::path{exe_path}.parent_path(); + return fs::path{}; } fs::path GetAppDataRoamingDirectory() { PWSTR appdata_roaming_path = nullptr; - SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &appdata_roaming_path); + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) { + std::wstring wideAppdataRoamingPath(appdata_roaming_path); + CoTaskMemFree(appdata_roaming_path); - auto fs_appdata_roaming_path = fs::path{appdata_roaming_path}; - - CoTaskMemFree(appdata_roaming_path); - - if (fs_appdata_roaming_path.empty()) { - LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideAppdataRoamingPath)}; + } else { + LOG_ERROR(Common_Filesystem, + "[GetAppDataRoamingDirectory] Failed to get the path to the %APPDATA% directory"); } - return fs_appdata_roaming_path; + return fs::path{}; } #else @@ -338,6 +348,57 @@ fs::path GetBundleDirectory() { #endif +fs::path GetDesktopPath() { +#if defined(_WIN32) + PWSTR DesktopPath = nullptr; + + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &DesktopPath))) { + std::wstring wideDesktopPath(DesktopPath); + CoTaskMemFree(DesktopPath); + + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideDesktopPath)}; + } else { + LOG_ERROR(Common_Filesystem, + "[GetDesktopPath] Failed to get the path to the desktop directory"); + } +#else + fs::path shortcut_path = GetHomeDirectory() / "Desktop"; + if (fs::exists(shortcut_path)) { + return shortcut_path; + } +#endif + return fs::path{}; +} + +fs::path GetAppsShortcutsPath() { +#if defined(_WIN32) + PWSTR AppShortcutsPath = nullptr; + + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_CommonPrograms, 0, NULL, &AppShortcutsPath))) { + std::wstring wideAppShortcutsPath(AppShortcutsPath); + CoTaskMemFree(AppShortcutsPath); + + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideAppShortcutsPath)}; + } else { + LOG_ERROR(Common_Filesystem, + "[GetAppsShortcutsPath] Failed to get the path to the App Shortcuts directory"); + } +#else + fs::path shortcut_path = GetHomeDirectory() / ".local/share/applications"; + if (!fs::exists(shortcut_path)) { + shortcut_path = std::filesystem::path("/usr/share/applications"); + return shortcut_path; + } else { + return shortcut_path; + } +#endif + return fs::path{}; +} + // vvvvvvvvvv Deprecated vvvvvvvvvv // std::string_view RemoveTrailingSlash(std::string_view path) { diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index 63801c924..b88a388d1 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -244,7 +244,6 @@ void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) { * @returns The path of the current user's %APPDATA% directory. */ [[nodiscard]] std::filesystem::path GetAppDataRoamingDirectory(); - #else /** @@ -275,6 +274,20 @@ void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) { #endif +/** + * Gets the path of the current user's desktop directory. + * + * @returns The path of the current user's desktop directory. + */ +[[nodiscard]] std::filesystem::path GetDesktopPath(); + +/** + * Gets the path of the current user's apps directory. + * + * @returns The path of the current user's apps directory. + */ +[[nodiscard]] std::filesystem::path GetAppsShortcutsPath(); + // vvvvvvvvvv Deprecated vvvvvvvvvv // // Removes the final '/' or '\' if one exists diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 2bb1a0239..fbe099661 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -566,10 +566,8 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut")); QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop")); -#ifndef WIN32 QAction* create_applications_menu_shortcut = shortcut_menu->addAction(tr("Add to Applications Menu")); -#endif context_menu.addSeparator(); QAction* properties = context_menu.addAction(tr("Properties")); @@ -647,11 +645,9 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() { emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop); }); -#ifndef WIN32 connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); }); -#endif connect(properties, &QAction::triggered, [this, path]() { emit OpenPerGameGeneralRequested(path); }); }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 1431cf2fe..e4dc717ed 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2840,8 +2840,236 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/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) { + + bool shortcut_succeeded = false; + + // Replace characters that are illegal in Windows filenames + std::filesystem::path shortcut_path_full = + shortcut_path / Common::FS::UTF8FilenameSantizer(name); + +#if defined(__linux__) || defined(__FreeBSD__) + shortcut_path_full += ".desktop"; +#elif defined(_WIN32) + shortcut_path_full += ".lnk"; +#endif + + LOG_INFO(Common, "[GMainWindow::CreateShortcutLink] Create shortcut path: {}", + shortcut_path_full.string()); + +#if defined(__linux__) || defined(__FreeBSD__) + // This desktop file template was writing referencing + // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html + try { + + // Plus 'Type' is required + if (name.empty()) { + LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Name is empty"); + shortcut_succeeded = false; + return shortcut_succeeded; + } + std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); + + if (shortcut_stream.is_open()) { + + 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={}", command.string()); + + if (!arguments.empty()) { + fmt::print(shortcut_stream, " {}", arguments); + } + + fmt::print(shortcut_stream, "\n"); + + if (!categories.empty()) { + fmt::print(shortcut_stream, "Categories={}\n", categories); + } + + if (!keywords.empty()) { + fmt::print(shortcut_stream, "Keywords={}\n", keywords); + } + + shortcut_stream.close(); + return true; + + } else { + LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Failed to create shortcut"); + return false; + } + + shortcut_stream.close(); + } catch (const std::exception& e) { + LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Failed to create shortcut: {}", + e.what()); + } +#elif defined(_WIN32) + // Initialize COM + auto hr = CoInitialize(NULL); + if (FAILED(hr)) { + return shortcut_succeeded; + } + + IShellLinkW* ps1; + + auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + (void**)&ps1); + + // The UTF-16 / UTF-8 conversion is broken in C++, it is necessary to perform these steps and + // resort to the native Windows function. + std::wstring wshortcut_path_full = Common::UTF8ToUTF16W(shortcut_path_full.string()); + std::wstring wicon_path = Common::UTF8ToUTF16W(icon_path.string()); + std::wstring wcommand = Common::UTF8ToUTF16W(command.string()); + std::wstring warguments = Common::UTF8ToUTF16W(arguments); + std::wstring wcomment = Common::UTF8ToUTF16W(comment); + + if (SUCCEEDED(hres)) { + if (std::filesystem::is_regular_file(command)) + hres = ps1->SetPath(wcommand.data()); + + if (SUCCEEDED(hres) && !arguments.empty()) + hres = ps1->SetArguments(warguments.data()); + + if (SUCCEEDED(hres) && !comment.empty()) + hres = ps1->SetDescription(wcomment.data()); + + if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) + hres = ps1->SetIconLocation(wicon_path.data(), 0); + + IPersistFile* pPersistFile = nullptr; + + if (SUCCEEDED(hres)) { + hres = ps1->QueryInterface(IID_IPersistFile, (void**)&pPersistFile); + + if (SUCCEEDED(hres) && pPersistFile != nullptr) { + hres = pPersistFile->Save(wshortcut_path_full.data(), TRUE); + if (SUCCEEDED(hres)) { + shortcut_succeeded = true; + } + } + } + + if (pPersistFile != nullptr) { + pPersistFile->Release(); + } + } else { + LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Failed to create IShellLinkWinstance"); + } + + ps1->Release(); + CoUninitialize(); +#endif + + if (shortcut_succeeded && std::filesystem::is_regular_file(shortcut_path_full)) { + LOG_INFO(Common, "[GMainWindow::CreateShortcutLink] Shortcut created"); + } else { + LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Shortcut error, failed to create it"); + shortcut_succeeded = false; + } + + return shortcut_succeeded; +} + +// Messages in pre-defined message boxes for less code spaghetti +bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, + const std::string title) { + QMessageBox::StandardButtons buttons; + int result = 0; + + switch (imsg) { + + case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES: + buttons = QMessageBox::Yes | QMessageBox::No; + + result = + QMessageBox::information(parent, tr("Create Shortcut"), + tr("Do you want to launch the game in fullscreen?"), buttons); + + LOG_INFO(Frontend, "Shortcut will launch in fullscreen"); + return (result == QMessageBox::No) ? false : true; + + case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: + QMessageBox::information( + parent, tr("Create Shortcut"), + tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title))); + LOG_INFO(Frontend, "Successfully created a shortcut to {}", title); + return true; + + case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: + result = QMessageBox::warning( + this, tr("Create Shortcut"), + tr("This will create a shortcut to the current AppImage. This may " + "not work well if you update. Continue?"), + QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel); + return (result == QMessageBox::StandardButton::Cancel) ? true : false; + case GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN: + buttons = QMessageBox::Ok; + QMessageBox::critical(parent, tr("Create Shortcut"), + tr("Cannot create shortcut in Apps. Restart yuzu as administrator."), + buttons); + LOG_ERROR(Frontend, "Cannot create shortcut in Apps. Restart yuzu as administrator."); + return true; + default: + buttons = QMessageBox::Ok; + QMessageBox::critical( + parent, tr("Create Shortcut"), + tr("Failed to create a shortcut to %1").arg(QString::fromStdString(title)), buttons); + LOG_ERROR(Frontend, "Failed to create a shortcut to {}", title); + return true; + } + + return true; +} + +bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, + std::filesystem::path& icons_path) { + + // Get path to Yuzu icons directory & icon extension + std::string ico_extension = "png"; +#if defined(_WIN32) + icons_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons"; + ico_extension = "ico"; +#elif defined(__linux__) || defined(__FreeBSD__) + icons_path = GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; +#endif + + // Create icons directory if it doesn't exist + if (!Common::FS::CreateDirs(icons_path)) { + QMessageBox::critical( + this, tr("Create Icon"), + tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") + .arg(QString::fromStdString(icons_path.string())), + QMessageBox::StandardButton::Ok); + icons_path = ""; // Reset path + return false; + } + + // Create icon file path + icons_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension) + : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); + return true; +} + void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { + // Get path to yuzu executable const QStringList args = QApplication::arguments(); std::filesystem::path yuzu_command = args[0].toStdString(); @@ -2851,159 +3079,111 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga yuzu_command = Common::FS::GetCurrentDir() / yuzu_command; } + // Shortcut path + std::filesystem::path shortcut_path{}; + if (target == GameListShortcutTarget::Desktop) { + shortcut_path = Common::FS::GetDesktopPath(); + if (!std::filesystem::exists(shortcut_path)) { + shortcut_path = + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); + } + } else if (target == GameListShortcutTarget::Applications) { + +#if defined(_WIN32) + HANDLE hProcess = GetCurrentProcess(); + if (!IsUserAnAdmin()) { + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN, + ""); + return; + } + CloseHandle(hProcess); +#endif // _WIN32 + + shortcut_path = Common::FS::GetAppsShortcutsPath(); + if (!std::filesystem::exists(shortcut_path)) { + shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + .toStdString(); + } + } + + // Icon path and title + std::string title; + std::filesystem::path icons_path; + if (std::filesystem::exists(shortcut_path)) { + + // Get title from game file + const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), + system->GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + const auto loader = + Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); + + title = fmt::format("{:016X}", program_id); + + if (control.first != nullptr) { + title = control.first->GetApplicationName(); + } else { + loader->ReadTitle(title); + } + + // Get icon from game file + std::vector 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(icon_image_file.size())); + + if (GMainWindow::MakeShortcutIcoPath(program_id, title, icons_path)) { + if (!SaveIconToFile(icon_data, icons_path)) { + LOG_ERROR(Frontend, "Could not write icon to file"); + } + } + + } else { + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, + title); + LOG_ERROR(Frontend, "[GMainWindow::OnGameListCreateShortcut] Invalid shortcut target"); + return; + } + +// Special case for AppImages #if defined(__linux__) // Warn once if we are making a shortcut to a volatile AppImage const std::string appimage_ending = std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); if (yuzu_command.string().ends_with(appimage_ending) && !UISettings::values.shortcut_already_warned) { - if (QMessageBox::warning(this, tr("Create Shortcut"), - tr("This will create a shortcut to the current AppImage. This may " - "not work well if you update. Continue?"), - QMessageBox::StandardButton::Ok | - QMessageBox::StandardButton::Cancel) == - QMessageBox::StandardButton::Cancel) { + if (GMainWindow::CreateShortcutMessagesGUI( + this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, title)) { return; } UISettings::values.shortcut_already_warned = true; } #endif // __linux__ - std::filesystem::path target_directory{}; - - switch (target) { - case GameListShortcutTarget::Desktop: { - const QString desktop_path = - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - target_directory = desktop_path.toUtf8().toStdString(); - break; + // Create shortcut + std::string arguments = fmt::format("-g \"{:s}\"", game_path); + if (GMainWindow::CreateShortcutMessagesGUI( + this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, title)) { + arguments = "-f " + arguments; } - case GameListShortcutTarget::Applications: { - const QString applications_path = - QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); - if (applications_path.isEmpty()) { - const char* home = std::getenv("HOME"); - if (home != nullptr) { - target_directory = std::filesystem::path(home) / ".local/share/applications"; - } - } else { - target_directory = applications_path.toUtf8().toStdString(); - } - break; - } - default: - return; - } - - const QDir dir(QString::fromStdString(target_directory.generic_string())); - if (!dir.exists()) { - QMessageBox::critical(this, tr("Create Shortcut"), - tr("Cannot create shortcut. Path \"%1\" does not exist.") - .arg(QString::fromStdString(target_directory.generic_string())), - QMessageBox::StandardButton::Ok); - return; - } - - const std::string game_file_name = std::filesystem::path(game_path).filename().string(); - // Determine full paths for icon and shortcut -#if defined(__linux__) || defined(__FreeBSD__) - const char* home = std::getenv("HOME"); - const std::filesystem::path home_path = (home == nullptr ? "~" : home); - const char* xdg_data_home = std::getenv("XDG_DATA_HOME"); - - std::filesystem::path system_icons_path = - (xdg_data_home == nullptr ? home_path / ".local/share/" - : std::filesystem::path(xdg_data_home)) / - "icons/hicolor/256x256"; - if (!Common::FS::CreateDirs(system_icons_path)) { - QMessageBox::critical( - this, tr("Create Icon"), - tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(system_icons_path)), - QMessageBox::StandardButton::Ok); - return; - } - std::filesystem::path icon_path = - system_icons_path / (program_id == 0 ? fmt::format("yuzu-{}.png", game_file_name) - : fmt::format("yuzu-{:016X}.png", program_id)); - const std::filesystem::path shortcut_path = - target_directory / (program_id == 0 ? fmt::format("yuzu-{}.desktop", game_file_name) - : fmt::format("yuzu-{:016X}.desktop", program_id)); -#elif defined(WIN32) - std::filesystem::path icons_path = - Common::FS::GetYuzuPathString(Common::FS::YuzuPath::IconsDir); - std::filesystem::path icon_path = - icons_path / ((program_id == 0 ? fmt::format("yuzu-{}.ico", game_file_name) - : fmt::format("yuzu-{:016X}.ico", program_id))); -#else - std::string icon_extension; -#endif - - // Get title from game file - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); - - std::string title{fmt::format("{:016X}", program_id)}; - - if (control.first != nullptr) { - title = control.first->GetApplicationName(); - } else { - loader->ReadTitle(title); - } - - // Get icon from game file - std::vector 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(icon_image_file.size())); -#if defined(__linux__) || defined(__FreeBSD__) - // Convert and write the icon as a PNG - if (!icon_data.save(QString::fromStdString(icon_path.string()))) { - LOG_ERROR(Frontend, "Could not write icon as PNG to file"); - } else { - LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); - } -#elif defined(WIN32) - if (!SaveIconToFile(icon_path.string(), icon_data)) { - LOG_ERROR(Frontend, "Could not write icon to file"); - return; - } -#endif // __linux__ - -#ifdef _WIN32 - // Replace characters that are illegal in Windows filenames by a dash - const std::string illegal_chars = "<>:\"/\\|?*"; - for (char c : illegal_chars) { - std::replace(title.begin(), title.end(), c, '_'); - } - const std::filesystem::path shortcut_path = target_directory / (title + ".lnk").c_str(); -#endif - const std::string comment = tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString(); - const std::string arguments = fmt::format("-g \"{:s}\"", game_path); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (!CreateShortcut(shortcut_path.string(), title, comment, icon_path.string(), - yuzu_command.string(), arguments, categories, keywords)) { - QMessageBox::critical(this, tr("Create Shortcut"), - tr("Failed to create a shortcut at %1") - .arg(QString::fromStdString(shortcut_path.string()))); + if (GMainWindow::CreateShortcutLink(shortcut_path, comment, icons_path, yuzu_command, arguments, + categories, keywords, title)) { + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, + title); return; } - LOG_INFO(Frontend, "Wrote a shortcut to {}", shortcut_path.string()); - QMessageBox::information( - this, tr("Create Shortcut"), - tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title))); + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, title); } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { @@ -3998,66 +4178,6 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file } } -bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title, - const std::string& comment, const std::string& icon_path, - const std::string& command, const std::string& arguments, - const std::string& categories, const std::string& keywords) { -#if defined(__linux__) || defined(__FreeBSD__) - // This desktop file template was writing referencing - // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html - std::string shortcut_contents{}; - shortcut_contents.append("[Desktop Entry]\n"); - shortcut_contents.append("Type=Application\n"); - shortcut_contents.append("Version=1.0\n"); - shortcut_contents.append(fmt::format("Name={:s}\n", title)); - shortcut_contents.append(fmt::format("Comment={:s}\n", comment)); - shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path)); - shortcut_contents.append(fmt::format("TryExec={:s}\n", command)); - shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments)); - shortcut_contents.append(fmt::format("Categories={:s}\n", categories)); - shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords)); - - std::ofstream shortcut_stream(shortcut_path); - if (!shortcut_stream.is_open()) { - LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path); - return false; - } - shortcut_stream << shortcut_contents; - shortcut_stream.close(); - - return true; -#elif defined(WIN32) - IShellLinkW* shell_link; - auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - (void**)&shell_link); - if (FAILED(hres)) { - return false; - } - shell_link->SetPath( - Common::UTF8ToUTF16W(command).data()); // Path to the object we are referring to - shell_link->SetArguments(Common::UTF8ToUTF16W(arguments).data()); - shell_link->SetDescription(Common::UTF8ToUTF16W(comment).data()); - shell_link->SetIconLocation(Common::UTF8ToUTF16W(icon_path).data(), 0); - - IPersistFile* persist_file; - hres = shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file); - if (FAILED(hres)) { - return false; - } - - hres = persist_file->Save(Common::UTF8ToUTF16W(shortcut_path).data(), TRUE); - if (FAILED(hres)) { - return false; - } - - persist_file->Release(); - shell_link->Release(); - - return true; -#endif - return false; -} - void GMainWindow::OnLoadAmiibo() { if (emu_thread == nullptr || !emu_thread->IsRunning()) { return; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 270a40c5f..bf6756b48 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -151,6 +152,14 @@ class GMainWindow : public QMainWindow { UI_EMU_STOPPING, }; + const enum { + CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, + CREATE_SHORTCUT_MSGBOX_SUCCESS, + CREATE_SHORTCUT_MSGBOX_ERROR, + CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, + CREATE_SHORTCUT_MSGBOX_ADMIN, + }; + public: void filterBarSetChecked(bool state); void UpdateUITheme(); @@ -433,11 +442,14 @@ private: bool ConfirmShutdownGame(); QString GetTasStateDescription() const; - bool CreateShortcut(const std::string& shortcut_path, const std::string& title, - const std::string& comment, const std::string& icon_path, - const std::string& command, const std::string& arguments, - const std::string& categories, const std::string& keywords); - + bool CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, const std::string title); + bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, + std::filesystem::path& icons_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); /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog * The only difference is that it returns a boolean. diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp index f2854c8ec..4d199ebd1 100644 --- a/src/yuzu/util/util.cpp +++ b/src/yuzu/util/util.cpp @@ -42,7 +42,7 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) { return circle_pixmap; } -bool SaveIconToFile(const std::string_view path, const QImage& image) { +bool SaveIconToFile(const QImage& image, const std::filesystem::path& icon_path) { #if defined(WIN32) #pragma pack(push, 2) struct IconDir { @@ -73,7 +73,7 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) { .id_count = static_cast(scale_sizes.size()), }; - Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write, + Common::FS::IOFile icon_file(icon_path.string(), Common::FS::FileAccessMode::Write, Common::FS::FileType::BinaryFile); if (!icon_file.IsOpen()) { return false; @@ -135,7 +135,16 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) { icon_file.Close(); return true; -#else - return false; +#elif defined(__linux__) || defined(__FreeBSD__) + // Convert and write the icon as a PNG + if (!image.save(QString::fromStdString(icon_path.string()))) { + LOG_ERROR(Frontend, "Could not write icon as PNG to file"); + } else { + LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); + } + + return true; #endif + + return false; } diff --git a/src/yuzu/util/util.h b/src/yuzu/util/util.h index 09c14ce3f..8839e160a 100644 --- a/src/yuzu/util/util.h +++ b/src/yuzu/util/util.h @@ -3,26 +3,36 @@ #pragma once +#include #include #include /// Returns a QFont object appropriate to use as a monospace font for debugging widgets, etc. + [[nodiscard]] QFont GetMonospaceFont(); /// Convert a size in bytes into a readable format (KiB, MiB, etc.) + [[nodiscard]] QString ReadableByteSize(qulonglong size); /** * Creates a circle pixmap from a specified color + * * @param color The color the pixmap shall have + * * @return QPixmap circle pixmap */ + [[nodiscard]] QPixmap CreateCirclePixmapFromColor(const QColor& color); /** * Saves a windows icon to a file - * @param path The icons path + * * @param image The image to save + * + * @param path The icons path + * * @return bool If the operation succeeded */ -[[nodiscard]] bool SaveIconToFile(const std::string_view path, const QImage& image); + +[[nodiscard]] bool SaveIconToFile(const QImage& image, const std::filesystem::path& icon_path); From 0a75519ab590e250c94dc04b3f6072a69ef7e96b Mon Sep 17 00:00:00 2001 From: boludoz Date: Sun, 15 Oct 2023 03:16:29 -0300 Subject: [PATCH 02/24] Fixes and improvements --- src/common/fs/path_util.cpp | 39 +++++++++++++++++++++++++++---------- src/yuzu/main.h | 2 +- src/yuzu/util/util.cpp | 4 ++-- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index a461161ed..f030939ce 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -363,13 +363,28 @@ fs::path GetDesktopPath() { LOG_ERROR(Common_Filesystem, "[GetDesktopPath] Failed to get the path to the desktop directory"); } -#else - fs::path shortcut_path = GetHomeDirectory() / "Desktop"; - if (fs::exists(shortcut_path)) { - return shortcut_path; - } -#endif return fs::path{}; +#else + fs::path shortcut_path{}; + + // Array of possible desktop + std::vector desktop_paths = { + "Desktop", "Escritorio", "Bureau", "Skrivebord", "Plocha", + "Skrivbord", "Desktop", "Рабочий стол", "Pulpit", "Área de Trabalho", + "Робочий стіл", "Bureaublad", "デスクトップ", "桌面", "Pöytä", + "바탕 화면", "바탕 화면", "سطح المكتب", "دسکتاپ", "שולחן עבודה"}; + + for (auto& path : desktop_paths) { + if (fs::exists(GetHomeDirectory() / path)) { + return path; + } + } + + LOG_ERROR(Common_Filesystem, + "[GetDesktopPath] Failed to get the path to the desktop directory"); + + return shortcut_path; +#endif } fs::path GetAppsShortcutsPath() { @@ -387,16 +402,20 @@ fs::path GetAppsShortcutsPath() { LOG_ERROR(Common_Filesystem, "[GetAppsShortcutsPath] Failed to get the path to the App Shortcuts directory"); } + + return fs::path{}; #else fs::path shortcut_path = GetHomeDirectory() / ".local/share/applications"; if (!fs::exists(shortcut_path)) { shortcut_path = std::filesystem::path("/usr/share/applications"); - return shortcut_path; - } else { - return shortcut_path; + if (!fs::exists(shortcut_path)) { + LOG_ERROR(Common_Filesystem, + "[GetAppsShortcutsPath] Failed to get the path to the App Shortcuts " + "directory"); + } } -#endif return fs::path{}; +#endif } // vvvvvvvvvv Deprecated vvvvvvvvvv // diff --git a/src/yuzu/main.h b/src/yuzu/main.h index bf6756b48..d7426607f 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -152,7 +152,7 @@ class GMainWindow : public QMainWindow { UI_EMU_STOPPING, }; - const enum { + enum { CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, CREATE_SHORTCUT_MSGBOX_SUCCESS, CREATE_SHORTCUT_MSGBOX_ERROR, diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp index 4d199ebd1..9755004ad 100644 --- a/src/yuzu/util/util.cpp +++ b/src/yuzu/util/util.cpp @@ -144,7 +144,7 @@ bool SaveIconToFile(const QImage& image, const std::filesystem::path& icon_path) } return true; -#endif - +#else return false; +#endif } From 4d4fe69223bd6cd053cbd2088e5925fb653a12d3 Mon Sep 17 00:00:00 2001 From: boludoz Date: Sun, 15 Oct 2023 14:44:23 -0300 Subject: [PATCH 03/24] Unnecessary feature removed --- src/common/fs/path_util.cpp | 70 ------------------------------------- src/common/fs/path_util.h | 15 +------- src/yuzu/main.cpp | 16 +++------ src/yuzu/util/util.h | 3 -- 4 files changed, 5 insertions(+), 99 deletions(-) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index f030939ce..bccf953e4 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -348,76 +348,6 @@ fs::path GetBundleDirectory() { #endif -fs::path GetDesktopPath() { -#if defined(_WIN32) - PWSTR DesktopPath = nullptr; - - if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &DesktopPath))) { - std::wstring wideDesktopPath(DesktopPath); - CoTaskMemFree(DesktopPath); - - // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with - // the Windows library (Filesystem converts the strings literally). - return fs::path{Common::UTF16ToUTF8(wideDesktopPath)}; - } else { - LOG_ERROR(Common_Filesystem, - "[GetDesktopPath] Failed to get the path to the desktop directory"); - } - return fs::path{}; -#else - fs::path shortcut_path{}; - - // Array of possible desktop - std::vector desktop_paths = { - "Desktop", "Escritorio", "Bureau", "Skrivebord", "Plocha", - "Skrivbord", "Desktop", "Рабочий стол", "Pulpit", "Área de Trabalho", - "Робочий стіл", "Bureaublad", "デスクトップ", "桌面", "Pöytä", - "바탕 화면", "바탕 화면", "سطح المكتب", "دسکتاپ", "שולחן עבודה"}; - - for (auto& path : desktop_paths) { - if (fs::exists(GetHomeDirectory() / path)) { - return path; - } - } - - LOG_ERROR(Common_Filesystem, - "[GetDesktopPath] Failed to get the path to the desktop directory"); - - return shortcut_path; -#endif -} - -fs::path GetAppsShortcutsPath() { -#if defined(_WIN32) - PWSTR AppShortcutsPath = nullptr; - - if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_CommonPrograms, 0, NULL, &AppShortcutsPath))) { - std::wstring wideAppShortcutsPath(AppShortcutsPath); - CoTaskMemFree(AppShortcutsPath); - - // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with - // the Windows library (Filesystem converts the strings literally). - return fs::path{Common::UTF16ToUTF8(wideAppShortcutsPath)}; - } else { - LOG_ERROR(Common_Filesystem, - "[GetAppsShortcutsPath] Failed to get the path to the App Shortcuts directory"); - } - - return fs::path{}; -#else - fs::path shortcut_path = GetHomeDirectory() / ".local/share/applications"; - if (!fs::exists(shortcut_path)) { - shortcut_path = std::filesystem::path("/usr/share/applications"); - if (!fs::exists(shortcut_path)) { - LOG_ERROR(Common_Filesystem, - "[GetAppsShortcutsPath] Failed to get the path to the App Shortcuts " - "directory"); - } - } - return fs::path{}; -#endif -} - // vvvvvvvvvv Deprecated vvvvvvvvvv // std::string_view RemoveTrailingSlash(std::string_view path) { diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index b88a388d1..63801c924 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -244,6 +244,7 @@ void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) { * @returns The path of the current user's %APPDATA% directory. */ [[nodiscard]] std::filesystem::path GetAppDataRoamingDirectory(); + #else /** @@ -274,20 +275,6 @@ void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) { #endif -/** - * Gets the path of the current user's desktop directory. - * - * @returns The path of the current user's desktop directory. - */ -[[nodiscard]] std::filesystem::path GetDesktopPath(); - -/** - * Gets the path of the current user's apps directory. - * - * @returns The path of the current user's apps directory. - */ -[[nodiscard]] std::filesystem::path GetAppsShortcutsPath(); - // vvvvvvvvvv Deprecated vvvvvvvvvv // // Removes the final '/' or '\' if one exists diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e4dc717ed..fd68ac9b6 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3082,13 +3082,9 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga // Shortcut path std::filesystem::path shortcut_path{}; if (target == GameListShortcutTarget::Desktop) { - shortcut_path = Common::FS::GetDesktopPath(); - if (!std::filesystem::exists(shortcut_path)) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); - } + shortcut_path = + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); } else if (target == GameListShortcutTarget::Applications) { - #if defined(_WIN32) HANDLE hProcess = GetCurrentProcess(); if (!IsUserAnAdmin()) { @@ -3098,12 +3094,8 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } CloseHandle(hProcess); #endif // _WIN32 - - shortcut_path = Common::FS::GetAppsShortcutsPath(); - if (!std::filesystem::exists(shortcut_path)) { - shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) - .toStdString(); - } + shortcut_path = + QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); } // Icon path and title diff --git a/src/yuzu/util/util.h b/src/yuzu/util/util.h index 8839e160a..31e82ff67 100644 --- a/src/yuzu/util/util.h +++ b/src/yuzu/util/util.h @@ -8,11 +8,9 @@ #include /// Returns a QFont object appropriate to use as a monospace font for debugging widgets, etc. - [[nodiscard]] QFont GetMonospaceFont(); /// Convert a size in bytes into a readable format (KiB, MiB, etc.) - [[nodiscard]] QString ReadableByteSize(qulonglong size); /** @@ -34,5 +32,4 @@ * * @return bool If the operation succeeded */ - [[nodiscard]] bool SaveIconToFile(const QImage& image, const std::filesystem::path& icon_path); From 9ffa1801c75073afb851351ecdd1a8b40e33cc5c Mon Sep 17 00:00:00 2001 From: boludoz Date: Sun, 15 Oct 2023 20:57:06 -0300 Subject: [PATCH 04/24] Typing and formatting errors fixed. --- src/common/fs/fs_util.cpp | 44 ++++++++++++++++++------------------- src/common/fs/fs_util.h | 8 +++---- src/common/fs/path_util.cpp | 8 +++---- src/yuzu/main.cpp | 24 ++++++++++---------- src/yuzu/util/util.cpp | 3 +-- src/yuzu/util/util.h | 10 ++------- 6 files changed, 43 insertions(+), 54 deletions(-) diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index 442f63728..e77958224 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp @@ -36,21 +36,21 @@ std::string PathToUTF8String(const std::filesystem::path& path) { return ToUTF8String(path.u8string()); } -std::u8string U8FilenameSantizer(const std::u8string_view u8filename) { - std::u8string u8path_santized{u8filename.begin(), u8filename.end()}; - size_t eSizeSanitized = u8path_santized.size(); +std::u8string U8FilenameSanitizer(const std::u8string_view u8filename) { + std::u8string u8path_sanitized{u8filename.begin(), u8filename.end()}; + size_t eSizeSanitized = u8path_sanitized.size(); - // Special case for ":", for example: 'Pepe: La secuela' --> 'Pepe - La - // secuela' or 'Pepe : La secuela' --> 'Pepe - La secuela' + // The name is improved to make it look more beautiful and prohibited characters and shapes are + // removed. Switch is used since it is better with many conditions. for (size_t i = 0; i < eSizeSanitized; i++) { - switch (u8path_santized[i]) { + switch (u8path_sanitized[i]) { case u8':': if (i == 0 || i == eSizeSanitized - 1) { - u8path_santized.replace(i, 1, u8"_"); - } else if (u8path_santized[i - 1] == u8' ') { - u8path_santized.replace(i, 1, u8"-"); + u8path_sanitized.replace(i, 1, u8"_"); + } else if (u8path_sanitized[i - 1] == u8' ') { + u8path_sanitized.replace(i, 1, u8"-"); } else { - u8path_santized.replace(i, 1, u8" -"); + u8path_sanitized.replace(i, 1, u8" -"); eSizeSanitized++; } break; @@ -63,36 +63,36 @@ std::u8string U8FilenameSantizer(const std::u8string_view u8filename) { case u8'>': case u8'|': case u8'\0': - u8path_santized.replace(i, 1, u8"_"); + u8path_sanitized.replace(i, 1, u8"_"); break; default: break; } } - // Delete duplicated spaces || Delete duplicated dots (MacOS i think) + // Delete duplicated spaces and dots for (size_t i = 0; i < eSizeSanitized - 1; i++) { - if ((u8path_santized[i] == u8' ' && u8path_santized[i + 1] == u8' ') || - (u8path_santized[i] == u8'.' && u8path_santized[i + 1] == u8'.')) { - u8path_santized.erase(i, 1); + if ((u8path_sanitized[i] == u8' ' && u8path_sanitized[i + 1] == u8' ') || + (u8path_sanitized[i] == u8'.' && u8path_sanitized[i + 1] == u8'.')) { + u8path_sanitized.erase(i, 1); i--; } } - // Delete all spaces and dots at the end (Windows almost) - while (u8path_santized.back() == u8' ' || u8path_santized.back() == u8'.') { - u8path_santized.pop_back(); + // Delete all spaces and dots at the end of the name + while (u8path_sanitized.back() == u8' ' || u8path_sanitized.back() == u8'.') { + u8path_sanitized.pop_back(); } - if (u8path_santized.empty()) { + if (u8path_sanitized.empty()) { return u8""; } - return u8path_santized; + return u8path_sanitized; } -std::string UTF8FilenameSantizer(const std::string_view filename) { - return ToUTF8String(U8FilenameSantizer(ToU8String(filename))); +std::string UTF8FilenameSanitizer(const std::string_view filename) { + return ToUTF8String(U8FilenameSanitizer(ToU8String(filename))); } } // namespace Common::FS diff --git a/src/common/fs/fs_util.h b/src/common/fs/fs_util.h index dbb4f5a9a..daec1f8cb 100644 --- a/src/common/fs/fs_util.h +++ b/src/common/fs/fs_util.h @@ -87,19 +87,19 @@ concept IsChar = std::same_as; * * @param u8_string dirty encoded filename string * - * @returns utf8_string santized filename string + * @returns utf8_string sanitized filename string * */ -[[nodiscard]] std::u8string U8FilenameSantizer(const std::u8string_view u8filename); +[[nodiscard]] std::u8string U8FilenameSanitizer(const std::u8string_view u8filename); /** * Fix filename (remove invalid characters) * * @param utf8_string dirty encoded filename string * - * @returns utf8_string santized filename string + * @returns utf8_string sanitized filename string * */ -[[nodiscard]] std::string UTF8FilenameSantizer(const std::string_view filename); +[[nodiscard]] std::string UTF8FilenameSanitizer(const std::string_view filename); } // namespace Common::FS \ No newline at end of file diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index bccf953e4..3d88fcf4f 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -260,9 +260,8 @@ fs::path GetExeDirectory() { // the Windows library (Filesystem converts the strings literally). return fs::path{Common::UTF16ToUTF8(wideExePath)}.parent_path(); } else { - LOG_ERROR(Common_Filesystem, - "[GetExeDirectory] Failed to get the path to the executable of the current " - "process"); + LOG_ERROR(Common_Filesystem, "Failed to get the path to the executable of the current " + "process"); } return fs::path{}; @@ -279,8 +278,7 @@ fs::path GetAppDataRoamingDirectory() { // the Windows library (Filesystem converts the strings literally). return fs::path{Common::UTF16ToUTF8(wideAppdataRoamingPath)}; } else { - LOG_ERROR(Common_Filesystem, - "[GetAppDataRoamingDirectory] Failed to get the path to the %APPDATA% directory"); + LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); } return fs::path{}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index fd68ac9b6..c3c12eeec 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2851,7 +2851,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, // Replace characters that are illegal in Windows filenames std::filesystem::path shortcut_path_full = - shortcut_path / Common::FS::UTF8FilenameSantizer(name); + shortcut_path / Common::FS::UTF8FilenameSanitizer(name); #if defined(__linux__) || defined(__FreeBSD__) shortcut_path_full += ".desktop"; @@ -2859,8 +2859,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, shortcut_path_full += ".lnk"; #endif - LOG_INFO(Common, "[GMainWindow::CreateShortcutLink] Create shortcut path: {}", - shortcut_path_full.string()); + LOG_ERROR(Frontend, "Create shortcut path: {}", shortcut_path_full.string()); #if defined(__linux__) || defined(__FreeBSD__) // This desktop file template was writing referencing @@ -2869,7 +2868,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, // Plus 'Type' is required if (name.empty()) { - LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Name is empty"); + LOG_ERROR(Frontend, "Name is empty"); shortcut_succeeded = false; return shortcut_succeeded; } @@ -2911,14 +2910,13 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, return true; } else { - LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Failed to create shortcut"); + LOG_ERROR(Frontend, "Failed to create shortcut"); return false; } shortcut_stream.close(); } catch (const std::exception& e) { - LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Failed to create shortcut: {}", - e.what()); + LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); } #elif defined(_WIN32) // Initialize COM @@ -2970,7 +2968,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, pPersistFile->Release(); } } else { - LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Failed to create IShellLinkWinstance"); + LOG_ERROR(Frontend, "Failed to create IShellLinkWinstance"); } ps1->Release(); @@ -2978,9 +2976,9 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, #endif if (shortcut_succeeded && std::filesystem::is_regular_file(shortcut_path_full)) { - LOG_INFO(Common, "[GMainWindow::CreateShortcutLink] Shortcut created"); + LOG_ERROR(Frontend, "Shortcut created"); } else { - LOG_ERROR(Common, "[GMainWindow::CreateShortcutLink] Shortcut error, failed to create it"); + LOG_ERROR(Frontend, "Shortcut error, failed to create it"); shortcut_succeeded = false; } @@ -3047,7 +3045,7 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi icons_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons"; ico_extension = "ico"; #elif defined(__linux__) || defined(__FreeBSD__) - icons_path = GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; + icons_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; #endif // Create icons directory if it doesn't exist @@ -3130,7 +3128,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); if (GMainWindow::MakeShortcutIcoPath(program_id, title, icons_path)) { - if (!SaveIconToFile(icon_data, icons_path)) { + if (!SaveIconToFile(icons_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } } @@ -3138,7 +3136,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } else { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, title); - LOG_ERROR(Frontend, "[GMainWindow::OnGameListCreateShortcut] Invalid shortcut target"); + LOG_ERROR(Frontend, "Invalid shortcut target"); return; } diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp index 9755004ad..7b2a47496 100644 --- a/src/yuzu/util/util.cpp +++ b/src/yuzu/util/util.cpp @@ -42,7 +42,7 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) { return circle_pixmap; } -bool SaveIconToFile(const QImage& image, const std::filesystem::path& icon_path) { +bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) { #if defined(WIN32) #pragma pack(push, 2) struct IconDir { @@ -142,7 +142,6 @@ bool SaveIconToFile(const QImage& image, const std::filesystem::path& icon_path) } else { LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); } - return true; #else return false; diff --git a/src/yuzu/util/util.h b/src/yuzu/util/util.h index 31e82ff67..4094cf6c2 100644 --- a/src/yuzu/util/util.h +++ b/src/yuzu/util/util.h @@ -15,21 +15,15 @@ /** * Creates a circle pixmap from a specified color - * * @param color The color the pixmap shall have - * * @return QPixmap circle pixmap */ - [[nodiscard]] QPixmap CreateCirclePixmapFromColor(const QColor& color); /** * Saves a windows icon to a file - * - * @param image The image to save - * * @param path The icons path - * + * @param image The image to save * @return bool If the operation succeeded */ -[[nodiscard]] bool SaveIconToFile(const QImage& image, const std::filesystem::path& icon_path); +[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image); From 74961d4dfb394c098da494f6beacdd994c089566 Mon Sep 17 00:00:00 2001 From: boludoz Date: Sun, 15 Oct 2023 21:40:10 -0300 Subject: [PATCH 05/24] Less code, simpler, better. --- src/common/fs/fs_util.cpp | 59 --------------------------------------- src/common/fs/fs_util.h | 22 +-------------- src/yuzu/main.cpp | 16 +++++++++-- 3 files changed, 15 insertions(+), 82 deletions(-) diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index e77958224..813a713c3 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp @@ -36,63 +36,4 @@ std::string PathToUTF8String(const std::filesystem::path& path) { return ToUTF8String(path.u8string()); } -std::u8string U8FilenameSanitizer(const std::u8string_view u8filename) { - std::u8string u8path_sanitized{u8filename.begin(), u8filename.end()}; - size_t eSizeSanitized = u8path_sanitized.size(); - - // The name is improved to make it look more beautiful and prohibited characters and shapes are - // removed. Switch is used since it is better with many conditions. - for (size_t i = 0; i < eSizeSanitized; i++) { - switch (u8path_sanitized[i]) { - case u8':': - if (i == 0 || i == eSizeSanitized - 1) { - u8path_sanitized.replace(i, 1, u8"_"); - } else if (u8path_sanitized[i - 1] == u8' ') { - u8path_sanitized.replace(i, 1, u8"-"); - } else { - u8path_sanitized.replace(i, 1, u8" -"); - eSizeSanitized++; - } - break; - case u8'\\': - case u8'/': - case u8'*': - case u8'?': - case u8'\"': - case u8'<': - case u8'>': - case u8'|': - case u8'\0': - u8path_sanitized.replace(i, 1, u8"_"); - break; - default: - break; - } - } - - // Delete duplicated spaces and dots - for (size_t i = 0; i < eSizeSanitized - 1; i++) { - if ((u8path_sanitized[i] == u8' ' && u8path_sanitized[i + 1] == u8' ') || - (u8path_sanitized[i] == u8'.' && u8path_sanitized[i + 1] == u8'.')) { - u8path_sanitized.erase(i, 1); - i--; - } - } - - // Delete all spaces and dots at the end of the name - while (u8path_sanitized.back() == u8' ' || u8path_sanitized.back() == u8'.') { - u8path_sanitized.pop_back(); - } - - if (u8path_sanitized.empty()) { - return u8""; - } - - return u8path_sanitized; -} - -std::string UTF8FilenameSanitizer(const std::string_view filename) { - return ToUTF8String(U8FilenameSanitizer(ToU8String(filename))); -} - } // namespace Common::FS diff --git a/src/common/fs/fs_util.h b/src/common/fs/fs_util.h index daec1f8cb..2492a9f94 100644 --- a/src/common/fs/fs_util.h +++ b/src/common/fs/fs_util.h @@ -82,24 +82,4 @@ concept IsChar = std::same_as; */ [[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path); -/** - * Fix filename (remove invalid characters) - * - * @param u8_string dirty encoded filename string - * - * @returns utf8_string sanitized filename string - * - */ -[[nodiscard]] std::u8string U8FilenameSanitizer(const std::u8string_view u8filename); - -/** - * Fix filename (remove invalid characters) - * - * @param utf8_string dirty encoded filename string - * - * @returns utf8_string sanitized filename string - * - */ -[[nodiscard]] std::string UTF8FilenameSanitizer(const std::string_view filename); - -} // namespace Common::FS \ No newline at end of file +} // namespace Common::FS diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c3c12eeec..f2b91a7f3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2849,9 +2849,21 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, bool shortcut_succeeded = false; + // Copy characters if they are not illegal in Windows filenames + std::string filename = ""; + const std::string illegal_chars = "<>:\"/\\|?*"; + filename.reserve(name.size()); + std::copy_if(name.begin(), name.end(), std::back_inserter(filename), + [&illegal_chars](char c) { return illegal_chars.find(c) == std::string::npos; }); + + if (filename.empty()) { + LOG_ERROR(Frontend, "Filename is empty"); + shortcut_succeeded = false; + return shortcut_succeeded; + } + // Replace characters that are illegal in Windows filenames - std::filesystem::path shortcut_path_full = - shortcut_path / Common::FS::UTF8FilenameSanitizer(name); + std::filesystem::path shortcut_path_full = shortcut_path / filename; #if defined(__linux__) || defined(__FreeBSD__) shortcut_path_full += ".desktop"; From 26417da5d36ea5aae4410a5c35405e27f39661d2 Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 03:26:40 -0300 Subject: [PATCH 06/24] Some improvements (suggestions) --- src/common/fs/path_util.cpp | 10 +-- src/yuzu/main.cpp | 162 +++++++++++++++++------------------- src/yuzu/main.h | 2 +- 3 files changed, 81 insertions(+), 93 deletions(-) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 3d88fcf4f..bcd64156e 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -254,11 +254,8 @@ fs::path GetExeDirectory() { WCHAR exe_path[MAX_PATH]; if (SUCCEEDED(GetModuleFileNameW(nullptr, exe_path, MAX_PATH))) { - std::wstring wideExePath(exe_path); - - // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with - // the Windows library (Filesystem converts the strings literally). - return fs::path{Common::UTF16ToUTF8(wideExePath)}.parent_path(); + std::wstring wide_exe_path(exe_path); + return fs::path{Common::UTF16ToUTF8(wide_exe_path)}.parent_path(); } else { LOG_ERROR(Common_Filesystem, "Failed to get the path to the executable of the current " "process"); @@ -273,9 +270,6 @@ fs::path GetAppDataRoamingDirectory() { if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) { std::wstring wideAppdataRoamingPath(appdata_roaming_path); CoTaskMemFree(appdata_roaming_path); - - // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with - // the Windows library (Filesystem converts the strings literally). return fs::path{Common::UTF16ToUTF8(wideAppdataRoamingPath)}; } else { LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f2b91a7f3..36f9551a1 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2847,8 +2847,6 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name) { - bool shortcut_succeeded = false; - // Copy characters if they are not illegal in Windows filenames std::string filename = ""; const std::string illegal_chars = "<>:\"/\\|?*"; @@ -2858,22 +2856,13 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, if (filename.empty()) { LOG_ERROR(Frontend, "Filename is empty"); - shortcut_succeeded = false; - return shortcut_succeeded; + return false; } - // Replace characters that are illegal in Windows filenames + // Append .desktop or .lnk extension std::filesystem::path shortcut_path_full = shortcut_path / filename; -#if defined(__linux__) || defined(__FreeBSD__) - shortcut_path_full += ".desktop"; -#elif defined(_WIN32) - shortcut_path_full += ".lnk"; -#endif - - LOG_ERROR(Frontend, "Create shortcut path: {}", shortcut_path_full.string()); - -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD // This desktop file template was writing referencing // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html try { @@ -2881,9 +2870,13 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, // Plus 'Type' is required if (name.empty()) { LOG_ERROR(Frontend, "Name is empty"); - shortcut_succeeded = false; - return shortcut_succeeded; + return false; } + + // Append .desktop extension + shortcut_path_full += ".desktop"; + + // Create shortcut file std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); if (shortcut_stream.is_open()) { @@ -2923,78 +2916,82 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, } else { LOG_ERROR(Frontend, "Failed to create shortcut"); - return false; } shortcut_stream.close(); } catch (const std::exception& e) { LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); } -#elif defined(_WIN32) - // Initialize COM - auto hr = CoInitialize(NULL); - if (FAILED(hr)) { - return shortcut_succeeded; - } + return false; +#elif defined(_WIN32) // Windows + HRESULT hr = CoInitialize(NULL); + if (SUCCEEDED(hr)) { - IShellLinkW* ps1; + IShellLinkW* ps1 = nullptr; + IPersistFile* persist_file = nullptr; - auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - (void**)&ps1); + SCOPE_EXIT({ + if (persist_file != nullptr) { + persist_file->Release(); + } + if (ps1 != nullptr) { + ps1->Release(); + } - // The UTF-16 / UTF-8 conversion is broken in C++, it is necessary to perform these steps and - // resort to the native Windows function. - std::wstring wshortcut_path_full = Common::UTF8ToUTF16W(shortcut_path_full.string()); - std::wstring wicon_path = Common::UTF8ToUTF16W(icon_path.string()); - std::wstring wcommand = Common::UTF8ToUTF16W(command.string()); - std::wstring warguments = Common::UTF8ToUTF16W(arguments); - std::wstring wcomment = Common::UTF8ToUTF16W(comment); + CoUninitialize(); + }); - if (SUCCEEDED(hres)) { - if (std::filesystem::is_regular_file(command)) - hres = ps1->SetPath(wcommand.data()); + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLinkW, (void**)&ps1); - if (SUCCEEDED(hres) && !arguments.empty()) - hres = ps1->SetArguments(warguments.data()); - - if (SUCCEEDED(hres) && !comment.empty()) - hres = ps1->SetDescription(wcomment.data()); - - if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) - hres = ps1->SetIconLocation(wicon_path.data(), 0); - - IPersistFile* pPersistFile = nullptr; + std::wstring wshortcut_path_full = Common::UTF8ToUTF16W(shortcut_path_full.string()); + std::wstring wicon_path = Common::UTF8ToUTF16W(icon_path.string()); + std::wstring wcommand = Common::UTF8ToUTF16W(command.string()); + std::wstring warguments = Common::UTF8ToUTF16W(arguments); + std::wstring wcomment = Common::UTF8ToUTF16W(comment); if (SUCCEEDED(hres)) { - hres = ps1->QueryInterface(IID_IPersistFile, (void**)&pPersistFile); + if (std::filesystem::is_regular_file(command)) { + hres = ps1->SetPath(wcommand.data()); + } else { + LOG_ERROR(Frontend, "Command is not a regular file"); + return false; + } - if (SUCCEEDED(hres) && pPersistFile != nullptr) { - hres = pPersistFile->Save(wshortcut_path_full.data(), TRUE); + if (SUCCEEDED(hres) && !arguments.empty()) { + hres = ps1->SetArguments(warguments.data()); + } + + if (SUCCEEDED(hres) && !comment.empty()) { + hres = ps1->SetDescription(wcomment.data()); + } + + if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) { + hres = ps1->SetIconLocation(wicon_path.data(), 0); + } + + if (SUCCEEDED(hres)) { + hres = ps1->QueryInterface(IID_IPersistFile, (void**)&persist_file); + } + + if (SUCCEEDED(hres) && persist_file != nullptr) { + // Append .lnk extension and save shortcut + shortcut_path_full += ".lnk"; + hres = persist_file->Save(wshortcut_path_full.data(), TRUE); if (SUCCEEDED(hres)) { - shortcut_succeeded = true; + return true; + } else { + LOG_ERROR(Frontend, "Failed to create shortcut"); } } + } else { + LOG_ERROR(Frontend, "Failed to create CoCreateInstance"); } - - if (pPersistFile != nullptr) { - pPersistFile->Release(); - } - } else { - LOG_ERROR(Frontend, "Failed to create IShellLinkWinstance"); } - - ps1->Release(); - CoUninitialize(); + return false; +#else // Unsupported platform + return false; #endif - - if (shortcut_succeeded && std::filesystem::is_regular_file(shortcut_path_full)) { - LOG_ERROR(Frontend, "Shortcut created"); - } else { - LOG_ERROR(Frontend, "Shortcut error, failed to create it"); - shortcut_succeeded = false; - } - - return shortcut_succeeded; } // Messages in pre-defined message boxes for less code spaghetti @@ -3049,31 +3046,31 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, } bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& icons_path) { + std::filesystem::path& out_icon_path) { // Get path to Yuzu icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) - icons_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons"; + out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons"; ico_extension = "ico"; #elif defined(__linux__) || defined(__FreeBSD__) - icons_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; + 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(icons_path)) { + 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(icons_path.string())), + .arg(QString::fromStdString(out_icon_path.string())), QMessageBox::StandardButton::Ok); - icons_path = ""; // Reset path + out_icon_path = ""; // Reset path return false; } // Create icon file path - icons_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension) - : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); + out_icon_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension) + : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); return true; } @@ -3096,13 +3093,11 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); } else if (target == GameListShortcutTarget::Applications) { #if defined(_WIN32) - HANDLE hProcess = GetCurrentProcess(); if (!IsUserAnAdmin()) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN, ""); return; } - CloseHandle(hProcess); #endif // _WIN32 shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); @@ -3110,9 +3105,8 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga // Icon path and title std::string title; - std::filesystem::path icons_path; + std::filesystem::path out_icon_path; if (std::filesystem::exists(shortcut_path)) { - // Get title from game file const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), system->GetContentProvider()}; @@ -3139,8 +3133,8 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); - if (GMainWindow::MakeShortcutIcoPath(program_id, title, icons_path)) { - if (!SaveIconToFile(icons_path, icon_data)) { + if (GMainWindow::MakeShortcutIcoPath(program_id, title, out_icon_path)) { + if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } } @@ -3178,8 +3172,8 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (GMainWindow::CreateShortcutLink(shortcut_path, comment, icons_path, yuzu_command, arguments, - categories, keywords, title)) { + if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, yuzu_command, + arguments, categories, keywords, title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, title); return; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index d7426607f..d3a1bf5b9 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -444,7 +444,7 @@ private: QString GetTasStateDescription() const; bool CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, const std::string title); bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& icons_path); + 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, From 89d3e81be8b923711a548b0973276353392449a6 Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 16:01:46 -0300 Subject: [PATCH 07/24] Sugestions and fixes. --- src/common/fs/path_util.cpp | 4 +- src/yuzu/main.cpp | 104 ++++++++++++++++++------------------ src/yuzu/main.h | 2 +- 3 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index bcd64156e..60c5e477e 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -268,9 +268,9 @@ fs::path GetAppDataRoamingDirectory() { PWSTR appdata_roaming_path = nullptr; if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) { - std::wstring wideAppdataRoamingPath(appdata_roaming_path); + std::wstring wide_appdata_roaming_path(appdata_roaming_path); CoTaskMemFree(appdata_roaming_path); - return fs::path{Common::UTF16ToUTF8(wideAppdataRoamingPath)}; + return fs::path{Common::UTF16ToUTF8(wide_appdata_roaming_path)}; } else { LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 36f9551a1..feb455763 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2859,11 +2859,15 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, return false; } - // Append .desktop or .lnk extension + if (!std::filesystem::is_regular_file(command)) { + LOG_ERROR(Frontend, "Command is not a regular file"); + return false; + } + std::filesystem::path shortcut_path_full = shortcut_path / filename; #if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD - // This desktop file template was writing referencing + // Reference for the desktop file template: // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html try { @@ -2911,17 +2915,17 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, fmt::print(shortcut_stream, "Keywords={}\n", keywords); } + // Flush and close file + shortcut_stream.flush(); shortcut_stream.close(); return true; - } else { LOG_ERROR(Frontend, "Failed to create shortcut"); } - - shortcut_stream.close(); } catch (const std::exception& e) { LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); } + shortcut_stream.close(); return false; #elif defined(_WIN32) // Windows HRESULT hr = CoInitialize(NULL); @@ -2944,19 +2948,15 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void**)&ps1); - std::wstring wshortcut_path_full = Common::UTF8ToUTF16W(shortcut_path_full.string()); + std::wstring wshortcut_path_full = + Common::UTF8ToUTF16W((shortcut_path_full).string() + ".lnk"); std::wstring wicon_path = Common::UTF8ToUTF16W(icon_path.string()); std::wstring wcommand = Common::UTF8ToUTF16W(command.string()); std::wstring warguments = Common::UTF8ToUTF16W(arguments); std::wstring wcomment = Common::UTF8ToUTF16W(comment); if (SUCCEEDED(hres)) { - if (std::filesystem::is_regular_file(command)) { - hres = ps1->SetPath(wcommand.data()); - } else { - LOG_ERROR(Frontend, "Command is not a regular file"); - return false; - } + hres = ps1->SetPath(wcommand.data()); if (SUCCEEDED(hres) && !arguments.empty()) { hres = ps1->SetArguments(warguments.data()); @@ -2975,8 +2975,6 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, } if (SUCCEEDED(hres) && persist_file != nullptr) { - // Append .lnk extension and save shortcut - shortcut_path_full += ".lnk"; hres = persist_file->Save(wshortcut_path_full.data(), TRUE); if (SUCCEEDED(hres)) { return true; @@ -2995,9 +2993,10 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, } // Messages in pre-defined message boxes for less code spaghetti -bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, - const std::string title) { +bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { QMessageBox::StandardButtons buttons; + std::string_view game_title_sv = game_title.toStdString(); + int result = 0; switch (imsg) { @@ -3013,18 +3012,18 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, return (result == QMessageBox::No) ? false : true; case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: - QMessageBox::information( - parent, tr("Create Shortcut"), - tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title))); - LOG_INFO(Frontend, "Successfully created a shortcut to {}", title); + QMessageBox::information(parent, tr("Create Shortcut"), + tr("Successfully created a shortcut to %1").arg(game_title)); + LOG_INFO(Frontend, "Successfully created a shortcut to {}", game_title_sv); return true; case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: - result = QMessageBox::warning( - this, tr("Create Shortcut"), - tr("This will create a shortcut to the current AppImage. This may " - "not work well if you update. Continue?"), - QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel); + buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; + result = + QMessageBox::warning(this, tr("Create Shortcut"), + tr("This will create a shortcut to the current AppImage. This may " + "not work well if you update. Continue?"), + buttons); return (result == QMessageBox::StandardButton::Cancel) ? true : false; case GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN: buttons = QMessageBox::Ok; @@ -3035,10 +3034,9 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, return true; default: buttons = QMessageBox::Ok; - QMessageBox::critical( - parent, tr("Create Shortcut"), - tr("Failed to create a shortcut to %1").arg(QString::fromStdString(title)), buttons); - LOG_ERROR(Frontend, "Failed to create a shortcut to {}", title); + QMessageBox::critical(parent, tr("Create Shortcut"), + tr("Failed to create a shortcut to %1").arg(game_title), buttons); + LOG_ERROR(Frontend, "Failed to create a shortcut to {}", game_title_sv); return true; } @@ -3077,6 +3075,10 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { + std::string game_title; + QString qt_game_title; + std::filesystem::path out_icon_path; + // Get path to yuzu executable const QStringList args = QApplication::arguments(); std::filesystem::path yuzu_command = args[0].toStdString(); @@ -3092,20 +3094,11 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga shortcut_path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); } else if (target == GameListShortcutTarget::Applications) { -#if defined(_WIN32) - if (!IsUserAnAdmin()) { - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN, - ""); - return; - } -#endif // _WIN32 shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); } // Icon path and title - std::string title; - std::filesystem::path out_icon_path; if (std::filesystem::exists(shortcut_path)) { // Get title from game file const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), @@ -3114,14 +3107,16 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); - title = fmt::format("{:016X}", program_id); + game_title = fmt::format("{:016X}", program_id); if (control.first != nullptr) { - title = control.first->GetApplicationName(); + game_title = control.first->GetApplicationName(); } else { - loader->ReadTitle(title); + loader->ReadTitle(game_title); } + qt_game_title = QString::fromStdString(game_title); + // Get icon from game file std::vector icon_image_file{}; if (control.second != nullptr) { @@ -3133,7 +3128,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); - if (GMainWindow::MakeShortcutIcoPath(program_id, title, out_icon_path)) { + if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } @@ -3141,20 +3136,26 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } else { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, - title); + qt_game_title); LOG_ERROR(Frontend, "Invalid shortcut target"); return; } -// Special case for AppImages -#if defined(__linux__) +#if defined(_WIN32) + if (!IsUserAnAdmin() && target == GameListShortcutTarget::Applications) { + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN, + qt_game_title); + return; + } +#elif defined(__linux__) + // Special case for AppImages // Warn once if we are making a shortcut to a volatile AppImage const std::string appimage_ending = std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); if (yuzu_command.string().ends_with(appimage_ending) && !UISettings::values.shortcut_already_warned) { if (GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, title)) { + this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, qt_game_title)) { return; } UISettings::values.shortcut_already_warned = true; @@ -3164,22 +3165,23 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga // Create shortcut std::string arguments = fmt::format("-g \"{:s}\"", game_path); if (GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, title)) { + this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qt_game_title)) { arguments = "-f " + arguments; } const std::string comment = - tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString(); + tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(game_title)).toStdString(); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, yuzu_command, - arguments, categories, keywords, title)) { + arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, - title); + qt_game_title); return; } - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, title); + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, + qt_game_title); } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index d3a1bf5b9..41902cc8d 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -442,7 +442,7 @@ private: bool ConfirmShutdownGame(); QString GetTasStateDescription() const; - bool CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, const std::string title); + 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, From d759de9f96faa8f530b3724b79ccc04ab0d01a09 Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 16:11:24 -0300 Subject: [PATCH 08/24] More missed suggestions --- src/yuzu/main.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index feb455763..90bb61c15 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2995,12 +2995,10 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, // Messages in pre-defined message boxes for less code spaghetti bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { QMessageBox::StandardButtons buttons; - std::string_view game_title_sv = game_title.toStdString(); int result = 0; switch (imsg) { - case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES: buttons = QMessageBox::Yes | QMessageBox::No; @@ -3009,12 +3007,11 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt tr("Do you want to launch the game in fullscreen?"), buttons); LOG_INFO(Frontend, "Shortcut will launch in fullscreen"); - return (result == QMessageBox::No) ? false : true; + return result == QMessageBox::Yes; case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: QMessageBox::information(parent, tr("Create Shortcut"), tr("Successfully created a shortcut to %1").arg(game_title)); - LOG_INFO(Frontend, "Successfully created a shortcut to {}", game_title_sv); return true; case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: @@ -3024,7 +3021,7 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt tr("This will create a shortcut to the current AppImage. This may " "not work well if you update. Continue?"), buttons); - return (result == QMessageBox::StandardButton::Cancel) ? true : false; + return result == QMessageBox::StandardButton::Ok; case GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN: buttons = QMessageBox::Ok; QMessageBox::critical(parent, tr("Create Shortcut"), @@ -3036,7 +3033,6 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt buttons = QMessageBox::Ok; QMessageBox::critical(parent, tr("Create Shortcut"), tr("Failed to create a shortcut to %1").arg(game_title), buttons); - LOG_ERROR(Frontend, "Failed to create a shortcut to {}", game_title_sv); return true; } From ae88d01d8dfc9c39206d3fb37938e44a3480c70f Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 16:47:21 -0300 Subject: [PATCH 09/24] .clear() instead = ""; and switch improved. --- src/yuzu/main.cpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 90bb61c15..82b38fc07 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2997,23 +2997,17 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt QMessageBox::StandardButtons buttons; int result = 0; - switch (imsg) { case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES: buttons = QMessageBox::Yes | QMessageBox::No; - result = QMessageBox::information(parent, tr("Create Shortcut"), tr("Do you want to launch the game in fullscreen?"), buttons); - - LOG_INFO(Frontend, "Shortcut will launch in fullscreen"); - return result == QMessageBox::Yes; - + return (result == QMessageBox::Yes); case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: QMessageBox::information(parent, tr("Create Shortcut"), tr("Successfully created a shortcut to %1").arg(game_title)); - return true; - + break; case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; result = @@ -3021,22 +3015,20 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt tr("This will create a shortcut to the current AppImage. This may " "not work well if you update. Continue?"), buttons); - return result == QMessageBox::StandardButton::Ok; + return (result == QMessageBox::Ok); case GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN: buttons = QMessageBox::Ok; QMessageBox::critical(parent, tr("Create Shortcut"), tr("Cannot create shortcut in Apps. Restart yuzu as administrator."), buttons); - LOG_ERROR(Frontend, "Cannot create shortcut in Apps. Restart yuzu as administrator."); - return true; + break; default: buttons = QMessageBox::Ok; QMessageBox::critical(parent, tr("Create Shortcut"), tr("Failed to create a shortcut to %1").arg(game_title), buttons); - return true; + break; } - - return true; + return false; } bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, @@ -3058,7 +3050,7 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi 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 = ""; // Reset path + out_icon_path.clear(); return false; } @@ -3165,7 +3157,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga arguments = "-f " + arguments; } const std::string comment = - tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(game_title)).toStdString(); + tr("Start %1 with the yuzu Emulator").arg(qt_game_title).toStdString(); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; From de0b35b97456313498785facccad5980cea737f7 Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 16:54:51 -0300 Subject: [PATCH 10/24] Comment using fmt instead qt. --- src/yuzu/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 82b38fc07..54b36552d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3156,8 +3156,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qt_game_title)) { arguments = "-f " + arguments; } - const std::string comment = - tr("Start %1 with the yuzu Emulator").arg(qt_game_title).toStdString(); + const std::string comment = fmt::format("Start {:s} with the yuzu Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; From 1ae0f0f3f64446b3128da0f1b1151d95739c9a6e Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 18:59:21 -0300 Subject: [PATCH 11/24] shortcut_stream.close(); fixed --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 54b36552d..e49de921c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2922,10 +2922,10 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, } else { LOG_ERROR(Frontend, "Failed to create shortcut"); } + shortcut_stream.close(); } catch (const std::exception& e) { LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); } - shortcut_stream.close(); return false; #elif defined(_WIN32) // Windows HRESULT hr = CoInitialize(NULL); From 1afe6d51eed4a420bb7289955333a2bb10c06b99 Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 23:42:45 -0300 Subject: [PATCH 12/24] More @liamwhite suggestions applied. --- src/common/fs/path_util.cpp | 12 +- src/yuzu/main.cpp | 216 ++++++++++++++++-------------------- 2 files changed, 98 insertions(+), 130 deletions(-) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 60c5e477e..732c1559f 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -252,29 +252,23 @@ void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) { fs::path GetExeDirectory() { WCHAR exe_path[MAX_PATH]; - if (SUCCEEDED(GetModuleFileNameW(nullptr, exe_path, MAX_PATH))) { std::wstring wide_exe_path(exe_path); return fs::path{Common::UTF16ToUTF8(wide_exe_path)}.parent_path(); - } else { - LOG_ERROR(Common_Filesystem, "Failed to get the path to the executable of the current " - "process"); } - + LOG_ERROR(Common_Filesystem, "Failed to get the path to the executable of the current " + "process"); return fs::path{}; } fs::path GetAppDataRoamingDirectory() { PWSTR appdata_roaming_path = nullptr; - if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) { std::wstring wide_appdata_roaming_path(appdata_roaming_path); CoTaskMemFree(appdata_roaming_path); return fs::path{Common::UTF16ToUTF8(wide_appdata_roaming_path)}; - } else { - LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); } - + LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); return fs::path{}; } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e49de921c..75fbd042a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2845,7 +2845,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, 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) { + const std::string& keywords, const std::string& name) try { // Copy characters if they are not illegal in Windows filenames std::string filename = ""; @@ -2869,145 +2869,120 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, #if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD // Reference for the desktop file template: // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html - try { - // Plus 'Type' is required - if (name.empty()) { - LOG_ERROR(Frontend, "Name is empty"); - return false; - } - - // Append .desktop extension - shortcut_path_full += ".desktop"; - - // Create shortcut file - std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); - - if (shortcut_stream.is_open()) { - - 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={}", command.string()); - - if (!arguments.empty()) { - fmt::print(shortcut_stream, " {}", arguments); - } - - fmt::print(shortcut_stream, "\n"); - - if (!categories.empty()) { - fmt::print(shortcut_stream, "Categories={}\n", categories); - } - - if (!keywords.empty()) { - fmt::print(shortcut_stream, "Keywords={}\n", keywords); - } - - // Flush and close file - shortcut_stream.flush(); - shortcut_stream.close(); - return true; - } else { - LOG_ERROR(Frontend, "Failed to create shortcut"); - } - shortcut_stream.close(); - } catch (const std::exception& e) { - LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); + // Plus 'Type' is required + if (name.empty()) { + LOG_ERROR(Frontend, "Name is empty"); + return false; } - return false; + + // Append .desktop extension + shortcut_path_full += ".desktop"; + + // Create shortcut file + 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; + } + + 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={}", command.string()); + if (!arguments.empty()) { + fmt::print(shortcut_stream, " {}", arguments); + } + fmt::print(shortcut_stream, "\n"); + if (!categories.empty()) { + fmt::print(shortcut_stream, "Categories={}\n", categories); + } + if (!keywords.empty()) { + fmt::print(shortcut_stream, "Keywords={}\n", keywords); + } + return true; #elif defined(_WIN32) // Windows HRESULT hr = CoInitialize(NULL); - if (SUCCEEDED(hr)) { - - IShellLinkW* ps1 = nullptr; - IPersistFile* persist_file = nullptr; - - SCOPE_EXIT({ - if (persist_file != nullptr) { - persist_file->Release(); - } - if (ps1 != nullptr) { - ps1->Release(); - } - - CoUninitialize(); - }); - - HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - IID_IShellLinkW, (void**)&ps1); - - std::wstring wshortcut_path_full = - Common::UTF8ToUTF16W((shortcut_path_full).string() + ".lnk"); - std::wstring wicon_path = Common::UTF8ToUTF16W(icon_path.string()); - std::wstring wcommand = Common::UTF8ToUTF16W(command.string()); - std::wstring warguments = Common::UTF8ToUTF16W(arguments); - std::wstring wcomment = Common::UTF8ToUTF16W(comment); - - if (SUCCEEDED(hres)) { - hres = ps1->SetPath(wcommand.data()); - - if (SUCCEEDED(hres) && !arguments.empty()) { - hres = ps1->SetArguments(warguments.data()); - } - - if (SUCCEEDED(hres) && !comment.empty()) { - hres = ps1->SetDescription(wcomment.data()); - } - - if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) { - hres = ps1->SetIconLocation(wicon_path.data(), 0); - } - - if (SUCCEEDED(hres)) { - hres = ps1->QueryInterface(IID_IPersistFile, (void**)&persist_file); - } - - if (SUCCEEDED(hres) && persist_file != nullptr) { - hres = persist_file->Save(wshortcut_path_full.data(), TRUE); - if (SUCCEEDED(hres)) { - return true; - } else { - LOG_ERROR(Frontend, "Failed to create shortcut"); - } - } - } else { - LOG_ERROR(Frontend, "Failed to create CoCreateInstance"); - } + if (FAILED(hr)) { + LOG_ERROR(Frontend, "CoInitialize failed"); + return false; } + + IShellLinkW* ps1 = nullptr; + IPersistFile* persist_file = nullptr; + + SCOPE_EXIT({ + if (persist_file != nullptr) { + persist_file->Release(); + } + if (ps1 != nullptr) { + ps1->Release(); + } + + CoUninitialize(); + }); + + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + (void**)&ps1); + + if (SUCCEEDED(hres)) { + hres = ps1->SetPath(Common::UTF8ToUTF16W(command.string()).data()); + } else { + LOG_ERROR(Frontend, "Failed to create CoCreateInstance"); + return false; + } + if (SUCCEEDED(hres) && !arguments.empty()) { + hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); + } + if (SUCCEEDED(hres) && !comment.empty()) { + hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); + } + if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) { + hres = ps1->SetIconLocation(Common::UTF8ToUTF16W(icon_path.string()).data(), 0); + } + if (SUCCEEDED(hres)) { + hres = ps1->QueryInterface(IID_IPersistFile, (void**)&persist_file); + } + if (SUCCEEDED(hres) && persist_file != nullptr) { + hres = persist_file->Save( + Common::UTF8ToUTF16W((shortcut_path_full).string() + ".lnk").data(), TRUE); + } + if (SUCCEEDED(hres)) { + return true; + } + LOG_ERROR(Frontend, "Failed to create shortcut"); return false; #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 bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { - QMessageBox::StandardButtons buttons; - int result = 0; + QMessageBox::StandardButtons buttons; switch (imsg) { case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES: buttons = QMessageBox::Yes | QMessageBox::No; result = QMessageBox::information(parent, tr("Create Shortcut"), tr("Do you want to launch the game in fullscreen?"), buttons); - return (result == QMessageBox::Yes); + return result == QMessageBox::Yes; case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: QMessageBox::information(parent, tr("Create Shortcut"), tr("Successfully created a shortcut to %1").arg(game_title)); - break; + return false; case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; result = @@ -3015,20 +2990,19 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt tr("This will create a shortcut to the current AppImage. This may " "not work well if you update. Continue?"), buttons); - return (result == QMessageBox::Ok); + return result == QMessageBox::Ok; case GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN: buttons = QMessageBox::Ok; QMessageBox::critical(parent, tr("Create Shortcut"), tr("Cannot create shortcut in Apps. Restart yuzu as administrator."), buttons); - break; + return false; default: buttons = QMessageBox::Ok; QMessageBox::critical(parent, tr("Create Shortcut"), tr("Failed to create a shortcut to %1").arg(game_title), buttons); - break; + return false; } - return false; } bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, From fc4b45ebd344a3e3d571b8516e73cd9afe824a9b Mon Sep 17 00:00:00 2001 From: boludoz Date: Mon, 16 Oct 2023 23:50:09 -0300 Subject: [PATCH 13/24] Moved check. --- src/yuzu/main.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 75fbd042a..0e0d7ef0e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2847,6 +2847,13 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name) try { +#if defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32) // Linux, FreeBSD and Windows + // Plus 'name' is required + if (name.empty()) { + LOG_ERROR(Frontend, "Name is empty"); + return false; + } + // Copy characters if they are not illegal in Windows filenames std::string filename = ""; const std::string illegal_chars = "<>:\"/\\|?*"; @@ -2865,17 +2872,12 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, } std::filesystem::path shortcut_path_full = shortcut_path / filename; +#endif #if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD // Reference for the desktop file template: // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html - // Plus 'Type' is required - if (name.empty()) { - LOG_ERROR(Frontend, "Name is empty"); - return false; - } - // Append .desktop extension shortcut_path_full += ".desktop"; From 9908434c14d68faa7fde933258aafd7da15b3b3b Mon Sep 17 00:00:00 2001 From: boludoz Date: Tue, 17 Oct 2023 02:57:35 -0300 Subject: [PATCH 14/24] Final refactorization --- src/yuzu/main.cpp | 131 ++++++++++++++++------------------------------ 1 file changed, 45 insertions(+), 86 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0e0d7ef0e..01b64e165 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2846,48 +2846,13 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::filesystem::path& command, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name) try { - -#if defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32) // Linux, FreeBSD and Windows - // Plus 'name' is required - if (name.empty()) { - LOG_ERROR(Frontend, "Name is empty"); - return false; - } - - // Copy characters if they are not illegal in Windows filenames - std::string filename = ""; - const std::string illegal_chars = "<>:\"/\\|?*"; - filename.reserve(name.size()); - std::copy_if(name.begin(), name.end(), std::back_inserter(filename), - [&illegal_chars](char c) { return illegal_chars.find(c) == std::string::npos; }); - - if (filename.empty()) { - LOG_ERROR(Frontend, "Filename is empty"); - return false; - } - - if (!std::filesystem::is_regular_file(command)) { - LOG_ERROR(Frontend, "Command is not a regular file"); - return false; - } - - std::filesystem::path shortcut_path_full = shortcut_path / filename; -#endif - #if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD - // Reference for the desktop file template: - // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html - - // Append .desktop extension - shortcut_path_full += ".desktop"; - - // Create shortcut file + 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; } - fmt::print(shortcut_stream, "[Desktop Entry]\n"); fmt::print(shortcut_stream, "Type=Application\n"); fmt::print(shortcut_stream, "Version=1.0\n"); @@ -2899,11 +2864,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); } fmt::print(shortcut_stream, "TryExec={}\n", command.string()); - fmt::print(shortcut_stream, "Exec={}", command.string()); - if (!arguments.empty()) { - fmt::print(shortcut_stream, " {}", arguments); - } - fmt::print(shortcut_stream, "\n"); + fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); if (!categories.empty()) { fmt::print(shortcut_stream, "Categories={}\n", categories); } @@ -2912,15 +2873,14 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, } return true; #elif defined(_WIN32) // Windows - HRESULT hr = CoInitialize(NULL); + 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(); @@ -2928,40 +2888,50 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, if (ps1 != nullptr) { ps1->Release(); } - - CoUninitialize(); }); - - HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - (void**)&ps1); - - if (SUCCEEDED(hres)) { - hres = ps1->SetPath(Common::UTF8ToUTF16W(command.string()).data()); - } else { - LOG_ERROR(Frontend, "Failed to create CoCreateInstance"); + HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + reinterpret_cast(&ps1)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); return false; } - if (SUCCEEDED(hres) && !arguments.empty()) { + 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 (SUCCEEDED(hres) && !comment.empty()) { + if (!comment.empty()) { hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set description"); + return false; + } } - if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) { - hres = ps1->SetIconLocation(Common::UTF8ToUTF16W(icon_path.string()).data(), 0); + 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; + } } - if (SUCCEEDED(hres)) { - hres = ps1->QueryInterface(IID_IPersistFile, (void**)&persist_file); + hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast(&persist_file)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); + return false; } - if (SUCCEEDED(hres) && persist_file != nullptr) { - hres = persist_file->Save( - Common::UTF8ToUTF16W((shortcut_path_full).string() + ".lnk").data(), TRUE); + 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; } - if (SUCCEEDED(hres)) { - return true; - } - LOG_ERROR(Frontend, "Failed to create shortcut"); - return false; + return true; #else // Unsupported platform return false; #endif @@ -2969,7 +2939,6 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); return false; } - // Messages in pre-defined message boxes for less code spaghetti bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { int result = 0; @@ -3009,7 +2978,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) @@ -3038,20 +3006,16 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { - std::string game_title; QString qt_game_title; std::filesystem::path out_icon_path; - // Get path to yuzu executable const QStringList args = QApplication::arguments(); std::filesystem::path yuzu_command = args[0].toStdString(); - // If relative path, make it an absolute path if (yuzu_command.c_str()[0] == '.') { yuzu_command = Common::FS::GetCurrentDir() / yuzu_command; } - // Shortcut path std::filesystem::path shortcut_path{}; if (target == GameListShortcutTarget::Desktop) { @@ -3061,7 +3025,6 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); } - // Icon path and title if (std::filesystem::exists(shortcut_path)) { // Get title from game file @@ -3070,17 +3033,20 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga const auto control = pm.GetControlMetadata(); const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); - game_title = fmt::format("{:016X}", program_id); - if (control.first != nullptr) { game_title = control.first->GetApplicationName(); } else { loader->ReadTitle(game_title); } - + // Delete illegal characters from 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); + } + } qt_game_title = QString::fromStdString(game_title); - // Get icon from game file std::vector icon_image_file{}; if (control.second != nullptr) { @@ -3088,23 +3054,19 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } 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(icon_image_file.size())); - if (GMainWindow::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 { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, qt_game_title); LOG_ERROR(Frontend, "Invalid shortcut target"); return; } - #if defined(_WIN32) if (!IsUserAnAdmin() && target == GameListShortcutTarget::Applications) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN, @@ -3125,7 +3087,6 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga UISettings::values.shortcut_already_warned = true; } #endif // __linux__ - // Create shortcut std::string arguments = fmt::format("-g \"{:s}\"", game_path); if (GMainWindow::CreateShortcutMessagesGUI( @@ -3142,7 +3103,6 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga qt_game_title); return; } - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, qt_game_title); } @@ -4177,7 +4137,6 @@ void GMainWindow::OnLoadAmiibo() { bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { - QMessageBox* box_dialog = new QMessageBox(parent); box_dialog->setWindowTitle(title); box_dialog->setText(text); From 2a7edda70ac7bfcce6a830c814a6b8cd559b8c03 Mon Sep 17 00:00:00 2001 From: boludoz Date: Wed, 18 Oct 2023 01:20:46 -0300 Subject: [PATCH 15/24] Deleted admin requisite (maybe it was another mistake). --- src/yuzu/main.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 01b64e165..37f1c0bc4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3067,13 +3067,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga LOG_ERROR(Frontend, "Invalid shortcut target"); return; } -#if defined(_WIN32) - if (!IsUserAnAdmin() && target == GameListShortcutTarget::Applications) { - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN, - qt_game_title); - return; - } -#elif defined(__linux__) +#if defined(__linux__) // Special case for AppImages // Warn once if we are making a shortcut to a volatile AppImage const std::string appimage_ending = From 4051bbbed7f0160a6565212affbbb24553a9b510 Mon Sep 17 00:00:00 2001 From: boludoz Date: Wed, 18 Oct 2023 01:26:50 -0300 Subject: [PATCH 16/24] Useless code removed related to admin privileges, if it is not an error we can add it later, that is what git is for. --- src/yuzu/main.cpp | 6 ------ src/yuzu/main.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 37f1c0bc4..73cd06478 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2962,12 +2962,6 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt "not work well if you update. Continue?"), buttons); return result == QMessageBox::Ok; - case GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN: - buttons = QMessageBox::Ok; - QMessageBox::critical(parent, tr("Create Shortcut"), - tr("Cannot create shortcut in Apps. Restart yuzu as administrator."), - buttons); - return false; default: buttons = QMessageBox::Ok; QMessageBox::critical(parent, tr("Create Shortcut"), diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 41902cc8d..d203e5301 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -157,7 +157,6 @@ class GMainWindow : public QMainWindow { CREATE_SHORTCUT_MSGBOX_SUCCESS, CREATE_SHORTCUT_MSGBOX_ERROR, CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, - CREATE_SHORTCUT_MSGBOX_ADMIN, }; public: From ac6290bea76e9719ef7806dab7f92ab53fdd27d0 Mon Sep 17 00:00:00 2001 From: boludoz Date: Wed, 18 Oct 2023 02:35:23 -0300 Subject: [PATCH 17/24] TODO: Implement shortcut creation for Apple. --- src/yuzu/game_list.cpp | 6 ++++++ src/yuzu/main.cpp | 8 ++++++-- src/yuzu/main.h | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index fbe099661..90433e245 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -564,10 +564,13 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity")); QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); +// TODO: Implement shortcut creation for macOS +#if !defined(__APPLE__) QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut")); QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop")); QAction* create_applications_menu_shortcut = shortcut_menu->addAction(tr("Add to Applications Menu")); +#endif context_menu.addSeparator(); QAction* properties = context_menu.addAction(tr("Properties")); @@ -642,12 +645,15 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { emit NavigateToGamedbEntryRequested(program_id, compatibility_list); }); +// 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); }); connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); }); +#endif connect(properties, &QAction::triggered, [this, path]() { emit OpenPerGameGeneralRequested(path); }); }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 73cd06478..ec3eb7536 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2839,7 +2839,8 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); } - +// TODO: Implement shortcut creation for macOS +#if !defined(__APPLE__) bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, const std::filesystem::path& icon_path, @@ -2997,9 +2998,11 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); return true; } - +#endif // !defined(__APPLE__) void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { +// TODO: Implement shortcut creation for macOS +#if !defined(__APPLE__) std::string game_title; QString qt_game_title; std::filesystem::path out_icon_path; @@ -3093,6 +3096,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, qt_game_title); +#endif } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index d203e5301..7a1a97f33 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -441,6 +441,8 @@ private: bool ConfirmShutdownGame(); QString GetTasStateDescription() const; +// TODO: Implement shortcut creation for macOS +#if !defined(__APPLE__) 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); @@ -449,6 +451,7 @@ private: const std::filesystem::path& command, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name); +#endif /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog * The only difference is that it returns a boolean. From ae2130470effa72c3ea1ffc045e9b6b2a77b23d3 Mon Sep 17 00:00:00 2001 From: boludoz Date: Wed, 18 Oct 2023 19:30:21 -0300 Subject: [PATCH 18/24] Reverted dirty code in main. --- src/yuzu/main.cpp | 8 ++------ src/yuzu/main.h | 3 --- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index ec3eb7536..73cd06478 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2839,8 +2839,7 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); } -// TODO: Implement shortcut creation for macOS -#if !defined(__APPLE__) + bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, const std::filesystem::path& icon_path, @@ -2998,11 +2997,9 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); return true; } -#endif // !defined(__APPLE__) + void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { -// TODO: Implement shortcut creation for macOS -#if !defined(__APPLE__) std::string game_title; QString qt_game_title; std::filesystem::path out_icon_path; @@ -3096,7 +3093,6 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, qt_game_title); -#endif } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7a1a97f33..d203e5301 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -441,8 +441,6 @@ private: bool ConfirmShutdownGame(); QString GetTasStateDescription() const; -// TODO: Implement shortcut creation for macOS -#if !defined(__APPLE__) 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); @@ -451,7 +449,6 @@ private: const std::filesystem::path& command, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name); -#endif /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog * The only difference is that it returns a boolean. From 7f62a48ab507d3874378c10944662d5b841c6c2e Mon Sep 17 00:00:00 2001 From: boludoz Date: Fri, 27 Oct 2023 00:30:35 -0300 Subject: [PATCH 19/24] We dont need that --- src/common/fs/path_util.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 732c1559f..0abd81a45 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -6,7 +6,6 @@ #include #include "common/fs/fs.h" -#include "common/string_util.h" #ifdef ANDROID #include "common/fs/fs_android.h" #endif @@ -15,7 +14,7 @@ #include "common/logging/log.h" #ifdef _WIN32 -#include // Used in GetExeDirectory() and GetWindowsDesktop() +#include // Used in GetExeDirectory() #else #include // Used in Get(Home/Data)Directory() #include // Used in GetHomeDirectory() @@ -251,25 +250,30 @@ void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) { #ifdef _WIN32 fs::path GetExeDirectory() { - WCHAR exe_path[MAX_PATH]; - if (SUCCEEDED(GetModuleFileNameW(nullptr, exe_path, MAX_PATH))) { - std::wstring wide_exe_path(exe_path); - return fs::path{Common::UTF16ToUTF8(wide_exe_path)}.parent_path(); + wchar_t exe_path[MAX_PATH]; + + if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH) == 0) { + LOG_ERROR(Common_Filesystem, + "Failed to get the path to the executable of the current process"); } - LOG_ERROR(Common_Filesystem, "Failed to get the path to the executable of the current " - "process"); - return fs::path{}; + + return fs::path{exe_path}.parent_path(); } fs::path GetAppDataRoamingDirectory() { PWSTR appdata_roaming_path = nullptr; - if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) { - std::wstring wide_appdata_roaming_path(appdata_roaming_path); - CoTaskMemFree(appdata_roaming_path); - return fs::path{Common::UTF16ToUTF8(wide_appdata_roaming_path)}; + + SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &appdata_roaming_path); + + auto fs_appdata_roaming_path = fs::path{appdata_roaming_path}; + + CoTaskMemFree(appdata_roaming_path); + + if (fs_appdata_roaming_path.empty()) { + LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); } - LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); - return fs::path{}; + + return fs_appdata_roaming_path; } #else From 4b8b223db2ed0f79ce81083128fe8085786877cc Mon Sep 17 00:00:00 2001 From: Franco M Date: Sun, 5 Nov 2023 00:39:43 +0000 Subject: [PATCH 20/24] modified: src/yuzu/main.cpp --- src/yuzu/main.cpp | 73 +++++------------------------------------------ 1 file changed, 7 insertions(+), 66 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c8efd1917..6b6feb1e6 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "core/loader/nca.h" #include "core/tools/renderdoc.h" #ifdef __APPLE__ @@ -2856,6 +2857,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, 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"); @@ -2983,7 +2985,6 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi #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)) { QMessageBox::critical( @@ -2996,8 +2997,8 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi } // Create icon file path - out_icon_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension) - : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); + out_icon_path /= (program_id == 0 ? std::format("yuzu-{}.{}", game_file_name, ico_extension) + : std::format("yuzu-{:016X}.{}", program_id, ico_extension)); return true; } @@ -3030,7 +3031,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga const auto control = pm.GetControlMetadata(); const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); - game_title = fmt::format("{:016X}", program_id); + game_title = std::format("{:016X}", program_id); if (control.first != nullptr) { game_title = control.first->GetApplicationName(); } else { @@ -3079,12 +3080,12 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } #endif // __linux__ // Create shortcut - std::string arguments = fmt::format("-g \"{:s}\"", game_path); + std::string arguments = std::format("-g \"{:s}\"", game_path); if (GMainWindow::CreateShortcutMessagesGUI( this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qt_game_title)) { arguments = "-f " + arguments; } - const std::string comment = fmt::format("Start {:s} with the yuzu Emulator", game_title); + const std::string comment = std::format("Start {:s} with the yuzu Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; @@ -4090,66 +4091,6 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file } } -bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title, - const std::string& comment, const std::string& icon_path, - const std::string& command, const std::string& arguments, - const std::string& categories, const std::string& keywords) { -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - // This desktop file template was writing referencing - // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html - std::string shortcut_contents{}; - shortcut_contents.append("[Desktop Entry]\n"); - shortcut_contents.append("Type=Application\n"); - shortcut_contents.append("Version=1.0\n"); - shortcut_contents.append(fmt::format("Name={:s}\n", title)); - shortcut_contents.append(fmt::format("Comment={:s}\n", comment)); - shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path)); - shortcut_contents.append(fmt::format("TryExec={:s}\n", command)); - shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments)); - shortcut_contents.append(fmt::format("Categories={:s}\n", categories)); - shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords)); - - std::ofstream shortcut_stream(shortcut_path); - if (!shortcut_stream.is_open()) { - LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path); - return false; - } - shortcut_stream << shortcut_contents; - shortcut_stream.close(); - - return true; -#elif defined(WIN32) - IShellLinkW* shell_link; - auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - (void**)&shell_link); - if (FAILED(hres)) { - return false; - } - shell_link->SetPath( - Common::UTF8ToUTF16W(command).data()); // Path to the object we are referring to - shell_link->SetArguments(Common::UTF8ToUTF16W(arguments).data()); - shell_link->SetDescription(Common::UTF8ToUTF16W(comment).data()); - shell_link->SetIconLocation(Common::UTF8ToUTF16W(icon_path).data(), 0); - - IPersistFile* persist_file; - hres = shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file); - if (FAILED(hres)) { - return false; - } - - hres = persist_file->Save(Common::UTF8ToUTF16W(shortcut_path).data(), TRUE); - if (FAILED(hres)) { - return false; - } - - persist_file->Release(); - shell_link->Release(); - - return true; -#endif - return false; -} - void GMainWindow::OnLoadAmiibo() { if (emu_thread == nullptr || !emu_thread->IsRunning()) { return; From 8d0d0e1c7a95858dc5eaffe0eb0484815b491d9d Mon Sep 17 00:00:00 2001 From: Franco M Date: Tue, 7 Nov 2023 02:32:19 +0000 Subject: [PATCH 21/24] Fixed clang --- src/yuzu/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 6b6feb1e6..2402ea6f5 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4,13 +4,14 @@ #include #include #include +#include #include #include #include #include -#include #include "core/loader/nca.h" #include "core/tools/renderdoc.h" + #ifdef __APPLE__ #include // for chdir #endif @@ -5331,4 +5332,4 @@ int main(int argc, char* argv[]) { int result = app.exec(); detached_tasks.WaitForAllTasks(); return result; -} +} \ No newline at end of file From c7b31d24b979c36e2a9e59e7ae6876ffbc82a81e Mon Sep 17 00:00:00 2001 From: Franco M Date: Wed, 8 Nov 2023 21:04:30 +0000 Subject: [PATCH 22/24] Final change, i think --- src/yuzu/main.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2402ea6f5..442408280 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -2998,8 +2997,8 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi } // Create icon file path - out_icon_path /= (program_id == 0 ? std::format("yuzu-{}.{}", game_file_name, ico_extension) - : std::format("yuzu-{:016X}.{}", program_id, ico_extension)); + out_icon_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension) + : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); return true; } @@ -3032,7 +3031,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga const auto control = pm.GetControlMetadata(); const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); - game_title = std::format("{:016X}", program_id); + game_title = fmt::format("{:016X}", program_id); if (control.first != nullptr) { game_title = control.first->GetApplicationName(); } else { @@ -3081,12 +3080,12 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga } #endif // __linux__ // Create shortcut - std::string arguments = std::format("-g \"{:s}\"", game_path); + std::string arguments = fmt::format("-g \"{:s}\"", game_path); if (GMainWindow::CreateShortcutMessagesGUI( this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qt_game_title)) { arguments = "-f " + arguments; } - const std::string comment = std::format("Start {:s} with the yuzu Emulator", game_title); + const std::string comment = fmt::format("Start {:s} with the yuzu Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; From f3053920bf75858b702b13a2d80589a386c397b9 Mon Sep 17 00:00:00 2001 From: Franco M Date: Thu, 9 Nov 2023 03:37:06 +0000 Subject: [PATCH 23/24] Minor changes --- src/yuzu/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 442408280..a4ad9d8a8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2980,7 +2980,7 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi // Get path to Yuzu icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) - out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons"; + out_icon_path = Common::FS::YuzuPath::IconsDir; ico_extension = "ico"; #elif defined(__linux__) || defined(__FreeBSD__) out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; @@ -5331,4 +5331,4 @@ int main(int argc, char* argv[]) { int result = app.exec(); detached_tasks.WaitForAllTasks(); return result; -} \ No newline at end of file +} From c9038af29e05458bd2f647158cc2903132c4c560 Mon Sep 17 00:00:00 2001 From: Franco M Date: Thu, 9 Nov 2023 04:53:10 +0000 Subject: [PATCH 24/24] Fix out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::IconsDir); --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a4ad9d8a8..e0a656a5e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2980,7 +2980,7 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi // Get path to Yuzu icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) - out_icon_path = Common::FS::YuzuPath::IconsDir; + out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::IconsDir); ico_extension = "ico"; #elif defined(__linux__) || defined(__FreeBSD__) out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256";