summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp3
-rw-r--r--src/yuzu/bootmanager.cpp5
-rw-r--r--src/yuzu/bootmanager.h5
-rw-r--r--src/yuzu/game_list.cpp14
-rw-r--r--src/yuzu/game_list.h7
-rw-r--r--src/yuzu/main.cpp192
-rw-r--r--src/yuzu/main.h7
-rw-r--r--src/yuzu/uisettings.h1
9 files changed, 228 insertions, 8 deletions
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 8e3e40cd5..41dc6d031 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -1345,8 +1345,10 @@ void EmitContext::DefineInputs(const IR::Program& program) {
1345 if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles || 1345 if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
1346 (profile.warp_size_potentially_larger_than_guest && 1346 (profile.warp_size_potentially_larger_than_guest &&
1347 (info.uses_subgroup_vote || info.uses_subgroup_mask))) { 1347 (info.uses_subgroup_vote || info.uses_subgroup_mask))) {
1348 AddCapability(spv::Capability::GroupNonUniform);
1348 subgroup_local_invocation_id = 1349 subgroup_local_invocation_id =
1349 DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId); 1350 DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
1351 Decorate(subgroup_local_invocation_id, spv::Decoration::Flat);
1350 } 1352 }
1351 if (info.uses_fswzadd) { 1353 if (info.uses_fswzadd) {
1352 const Id f32_one{Const(1.0f)}; 1354 const Id f32_one{Const(1.0f)};
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 67540cb80..f45030311 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -421,7 +421,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
421 VkPhysicalDevice8BitStorageFeatures bit8_storage{ 421 VkPhysicalDevice8BitStorageFeatures bit8_storage{
422 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, 422 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,
423 .pNext = nullptr, 423 .pNext = nullptr,
424 .storageBuffer8BitAccess = false, 424 .storageBuffer8BitAccess = true,
425 .uniformAndStorageBuffer8BitAccess = true, 425 .uniformAndStorageBuffer8BitAccess = true,
426 .storagePushConstant8 = false, 426 .storagePushConstant8 = false,
427 }; 427 };
@@ -1044,6 +1044,7 @@ void Device::CheckSuitability(bool requires_swapchain) const {
1044 std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"), 1044 std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"),
1045 std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess, 1045 std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess,
1046 "uniformAndStorageBuffer16BitAccess"), 1046 "uniformAndStorageBuffer16BitAccess"),
1047 std::make_pair(bit8_storage.storageBuffer8BitAccess, "storageBuffer8BitAccess"),
1047 std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess, 1048 std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess,
1048 "uniformAndStorageBuffer8BitAccess"), 1049 "uniformAndStorageBuffer8BitAccess"),
1049 std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"), 1050 std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"),
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 1a47fb9c9..642f96690 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -79,6 +79,11 @@ void EmuThread::run() {
79 79
80 system.GetCpuManager().OnGpuReady(); 80 system.GetCpuManager().OnGpuReady();
81 81
82 system.RegisterExitCallback([this]() {
83 stop_source.request_stop();
84 SetRunning(false);
85 });
86
82 // Holds whether the cpu was running during the last iteration, 87 // Holds whether the cpu was running during the last iteration,
83 // so that the DebugModeLeft signal can be emitted before the 88 // so that the DebugModeLeft signal can be emitted before the
84 // next execution step 89 // next execution step
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index f4deae4ee..f0edad6e4 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -84,9 +84,10 @@ public:
84 } 84 }
85 85
86 /** 86 /**
87 * Requests for the emulation thread to stop running 87 * Requests for the emulation thread to immediately stop running
88 */ 88 */
89 void RequestStop() { 89 void ForceStop() {
90 LOG_WARNING(Frontend, "Force stopping EmuThread");
90 stop_source.request_stop(); 91 stop_source.request_stop();
91 SetRunning(false); 92 SetRunning(false);
92 } 93 }
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 5c33c1b0f..22aa19c56 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -554,6 +554,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
554 QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC")); 554 QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC"));
555 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); 555 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
556 QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); 556 QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
557#ifndef WIN32
558 QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut"));
559 QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop"));
560 QAction* create_applications_menu_shortcut =
561 shortcut_menu->addAction(tr("Add to Applications Menu"));
562#endif
557 context_menu.addSeparator(); 563 context_menu.addSeparator();
558 QAction* properties = context_menu.addAction(tr("Properties")); 564 QAction* properties = context_menu.addAction(tr("Properties"));
559 565
@@ -619,6 +625,14 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
619 connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { 625 connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
620 emit NavigateToGamedbEntryRequested(program_id, compatibility_list); 626 emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
621 }); 627 });
628#ifndef WIN32
629 connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() {
630 emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop);
631 });
632 connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() {
633 emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications);
634 });
635#endif
622 connect(properties, &QAction::triggered, 636 connect(properties, &QAction::triggered,
623 [this, path]() { emit OpenPerGameGeneralRequested(path); }); 637 [this, path]() { emit OpenPerGameGeneralRequested(path); });
624}; 638};
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index cdf085019..f7ff93ed9 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -52,6 +52,11 @@ enum class DumpRomFSTarget {
52 SDMC, 52 SDMC,
53}; 53};
54 54
55enum class GameListShortcutTarget {
56 Desktop,
57 Applications,
58};
59
55enum class InstalledEntryType { 60enum class InstalledEntryType {
56 Game, 61 Game,
57 Update, 62 Update,
@@ -108,6 +113,8 @@ signals:
108 const std::string& game_path); 113 const std::string& game_path);
109 void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); 114 void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
110 void CopyTIDRequested(u64 program_id); 115 void CopyTIDRequested(u64 program_id);
116 void CreateShortcut(u64 program_id, const std::string& game_path,
117 GameListShortcutTarget target);
111 void NavigateToGamedbEntryRequested(u64 program_id, 118 void NavigateToGamedbEntryRequested(u64 program_id,
112 const CompatibilityList& compatibility_list); 119 const CompatibilityList& compatibility_list);
113 void OpenPerGameGeneralRequested(const std::string& file); 120 void OpenPerGameGeneralRequested(const std::string& file);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 885e24990..70552bdb8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -4,6 +4,8 @@
4#include <cinttypes> 4#include <cinttypes>
5#include <clocale> 5#include <clocale>
6#include <cmath> 6#include <cmath>
7#include <fstream>
8#include <iostream>
7#include <memory> 9#include <memory>
8#include <thread> 10#include <thread>
9#ifdef __APPLE__ 11#ifdef __APPLE__
@@ -1249,6 +1251,7 @@ void GMainWindow::ConnectWidgetEvents() {
1249 connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID); 1251 connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
1250 connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, 1252 connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
1251 &GMainWindow::OnGameListNavigateToGamedbEntry); 1253 &GMainWindow::OnGameListNavigateToGamedbEntry);
1254 connect(game_list, &GameList::CreateShortcut, this, &GMainWindow::OnGameListCreateShortcut);
1252 connect(game_list, &GameList::AddDirectory, this, &GMainWindow::OnGameListAddDirectory); 1255 connect(game_list, &GameList::AddDirectory, this, &GMainWindow::OnGameListAddDirectory);
1253 connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, 1256 connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
1254 &GMainWindow::OnGameListAddDirectory); 1257 &GMainWindow::OnGameListAddDirectory);
@@ -1707,9 +1710,6 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1707 system->RegisterExecuteProgramCallback( 1710 system->RegisterExecuteProgramCallback(
1708 [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); 1711 [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); });
1709 1712
1710 // Register an Exit callback such that Core can exit the currently running application.
1711 system->RegisterExitCallback([this]() { render_window->Exit(); });
1712
1713 connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); 1713 connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
1714 connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity); 1714 connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity);
1715 // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views 1715 // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views
@@ -1796,12 +1796,16 @@ void GMainWindow::ShutdownGame() {
1796 system->SetShuttingDown(true); 1796 system->SetShuttingDown(true);
1797 system->DetachDebugger(); 1797 system->DetachDebugger();
1798 discord_rpc->Pause(); 1798 discord_rpc->Pause();
1799 emu_thread->RequestStop(); 1799
1800 RequestGameExit();
1800 1801
1801 emit EmulationStopping(); 1802 emit EmulationStopping();
1802 1803
1803 // Wait for emulation thread to complete and delete it 1804 // Wait for emulation thread to complete and delete it
1804 emu_thread->wait(); 1805 if (!emu_thread->wait(5000)) {
1806 emu_thread->ForceStop();
1807 emu_thread->wait();
1808 }
1805 emu_thread = nullptr; 1809 emu_thread = nullptr;
1806 1810
1807 emulation_running = false; 1811 emulation_running = false;
@@ -2378,6 +2382,152 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
2378 QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); 2382 QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory));
2379} 2383}
2380 2384
2385void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
2386 GameListShortcutTarget target) {
2387 // Get path to yuzu executable
2388 const QStringList args = QApplication::arguments();
2389 std::filesystem::path yuzu_command = args[0].toStdString();
2390
2391#if defined(__linux__) || defined(__FreeBSD__)
2392 // If relative path, make it an absolute path
2393 if (yuzu_command.c_str()[0] == '.') {
2394 yuzu_command = Common::FS::GetCurrentDir() / yuzu_command;
2395 }
2396
2397#if defined(__linux__)
2398 // Warn once if we are making a shortcut to a volatile AppImage
2399 const std::string appimage_ending =
2400 std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage");
2401 if (yuzu_command.string().ends_with(appimage_ending) &&
2402 !UISettings::values.shortcut_already_warned) {
2403 if (QMessageBox::warning(this, tr("Create Shortcut"),
2404 tr("This will create a shortcut to the current AppImage. This may "
2405 "not work well if you update. Continue?"),
2406 QMessageBox::StandardButton::Ok |
2407 QMessageBox::StandardButton::Cancel) ==
2408 QMessageBox::StandardButton::Cancel) {
2409 return;
2410 }
2411 UISettings::values.shortcut_already_warned = true;
2412 }
2413#endif // __linux__
2414#endif // __linux__ || __FreeBSD__
2415
2416 std::filesystem::path target_directory{};
2417 // Determine target directory for shortcut
2418#if defined(__linux__) || defined(__FreeBSD__)
2419 const char* home = std::getenv("HOME");
2420 const std::filesystem::path home_path = (home == nullptr ? "~" : home);
2421 const char* xdg_data_home = std::getenv("XDG_DATA_HOME");
2422
2423 if (target == GameListShortcutTarget::Desktop) {
2424 target_directory = home_path / "Desktop";
2425 if (!Common::FS::IsDir(target_directory)) {
2426 QMessageBox::critical(
2427 this, tr("Create Shortcut"),
2428 tr("Cannot create shortcut on desktop. Path \"%1\" does not exist.")
2429 .arg(QString::fromStdString(target_directory)),
2430 QMessageBox::StandardButton::Ok);
2431 return;
2432 }
2433 } else if (target == GameListShortcutTarget::Applications) {
2434 target_directory = (xdg_data_home == nullptr ? home_path / ".local/share" : xdg_data_home) /
2435 "applications";
2436 if (!Common::FS::CreateDirs(target_directory)) {
2437 QMessageBox::critical(this, tr("Create Shortcut"),
2438 tr("Cannot create shortcut in applications menu. Path \"%1\" "
2439 "does not exist and cannot be created.")
2440 .arg(QString::fromStdString(target_directory)),
2441 QMessageBox::StandardButton::Ok);
2442 return;
2443 }
2444 }
2445#endif
2446
2447 const std::string game_file_name = std::filesystem::path(game_path).filename().string();
2448 // Determine full paths for icon and shortcut
2449#if defined(__linux__) || defined(__FreeBSD__)
2450 std::filesystem::path system_icons_path =
2451 (xdg_data_home == nullptr ? home_path / ".local/share/" : xdg_data_home) /
2452 "icons/hicolor/256x256";
2453 if (!Common::FS::CreateDirs(system_icons_path)) {
2454 QMessageBox::critical(
2455 this, tr("Create Icon"),
2456 tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
2457 .arg(QString::fromStdString(system_icons_path)),
2458 QMessageBox::StandardButton::Ok);
2459 return;
2460 }
2461 std::filesystem::path icon_path =
2462 system_icons_path / (program_id == 0 ? fmt::format("yuzu-{}.png", game_file_name)
2463 : fmt::format("yuzu-{:016X}.png", program_id));
2464 const std::filesystem::path shortcut_path =
2465 target_directory / (program_id == 0 ? fmt::format("yuzu-{}.desktop", game_file_name)
2466 : fmt::format("yuzu-{:016X}.desktop", program_id));
2467#else
2468 const std::filesystem::path icon_path{};
2469 const std::filesystem::path shortcut_path{};
2470#endif
2471
2472 // Get title from game file
2473 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
2474 system->GetContentProvider()};
2475 const auto control = pm.GetControlMetadata();
2476 const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read));
2477
2478 std::string title{fmt::format("{:016X}", program_id)};
2479
2480 if (control.first != nullptr) {
2481 title = control.first->GetApplicationName();
2482 } else {
2483 loader->ReadTitle(title);
2484 }
2485
2486 // Get icon from game file
2487 std::vector<u8> icon_image_file{};
2488 if (control.second != nullptr) {
2489 icon_image_file = control.second->ReadAllBytes();
2490 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
2491 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
2492 }
2493
2494 QImage icon_jpeg =
2495 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
2496#if defined(__linux__) || defined(__FreeBSD__)
2497 // Convert and write the icon as a PNG
2498 if (!icon_jpeg.save(QString::fromStdString(icon_path.string()))) {
2499 LOG_ERROR(Frontend, "Could not write icon as PNG to file");
2500 } else {
2501 LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
2502 }
2503#endif // __linux__
2504
2505#if defined(__linux__) || defined(__FreeBSD__)
2506 const std::string comment =
2507 tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString();
2508 const std::string arguments = fmt::format("-g \"{:s}\"", game_path);
2509 const std::string categories = "Game;Emulator;Qt;";
2510 const std::string keywords = "Switch;Nintendo;";
2511#else
2512 const std::string comment{};
2513 const std::string arguments{};
2514 const std::string categories{};
2515 const std::string keywords{};
2516#endif
2517 if (!CreateShortcut(shortcut_path.string(), title, comment, icon_path.string(),
2518 yuzu_command.string(), arguments, categories, keywords)) {
2519 QMessageBox::critical(this, tr("Create Shortcut"),
2520 tr("Failed to create a shortcut at %1")
2521 .arg(QString::fromStdString(shortcut_path.string())));
2522 return;
2523 }
2524
2525 LOG_INFO(Frontend, "Wrote a shortcut to {}", shortcut_path.string());
2526 QMessageBox::information(
2527 this, tr("Create Shortcut"),
2528 tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title)));
2529}
2530
2381void GMainWindow::OnGameListOpenDirectory(const QString& directory) { 2531void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
2382 std::filesystem::path fs_path; 2532 std::filesystem::path fs_path;
2383 if (directory == QStringLiteral("SDMC")) { 2533 if (directory == QStringLiteral("SDMC")) {
@@ -3301,6 +3451,38 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
3301 } 3451 }
3302} 3452}
3303 3453
3454bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title,
3455 const std::string& comment, const std::string& icon_path,
3456 const std::string& command, const std::string& arguments,
3457 const std::string& categories, const std::string& keywords) {
3458#if defined(__linux__) || defined(__FreeBSD__)
3459 // This desktop file template was writting referencing
3460 // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
3461 std::string shortcut_contents{};
3462 shortcut_contents.append("[Desktop Entry]\n");
3463 shortcut_contents.append("Type=Application\n");
3464 shortcut_contents.append("Version=1.0\n");
3465 shortcut_contents.append(fmt::format("Name={:s}\n", title));
3466 shortcut_contents.append(fmt::format("Comment={:s}\n", comment));
3467 shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path));
3468 shortcut_contents.append(fmt::format("TryExec={:s}\n", command));
3469 shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments));
3470 shortcut_contents.append(fmt::format("Categories={:s}\n", categories));
3471 shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords));
3472
3473 std::ofstream shortcut_stream(shortcut_path);
3474 if (!shortcut_stream.is_open()) {
3475 LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path);
3476 return false;
3477 }
3478 shortcut_stream << shortcut_contents;
3479 shortcut_stream.close();
3480
3481 return true;
3482#endif
3483 return false;
3484}
3485
3304void GMainWindow::OnLoadAmiibo() { 3486void GMainWindow::OnLoadAmiibo() {
3305 if (emu_thread == nullptr || !emu_thread->IsRunning()) { 3487 if (emu_thread == nullptr || !emu_thread->IsRunning()) {
3306 return; 3488 return;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 27644fae5..1047ba276 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -38,6 +38,7 @@ class QProgressDialog;
38class WaitTreeWidget; 38class WaitTreeWidget;
39enum class GameListOpenTarget; 39enum class GameListOpenTarget;
40enum class GameListRemoveTarget; 40enum class GameListRemoveTarget;
41enum class GameListShortcutTarget;
41enum class DumpRomFSTarget; 42enum class DumpRomFSTarget;
42enum class InstalledEntryType; 43enum class InstalledEntryType;
43class GameListPlaceholder; 44class GameListPlaceholder;
@@ -293,6 +294,8 @@ private slots:
293 void OnGameListCopyTID(u64 program_id); 294 void OnGameListCopyTID(u64 program_id);
294 void OnGameListNavigateToGamedbEntry(u64 program_id, 295 void OnGameListNavigateToGamedbEntry(u64 program_id,
295 const CompatibilityList& compatibility_list); 296 const CompatibilityList& compatibility_list);
297 void OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
298 GameListShortcutTarget target);
296 void OnGameListOpenDirectory(const QString& directory); 299 void OnGameListOpenDirectory(const QString& directory);
297 void OnGameListAddDirectory(); 300 void OnGameListAddDirectory();
298 void OnGameListShowList(bool show); 301 void OnGameListShowList(bool show);
@@ -366,6 +369,10 @@ private:
366 bool CheckDarkMode(); 369 bool CheckDarkMode();
367 370
368 QString GetTasStateDescription() const; 371 QString GetTasStateDescription() const;
372 bool CreateShortcut(const std::string& shortcut_path, const std::string& title,
373 const std::string& comment, const std::string& icon_path,
374 const std::string& command, const std::string& arguments,
375 const std::string& categories, const std::string& keywords);
369 376
370 std::unique_ptr<Ui::MainWindow> ui; 377 std::unique_ptr<Ui::MainWindow> ui;
371 378
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 452038cd9..2006b883e 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -138,6 +138,7 @@ struct Values {
138 138
139 bool configuration_applied; 139 bool configuration_applied;
140 bool reset_to_defaults; 140 bool reset_to_defaults;
141 bool shortcut_already_warned{false};
141 Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; 142 Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"};
142}; 143};
143 144