mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 21:32:50 +00:00
macOS: Implement shortcuts
This commit is contained in:
parent
b57ea3a229
commit
574e934bf3
@ -20,6 +20,12 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#include <limits.h>
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(sys_log, "SYS");
|
||||
|
||||
namespace rpcs3::utils
|
||||
@ -115,7 +121,20 @@ namespace rpcs3::utils
|
||||
const usz last = path_to_exe.find_last_of('\\');
|
||||
return last == std::string::npos ? std::string("") : path_to_exe.substr(0, last + 1);
|
||||
}
|
||||
#elif !defined(__APPLE__)
|
||||
#elif defined(__APPLE__)
|
||||
std::string get_app_bundle_path()
|
||||
{
|
||||
char bin_path[PATH_MAX];
|
||||
uint32_t bin_path_size = sizeof(bin_path);
|
||||
if (_NSGetExecutablePath(bin_path, &bin_path_size) != 0)
|
||||
{
|
||||
sys_log.error("Failed to find app binary path");
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::filesystem::path(bin_path).parent_path().parent_path().parent_path();
|
||||
}
|
||||
#else
|
||||
std::string get_executable_path()
|
||||
{
|
||||
if (const char* appimage_path = ::getenv("APPIMAGE"))
|
||||
|
@ -15,7 +15,9 @@ namespace rpcs3::utils
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string get_exe_dir();
|
||||
#elif !defined(__APPLE__)
|
||||
#elif defined(__APPLE__)
|
||||
std::string get_app_bundle_path();
|
||||
#else
|
||||
std::string get_executable_path();
|
||||
#endif
|
||||
|
||||
|
@ -981,8 +981,9 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
|
||||
: tr("&Create Custom Gamepad Configuration"));
|
||||
QAction* configure_patches = menu.addAction(tr("&Manage Game Patches"));
|
||||
QAction* create_ppu_cache = menu.addAction(tr("&Create PPU Cache"));
|
||||
#ifndef __APPLE__
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
const auto on_shortcut = [this, gameinfo](bool is_desktop_shortcut)
|
||||
{
|
||||
const std::string target_cli_args = fmt::format("--no-gui \"%s\"", gameinfo->info.path);
|
||||
@ -1004,12 +1005,15 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
|
||||
connect(create_desktop_shortcut, &QAction::triggered, this, [this, gameinfo, on_shortcut](){ on_shortcut(true); });
|
||||
#ifdef _WIN32
|
||||
QAction* create_start_menu_shortcut = shortcut_menu->addAction(tr("&Create Start Menu Shortcut"));
|
||||
#elif defined(__APPLE__)
|
||||
QAction* create_start_menu_shortcut = shortcut_menu->addAction(tr("&Create Launchpad Shortcut"));
|
||||
#else
|
||||
QAction* create_start_menu_shortcut = shortcut_menu->addAction(tr("&Create Application Menu Shortcut"));
|
||||
#endif
|
||||
connect(create_start_menu_shortcut, &QAction::triggered, this, [this, gameinfo, on_shortcut](){ on_shortcut(false); });
|
||||
#endif
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
QAction* rename_title = menu.addAction(tr("&Rename In Game List"));
|
||||
QAction* hide_serial = menu.addAction(tr("&Hide From Game List"));
|
||||
hide_serial->setCheckable(true);
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <objidl.h>
|
||||
#include <shlguid.h>
|
||||
#include <comdef.h>
|
||||
#elif !defined(__APPLE__)
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
@ -210,7 +210,112 @@ namespace gui::utils
|
||||
|
||||
return cleanup(true, {});
|
||||
|
||||
#elif !defined(__APPLE__)
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
const std::string app_bundle_path = rpcs3::utils::get_app_bundle_path();
|
||||
if (app_bundle_path.empty())
|
||||
{
|
||||
sys_log.error("Failed to create shortcut. App bundle path empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string link_path;
|
||||
|
||||
if (const char* home = ::getenv("HOME"))
|
||||
{
|
||||
if (is_desktop_shortcut)
|
||||
{
|
||||
link_path = fmt::format("%s/Desktop/%s.app", home, simple_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
link_path = fmt::format("%s/Applications/RPCS3/%s.app", home, simple_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_log.error("Failed to create shortcut. home path empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string contents_dir = link_path + "/Contents/";
|
||||
const std::string macos_dir = contents_dir + "/MacOS/";
|
||||
const std::string resources_dir = contents_dir + "/Resources/";
|
||||
|
||||
if (!fs::create_path(contents_dir) || !fs::create_path(macos_dir) || !fs::create_path(resources_dir))
|
||||
{
|
||||
sys_log.error("Failed to create shortcut. Could not create app bundle structure.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string plist_path = contents_dir + "Info.plist";
|
||||
const std::string launcher_path = macos_dir + "launcher";
|
||||
|
||||
std::string launcher_content;
|
||||
fmt::append(launcher_content, "#!/bin/bash\nopen \"%s\" --args %s", app_bundle_path, target_cli_args);
|
||||
|
||||
fs::file launcher_file(launcher_path, fs::read + fs::rewrite);
|
||||
if (!launcher_file)
|
||||
{
|
||||
sys_log.error("Failed to create launcher file: %s", launcher_path);
|
||||
return false;
|
||||
}
|
||||
if (launcher_file.write(launcher_content.data(), launcher_content.size()) != launcher_content.size())
|
||||
{
|
||||
sys_log.error("Failed to write launcher file: %s", launcher_path);
|
||||
return false;
|
||||
}
|
||||
launcher_file.close();
|
||||
|
||||
if (chmod(launcher_path.c_str(), S_IRWXU) != 0)
|
||||
{
|
||||
sys_log.error("Failed to change file permissions for launcher file: %s (%d)", strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string plist_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
|
||||
"<plist version=\"1.0\">\n"
|
||||
"<dict>\n"
|
||||
"\t<key>CFBundleExecutable</key>\n"
|
||||
"\t<string>launcher</string>\n"
|
||||
"\t<key>CFBundleIconFile</key>\n"
|
||||
"\t<string>shortcut.icns</string>\n"
|
||||
"\t<key>CFBundleInfoDictionaryVersion</key>\n"
|
||||
"\t<string>1.0</string>\n"
|
||||
"\t<key>CFBundlePackageType</key>\n"
|
||||
"\t<string>APPL</string>\n"
|
||||
"\t<key>CFBundleSignature</key>\n"
|
||||
"\t<string>\?\?\?\?</string>\n"
|
||||
"</dict>\n"
|
||||
"</plist>\n";
|
||||
|
||||
fs::file plist_file(plist_path, fs::read + fs::rewrite);
|
||||
if (!plist_file)
|
||||
{
|
||||
sys_log.error("Failed to create plist file: %s", plist_path);
|
||||
return false;
|
||||
}
|
||||
if (plist_file.write(plist_content.data(), plist_content.size()) != plist_content.size())
|
||||
{
|
||||
sys_log.error("Failed to write plist file: %s", plist_path);
|
||||
return false;
|
||||
}
|
||||
plist_file.close();
|
||||
|
||||
if (!src_icon_path.empty())
|
||||
{
|
||||
std::string target_icon_path = resources_dir;
|
||||
if (!create_square_shortcut_icon_file(src_icon_path, resources_dir, target_icon_path, "icns", 512))
|
||||
{
|
||||
// Error is logged in create_square_shortcut_icon_file
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
#else
|
||||
|
||||
const std::string exe_path = rpcs3::utils::get_executable_path();
|
||||
if (exe_path.empty())
|
||||
@ -288,9 +393,6 @@ namespace gui::utils
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
sys_log.error("Cannot create shortcuts on this operating system");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user