diff --git a/rpcs3/rpcs3qt/game_list_actions.cpp b/rpcs3/rpcs3qt/game_list_actions.cpp index 8cc4f767ef..b37348f49d 100644 --- a/rpcs3/rpcs3qt/game_list_actions.cpp +++ b/rpcs3/rpcs3qt/game_list_actions.cpp @@ -811,7 +811,7 @@ bool game_list_actions::RemoveContentList(const std::string& serial, bool is_int // Add serial (title id) to the list of serials to be removed in "games.yml" file (if any) if (content_types & DISC) { - if (const auto it = m_content_info.disc_list.find(serial); it != m_content_info.disc_list.cend()) + if (m_content_info.disc_list.contains(serial)) m_content_info.removed_disc_list.insert(serial); } @@ -851,18 +851,10 @@ bool game_list_actions::RemoveContentList(const std::string& serial, bool is_int { if (const auto it = m_content_info.name_list.find(serial); it != m_content_info.name_list.cend()) { - const bool remove_rpcs3_links = ValidateRemoval(serial, rpcs3::utils::get_games_shortcuts_dir(), "link"); - - for (const auto& name : it->second) + for (const std::string& name : it->second) { - // Remove illegal characters from name to match the link name created by gui::utils::create_shortcut() - const std::string simple_name = QString::fromStdString(vfs::escape(name, true)).simplified().toStdString(); - - // Remove rpcs3 shortcuts - if (remove_rpcs3_links) - RemoveContentBySerial(rpcs3::utils::get_games_shortcuts_dir(), simple_name + ".lnk", "link"); - - // TODO: Remove shortcuts from desktop/start menu + // Remove all shortcuts + gui::utils::remove_shortcuts(name, serial); } } } diff --git a/rpcs3/rpcs3qt/shortcut_utils.cpp b/rpcs3/rpcs3qt/shortcut_utils.cpp index 00bec65f13..615d794f26 100644 --- a/rpcs3/rpcs3qt/shortcut_utils.cpp +++ b/rpcs3/rpcs3qt/shortcut_utils.cpp @@ -32,9 +32,17 @@ LOG_CHANNEL(sys_log, "SYS"); namespace gui::utils { - bool create_square_shortcut_icon_file(const std::string& path, const std::string& src_icon_path, const std::string& target_icon_dir, std::string& target_icon_path, const std::string& extension, int size) +#ifdef _WIN32 + static const std::string icon_extension = "ico"; +#elif defined(__APPLE__) + static const std::string icon_extension = "icns"; +#else + static const std::string icon_extension = "png"; +#endif + + bool create_square_shortcut_icon_file(const std::string& path, const std::string& src_icon_path, const std::string& target_icon_dir, std::string& target_icon_path, int size) { - if (src_icon_path.empty() || target_icon_dir.empty() || extension.empty()) + if (src_icon_path.empty() || target_icon_dir.empty()) { sys_log.error("Failed to create shortcut. Icon parameters empty."); return false; @@ -55,7 +63,7 @@ namespace gui::utils return false; } - target_icon_path = target_icon_dir + "shortcut." + fmt::to_lower(extension); + target_icon_path = target_icon_dir + "shortcut." + fmt::to_lower(icon_extension); QFile icon_file(QString::fromStdString(target_icon_path)); if (!icon_file.open(QFile::OpenModeFlag::ReadWrite | QFile::OpenModeFlag::Truncate)) @@ -65,7 +73,7 @@ namespace gui::utils } // Use QImageWriter instead of QPixmap::save in order to be able to log errors - if (QImageWriter writer(&icon_file, fmt::to_upper(extension).c_str()); !writer.write(icon.toImage())) + if (QImageWriter writer(&icon_file, fmt::to_upper(icon_extension).c_str()); !writer.write(icon.toImage())) { sys_log.error("Failed to write icon file '%s': %s", target_icon_path, writer.errorString()); return false; @@ -100,21 +108,21 @@ namespace gui::utils std::string link_path; - if (location == shortcut_location::desktop) + switch (location) { + case shortcut_location::desktop: link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DesktopLocation).toStdString(); - } - else if (location == shortcut_location::applications) - { + break; + case shortcut_location::applications: link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ApplicationsLocation).toStdString(); - } + break; #ifdef _WIN32 - else if (location == shortcut_location::rpcs3_shortcuts) - { - link_path = rpcs3::utils::get_games_dir() + "/shortcuts/"; + case shortcut_location::rpcs3_shortcuts: + link_path = rpcs3::utils::get_games_shortcuts_dir(); fs::create_dir(link_path); - } + break; #endif + } if (!fs::is_dir(link_path) && !fs::create_dir(link_path)) { @@ -199,7 +207,7 @@ namespace gui::utils if (!src_icon_path.empty() && !target_icon_dir.empty()) { std::string target_icon_path; - if (!create_square_shortcut_icon_file(path, src_icon_path, target_icon_dir, target_icon_path, "ico", 512)) + if (!create_square_shortcut_icon_file(path, src_icon_path, target_icon_dir, target_icon_path, 512)) return cleanup(false, ".ico creation failed"); const std::wstring w_icon_path = utf8_to_wchar(target_icon_path); @@ -311,7 +319,7 @@ namespace gui::utils if (!src_icon_path.empty()) { std::string target_icon_path = resources_dir; - if (!create_square_shortcut_icon_file(path, src_icon_path, resources_dir, target_icon_path, "icns", 512)) + if (!create_square_shortcut_icon_file(path, src_icon_path, resources_dir, target_icon_path, 512)) { // Error is logged in create_square_shortcut_icon_file return false; @@ -349,7 +357,7 @@ namespace gui::utils if (!src_icon_path.empty() && !target_icon_dir.empty()) { std::string target_icon_path; - if (!create_square_shortcut_icon_file(path, src_icon_path, target_icon_dir, target_icon_path, "png", 512)) + if (!create_square_shortcut_icon_file(path, src_icon_path, target_icon_dir, target_icon_path, 512)) { // Error is logged in create_square_shortcut_icon_file return false; @@ -381,6 +389,85 @@ namespace gui::utils } return true; +#endif + } + + void remove_shortcuts(const std::string& name, [[maybe_unused]] const std::string& serial) + { + const std::string simple_name = QString::fromStdString(vfs::escape(name, true)).simplified().toStdString(); + if (simple_name.empty() || simple_name == "." || simple_name == "..") + { + sys_log.error("Failed to remove shortcuts: Cleaned file name empty or not allowed"); + return; + } + + const auto remove_file = [](const std::string& path) + { + if (!path.empty() && fs::is_file(path)) + { + if (fs::remove_file(path)) + { + sys_log.success("Removed shortcut file '%s'", path); + } + else + { + sys_log.error("Failed to remove shortcut file '%s': error='%s'", path, fs::g_tls_error); + } + } + }; + + std::vector locations = { + shortcut_location::desktop, + shortcut_location::applications + }; +#ifdef _WIN32 + locations.push_back(shortcut_location::rpcs3_shortcuts); +#endif + + for (shortcut_location location : locations) + { + std::string link_path; + + switch (location) + { + case shortcut_location::desktop: + link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DesktopLocation).toStdString(); + break; + case shortcut_location::applications: + link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ApplicationsLocation).toStdString(); + link_path += "/RPCS3"; + break; +#ifdef _WIN32 + case shortcut_location::rpcs3_shortcuts: + link_path = rpcs3::utils::get_games_shortcuts_dir(); + break; +#endif + } + +#ifdef _WIN32 + fmt::append(link_path, "/%s.lnk", simple_name); + remove_file(link_path); +#elif defined(__APPLE__) + fmt::append(link_path, "/%s.app", simple_name); + + const std::string contents_dir = link_path + "/Contents/"; + const std::string plist_path = contents_dir + "Info.plist"; + const std::string launcher_path = contents_dir + "MacOS/launcher"; + const std::string resources_dir = contents_dir + "Resources"; + const std::string icon_path = fmt::format("%s/shortcut.%s", resources_dir, icon_extension); + + remove_file(plist_path); + remove_file(launcher_path); + remove_file(icon_path); +#else + fmt::append(link_path, "/%s.desktop", simple_name); + remove_file(link_path); +#endif + } + +#ifndef __APPLE__ + const std::string icon_path = fmt::format("%sIcons/game_icons/%s/shortcut.%s", fs::get_config_dir(), serial, icon_extension); + remove_file(icon_path); #endif } } diff --git a/rpcs3/rpcs3qt/shortcut_utils.h b/rpcs3/rpcs3qt/shortcut_utils.h index 11208a2bf0..4e7fcdf0ce 100644 --- a/rpcs3/rpcs3qt/shortcut_utils.h +++ b/rpcs3/rpcs3qt/shortcut_utils.h @@ -2,7 +2,7 @@ namespace gui::utils { - enum shortcut_location + enum class shortcut_location { desktop, applications, @@ -19,4 +19,6 @@ namespace gui::utils const std::string& src_icon_path, const std::string& target_icon_dir, shortcut_location shortcut_location); + + void remove_shortcuts(const std::string& name, const std::string& serial); }