summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/fs/path_util.cpp10
-rw-r--r--src/yuzu/main.cpp158
-rw-r--r--src/yuzu/main.h2
3 files changed, 79 insertions, 91 deletions
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index 3d88fcf4f..bcd64156e 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -254,11 +254,8 @@ fs::path GetExeDirectory() {
254 WCHAR exe_path[MAX_PATH]; 254 WCHAR exe_path[MAX_PATH];
255 255
256 if (SUCCEEDED(GetModuleFileNameW(nullptr, exe_path, MAX_PATH))) { 256 if (SUCCEEDED(GetModuleFileNameW(nullptr, exe_path, MAX_PATH))) {
257 std::wstring wideExePath(exe_path); 257 std::wstring wide_exe_path(exe_path);
258 258 return fs::path{Common::UTF16ToUTF8(wide_exe_path)}.parent_path();
259 // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with
260 // the Windows library (Filesystem converts the strings literally).
261 return fs::path{Common::UTF16ToUTF8(wideExePath)}.parent_path();
262 } else { 259 } else {
263 LOG_ERROR(Common_Filesystem, "Failed to get the path to the executable of the current " 260 LOG_ERROR(Common_Filesystem, "Failed to get the path to the executable of the current "
264 "process"); 261 "process");
@@ -273,9 +270,6 @@ fs::path GetAppDataRoamingDirectory() {
273 if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) { 270 if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) {
274 std::wstring wideAppdataRoamingPath(appdata_roaming_path); 271 std::wstring wideAppdataRoamingPath(appdata_roaming_path);
275 CoTaskMemFree(appdata_roaming_path); 272 CoTaskMemFree(appdata_roaming_path);
276
277 // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with
278 // the Windows library (Filesystem converts the strings literally).
279 return fs::path{Common::UTF16ToUTF8(wideAppdataRoamingPath)}; 273 return fs::path{Common::UTF16ToUTF8(wideAppdataRoamingPath)};
280 } else { 274 } else {
281 LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); 275 LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory");
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f2b91a7f3..36f9551a1 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2847,8 +2847,6 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
2847 const std::string& arguments, const std::string& categories, 2847 const std::string& arguments, const std::string& categories,
2848 const std::string& keywords, const std::string& name) { 2848 const std::string& keywords, const std::string& name) {
2849 2849
2850 bool shortcut_succeeded = false;
2851
2852 // Copy characters if they are not illegal in Windows filenames 2850 // Copy characters if they are not illegal in Windows filenames
2853 std::string filename = ""; 2851 std::string filename = "";
2854 const std::string illegal_chars = "<>:\"/\\|?*"; 2852 const std::string illegal_chars = "<>:\"/\\|?*";
@@ -2858,22 +2856,13 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
2858 2856
2859 if (filename.empty()) { 2857 if (filename.empty()) {
2860 LOG_ERROR(Frontend, "Filename is empty"); 2858 LOG_ERROR(Frontend, "Filename is empty");
2861 shortcut_succeeded = false; 2859 return false;
2862 return shortcut_succeeded;
2863 } 2860 }
2864 2861
2865 // Replace characters that are illegal in Windows filenames 2862 // Append .desktop or .lnk extension
2866 std::filesystem::path shortcut_path_full = shortcut_path / filename; 2863 std::filesystem::path shortcut_path_full = shortcut_path / filename;
2867 2864
2868#if defined(__linux__) || defined(__FreeBSD__) 2865#if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD
2869 shortcut_path_full += ".desktop";
2870#elif defined(_WIN32)
2871 shortcut_path_full += ".lnk";
2872#endif
2873
2874 LOG_ERROR(Frontend, "Create shortcut path: {}", shortcut_path_full.string());
2875
2876#if defined(__linux__) || defined(__FreeBSD__)
2877 // This desktop file template was writing referencing 2866 // This desktop file template was writing referencing
2878 // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html 2867 // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
2879 try { 2868 try {
@@ -2881,9 +2870,13 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
2881 // Plus 'Type' is required 2870 // Plus 'Type' is required
2882 if (name.empty()) { 2871 if (name.empty()) {
2883 LOG_ERROR(Frontend, "Name is empty"); 2872 LOG_ERROR(Frontend, "Name is empty");
2884 shortcut_succeeded = false; 2873 return false;
2885 return shortcut_succeeded;
2886 } 2874 }
2875
2876 // Append .desktop extension
2877 shortcut_path_full += ".desktop";
2878
2879 // Create shortcut file
2887 std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); 2880 std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc);
2888 2881
2889 if (shortcut_stream.is_open()) { 2882 if (shortcut_stream.is_open()) {
@@ -2923,78 +2916,82 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
2923 2916
2924 } else { 2917 } else {
2925 LOG_ERROR(Frontend, "Failed to create shortcut"); 2918 LOG_ERROR(Frontend, "Failed to create shortcut");
2926 return false;
2927 } 2919 }
2928 2920
2929 shortcut_stream.close(); 2921 shortcut_stream.close();
2930 } catch (const std::exception& e) { 2922 } catch (const std::exception& e) {
2931 LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); 2923 LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what());
2932 } 2924 }
2933#elif defined(_WIN32) 2925 return false;
2934 // Initialize COM 2926#elif defined(_WIN32) // Windows
2935 auto hr = CoInitialize(NULL); 2927 HRESULT hr = CoInitialize(NULL);
2936 if (FAILED(hr)) { 2928 if (SUCCEEDED(hr)) {
2937 return shortcut_succeeded;
2938 }
2939 2929
2940 IShellLinkW* ps1; 2930 IShellLinkW* ps1 = nullptr;
2931 IPersistFile* persist_file = nullptr;
2941 2932
2942 auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, 2933 SCOPE_EXIT({
2943 (void**)&ps1); 2934 if (persist_file != nullptr) {
2935 persist_file->Release();
2936 }
2937 if (ps1 != nullptr) {
2938 ps1->Release();
2939 }
2944 2940
2945 // The UTF-16 / UTF-8 conversion is broken in C++, it is necessary to perform these steps and 2941 CoUninitialize();
2946 // resort to the native Windows function. 2942 });
2947 std::wstring wshortcut_path_full = Common::UTF8ToUTF16W(shortcut_path_full.string());
2948 std::wstring wicon_path = Common::UTF8ToUTF16W(icon_path.string());
2949 std::wstring wcommand = Common::UTF8ToUTF16W(command.string());
2950 std::wstring warguments = Common::UTF8ToUTF16W(arguments);
2951 std::wstring wcomment = Common::UTF8ToUTF16W(comment);
2952 2943
2953 if (SUCCEEDED(hres)) { 2944 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2954 if (std::filesystem::is_regular_file(command)) 2945 IID_IShellLinkW, (void**)&ps1);
2955 hres = ps1->SetPath(wcommand.data());
2956 2946
2957 if (SUCCEEDED(hres) && !arguments.empty()) 2947 std::wstring wshortcut_path_full = Common::UTF8ToUTF16W(shortcut_path_full.string());
2958 hres = ps1->SetArguments(warguments.data()); 2948 std::wstring wicon_path = Common::UTF8ToUTF16W(icon_path.string());
2949 std::wstring wcommand = Common::UTF8ToUTF16W(command.string());
2950 std::wstring warguments = Common::UTF8ToUTF16W(arguments);
2951 std::wstring wcomment = Common::UTF8ToUTF16W(comment);
2952
2953 if (SUCCEEDED(hres)) {
2954 if (std::filesystem::is_regular_file(command)) {
2955 hres = ps1->SetPath(wcommand.data());
2956 } else {
2957 LOG_ERROR(Frontend, "Command is not a regular file");
2958 return false;
2959 }
2959 2960
2960 if (SUCCEEDED(hres) && !comment.empty()) 2961 if (SUCCEEDED(hres) && !arguments.empty()) {
2961 hres = ps1->SetDescription(wcomment.data()); 2962 hres = ps1->SetArguments(warguments.data());
2963 }
2962 2964
2963 if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) 2965 if (SUCCEEDED(hres) && !comment.empty()) {
2964 hres = ps1->SetIconLocation(wicon_path.data(), 0); 2966 hres = ps1->SetDescription(wcomment.data());
2967 }
2965 2968
2966 IPersistFile* pPersistFile = nullptr; 2969 if (SUCCEEDED(hres) && std::filesystem::is_regular_file(icon_path)) {
2970 hres = ps1->SetIconLocation(wicon_path.data(), 0);
2971 }
2967 2972
2968 if (SUCCEEDED(hres)) { 2973 if (SUCCEEDED(hres)) {
2969 hres = ps1->QueryInterface(IID_IPersistFile, (void**)&pPersistFile); 2974 hres = ps1->QueryInterface(IID_IPersistFile, (void**)&persist_file);
2975 }
2970 2976
2971 if (SUCCEEDED(hres) && pPersistFile != nullptr) { 2977 if (SUCCEEDED(hres) && persist_file != nullptr) {
2972 hres = pPersistFile->Save(wshortcut_path_full.data(), TRUE); 2978 // Append .lnk extension and save shortcut
2979 shortcut_path_full += ".lnk";
2980 hres = persist_file->Save(wshortcut_path_full.data(), TRUE);
2973 if (SUCCEEDED(hres)) { 2981 if (SUCCEEDED(hres)) {
2974 shortcut_succeeded = true; 2982 return true;
2983 } else {
2984 LOG_ERROR(Frontend, "Failed to create shortcut");
2975 } 2985 }
2976 } 2986 }
2987 } else {
2988 LOG_ERROR(Frontend, "Failed to create CoCreateInstance");
2977 } 2989 }
2978
2979 if (pPersistFile != nullptr) {
2980 pPersistFile->Release();
2981 }
2982 } else {
2983 LOG_ERROR(Frontend, "Failed to create IShellLinkWinstance");
2984 } 2990 }
2985 2991 return false;
2986 ps1->Release(); 2992#else // Unsupported platform
2987 CoUninitialize(); 2993 return false;
2988#endif 2994#endif
2989
2990 if (shortcut_succeeded && std::filesystem::is_regular_file(shortcut_path_full)) {
2991 LOG_ERROR(Frontend, "Shortcut created");
2992 } else {
2993 LOG_ERROR(Frontend, "Shortcut error, failed to create it");
2994 shortcut_succeeded = false;
2995 }
2996
2997 return shortcut_succeeded;
2998} 2995}
2999 2996
3000// Messages in pre-defined message boxes for less code spaghetti 2997// Messages in pre-defined message boxes for less code spaghetti
@@ -3049,31 +3046,31 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, const int& imsg,
3049} 3046}
3050 3047
3051bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, 3048bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
3052 std::filesystem::path& icons_path) { 3049 std::filesystem::path& out_icon_path) {
3053 3050
3054 // Get path to Yuzu icons directory & icon extension 3051 // Get path to Yuzu icons directory & icon extension
3055 std::string ico_extension = "png"; 3052 std::string ico_extension = "png";
3056#if defined(_WIN32) 3053#if defined(_WIN32)
3057 icons_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons"; 3054 out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "icons";
3058 ico_extension = "ico"; 3055 ico_extension = "ico";
3059#elif defined(__linux__) || defined(__FreeBSD__) 3056#elif defined(__linux__) || defined(__FreeBSD__)
3060 icons_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; 3057 out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256";
3061#endif 3058#endif
3062 3059
3063 // Create icons directory if it doesn't exist 3060 // Create icons directory if it doesn't exist
3064 if (!Common::FS::CreateDirs(icons_path)) { 3061 if (!Common::FS::CreateDirs(out_icon_path)) {
3065 QMessageBox::critical( 3062 QMessageBox::critical(
3066 this, tr("Create Icon"), 3063 this, tr("Create Icon"),
3067 tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") 3064 tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
3068 .arg(QString::fromStdString(icons_path.string())), 3065 .arg(QString::fromStdString(out_icon_path.string())),
3069 QMessageBox::StandardButton::Ok); 3066 QMessageBox::StandardButton::Ok);
3070 icons_path = ""; // Reset path 3067 out_icon_path = ""; // Reset path
3071 return false; 3068 return false;
3072 } 3069 }
3073 3070
3074 // Create icon file path 3071 // Create icon file path
3075 icons_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension) 3072 out_icon_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension)
3076 : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); 3073 : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension));
3077 return true; 3074 return true;
3078} 3075}
3079 3076
@@ -3096,13 +3093,11 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3096 QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); 3093 QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString();
3097 } else if (target == GameListShortcutTarget::Applications) { 3094 } else if (target == GameListShortcutTarget::Applications) {
3098#if defined(_WIN32) 3095#if defined(_WIN32)
3099 HANDLE hProcess = GetCurrentProcess();
3100 if (!IsUserAnAdmin()) { 3096 if (!IsUserAnAdmin()) {
3101 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN, 3097 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ADMIN,
3102 ""); 3098 "");
3103 return; 3099 return;
3104 } 3100 }
3105 CloseHandle(hProcess);
3106#endif // _WIN32 3101#endif // _WIN32
3107 shortcut_path = 3102 shortcut_path =
3108 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); 3103 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
@@ -3110,9 +3105,8 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3110 3105
3111 // Icon path and title 3106 // Icon path and title
3112 std::string title; 3107 std::string title;
3113 std::filesystem::path icons_path; 3108 std::filesystem::path out_icon_path;
3114 if (std::filesystem::exists(shortcut_path)) { 3109 if (std::filesystem::exists(shortcut_path)) {
3115
3116 // Get title from game file 3110 // Get title from game file
3117 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), 3111 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
3118 system->GetContentProvider()}; 3112 system->GetContentProvider()};
@@ -3139,8 +3133,8 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3139 QImage icon_data = 3133 QImage icon_data =
3140 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size())); 3134 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
3141 3135
3142 if (GMainWindow::MakeShortcutIcoPath(program_id, title, icons_path)) { 3136 if (GMainWindow::MakeShortcutIcoPath(program_id, title, out_icon_path)) {
3143 if (!SaveIconToFile(icons_path, icon_data)) { 3137 if (!SaveIconToFile(out_icon_path, icon_data)) {
3144 LOG_ERROR(Frontend, "Could not write icon to file"); 3138 LOG_ERROR(Frontend, "Could not write icon to file");
3145 } 3139 }
3146 } 3140 }
@@ -3178,8 +3172,8 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3178 const std::string categories = "Game;Emulator;Qt;"; 3172 const std::string categories = "Game;Emulator;Qt;";
3179 const std::string keywords = "Switch;Nintendo;"; 3173 const std::string keywords = "Switch;Nintendo;";
3180 3174
3181 if (GMainWindow::CreateShortcutLink(shortcut_path, comment, icons_path, yuzu_command, arguments, 3175 if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, yuzu_command,
3182 categories, keywords, title)) { 3176 arguments, categories, keywords, title)) {
3183 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, 3177 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS,
3184 title); 3178 title);
3185 return; 3179 return;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index d7426607f..d3a1bf5b9 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -444,7 +444,7 @@ private:
444 QString GetTasStateDescription() const; 444 QString GetTasStateDescription() const;
445 bool CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, const std::string title); 445 bool CreateShortcutMessagesGUI(QWidget* parent, const int& imsg, const std::string title);
446 bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, 446 bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
447 std::filesystem::path& icons_path); 447 std::filesystem::path& out_icon_path);
448 bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, 448 bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment,
449 const std::filesystem::path& icon_path, 449 const std::filesystem::path& icon_path,
450 const std::filesystem::path& command, const std::string& arguments, 450 const std::filesystem::path& command, const std::string& arguments,