19
19
#include < wx/utils.h>
20
20
#include < wx/clipbrd.h>
21
21
22
-
23
22
#include < boost/algorithm/string.hpp>
24
23
#include < boost/tokenizer.hpp>
25
24
@@ -526,7 +525,6 @@ void wxGameList::OnKeyDown(wxListEvent& event)
526
525
}
527
526
}
528
527
529
-
530
528
enum ContextMenuEntries
531
529
{
532
530
kContextMenuRefreshGames = wxID_HIGHEST + 1 ,
@@ -732,7 +730,7 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
732
730
{
733
731
if (wxTheClipboard->Open ())
734
732
{
735
- wxTheClipboard->SetData (new wxTextDataObject (gameInfo.GetTitleName ()));
733
+ wxTheClipboard->SetData (new wxTextDataObject (wxString::FromUTF8 ( gameInfo.GetTitleName () )));
736
734
wxTheClipboard->Close ();
737
735
}
738
736
break ;
@@ -1276,129 +1274,169 @@ void wxGameList::DeleteCachedStrings()
1276
1274
m_name_cache.clear ();
1277
1275
}
1278
1276
1279
- #if BOOST_OS_LINUX || BOOST_OS_WINDOWS
1280
- void wxGameList::CreateShortcut (GameInfo2& gameInfo) {
1281
- const auto title_id = gameInfo.GetBaseTitleId ();
1282
- const auto title_name = gameInfo.GetTitleName ();
1283
- auto exe_path = ActiveSettings::GetExecutablePath ();
1284
- const char *flatpak_id = getenv (" FLATPAK_ID" );
1285
-
1286
- // GetExecutablePath returns the AppImage's temporary mount location, instead of its actual path
1287
- wxString appimage_path;
1288
- if (wxGetEnv ((" APPIMAGE" ), &appimage_path)) {
1289
- exe_path = appimage_path.utf8_string ();
1290
- }
1291
-
1292
1277
#if BOOST_OS_LINUX
1293
- const wxString desktop_entry_name = wxString::Format (" %s.desktop" , title_name);
1294
- wxFileDialog entry_dialog (this , _ (" Choose desktop entry location" ), " ~/.local/share/applications" , desktop_entry_name,
1295
- " Desktop file (*.desktop)|*.desktop" , wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);
1296
- #elif BOOST_OS_WINDOWS
1297
- // Get '%APPDATA%\Microsoft\Windows\Start Menu\Programs' path
1298
- PWSTR user_shortcut_folder;
1299
- SHGetKnownFolderPath (FOLDERID_Programs, 0 , NULL , &user_shortcut_folder);
1300
- const wxString shortcut_name = wxString::Format (" %s.lnk" , title_name);
1301
- wxFileDialog entry_dialog (this , _ (" Choose shortcut location" ), _pathToUtf8 (user_shortcut_folder), shortcut_name,
1302
- " Shortcut (*.lnk)|*.lnk" , wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);
1303
- #endif
1304
- const auto result = entry_dialog.ShowModal ();
1305
- if (result == wxID_CANCEL)
1306
- return ;
1307
- const auto output_path = entry_dialog.GetPath ();
1278
+ void wxGameList::CreateShortcut (GameInfo2& gameInfo)
1279
+ {
1280
+ const auto titleId = gameInfo.GetBaseTitleId ();
1281
+ const auto titleName = wxString::FromUTF8 (gameInfo.GetTitleName ());
1282
+ auto exePath = ActiveSettings::GetExecutablePath ();
1283
+ const char * flatpakId = getenv (" FLATPAK_ID" );
1284
+
1285
+ const wxString desktopEntryName = wxString::Format (" %s.desktop" , titleName);
1286
+ wxFileDialog entryDialog (this , _ (" Choose desktop entry location" ), " ~/.local/share/applications" , desktopEntryName,
1287
+ " Desktop file (*.desktop)|*.desktop" , wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);
1288
+ const auto result = entryDialog.ShowModal ();
1289
+ if (result == wxID_CANCEL)
1290
+ return ;
1291
+ const auto output_path = entryDialog.GetPath ();
1308
1292
1309
- #if BOOST_OS_LINUX
1310
- std::optional<fs::path> icon_path;
1311
- // Obtain and convert icon
1312
- {
1313
- m_icon_cache_mtx.lock ();
1314
- const auto icon_iter = m_icon_cache.find (title_id);
1315
- const auto result_index = (icon_iter != m_icon_cache.cend ()) ? std::optional<int >(icon_iter->second .first ) : std::nullopt;
1316
- m_icon_cache_mtx.unlock ();
1317
-
1318
- // In most cases it should find it
1319
- if (!result_index){
1320
- wxMessageBox (_ (" Icon is yet to load, so will not be used by the shortcut" ), _ (" Warning" ), wxOK | wxCENTRE | wxICON_WARNING);
1321
- }
1322
- else {
1323
- const fs::path out_icon_dir = ActiveSettings::GetUserDataPath (" icons" );
1324
-
1325
- if (!fs::exists (out_icon_dir) && !fs::create_directories (out_icon_dir)){
1326
- wxMessageBox (_ (" Cannot access the icon directory, the shortcut will have no icon" ), _ (" Warning" ), wxOK | wxCENTRE | wxICON_WARNING);
1327
- }
1328
- else {
1329
- icon_path = out_icon_dir / fmt::format (" {:016x}.png" , gameInfo.GetBaseTitleId ());
1293
+ std::optional<fs::path> iconPath;
1294
+ // Obtain and convert icon
1295
+ [&]()
1296
+ {
1297
+ int iconIndex, smallIconIndex;
1298
+
1299
+ if (!QueryIconForTitle (titleId, iconIndex, smallIconIndex))
1300
+ {
1301
+ cemuLog_log (LogType::Force, " Icon hasn't loaded" );
1302
+ return ;
1303
+ }
1304
+ const fs::path outIconDir = ActiveSettings::GetUserDataPath (" icons" );
1330
1305
1331
- auto image = m_image_list->GetIcon (result_index.value ()).ConvertToImage ();
1306
+ if (!fs::exists (outIconDir) && !fs::create_directories (outIconDir))
1307
+ {
1308
+ cemuLog_log (LogType::Force, " Failed to create icon directory" );
1309
+ return ;
1310
+ }
1332
1311
1333
- wxFileOutputStream png_file (_pathToUtf8 (icon_path.value ()));
1334
- wxPNGHandler pngHandler;
1335
- if (!pngHandler.SaveFile (&image, png_file, false )) {
1336
- icon_path = std::nullopt;
1337
- wxMessageBox (_ (" The icon was unable to be saved, the shortcut will have no icon" ), _ (" Warning" ), wxOK | wxCENTRE | wxICON_WARNING);
1338
- }
1339
- }
1340
- }
1341
- }
1342
-
1343
- std::string desktop_exec_entry;
1344
- if (flatpak_id)
1345
- desktop_exec_entry = fmt::format (" /usr/bin/flatpak run {0} --title-id {1:016x}" , flatpak_id, title_id);
1346
- else
1347
- desktop_exec_entry = fmt::format (" {0:?} --title-id {1:016x}" , _pathToUtf8 (exe_path), title_id);
1348
-
1349
- // 'Icon' accepts spaces in file name, does not accept quoted file paths
1350
- // 'Exec' does not accept non-escaped spaces, and can accept quoted file paths
1351
- auto desktop_entry_string =
1352
- fmt::format (" [Desktop Entry]\n "
1353
- " Name={0}\n "
1354
- " Comment=Play {0} on Cemu\n "
1355
- " Exec={1}\n "
1356
- " Icon={2}\n "
1357
- " Terminal=false\n "
1358
- " Type=Application\n "
1359
- " Categories=Game;\n " ,
1360
- title_name,
1361
- desktop_exec_entry,
1362
- _pathToUtf8 (icon_path.value_or (" " )));
1363
-
1364
- if (flatpak_id)
1365
- desktop_entry_string += fmt::format (" X-Flatpak={}\n " , flatpak_id);
1366
-
1367
- std::ofstream output_stream (output_path);
1368
- if (!output_stream.good ())
1369
- {
1370
- auto errorMsg = formatWxString (_ (" Failed to save desktop entry to {}" ), output_path.utf8_string ());
1371
- wxMessageBox (errorMsg, _ (" Error" ), wxOK | wxCENTRE | wxICON_ERROR);
1372
- return ;
1373
- }
1374
- output_stream << desktop_entry_string;
1312
+ iconPath = outIconDir / fmt::format (" {:016x}.png" , gameInfo.GetBaseTitleId ());
1313
+ wxFileOutputStream pngFileStream (_pathToUtf8 (iconPath.value ()));
1375
1314
1315
+ auto image = m_image_list->GetIcon (iconIndex).ConvertToImage ();
1316
+ wxPNGHandler pngHandler;
1317
+ if (!pngHandler.SaveFile (&image, pngFileStream, false ))
1318
+ {
1319
+ iconPath = std::nullopt;
1320
+ cemuLog_log (LogType::Force, " Icon failed to save" );
1321
+ }
1322
+ }();
1323
+
1324
+ std::string desktopExecEntry = flatpakId ? fmt::format (" /usr/bin/flatpak run {0} --title-id {1:016x}" , flatpakId, titleId)
1325
+ : fmt::format (" {0:?} --title-id {1:016x}" , _pathToUtf8 (exePath), titleId);
1326
+
1327
+ // 'Icon' accepts spaces in file name, does not accept quoted file paths
1328
+ // 'Exec' does not accept non-escaped spaces, and can accept quoted file paths
1329
+ auto desktopEntryString = fmt::format (
1330
+ " [Desktop Entry]\n "
1331
+ " Name={0}\n "
1332
+ " Comment=Play {0} on Cemu\n "
1333
+ " Exec={1}\n "
1334
+ " Icon={2}\n "
1335
+ " Terminal=false\n "
1336
+ " Type=Application\n "
1337
+ " Categories=Game;\n " ,
1338
+ titleName.utf8_string (),
1339
+ desktopExecEntry,
1340
+ _pathToUtf8 (iconPath.value_or (" " )));
1341
+
1342
+ if (flatpakId)
1343
+ desktopEntryString += fmt::format (" X-Flatpak={}\n " , flatpakId);
1344
+
1345
+ std::ofstream outputStream (output_path.utf8_string ());
1346
+ if (!outputStream.good ())
1347
+ {
1348
+ auto errorMsg = formatWxString (_ (" Failed to save desktop entry to {}" ), output_path.utf8_string ());
1349
+ wxMessageBox (errorMsg, _ (" Error" ), wxOK | wxCENTRE | wxICON_ERROR);
1350
+ return ;
1351
+ }
1352
+ outputStream << desktopEntryString;
1353
+ }
1376
1354
#elif BOOST_OS_WINDOWS
1377
- IShellLinkW *shell_link;
1378
- HRESULT hres = CoCreateInstance (CLSID_ShellLink, nullptr , CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast <LPVOID*>(&shell_link));
1379
- if (SUCCEEDED (hres))
1380
- {
1381
- const auto description = wxString::Format (" Play %s on Cemu" , title_name);
1382
- const auto args = wxString::Format (" -t %016llx" , title_id);
1383
-
1384
- shell_link->SetPath (exe_path.wstring ().c_str ());
1385
- shell_link->SetDescription (description.wc_str ());
1386
- shell_link->SetArguments (args.wc_str ());
1387
- shell_link->SetWorkingDirectory (exe_path.parent_path ().wstring ().c_str ());
1388
- // Use icon from Cemu exe for now since we can't embed icons into the shortcut
1389
- // in the future we could convert and store icons in AppData or ProgramData
1390
- shell_link->SetIconLocation (exe_path.wstring ().c_str (), 0 );
1391
-
1392
- IPersistFile *shell_link_file;
1393
- // save the shortcut
1394
- hres = shell_link->QueryInterface (IID_IPersistFile, reinterpret_cast <LPVOID*>(&shell_link_file));
1395
- if (SUCCEEDED (hres))
1396
- {
1397
- hres = shell_link_file->Save (output_path.wc_str (), TRUE );
1398
- shell_link_file->Release ();
1399
- }
1400
- shell_link->Release ();
1401
- }
1402
- #endif
1355
+ void wxGameList::CreateShortcut (GameInfo2& gameInfo)
1356
+ {
1357
+ const auto titleId = gameInfo.GetBaseTitleId ();
1358
+ const auto titleName = wxString::FromUTF8 (gameInfo.GetTitleName ());
1359
+ auto exePath = ActiveSettings::GetExecutablePath ();
1360
+
1361
+ // Get '%APPDATA%\Microsoft\Windows\Start Menu\Programs' path
1362
+ PWSTR userShortcutFolder;
1363
+ SHGetKnownFolderPath (FOLDERID_Programs, 0 , NULL , &userShortcutFolder);
1364
+ const wxString shortcutName = wxString::Format (" %s.lnk" , titleName);
1365
+ wxFileDialog shortcutDialog (this , _ (" Choose shortcut location" ), _pathToUtf8 (userShortcutFolder), shortcutName,
1366
+ " Shortcut (*.lnk)|*.lnk" , wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);
1367
+
1368
+ const auto result = shortcutDialog.ShowModal ();
1369
+ if (result == wxID_CANCEL)
1370
+ return ;
1371
+ const auto outputPath = shortcutDialog.GetPath ();
1372
+
1373
+ std::optional<fs::path> icon_path = std::nullopt;
1374
+ [&]()
1375
+ {
1376
+ int iconIdx;
1377
+ int smallIconIdx;
1378
+ if (!QueryIconForTitle (titleId, iconIdx, smallIconIdx))
1379
+ {
1380
+ cemuLog_log (LogType::Force, " Icon hasn't loaded" );
1381
+ return ;
1382
+ }
1383
+ const auto icon = m_image_list->GetIcon (iconIdx);
1384
+ PWSTR localAppData;
1385
+ const auto hres = SHGetKnownFolderPath (FOLDERID_LocalAppData, 0 , NULL , &localAppData);
1386
+ wxBitmap bitmap{};
1387
+ auto folder = fs::path (localAppData) / " Cemu" / " icons" ;
1388
+ if (!SUCCEEDED (hres) || (!fs::exists (folder) && !fs::create_directories (folder)))
1389
+ {
1390
+ cemuLog_log (LogType::Force, " Failed to create icon directory" );
1391
+ return ;
1392
+ }
1393
+ if (!bitmap.CopyFromIcon (icon))
1394
+ {
1395
+ cemuLog_log (LogType::Force, " Failed to copy icon" );
1396
+ return ;
1397
+ }
1398
+
1399
+ icon_path = folder / fmt::format (" {:016x}.ico" , titleId);
1400
+ auto stream = wxFileOutputStream (_pathToUtf8 (*icon_path));
1401
+ auto image = bitmap.ConvertToImage ();
1402
+ wxICOHandler icohandler{};
1403
+ if (!icohandler.SaveFile (&image, stream, false ))
1404
+ {
1405
+ icon_path = std::nullopt;
1406
+ cemuLog_log (LogType::Force, " Icon failed to save" );
1407
+ }
1408
+ }();
1409
+
1410
+ IShellLinkW* shellLink;
1411
+ HRESULT hres = CoCreateInstance (CLSID_ShellLink, nullptr , CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast <LPVOID*>(&shellLink));
1412
+ if (SUCCEEDED (hres))
1413
+ {
1414
+ const auto description = wxString::Format (" Play %s on Cemu" , titleName);
1415
+ const auto args = wxString::Format (" -t %016llx" , titleId);
1416
+
1417
+ shellLink->SetPath (exePath.wstring ().c_str ());
1418
+ shellLink->SetDescription (description.wc_str ());
1419
+ shellLink->SetArguments (args.wc_str ());
1420
+ shellLink->SetWorkingDirectory (exePath.parent_path ().wstring ().c_str ());
1421
+
1422
+ if (icon_path)
1423
+ shellLink->SetIconLocation (icon_path->wstring ().c_str (), 0 );
1424
+ else
1425
+ shellLink->SetIconLocation (exePath.wstring ().c_str (), 0 );
1426
+
1427
+ IPersistFile* shellLinkFile;
1428
+ // save the shortcut
1429
+ hres = shellLink->QueryInterface (IID_IPersistFile, reinterpret_cast <LPVOID*>(&shellLinkFile));
1430
+ if (SUCCEEDED (hres))
1431
+ {
1432
+ hres = shellLinkFile->Save (outputPath.wc_str (), TRUE );
1433
+ shellLinkFile->Release ();
1434
+ }
1435
+ shellLink->Release ();
1436
+ }
1437
+ if (!SUCCEEDED (hres)) {
1438
+ auto errorMsg = formatWxString (_ (" Failed to save shortcut to {}" ), outputPath);
1439
+ wxMessageBox (errorMsg, _ (" Error" ), wxOK | wxCENTRE | wxICON_ERROR);
1440
+ }
1403
1441
}
1404
- #endif
1442
+ #endif
0 commit comments