mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +00:00
PKG: Ask to user if he wants to install game shortcut on PKG installation
This commit is contained in:
parent
b7d80ab335
commit
0d126afb1f
@ -858,6 +858,12 @@ bool package_reader::extract_data(atomic_t<double>& sync)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
pkg_log.notice("Created file %s", path);
|
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
|
else
|
||||||
|
@ -312,6 +312,11 @@ public:
|
|||||||
bool extract_data(atomic_t<double>& sync);
|
bool extract_data(atomic_t<double>& sync);
|
||||||
psf::registry get_psf() const { return m_psf; }
|
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:
|
private:
|
||||||
bool read_header();
|
bool read_header();
|
||||||
bool read_metadata();
|
bool read_metadata();
|
||||||
@ -334,4 +339,7 @@ private:
|
|||||||
PKGHeader m_header{};
|
PKGHeader m_header{};
|
||||||
PKGMetaData m_metadata{};
|
PKGMetaData m_metadata{};
|
||||||
psf::registry m_psf{};
|
psf::registry m_psf{};
|
||||||
|
|
||||||
|
// Expose bootable file installed (if installed such)
|
||||||
|
std::string m_bootable_file_path;
|
||||||
};
|
};
|
||||||
|
@ -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_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);
|
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()));
|
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."));
|
QMessageBox::information(this, tr("Success!"), tr("Successfully created a shortcut."));
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "input_dialog.h"
|
#include "input_dialog.h"
|
||||||
#include "camera_settings_dialog.h"
|
#include "camera_settings_dialog.h"
|
||||||
#include "ipc_settings_dialog.h"
|
#include "ipc_settings_dialog.h"
|
||||||
|
#include "shortcut_utils.h"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
@ -40,6 +41,8 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
#include "rpcs3_version.h"
|
#include "rpcs3_version.h"
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
@ -846,6 +849,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
|
|||||||
package_error error = package_error::no_error;
|
package_error error = package_error::no_error;
|
||||||
|
|
||||||
bool cancelled = false;
|
bool cancelled = false;
|
||||||
|
std::map<std::string, QString> bootable_paths_installed; // -> title
|
||||||
|
|
||||||
for (usz i = 0, count = packages.size(); i < count; i++)
|
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 path = sstr(package.path);
|
||||||
const std::string file_name = sstr(file_info.fileName());
|
const std::string file_name = sstr(file_info.fileName());
|
||||||
|
|
||||||
|
std::string bootable_path;
|
||||||
|
|
||||||
// Run PKG unpacking asynchronously
|
// 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);
|
package_reader reader(path);
|
||||||
error = reader.check_target_app_version();
|
error = reader.check_target_app_version();
|
||||||
|
|
||||||
if (error == package_error::no_error)
|
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;
|
return false;
|
||||||
@ -922,7 +932,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pdlg.setHidden(true);
|
pdlg.hide();
|
||||||
pdlg.SignalFailure();
|
pdlg.SignalFailure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,9 +941,132 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
|
|||||||
m_game_list_frame->Refresh(true);
|
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));
|
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))
|
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
|
else
|
||||||
|
@ -66,7 +66,7 @@ namespace gui::utils
|
|||||||
[[maybe_unused]] const std::string& description,
|
[[maybe_unused]] const std::string& description,
|
||||||
[[maybe_unused]] const std::string& src_icon_path,
|
[[maybe_unused]] const std::string& src_icon_path,
|
||||||
[[maybe_unused]] const std::string& target_icon_dir,
|
[[maybe_unused]] const std::string& target_icon_dir,
|
||||||
bool is_desktop_shortcut)
|
shortcut_location location)
|
||||||
{
|
{
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
{
|
{
|
||||||
@ -84,14 +84,21 @@ namespace gui::utils
|
|||||||
|
|
||||||
std::string link_path;
|
std::string link_path;
|
||||||
|
|
||||||
if (is_desktop_shortcut)
|
if (location == shortcut_location::desktop)
|
||||||
{
|
{
|
||||||
link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DesktopLocation).toStdString();
|
link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DesktopLocation).toStdString();
|
||||||
}
|
}
|
||||||
else
|
else if (location == shortcut_location::applications)
|
||||||
{
|
{
|
||||||
link_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::ApplicationsLocation).toStdString();
|
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))
|
if (!fs::is_dir(link_path))
|
||||||
{
|
{
|
||||||
@ -99,7 +106,7 @@ namespace gui::utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_desktop_shortcut)
|
if (location == shortcut_location::applications)
|
||||||
{
|
{
|
||||||
link_path += "/RPCS3";
|
link_path += "/RPCS3";
|
||||||
|
|
||||||
@ -197,7 +204,7 @@ namespace gui::utils
|
|||||||
res = pPersistFile->Save(w_link_file.c_str(), TRUE);
|
res = pPersistFile->Save(w_link_file.c_str(), TRUE);
|
||||||
if (FAILED(res))
|
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)));
|
return cleanup(false, fmt::format("Saving file to desktop failed (%s)", str_error(res)));
|
||||||
}
|
}
|
||||||
@ -348,7 +355,7 @@ namespace gui::utils
|
|||||||
}
|
}
|
||||||
shortcut_file.close();
|
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
|
if (chmod(link_path.c_str(), S_IRWXU) != 0) // enables user to execute file
|
||||||
{
|
{
|
||||||
|
@ -2,10 +2,19 @@
|
|||||||
|
|
||||||
namespace gui::utils
|
namespace gui::utils
|
||||||
{
|
{
|
||||||
|
enum shortcut_location
|
||||||
|
{
|
||||||
|
desktop,
|
||||||
|
applications,
|
||||||
|
#ifdef _WIN32
|
||||||
|
rpcs3_shortcuts,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
bool create_shortcut(const std::string& name,
|
bool create_shortcut(const std::string& name,
|
||||||
const std::string& target_cli_args,
|
const std::string& target_cli_args,
|
||||||
const std::string& description,
|
const std::string& description,
|
||||||
const std::string& src_icon_path,
|
const std::string& src_icon_path,
|
||||||
const std::string& target_icon_dir,
|
const std::string& target_icon_dir,
|
||||||
bool is_desktop_shortcut);
|
shortcut_location shortcut_location);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user