diff options
Diffstat (limited to 'src/yuzu')
| -rw-r--r-- | src/yuzu/game_list.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 451 | ||||
| -rw-r--r-- | src/yuzu/main.h | 22 | ||||
| -rw-r--r-- | src/yuzu/util/util.cpp | 12 | ||||
| -rw-r--r-- | src/yuzu/util/util.h | 3 | 
5 files changed, 295 insertions, 197 deletions
| 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..0e0d7ef0e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2840,170 +2840,311 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,      QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory));  } -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(); +bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, +                                     const std::string& comment, +                                     const std::filesystem::path& icon_path, +                                     const std::filesystem::path& command, +                                     const std::string& arguments, const std::string& categories, +                                     const std::string& keywords, const std::string& name) try { + +#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; +    } -    // If relative path, make it an absolute path -    if (yuzu_command.c_str()[0] == '.') { -        yuzu_command = Common::FS::GetCurrentDir() / yuzu_command; +    // 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 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) { -            return; -        } -        UISettings::values.shortcut_already_warned = true; +    if (!std::filesystem::is_regular_file(command)) { +        LOG_ERROR(Frontend, "Command is not a regular file"); +        return false;      } -#endif // __linux__ -    std::filesystem::path target_directory{}; +    std::filesystem::path shortcut_path_full = shortcut_path / filename; +#endif -    switch (target) { -    case GameListShortcutTarget::Desktop: { -        const QString desktop_path = -            QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); -        target_directory = desktop_path.toUtf8().toStdString(); -        break; +#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::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;      } -    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(); + +    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 (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();          } -        break; +        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;      } -    default: -        return; +    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; +} -    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; +// Messages in pre-defined message boxes for less code spaghetti +bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { +    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; +    case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: +        QMessageBox::information(parent, tr("Create Shortcut"), +                                 tr("Successfully created a shortcut to %1").arg(game_title)); +        return false; +    case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: +        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::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"), +                              tr("Failed to create a shortcut to %1").arg(game_title), buttons); +        return false;      } +} -    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"); +bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, +                                      std::filesystem::path& out_icon_path) { + +    // Get path to Yuzu icons directory & icon extension +    std::string ico_extension = "png"; +#if defined(_WIN32) +    out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons"; +    ico_extension = "ico"; +#elif defined(__linux__) || defined(__FreeBSD__) +    out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; +#endif -    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)) { +    // Create icons directory if it doesn't exist +    if (!Common::FS::CreateDirs(out_icon_path)) {          QMessageBox::critical(              this, tr("Create Icon"),              tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") -                .arg(QString::fromStdString(system_icons_path)), +                .arg(QString::fromStdString(out_icon_path.string())),              QMessageBox::StandardButton::Ok); -        return; +        out_icon_path.clear(); +        return false;      } -    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)); +    // 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)); +    return true; +} -    std::string title{fmt::format("{:016X}", program_id)}; +void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, +                                           GameListShortcutTarget target) { -    if (control.first != nullptr) { -        title = control.first->GetApplicationName(); -    } else { -        loader->ReadTitle(title); +    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;      } -    // Get icon from game file -    std::vector<u8> 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); +    // Shortcut path +    std::filesystem::path shortcut_path{}; +    if (target == GameListShortcutTarget::Desktop) { +        shortcut_path = +            QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); +    } else if (target == GameListShortcutTarget::Applications) { +        shortcut_path = +            QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();      } -    QImage icon_data = -        QImage::fromData(icon_image_file.data(), static_cast<int>(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"); +    // Icon path and title +    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)); + +        game_title = fmt::format("{:016X}", program_id); + +        if (control.first != nullptr) { +            game_title = control.first->GetApplicationName(); +        } else { +            loader->ReadTitle(game_title); +        } + +        qt_game_title = QString::fromStdString(game_title); + +        // Get icon from game file +        std::vector<u8> 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<int>(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 { -        LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); +        GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, +                                               qt_game_title); +        LOG_ERROR(Frontend, "Invalid shortcut target"); +        return;      } -#elif defined(WIN32) -    if (!SaveIconToFile(icon_path.string(), icon_data)) { -        LOG_ERROR(Frontend, "Could not write icon to file"); + +#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, qt_game_title)) { +            return; +        } +        UISettings::values.shortcut_already_warned = true; +    }  #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, '_'); +    // Create shortcut +    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::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 comment = fmt::format("Start {:s} with the yuzu Emulator", game_title);      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, out_icon_path, yuzu_command, +                                        arguments, categories, keywords, game_title)) { +        GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, +                                               qt_game_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, +                                           qt_game_title);  }  void GMainWindow::OnGameListOpenDirectory(const QString& directory) { @@ -3998,66 +4139,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..41902cc8d 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -6,6 +6,7 @@  #include <memory>  #include <optional> +#include <filesystem>  #include <QMainWindow>  #include <QMessageBox>  #include <QTimer> @@ -151,6 +152,14 @@ class GMainWindow : public QMainWindow {          UI_EMU_STOPPING,      }; +    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, int imsg, const QString& game_title); +    bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, +                             std::filesystem::path& out_icon_path); +    bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, +                            const std::filesystem::path& icon_path, +                            const std::filesystem::path& command, const std::string& arguments, +                            const std::string& categories, const std::string& keywords, +                            const std::string& name);      /**       * 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..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 std::string_view path, const QImage& image) { +bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) {  #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<WORD>(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,6 +135,14 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {      icon_file.Close();      return true; +#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;  #else      return false;  #endif diff --git a/src/yuzu/util/util.h b/src/yuzu/util/util.h index 09c14ce3f..4094cf6c2 100644 --- a/src/yuzu/util/util.h +++ b/src/yuzu/util/util.h @@ -3,6 +3,7 @@  #pragma once +#include <filesystem>  #include <QFont>  #include <QString> @@ -25,4 +26,4 @@   * @param image The image to save   * @return bool If the operation succeeded   */ -[[nodiscard]] bool SaveIconToFile(const std::string_view path, const QImage& image); +[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image); | 
