mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-26 02:54:17 +01:00
Add '--title-id' parameter and desktop shortcut creation (#889)
* Add '--title-id' launch option to launch titles by title id * Add title id column to game list * Add option to create game shortcuts Co-authored-by: Exzap <13877693+Exzap@users.noreply.github.com>
This commit is contained in:
parent
ea86c77088
commit
f1c200a016
@ -100,6 +100,7 @@ void CemuConfig::Load(XMLConfigParser& parser)
|
|||||||
column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time);
|
column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time);
|
||||||
column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started);
|
column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started);
|
||||||
column_width.region = loadColumnSize("region_width", DefaultColumnSize::region);
|
column_width.region = loadColumnSize("region_width", DefaultColumnSize::region);
|
||||||
|
column_width.title_id = loadColumnSize("title_id", DefaultColumnSize::title_id);
|
||||||
|
|
||||||
recent_launch_files.clear();
|
recent_launch_files.clear();
|
||||||
auto launch_parser = parser.get("RecentLaunchFiles");
|
auto launch_parser = parser.get("RecentLaunchFiles");
|
||||||
@ -398,6 +399,7 @@ void CemuConfig::Save(XMLConfigParser& parser)
|
|||||||
gamelist.set("game_time_width", column_width.game_time);
|
gamelist.set("game_time_width", column_width.game_time);
|
||||||
gamelist.set("game_started_width", column_width.game_started);
|
gamelist.set("game_started_width", column_width.game_started);
|
||||||
gamelist.set("region_width", column_width.region);
|
gamelist.set("region_width", column_width.region);
|
||||||
|
gamelist.set("title_id", column_width.title_id);
|
||||||
|
|
||||||
auto launch_files_parser = config.set("RecentLaunchFiles");
|
auto launch_files_parser = config.set("RecentLaunchFiles");
|
||||||
for (const auto& entry : recent_launch_files)
|
for (const auto& entry : recent_launch_files)
|
||||||
|
@ -340,6 +340,7 @@ namespace DefaultColumnSize {
|
|||||||
game_time = 140u,
|
game_time = 140u,
|
||||||
game_started = 160u,
|
game_started = 160u,
|
||||||
region = 80u,
|
region = 80u,
|
||||||
|
title_id = 160u
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -427,6 +428,7 @@ struct CemuConfig
|
|||||||
uint32 game_time = DefaultColumnSize::game_time;
|
uint32 game_time = DefaultColumnSize::game_time;
|
||||||
uint32 game_started = DefaultColumnSize::game_started;
|
uint32 game_started = DefaultColumnSize::game_started;
|
||||||
uint32 region = DefaultColumnSize::region;
|
uint32 region = DefaultColumnSize::region;
|
||||||
|
uint32 title_id = 0;
|
||||||
} column_width{};
|
} column_width{};
|
||||||
|
|
||||||
// graphics
|
// graphics
|
||||||
|
@ -60,6 +60,7 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
|||||||
("version,v", "Displays the version of Cemu")
|
("version,v", "Displays the version of Cemu")
|
||||||
|
|
||||||
("game,g", po::wvalue<std::wstring>(), "Path of game to launch")
|
("game,g", po::wvalue<std::wstring>(), "Path of game to launch")
|
||||||
|
("title-id,t", po::value<std::string>(), "Title ID of the title to be launched (overridden by --game)")
|
||||||
("mlc,m", po::wvalue<std::wstring>(), "Custom mlc folder location")
|
("mlc,m", po::wvalue<std::wstring>(), "Custom mlc folder location")
|
||||||
|
|
||||||
("fullscreen,f", po::value<bool>()->implicit_value(true), "Launch games in fullscreen mode")
|
("fullscreen,f", po::value<bool>()->implicit_value(true), "Launch games in fullscreen mode")
|
||||||
@ -133,6 +134,21 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
|||||||
|
|
||||||
s_load_game_file = tmp;
|
s_load_game_file = tmp;
|
||||||
}
|
}
|
||||||
|
if (vm.count("title-id"))
|
||||||
|
{
|
||||||
|
auto title_param = vm["title-id"].as<std::string>();
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (title_param.starts_with('=')){
|
||||||
|
title_param.erase(title_param.begin());
|
||||||
|
}
|
||||||
|
s_load_title_id = std::stoull(title_param, nullptr, 16);
|
||||||
|
}
|
||||||
|
catch (std::invalid_argument const& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Expected title_param ID as an unsigned 64-bit hexadecimal string\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (vm.count("mlc"))
|
if (vm.count("mlc"))
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,7 @@ public:
|
|||||||
static bool HandleCommandline(const std::vector<std::wstring>& args);
|
static bool HandleCommandline(const std::vector<std::wstring>& args);
|
||||||
|
|
||||||
static std::optional<fs::path> GetLoadFile() { return s_load_game_file; }
|
static std::optional<fs::path> GetLoadFile() { return s_load_game_file; }
|
||||||
|
static std::optional<uint64> GetLoadTitleID() {return s_load_title_id;}
|
||||||
static std::optional<fs::path> GetMLCPath() { return s_mlc_path; }
|
static std::optional<fs::path> GetMLCPath() { return s_mlc_path; }
|
||||||
|
|
||||||
static std::optional<bool> RenderUpsideDownEnabled() { return s_render_upside_down; }
|
static std::optional<bool> RenderUpsideDownEnabled() { return s_render_upside_down; }
|
||||||
@ -35,6 +36,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
inline static std::optional<fs::path> s_load_game_file{};
|
inline static std::optional<fs::path> s_load_game_file{};
|
||||||
|
inline static std::optional<uint64> s_load_title_id{};
|
||||||
inline static std::optional<fs::path> s_mlc_path{};
|
inline static std::optional<fs::path> s_mlc_path{};
|
||||||
|
|
||||||
inline static std::optional<bool> s_render_upside_down{};
|
inline static std::optional<bool> s_render_upside_down{};
|
||||||
|
@ -305,7 +305,32 @@ MainWindow::MainWindow()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto* main_sizer = new wxBoxSizer(wxVERTICAL);
|
auto* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
if (!LaunchSettings::GetLoadFile().has_value())
|
auto load_file = LaunchSettings::GetLoadFile();
|
||||||
|
auto load_title_id = LaunchSettings::GetLoadTitleID();
|
||||||
|
bool quick_launch = false;
|
||||||
|
|
||||||
|
if (load_file)
|
||||||
|
{
|
||||||
|
MainWindow::RequestLaunchGame(load_file.value(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
||||||
|
quick_launch = true;
|
||||||
|
}
|
||||||
|
else if (load_title_id)
|
||||||
|
{
|
||||||
|
TitleInfo info;
|
||||||
|
TitleId baseId;
|
||||||
|
if (CafeTitleList::FindBaseTitleId(load_title_id.value(), baseId) && CafeTitleList::GetFirstByTitleId(baseId, info))
|
||||||
|
{
|
||||||
|
MainWindow::RequestLaunchGame(info.GetPath(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
||||||
|
quick_launch = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxString errorMsg = fmt::format("Title ID {:016x} not found", load_title_id.value());
|
||||||
|
wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!quick_launch)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
m_main_panel = new wxPanel(this);
|
m_main_panel = new wxPanel(this);
|
||||||
@ -328,7 +353,7 @@ MainWindow::MainWindow()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// launching game via -g option. Dont setup or load game list
|
// launching game via -g or -t option. Don't set up or load game list
|
||||||
m_game_list = nullptr;
|
m_game_list = nullptr;
|
||||||
m_info_bar = nullptr;
|
m_info_bar = nullptr;
|
||||||
}
|
}
|
||||||
@ -350,10 +375,6 @@ MainWindow::MainWindow()
|
|||||||
Bind(wxEVT_OPEN_GRAPHIC_PACK, &MainWindow::OnGraphicWindowOpen, this);
|
Bind(wxEVT_OPEN_GRAPHIC_PACK, &MainWindow::OnGraphicWindowOpen, this);
|
||||||
Bind(wxEVT_LAUNCH_GAME, &MainWindow::OnLaunchFromFile, this);
|
Bind(wxEVT_LAUNCH_GAME, &MainWindow::OnLaunchFromFile, this);
|
||||||
|
|
||||||
if (LaunchSettings::GetLoadFile().has_value())
|
|
||||||
{
|
|
||||||
MainWindow::RequestLaunchGame(LaunchSettings::GetLoadFile().value(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
|
||||||
}
|
|
||||||
if (LaunchSettings::GDBStubEnabled())
|
if (LaunchSettings::GDBStubEnabled())
|
||||||
{
|
{
|
||||||
g_gdbstub = std::make_unique<GDBServer>(config.gdb_port);
|
g_gdbstub = std::make_unique<GDBServer>(config.gdb_port);
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
#include <wx/textdlg.h>
|
#include <wx/textdlg.h>
|
||||||
#include <wx/stattext.h>
|
#include <wx/stattext.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
|
#include <wx/wfstream.h>
|
||||||
|
#include <wx/imagpng.h>
|
||||||
|
#include <wx/string.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/tokenizer.hpp>
|
#include <boost/tokenizer.hpp>
|
||||||
@ -30,6 +33,17 @@
|
|||||||
|
|
||||||
#include "Cafe/IOSU/PDM/iosu_pdm.h" // for last played and play time
|
#include "Cafe/IOSU/PDM/iosu_pdm.h" // for last played and play time
|
||||||
|
|
||||||
|
#if BOOST_OS_WINDOWS
|
||||||
|
// for shortcut creation
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winnls.h>
|
||||||
|
#include <shobjidl.h>
|
||||||
|
#include <objbase.h>
|
||||||
|
#include <objidl.h>
|
||||||
|
#include <shlguid.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// public events
|
// public events
|
||||||
wxDEFINE_EVENT(wxEVT_OPEN_SETTINGS, wxCommandEvent);
|
wxDEFINE_EVENT(wxEVT_OPEN_SETTINGS, wxCommandEvent);
|
||||||
wxDEFINE_EVENT(wxEVT_GAMELIST_BEGIN_UPDATE, wxCommandEvent);
|
wxDEFINE_EVENT(wxEVT_GAMELIST_BEGIN_UPDATE, wxCommandEvent);
|
||||||
@ -79,6 +93,7 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id)
|
|||||||
InsertColumn(ColumnGameTime, _("You've played"), wxLIST_FORMAT_LEFT, config.column_width.game_time);
|
InsertColumn(ColumnGameTime, _("You've played"), wxLIST_FORMAT_LEFT, config.column_width.game_time);
|
||||||
InsertColumn(ColumnGameStarted, _("Last played"), wxLIST_FORMAT_LEFT, config.column_width.game_started);
|
InsertColumn(ColumnGameStarted, _("Last played"), wxLIST_FORMAT_LEFT, config.column_width.game_started);
|
||||||
InsertColumn(ColumnRegion, _("Region"), wxLIST_FORMAT_LEFT, config.column_width.region);
|
InsertColumn(ColumnRegion, _("Region"), wxLIST_FORMAT_LEFT, config.column_width.region);
|
||||||
|
InsertColumn(ColumnTitleID, _("Title ID"), wxLIST_FORMAT_LEFT, config.column_width.title_id);
|
||||||
|
|
||||||
const char transparent_bitmap[kIconWidth * kIconWidth * 4] = {0};
|
const char transparent_bitmap[kIconWidth * kIconWidth * 4] = {0};
|
||||||
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
||||||
@ -244,6 +259,8 @@ int wxGameList::GetColumnDefaultWidth(int column)
|
|||||||
return DefaultColumnSize::game_started;
|
return DefaultColumnSize::game_started;
|
||||||
case ColumnRegion:
|
case ColumnRegion:
|
||||||
return DefaultColumnSize::region;
|
return DefaultColumnSize::region;
|
||||||
|
case ColumnTitleID:
|
||||||
|
return DefaultColumnSize::title_id;
|
||||||
default:
|
default:
|
||||||
return 80;
|
return 80;
|
||||||
}
|
}
|
||||||
@ -528,6 +545,7 @@ enum ContextMenuEntries
|
|||||||
kContextMenuStyleList,
|
kContextMenuStyleList,
|
||||||
kContextMenuStyleIcon,
|
kContextMenuStyleIcon,
|
||||||
kContextMenuStyleIconSmall,
|
kContextMenuStyleIconSmall,
|
||||||
|
kContextMenuCreateShortcut
|
||||||
};
|
};
|
||||||
void wxGameList::OnContextMenu(wxContextMenuEvent& event)
|
void wxGameList::OnContextMenu(wxContextMenuEvent& event)
|
||||||
{
|
{
|
||||||
@ -568,6 +586,10 @@ void wxGameList::OnContextMenu(wxContextMenuEvent& event)
|
|||||||
menu.Append(kContextMenuEditGraphicPacks, _("&Edit graphic packs"));
|
menu.Append(kContextMenuEditGraphicPacks, _("&Edit graphic packs"));
|
||||||
menu.Append(kContextMenuEditGameProfile, _("&Edit game profile"));
|
menu.Append(kContextMenuEditGameProfile, _("&Edit game profile"));
|
||||||
|
|
||||||
|
menu.AppendSeparator();
|
||||||
|
#if BOOST_OS_LINUX || BOOST_OS_WINDOWS
|
||||||
|
menu.Append(kContextMenuCreateShortcut, _("&Create shortcut"));
|
||||||
|
#endif
|
||||||
menu.AppendSeparator();
|
menu.AppendSeparator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -687,6 +709,11 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
|
|||||||
(new GameProfileWindow(GetParent(), title_id))->Show();
|
(new GameProfileWindow(GetParent(), title_id))->Show();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kContextMenuCreateShortcut:
|
||||||
|
#if BOOST_OS_LINUX || BOOST_OS_WINDOWS
|
||||||
|
CreateShortcut(gameInfo);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -729,6 +756,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
|
|||||||
ShowGameTime,
|
ShowGameTime,
|
||||||
ShowLastPlayed,
|
ShowLastPlayed,
|
||||||
ShowRegion,
|
ShowRegion,
|
||||||
|
ShowTitleId
|
||||||
};
|
};
|
||||||
const int column = event.GetColumn();
|
const int column = event.GetColumn();
|
||||||
wxMenu menu;
|
wxMenu menu;
|
||||||
@ -744,6 +772,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
|
|||||||
menu.AppendCheckItem(ShowGameTime, _("Show &game time"))->Check(GetColumnWidth(ColumnGameTime) > 0);
|
menu.AppendCheckItem(ShowGameTime, _("Show &game time"))->Check(GetColumnWidth(ColumnGameTime) > 0);
|
||||||
menu.AppendCheckItem(ShowLastPlayed, _("Show &last played"))->Check(GetColumnWidth(ColumnGameStarted) > 0);
|
menu.AppendCheckItem(ShowLastPlayed, _("Show &last played"))->Check(GetColumnWidth(ColumnGameStarted) > 0);
|
||||||
menu.AppendCheckItem(ShowRegion, _("Show ®ion"))->Check(GetColumnWidth(ColumnRegion) > 0);
|
menu.AppendCheckItem(ShowRegion, _("Show ®ion"))->Check(GetColumnWidth(ColumnRegion) > 0);
|
||||||
|
menu.AppendCheckItem(ShowTitleId, _("Show &title ID"))->Check(GetColumnWidth(ColumnTitleID) > 0);
|
||||||
|
|
||||||
menu.Bind(wxEVT_COMMAND_MENU_SELECTED,
|
menu.Bind(wxEVT_COMMAND_MENU_SELECTED,
|
||||||
[this](wxCommandEvent& event) {
|
[this](wxCommandEvent& event) {
|
||||||
@ -773,6 +802,9 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
|
|||||||
case ShowRegion:
|
case ShowRegion:
|
||||||
config.column_width.region = menu->IsChecked(ShowRegion) ? DefaultColumnSize::region : 0;
|
config.column_width.region = menu->IsChecked(ShowRegion) ? DefaultColumnSize::region : 0;
|
||||||
break;
|
break;
|
||||||
|
case ShowTitleId:
|
||||||
|
config.column_width.title_id = menu->IsChecked(ShowTitleId) ? DefaultColumnSize::title_id : 0;
|
||||||
|
break;
|
||||||
case ResetWidth:
|
case ResetWidth:
|
||||||
{
|
{
|
||||||
switch (column)
|
switch (column)
|
||||||
@ -797,6 +829,8 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
|
|||||||
case ColumnRegion:
|
case ColumnRegion:
|
||||||
config.column_width.region = DefaultColumnSize::region;
|
config.column_width.region = DefaultColumnSize::region;
|
||||||
break;
|
break;
|
||||||
|
case ColumnTitleID:
|
||||||
|
config.column_width.title_id = DefaultColumnSize::title_id;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -836,6 +870,7 @@ void wxGameList::ApplyGameListColumnWidths()
|
|||||||
SetColumnWidth(ColumnGameTime, config.column_width.game_time);
|
SetColumnWidth(ColumnGameTime, config.column_width.game_time);
|
||||||
SetColumnWidth(ColumnGameStarted, config.column_width.game_started);
|
SetColumnWidth(ColumnGameStarted, config.column_width.game_started);
|
||||||
SetColumnWidth(ColumnRegion, config.column_width.region);
|
SetColumnWidth(ColumnRegion, config.column_width.region);
|
||||||
|
SetColumnWidth(ColumnTitleID, config.column_width.title_id);
|
||||||
|
|
||||||
AdjustLastColumnWidth();
|
AdjustLastColumnWidth();
|
||||||
}
|
}
|
||||||
@ -1003,6 +1038,7 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)
|
|||||||
|
|
||||||
const auto region_text = fmt::format("{}", gameInfo.GetRegion());
|
const auto region_text = fmt::format("{}", gameInfo.GetRegion());
|
||||||
SetItem(index, ColumnRegion, _(region_text));
|
SetItem(index, ColumnRegion, _(region_text));
|
||||||
|
SetItem(index, ColumnTitleID, _(fmt::format("{:016x}", titleId)));
|
||||||
}
|
}
|
||||||
else if (m_style == Style::kIcons)
|
else if (m_style == Style::kIcons)
|
||||||
{
|
{
|
||||||
@ -1189,3 +1225,105 @@ void wxGameList::DeleteCachedStrings()
|
|||||||
{
|
{
|
||||||
m_name_cache.clear();
|
m_name_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BOOST_OS_LINUX || BOOST_OS_WINDOWS
|
||||||
|
void wxGameList::CreateShortcut(GameInfo2& gameInfo) {
|
||||||
|
const auto title_id = gameInfo.GetBaseTitleId();
|
||||||
|
const auto title_name = gameInfo.GetTitleName();
|
||||||
|
const auto exe_path = ActiveSettings::GetExecutablePath();
|
||||||
|
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
const wxString desktop_entry_name = wxString::Format("%s.desktop", title_name);
|
||||||
|
wxFileDialog entry_dialog(this, _("Choose desktop entry location"), "~/.local/share/applications", desktop_entry_name,
|
||||||
|
"Desktop file (*.desktop)|*.desktop", wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);
|
||||||
|
#elif BOOST_OS_WINDOWS
|
||||||
|
// Get '%APPDATA%\Microsoft\Windows\Start Menu\Programs' path
|
||||||
|
PWSTR user_shortcut_folder;
|
||||||
|
SHGetKnownFolderPath(FOLDERID_Programs, 0, NULL, &user_shortcut_folder);
|
||||||
|
const wxString shortcut_name = wxString::Format("%s.lnk", title_name);
|
||||||
|
wxFileDialog entry_dialog(this, _("Choose shortcut location"), _pathToUtf8(user_shortcut_folder), shortcut_name,
|
||||||
|
"Shortcut (*.lnk)|*.lnk", wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);
|
||||||
|
#endif
|
||||||
|
const auto result = entry_dialog.ShowModal();
|
||||||
|
if (result == wxID_CANCEL)
|
||||||
|
return;
|
||||||
|
const auto output_path = entry_dialog.GetPath();
|
||||||
|
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
std::optional<fs::path> icon_path;
|
||||||
|
// Obtain and convert icon
|
||||||
|
{
|
||||||
|
m_icon_cache_mtx.lock();
|
||||||
|
const auto icon_iter = m_icon_cache.find(title_id);
|
||||||
|
const auto result_index = (icon_iter != m_icon_cache.cend()) ? std::optional<int>(icon_iter->second.first) : std::nullopt;
|
||||||
|
m_icon_cache_mtx.unlock();
|
||||||
|
|
||||||
|
// In most cases it should find it
|
||||||
|
if (!result_index){
|
||||||
|
wxMessageBox("Icon is yet to load, so will not be used by the shortcut", "Warning", wxOK | wxCENTRE | wxICON_WARNING);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const auto out_icon_dir = ActiveSettings::GetDataPath("icons");
|
||||||
|
fs::create_directories(out_icon_dir);
|
||||||
|
icon_path = out_icon_dir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||||
|
|
||||||
|
auto image = m_image_list->GetIcon(result_index.value()).ConvertToImage();
|
||||||
|
|
||||||
|
wxFileOutputStream png_file(_pathToUtf8(icon_path.value()));
|
||||||
|
wxPNGHandler pngHandler;
|
||||||
|
pngHandler.SaveFile(&image, png_file, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto desktop_entry_string =
|
||||||
|
fmt::format("[Desktop Entry]\n"
|
||||||
|
"Name={}\n"
|
||||||
|
"Comment=Play {} on Cemu\n"
|
||||||
|
"Exec={} --title-id {:016x}\n"
|
||||||
|
"Icon={}\n"
|
||||||
|
"Terminal=false\n"
|
||||||
|
"Type=Application\n"
|
||||||
|
"Categories=Game;",
|
||||||
|
title_name,
|
||||||
|
title_name,
|
||||||
|
_pathToUtf8(exe_path),
|
||||||
|
title_id,
|
||||||
|
_pathToUtf8(icon_path.value_or("")));
|
||||||
|
|
||||||
|
std::ofstream output_stream(output_path);
|
||||||
|
if (!output_stream.good())
|
||||||
|
{
|
||||||
|
const wxString errorMsg = fmt::format("Failed to save desktop entry to {}", output_path.utf8_string());
|
||||||
|
wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
output_stream << desktop_entry_string;
|
||||||
|
|
||||||
|
#elif BOOST_OS_WINDOWS
|
||||||
|
IShellLinkW *shell_link;
|
||||||
|
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast<LPVOID*>(&shell_link));
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
const auto description = wxString::Format("Play %s on Cemu", title_name);
|
||||||
|
const auto args = wxString::Format("-t %016llx", title_id);
|
||||||
|
|
||||||
|
shell_link->SetPath(exe_path.wstring().c_str());
|
||||||
|
shell_link->SetDescription(description.wc_str());
|
||||||
|
shell_link->SetArguments(args.wc_str());
|
||||||
|
shell_link->SetWorkingDirectory(exe_path.parent_path().wstring().c_str());
|
||||||
|
// Use icon from Cemu exe for now since we can't embed icons into the shortcut
|
||||||
|
// in the future we could convert and store icons in AppData or ProgramData
|
||||||
|
shell_link->SetIconLocation(exe_path.wstring().c_str(), 0);
|
||||||
|
|
||||||
|
IPersistFile *shell_link_file;
|
||||||
|
// save the shortcut
|
||||||
|
hres = shell_link->QueryInterface(IID_IPersistFile, reinterpret_cast<LPVOID*>(&shell_link_file));
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
hres = shell_link_file->Save(output_path.wc_str(), TRUE);
|
||||||
|
shell_link_file->Release();
|
||||||
|
}
|
||||||
|
shell_link->Release();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
@ -10,6 +10,7 @@
|
|||||||
#include <wx/listctrl.h>
|
#include <wx/listctrl.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
|
#include <Cafe/TitleList/GameInfo.h>
|
||||||
#include "util/helpers/Semaphore.h"
|
#include "util/helpers/Semaphore.h"
|
||||||
|
|
||||||
class wxTitleIdEvent : public wxCommandEvent
|
class wxTitleIdEvent : public wxCommandEvent
|
||||||
@ -52,6 +53,10 @@ public:
|
|||||||
void ReloadGameEntries(bool cached = false);
|
void ReloadGameEntries(bool cached = false);
|
||||||
void DeleteCachedStrings();
|
void DeleteCachedStrings();
|
||||||
|
|
||||||
|
#if BOOST_OS_LINUX || BOOST_OS_WINDOWS
|
||||||
|
void CreateShortcut(GameInfo2& gameInfo);
|
||||||
|
#endif
|
||||||
|
|
||||||
long FindListItemByTitleId(uint64 title_id) const;
|
long FindListItemByTitleId(uint64 title_id) const;
|
||||||
void OnClose(wxCloseEvent& event);
|
void OnClose(wxCloseEvent& event);
|
||||||
|
|
||||||
@ -75,8 +80,9 @@ private:
|
|||||||
ColumnGameTime,
|
ColumnGameTime,
|
||||||
ColumnGameStarted,
|
ColumnGameStarted,
|
||||||
ColumnRegion,
|
ColumnRegion,
|
||||||
//ColumnFavorite,
|
ColumnTitleID,
|
||||||
ColumnCounts
|
//ColumnFavorite,
|
||||||
|
ColumnCounts,
|
||||||
};
|
};
|
||||||
|
|
||||||
int s_last_column = ColumnName;
|
int s_last_column = ColumnName;
|
||||||
|
Loading…
Reference in New Issue
Block a user