diff --git a/Common/System/Request.cpp b/Common/System/Request.cpp index 8e78352908..3dc290af1a 100644 --- a/Common/System/Request.cpp +++ b/Common/System/Request.cpp @@ -115,3 +115,7 @@ void RequestManager::Clear() { void System_CreateGameShortcut(const Path &path, const std::string &title) { g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, nullptr, nullptr, path.ToString(), title, 0); } + +void System_ShowFileInFolder(const Path &path) { + g_requestManager.MakeSystemRequest(SystemRequestType::SHOW_FILE_IN_FOLDER, nullptr, nullptr, path.ToString(), "", 0); +} diff --git a/Common/System/Request.h b/Common/System/Request.h index e6b3a10b37..8f734cdd02 100644 --- a/Common/System/Request.h +++ b/Common/System/Request.h @@ -166,4 +166,4 @@ inline void System_SendDebugScreenshot(const std::string &data, int height) { // Non-inline to avoid including Path.h void System_CreateGameShortcut(const Path &path, const std::string &title); - +void System_ShowFileInFolder(const Path &path); diff --git a/Common/System/System.h b/Common/System/System.h index 1032411069..f0e496d402 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -49,7 +49,6 @@ enum class LaunchUrlType { }; void System_Vibrate(int length_ms); -void System_ShowFileInFolder(const char *path); void System_LaunchUrl(LaunchUrlType urlType, const char *url); // It's sometimes a little unclear what should be a request, and what should be a separate function. @@ -72,6 +71,7 @@ enum class SystemRequestType { TOGGLE_FULLSCREEN_STATE, GRAPHICS_BACKEND_FAILED_ALERT, CREATE_GAME_SHORTCUT, + SHOW_FILE_IN_FOLDER, // Commonly ignored, used when automated tests generate output. SEND_DEBUG_OUTPUT, @@ -135,6 +135,7 @@ enum SystemProperty { SYSPROP_HAS_TEXT_INPUT_DIALOG, // Indicates that System_InputBoxGetString is available. SYSPROP_CAN_CREATE_SHORTCUT, + SYSPROP_CAN_SHOW_FILE, SYSPROP_SUPPORTS_HTTPS, diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 52c738209d..db09b3a87f 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -252,6 +252,7 @@ bool System_GetPropertyBool(SystemProperty prop) { case SYSPROP_HAS_FOLDER_BROWSER: case SYSPROP_HAS_OPEN_DIRECTORY: case SYSPROP_HAS_TEXT_INPUT_DIALOG: + case SYSPROP_CAN_SHOW_FILE: return true; case SYSPROP_SUPPORTS_OPEN_FILE_IN_EDITOR: return true; // FileUtil.cpp: OpenFileInEditor @@ -407,6 +408,9 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string emit(qtcamera->onStopCamera()); } return true; + case SystemRequestType::SHOW_FILE_IN_FOLDER: + QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromUtf8(param1.c_str()))); + return true; default: return false; } @@ -424,10 +428,6 @@ void System_Vibrate(int length_ms) { length_ms = 25; } -void System_ShowFileInFolder(const char *path) { - QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromUtf8(path))); -} - void System_LaunchUrl(LaunchUrlType urlType, const char *url) { QDesktopServices::openUrl(QUrl(url)); diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 3bc1bb9692..4a9d7dca9f 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -325,6 +325,31 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string g_windowState.update = true; return true; } + case SystemRequestType::SHOW_FILE_IN_FOLDER: + { +#if PPSSPP_PLATFORM(WINDOWS) + SFGAOF flags; + PIDLIST_ABSOLUTE pidl = nullptr; + HRESULT hr = SHParseDisplayName(ConvertUTF8ToWString(ReplaceAll(path, "/", "\\")).c_str(), nullptr, &pidl, 0, &flags); + if (pidl) { + if (SUCCEEDED(hr)) + SHOpenFolderAndSelectItems(pidl, 0, NULL, 0); + CoTaskMemFree(pidl); + } +#elif PPSSPP_PLATFORM(MAC) + OSXShowInFinder(param1.c_str()); +#elif (PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)) + pid_t pid = fork(); + if (pid < 0) + return true; + + if (pid == 0) { + execlp("xdg-open", "xdg-open", param1.c_str(), nullptr); + exit(1); + } +#endif /* PPSSPP_PLATFORM(WINDOWS) */ + return true; + } default: return false; } @@ -333,30 +358,6 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string void System_AskForPermission(SystemPermission permission) {} PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } -void System_ShowFileInFolder(const char *path) { -#if PPSSPP_PLATFORM(WINDOWS) - SFGAOF flags; - PIDLIST_ABSOLUTE pidl = nullptr; - HRESULT hr = SHParseDisplayName(ConvertUTF8ToWString(ReplaceAll(path, "/", "\\")).c_str(), nullptr, &pidl, 0, &flags); - if (pidl) { - if (SUCCEEDED(hr)) - SHOpenFolderAndSelectItems(pidl, 0, NULL, 0); - CoTaskMemFree(pidl); - } -#elif PPSSPP_PLATFORM(MAC) - OSXShowInFinder(path); -#elif (PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)) - pid_t pid = fork(); - if (pid < 0) - return; - - if (pid == 0) { - execlp("xdg-open", "xdg-open", path, nullptr); - exit(1); - } -#endif /* PPSSPP_PLATFORM(WINDOWS) */ -} - void System_LaunchUrl(LaunchUrlType urlType, const char *url) { switch (urlType) { case LaunchUrlType::BROWSER_URL: @@ -546,6 +547,8 @@ float System_GetPropertyFloat(SystemProperty prop) { bool System_GetPropertyBool(SystemProperty prop) { switch (prop) { + case SYSPROP_CAN_SHOW_FILE: + return true; case SYSPROP_HAS_OPEN_DIRECTORY: #if PPSSPP_PLATFORM(WINDOWS) return true; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 4564bb6481..c07ca1d5f8 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -334,7 +334,7 @@ void GameScreen::render() { } UI::EventReturn GameScreen::OnShowInFolder(UI::EventParams &e) { - System_ShowFileInFolder(gamePath_.c_str()); + System_ShowFileInFolder(gamePath_); return UI::EVENT_DONE; } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 06f0047f07..6b72c516ad 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -977,7 +977,9 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { if (System_GetPropertyBool(SYSPROP_HAS_OPEN_DIRECTORY)) { systemSettings->Add(new Choice(sy->T("Show Memory Stick folder")))->OnClick.Add([](UI::EventParams &p) { - System_ShowFileInFolder(File::ResolvePath(g_Config.memStickDirectory.ToString()).c_str()); + // TODO: Should build ResolvePath into System_ShowFileInFolder()? + std::string resolved = File::ResolvePath(g_Config.memStickDirectory.ToString()); + System_ShowFileInFolder(Path(resolved)); return UI::EVENT_DONE; }); } diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 499bdc81a2..5344e672f9 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -602,15 +602,14 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string } return true; } + case SystemRequestType::SHOW_FILE_IN_FOLDER: + OpenFolder(param1); + return true; default: return false; } } -void System_ShowFileInFolder(const char *path) { - OpenFolder(std::string(path)); -} - void System_LaunchUrl(LaunchUrlType urlType, const char *url) { auto uri = ref new Windows::Foundation::Uri(ToPlatformString(url)); diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index c96643cc38..5d71509b6f 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -29,6 +29,7 @@ #include "Common/Data/Text/Parsers.h" #include "Common/StringUtils.h" #include "Common/System/System.h" +#include "Common/System/Request.h" #include "Core/Config.h" #include "Core/Screenshot.h" @@ -1213,7 +1214,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case IDC_GEDBG_RECORD: GPURecord::SetCallback([](const Path &path) { // Opens a Windows Explorer window with the file. - System_ShowFileInFolder(path.c_str()); + System_ShowFileInFolder(path); }); GPURecord::Activate(); break; diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp index f7f015c122..da061903c2 100644 --- a/Windows/W32Util/Misc.cpp +++ b/Windows/W32Util/Misc.cpp @@ -4,9 +4,12 @@ #include #include #include +#include #include "Misc.h" #include "Common/Data/Encoding/Utf8.h" +#include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" bool KeyDownAsync(int vkey) { #if PPSSPP_PLATFORM(UWP) @@ -94,6 +97,21 @@ namespace W32Util *yres = rc.bottom - rc.top; } + void ShowFileInFolder(const std::string &path) { + // SHParseDisplayName can't handle relative paths, so normalize first. + std::string resolved = ReplaceAll(File::ResolvePath(path), "/", "\\"); + + SFGAOF flags{}; + PIDLIST_ABSOLUTE pidl = nullptr; + HRESULT hr = SHParseDisplayName(ConvertUTF8ToWString(resolved).c_str(), nullptr, &pidl, 0, &flags); + + if (pidl) { + if (SUCCEEDED(hr)) + SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0); + CoTaskMemFree(pidl); + } + } + static const wchar_t *RemoveExecutableFromCommandLine(const wchar_t *cmdline) { if (!cmdline) { return L""; diff --git a/Windows/W32Util/Misc.h b/Windows/W32Util/Misc.h index 8fd41b0989..4e0dbf6d58 100644 --- a/Windows/W32Util/Misc.h +++ b/Windows/W32Util/Misc.h @@ -3,6 +3,7 @@ #include #include #include + #include "Common/CommonWindows.h" namespace W32Util @@ -16,6 +17,7 @@ namespace W32Util void GetSelfExecuteParams(std::wstring &workingDirectory, std::wstring &moduleFilename); void GetWindowRes(HWND hWnd, int *xres, int *yres); + void ShowFileInFolder(const std::string &path); struct ClipboardData { ClipboardData(const char *format, size_t sz); diff --git a/Windows/main.cpp b/Windows/main.cpp index 45007fa1f9..bdc094728b 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -26,10 +26,10 @@ #include "Common/GPU/Vulkan/VulkanLoader.h" #include "ppsspp_config.h" -#include -#include -#include #include +#include +#include +#include #include "Common/System/Display.h" #include "Common/System/NativeApp.h" @@ -122,21 +122,6 @@ static double g_lastKeepAwake = 0.0; // Should this be configurable? 2 hours currently. static const double ACTIVITY_IDLE_TIMEOUT = 2.0 * 3600.0; -void System_ShowFileInFolder(const char *path) { - // SHParseDisplayName can't handle relative paths, so normalize first. - std::string resolved = ReplaceAll(File::ResolvePath(path), "/", "\\"); - - SFGAOF flags{}; - PIDLIST_ABSOLUTE pidl = nullptr; - HRESULT hr = SHParseDisplayName(ConvertUTF8ToWString(resolved).c_str(), nullptr, &pidl, 0, &flags); - - if (pidl) { - if (SUCCEEDED(hr)) - SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0); - CoTaskMemFree(pidl); - } -} - void System_LaunchUrl(LaunchUrlType urlType, const char *url) { ShellExecute(NULL, L"open", ConvertUTF8ToWString(url).c_str(), NULL, NULL, SW_SHOWNORMAL); } @@ -368,6 +353,7 @@ bool System_GetPropertyBool(SystemProperty prop) { case SYSPROP_HAS_OPEN_DIRECTORY: case SYSPROP_HAS_TEXT_INPUT_DIALOG: case SYSPROP_CAN_CREATE_SHORTCUT: + case SYSPROP_CAN_SHOW_FILE: return true; case SYSPROP_HAS_IMAGE_BROWSER: return true; @@ -608,6 +594,11 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string }).detach(); return true; } + + case SystemRequestType::SHOW_FILE_IN_FOLDER: + W32Util::ShowFileInFolder(param1); + break; + case SystemRequestType::TOGGLE_FULLSCREEN_STATE: { bool flag = !MainWindow::IsFullscreen(); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 1cd0adc908..5bb7e644fc 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -391,10 +391,6 @@ void System_Vibrate(int length_ms) { PushCommand("vibrate", temp); } -void System_ShowFileInFolder(const char *path) { - // Unsupported -} - void System_LaunchUrl(LaunchUrlType urlType, const char *url) { switch (urlType) { case LaunchUrlType::BROWSER_URL: PushCommand("launchBrowser", url); break; diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 34297dcd8b..c768ef2dc5 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -754,10 +754,6 @@ void stopLocation() { @end -void System_ShowFileInFolder(const char *path) { - // Unsupported -} - void System_LaunchUrl(LaunchUrlType urlType, char const* url) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]];