PKG: Ask to user if he wants to install game shortcut on PKG installation

This commit is contained in:
Eladash 2022-12-03 09:32:10 +02:00 committed by Ivan
parent b7d80ab335
commit 0d126afb1f
6 changed files with 175 additions and 12 deletions

View File

@ -858,6 +858,12 @@ bool package_reader::extract_data(atomic_t<double>& sync)
else
{
pkg_log.notice("Created file %s", path);
if (name == "USRDIR/EBOOT.BIN" && entry.file_size > 4)
{
// Expose the creation of a bootable file
m_bootable_file_path = path;
}
}
}
else

View File

@ -312,6 +312,11 @@ public:
bool extract_data(atomic_t<double>& sync);
psf::registry get_psf() const { return m_psf; }
std::string try_get_bootable_file_path_if_created_new() const
{
return m_bootable_file_path;
}
private:
bool read_header();
bool read_metadata();
@ -334,4 +339,7 @@ private:
PKGHeader m_header{};
PKGMetaData m_metadata{};
psf::registry m_psf{};
// Expose bootable file installed (if installed such)
std::string m_bootable_file_path;
};

View File

@ -1021,7 +1021,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
const std::string target_cli_args = fmt::format("--no-gui \"%s\"", gameinfo->info.path);
const std::string target_icon_dir = fmt::format("%sIcons/game_icons/%s/", fs::get_config_dir(), gameinfo->info.serial);
if (gui::utils::create_shortcut(gameinfo->info.name, target_cli_args, gameinfo->info.name, gameinfo->info.icon_path, target_icon_dir, is_desktop_shortcut))
if (gui::utils::create_shortcut(gameinfo->info.name, target_cli_args, gameinfo->info.name, gameinfo->info.icon_path, target_icon_dir, is_desktop_shortcut ? gui::utils::shortcut_location::desktop : gui::utils::shortcut_location::rpcs3_shortcuts))
{
game_list_log.success("Created %s shortcut for %s", is_desktop_shortcut ? "desktop" : "application menu", sstr(qstr(gameinfo->info.name).simplified()));
QMessageBox::information(this, tr("Success!"), tr("Successfully created a shortcut."));

View File

@ -30,6 +30,7 @@
#include "input_dialog.h"
#include "camera_settings_dialog.h"
#include "ipc_settings_dialog.h"
#include "shortcut_utils.h"
#include <thread>
#include <charconv>
@ -40,6 +41,8 @@
#include <QMessageBox>
#include <QFileDialog>
#include <QFontDatabase>
#include <QBuffer>
#include <QTemporaryFile>
#include "rpcs3_version.h"
#include "Emu/IdManager.h"
@ -846,6 +849,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
package_error error = package_error::no_error;
bool cancelled = false;
std::map<std::string, QString> bootable_paths_installed; // -> title
for (usz i = 0, count = packages.size(); i < count; i++)
{
@ -882,15 +886,21 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
const std::string path = sstr(package.path);
const std::string file_name = sstr(file_info.fileName());
std::string bootable_path;
// Run PKG unpacking asynchronously
named_thread worker("PKG Installer", [path, &progress, &error]
named_thread worker("PKG Installer", [path, &progress, &error, &bootable_path]
{
package_reader reader(path);
error = reader.check_target_app_version();
if (error == package_error::no_error)
{
return reader.extract_data(progress);
if (reader.extract_data(progress))
{
bootable_path = reader.try_get_bootable_file_path_if_created_new();
return true;
}
}
return false;
@ -922,7 +932,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
}
else
{
pdlg.setHidden(true);
pdlg.hide();
pdlg.SignalFailure();
}
@ -931,9 +941,132 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
m_game_list_frame->Refresh(true);
gui_log.success("Successfully installed %s (title_id=%s, title=%s, version=%s).", file_name, sstr(package.title_id), sstr(package.title), sstr(package.version));
if (!bootable_path.empty())
{
bootable_paths_installed[bootable_path] = package.title;
}
if (i == (count - 1))
{
m_gui_settings->ShowInfoBox(tr("Success!"), tr("Successfully installed software from package(s)!"), gui::ib_pkg_success, this);
pdlg.hide();
bool create_desktop_shortcuts = false;
bool create_app_shortcut = false;
if (bootable_paths_installed.empty())
{
m_gui_settings->ShowInfoBox(tr("Success!"), tr("Successfully installed software from package(s)!"), gui::ib_pkg_success, this);
}
else
{
auto dlg = new QDialog(this);
dlg->setWindowTitle(tr("Success!"));
QVBoxLayout* vlayout = new QVBoxLayout(dlg);
QCheckBox* desk_check = new QCheckBox(tr("Add desktop shortcut(s)"));
#ifdef _WIN32
QCheckBox* quick_check = new QCheckBox(tr("Add Start menu shortcut(s)"));
#elif defined(__APPLE__)
QCheckBox* quick_check = new QCheckBox(tr("Add dock shortcut(s)"));
#else
QCheckBox* quick_check = new QCheckBox(tr("Add launcher shortcut(s)"));
#endif
QLabel* label = new QLabel(tr("Successfully installed software from package(s)!\nWould you like to install shortcuts to the installed software? (%1 new software detected)\n\n").arg(bootable_paths_installed.size()), dlg);
vlayout->addWidget(label);
vlayout->addStretch(10);
vlayout->addWidget(desk_check);
vlayout->addStretch(3);
vlayout->addWidget(quick_check);
vlayout->addStretch(3);
QDialogButtonBox* btn_box = new QDialogButtonBox(QDialogButtonBox::Ok);
vlayout->addWidget(btn_box);
dlg->setLayout(vlayout);
connect(btn_box, &QDialogButtonBox::accepted, this, [&]()
{
create_desktop_shortcuts = desk_check->isChecked();
create_app_shortcut = quick_check->isChecked();
dlg->accept();
});
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->exec();
}
for (const auto& [boot_path, title] : bootable_paths_installed)
{
if (std::string game_dir = fs::get_parent_dir(boot_path, 2); fs::is_dir(game_dir) && fs::is_file(boot_path))
{
const std::string target_cli_args = fmt::format("--no-gui \"%%RPCS3_GAMEID%%:%s\"", game_dir.substr(game_dir.find_last_of(fs::delim) + 1));
const std::string std_title_id = sstr(package.title_id);
const std::string target_icon_dir = fmt::format("%sIcons/game_icons/%s/", fs::get_config_dir(), std_title_id);
// Copy the icon used by rpcs3 to a file
QTemporaryFile tmp_file(QDir::tempPath() + "/tempFile");
if (!tmp_file.open())
{
gui_log.error("Failed to create icon for '%s'", sstr(title.simplified()));
continue;
}
const QIcon icon = gui::utils::get_app_icon_from_path(rpcs3::utils::get_sfo_dir_from_game_path(boot_path + "/../../"), std_title_id);
QPixmap pix = icon.pixmap(icon.actualSize(QSize(1000, 1000)));
QByteArray bytes;
QBuffer buffer(&bytes);
buffer.open(QIODevice::ReadWrite);
pix.save(&buffer, "PNG");
tmp_file.write(bytes.data(), bytes.size());
std::string icon_path = sstr(tmp_file.fileName());
#ifdef _WIN32
if (gui::utils::create_shortcut(sstr(title), target_cli_args, sstr(title), icon_path, target_icon_dir, gui::utils::shortcut_location::rpcs3_shortcuts))
{
gui_log.success("Created a shortcut for '%s' at '%s/games/shortcuts/'", sstr(title.simplified()), fs::get_config_dir());
}
#endif
struct install_shortcut_info
{
std::string type;
gui::utils::shortcut_location location;
bool to_install;
};
std::initializer_list<install_shortcut_info> installing_locations =
{
{"desktop", gui::utils::shortcut_location::desktop, create_desktop_shortcuts},
#ifdef _WIN32
{"Start menu", gui::utils::shortcut_location::applications, create_app_shortcut},
#elif defined(__APPLE__)
{"dock", gui::utils::shortcut_location::applications, create_app_shortcut},
#else
{"launcher", gui::utils::shortcut_location::applications, create_app_shortcut},
#endif
};
for (const auto& loc : installing_locations)
{
if (!loc.to_install)
{
continue;
}
if (gui::utils::create_shortcut(sstr(title), target_cli_args, sstr(title), icon_path, target_icon_dir, loc.location))
{
gui_log.success("Created %s shortcut for %s", loc.type, sstr(title.simplified()));
}
else
{
gui_log.error("Failed to create %s shortcut for %s", loc.type, sstr(title.simplified()));
}
}
}
}
}
}
else

View File

@ -66,7 +66,7 @@ namespace gui::utils
[[maybe_unused]] const std::string& description,
[[maybe_unused]] const std::string& src_icon_path,
[[maybe_unused]] const std::string& target_icon_dir,
bool is_desktop_shortcut)
shortcut_location location)
{
if (name.empty())
{
@ -84,14 +84,21 @@ namespace gui::utils
std::string link_path;
if (is_desktop_shortcut)
if (location == shortcut_location::desktop)
{
link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DesktopLocation).toStdString();
}
else
else if (location == shortcut_location::applications)
{
link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ApplicationsLocation).toStdString();
}
#ifdef _WIN32
else if (location == shortcut_location::rpcs3_shortcuts)
{
link_path = fs::get_config_dir() + "/games/shortcuts/";
fs::create_dir(link_path);
}
#endif
if (!fs::is_dir(link_path))
{
@ -99,7 +106,7 @@ namespace gui::utils
return false;
}
if (!is_desktop_shortcut)
if (location == shortcut_location::applications)
{
link_path += "/RPCS3";
@ -197,7 +204,7 @@ namespace gui::utils
res = pPersistFile->Save(w_link_file.c_str(), TRUE);
if (FAILED(res))
{
if (is_desktop_shortcut)
if (location == shortcut_location::desktop)
{
return cleanup(false, fmt::format("Saving file to desktop failed (%s)", str_error(res)));
}
@ -348,7 +355,7 @@ namespace gui::utils
}
shortcut_file.close();
if (is_desktop_shortcut)
if (location == shortcut_location::desktop)
{
if (chmod(link_path.c_str(), S_IRWXU) != 0) // enables user to execute file
{

View File

@ -2,10 +2,19 @@
namespace gui::utils
{
enum shortcut_location
{
desktop,
applications,
#ifdef _WIN32
rpcs3_shortcuts,
#endif
};
bool create_shortcut(const std::string& name,
const std::string& target_cli_args,
const std::string& description,
const std::string& src_icon_path,
const std::string& target_icon_dir,
bool is_desktop_shortcut);
shortcut_location shortcut_location);
}