diff --git a/CMakeLists.txt b/CMakeLists.txt
index 36dbf12c73..a6f2ea7c7e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -712,6 +712,10 @@ add_library(Common STATIC
Common/Render/Text/draw_text_uwp.h
Common/System/Display.cpp
Common/System/Display.h
+ Common/System/System.h
+ Common/System/NativeApp.h
+ Common/System/Request.cpp
+ Common/System/Request.h
Common/Thread/Channel.h
Common/Thread/ParallelLoop.cpp
Common/Thread/ParallelLoop.h
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index c066494c66..3fabaafa64 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -550,6 +550,7 @@
+
@@ -1005,6 +1006,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index cce4e7656a..879e3495b8 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -494,6 +494,9 @@
ext\basis_universal
+
+ System
+
@@ -920,6 +923,9 @@
ext\basis_universal
+
+ System
+
diff --git a/Common/System/NativeApp.h b/Common/System/NativeApp.h
index 6788642eb4..bb0c7af962 100644
--- a/Common/System/NativeApp.h
+++ b/Common/System/NativeApp.h
@@ -23,9 +23,6 @@ void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, boo
// Generic host->C++ messaging, used for functionality like system-native popup input boxes.
void NativeMessageReceived(const char *message, const char *value);
-// This is used to communicate back and thread requested input box strings.
-void NativeInputBoxReceived(std::function cb, bool result, const std::string &value);
-
// Easy way for the Java side to ask the C++ side for configuration options, such as
// the rotation lock which must be controlled from Java on Android.
// It is currently not called on non-Android platforms.
diff --git a/Common/System/Request.cpp b/Common/System/Request.cpp
new file mode 100644
index 0000000000..883514d8da
--- /dev/null
+++ b/Common/System/Request.cpp
@@ -0,0 +1,72 @@
+#include "Common/System/Request.h"
+#include "Common/System/System.h"
+#include "Common/Log.h"
+
+RequestManager g_requestManager;
+
+const char *RequestTypeAsString(SystemRequestType type) {
+ switch (type) {
+ case SystemRequestType::INPUT_TEXT_MODAL: return "INPUT_TEXT_MODAL";
+ default: return "N/A";
+ }
+}
+
+bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, const std::string ¶m1, const std::string ¶m2) {
+ int requestId = idCounter_++;
+ if (!System_MakeRequest(type, requestId, param1, param2)) {
+ return false;
+ }
+
+ if (!callback) {
+ // We don't expect a response, this is a one-directional request. We're thus done.
+ return true;
+ }
+
+ std::lock_guard guard(callbackMutex_);
+ callbackMap_[requestId] = callback;
+ return true;
+}
+
+void RequestManager::PostSystemSuccess(int requestId, const char *responseString, int responseValue) {
+ std::lock_guard guard(callbackMutex_);
+ auto iter = callbackMap_.find(requestId);
+ if (iter == callbackMap_.end()) {
+ ERROR_LOG(SYSTEM, "PostSystemSuccess: Unexpected request ID %d (responseString=%s)", requestId, responseString);
+ return;
+ }
+
+ std::lock_guard responseGuard(responseMutex_);
+ PendingResponse response;
+ response.callback = iter->second;
+ response.responseString = responseString;
+ response.responseValue = responseValue;
+ pendingResponses_.push_back(response);
+}
+
+void RequestManager::PostSystemFailure(int requestId) {
+ std::lock_guard guard(callbackMutex_);
+ auto iter = callbackMap_.find(requestId);
+ if (iter == callbackMap_.end()) {
+ ERROR_LOG(SYSTEM, "PostSystemFailure: Unexpected request ID %d", requestId);
+ return;
+ }
+ callbackMap_.erase(iter);
+}
+
+void RequestManager::ProcessRequests() {
+ std::lock_guard guard(responseMutex_);
+ for (auto &iter : pendingResponses_) {
+ if (iter.callback) {
+ iter.callback(iter.responseString.c_str(), iter.responseValue);
+ }
+ }
+ pendingResponses_.clear();
+}
+
+void RequestManager::Clear() {
+ std::lock_guard guard(callbackMutex_);
+ std::lock_guard responseGuard(responseMutex_);
+
+ pendingResponses_.clear();
+ callbackMap_.clear();
+}
diff --git a/Common/System/Request.h b/Common/System/Request.h
new file mode 100644
index 0000000000..19afe99721
--- /dev/null
+++ b/Common/System/Request.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include
+#include
+#include
@@ -811,6 +814,9 @@
ext\basis_universal
+
+ System
+
diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp
index 1529a18887..39e27cbf56 100644
--- a/UWP/PPSSPP_UWPMain.cpp
+++ b/UWP/PPSSPP_UWPMain.cpp
@@ -443,6 +443,8 @@ void System_Notify(SystemNotification notification) {
}
}
+bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; }
+
void System_SendMessage(const char *command, const char *parameter) {
using namespace concurrency;
diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp
index f02d1e4f79..d81d20b121 100644
--- a/Windows/MainWindow.cpp
+++ b/Windows/MainWindow.cpp
@@ -107,7 +107,6 @@ struct VerySleepy_AddrInfo {
};
static std::wstring windowTitle;
-extern ScreenManager *screenManager;
#define TIMER_CURSORUPDATE 1
#define TIMER_CURSORMOVEUPDATE 2
@@ -473,7 +472,6 @@ namespace MainWindow
}
void UpdateWindowTitle() {
- // Seems to be fine to call now since we use a UNICODE build...
std::wstring title = windowTitle;
if (PPSSPP_ID >= 1 && GetInstancePeerCount() > 1) {
title.append(ConvertUTF8ToWString(StringFromFormat(" (instance: %d)", (int)PPSSPP_ID)));
diff --git a/Windows/main.cpp b/Windows/main.cpp
index 4bf24d4d34..15fd6891d0 100644
--- a/Windows/main.cpp
+++ b/Windows/main.cpp
@@ -34,6 +34,7 @@
#include "Common/System/Display.h"
#include "Common/System/NativeApp.h"
#include "Common/System/System.h"
+#include "Common/System/Request.h"
#include "Common/File/FileUtil.h"
#include "Common/File/VFS/VFS.h"
#include "Common/File/VFS/DirectoryReader.h"
@@ -109,8 +110,8 @@ static std::string restartArgs;
int g_activeWindow = 0;
-static std::thread inputBoxThread;
-static bool inputBoxRunning = false;
+static std::thread g_inputBoxThread;
+static bool g_inputBoxRunning = false;
int g_lastNumInstances = 0;
void System_ShowFileInFolder(const char *path) {
@@ -376,12 +377,13 @@ static BOOL PostDialogMessage(Dialog *dialog, UINT message, WPARAM wParam = 0, L
return PostMessage(dialog->GetDlgHandle(), message, wParam, lParam);
}
+// This can come from any thread, so this mostly uses PostMessage. Can't access most data directly.
void System_Notify(SystemNotification notification) {
switch (notification) {
case SystemNotification::BOOT_DONE:
{
if (g_symbolMap)
- g_symbolMap->SortSymbols();
+ g_symbolMap->SortSymbols(); // internal locking is performed here
PostMessage(MainWindow::GetHWND(), WM_USER + 1, 0, 0);
if (disasmWindow)
@@ -413,7 +415,7 @@ void System_Notify(SystemNotification notification) {
case SystemNotification::SYMBOL_MAP_UPDATED:
if (g_symbolMap)
- g_symbolMap->SortSymbols();
+ g_symbolMap->SortSymbols(); // internal locking is performed here
PostMessage(MainWindow::GetHWND(), WM_USER + 1, 0, 0);
break;
@@ -428,6 +430,28 @@ void System_Notify(SystemNotification notification) {
}
}
+bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) {
+ switch (type) {
+ case SystemRequestType::INPUT_TEXT_MODAL:
+ if (g_inputBoxRunning) {
+ g_inputBoxThread.join();
+ }
+
+ g_inputBoxRunning = true;
+ g_inputBoxThread = std::thread([=] {
+ std::string out;
+ if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), param2, out)) {
+ g_requestManager.PostSystemSuccess(requestId, out.c_str());
+ } else {
+ g_requestManager.PostSystemFailure(requestId);
+ }
+ });
+ return true;
+ default:
+ return false;
+ }
+}
+
void System_SendMessage(const char *command, const char *parameter) {
if (!strcmp(command, "finish")) {
if (!NativeIsRestarting()) {
@@ -497,22 +521,6 @@ void EnableCrashingOnCrashes() {
FreeLibrary(kernel32);
}
-void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) {
- if (inputBoxRunning) {
- inputBoxThread.join();
- }
-
- inputBoxRunning = true;
- inputBoxThread = std::thread([=] {
- std::string out;
- if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(title).c_str(), defaultValue, out)) {
- NativeInputBoxReceived(cb, true, out);
- } else {
- NativeInputBoxReceived(cb, false, "");
- }
- });
-}
-
void System_Toast(const char *text) {
// Not-very-good implementation. Will normally not be used on Windows anyway.
std::wstring str = ConvertUTF8ToWString(text);
@@ -619,9 +627,9 @@ static void WinMainInit() {
}
static void WinMainCleanup() {
- if (inputBoxRunning) {
- inputBoxThread.join();
- inputBoxRunning = false;
+ if (g_inputBoxRunning) {
+ g_inputBoxThread.join();
+ g_inputBoxRunning = false;
}
net::Shutdown();
CoUninitialize();
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 61aaefc181..28775b9b2f 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -214,6 +214,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Common/Net/WebsocketServer.cpp \
$(SRC)/Common/Profiler/Profiler.cpp \
$(SRC)/Common/System/Display.cpp \
+ $(SRC)/Common/System/Request.cpp \
$(SRC)/Common/Thread/ThreadUtil.cpp \
$(SRC)/Common/Thread/ThreadManager.cpp \
$(SRC)/Common/Thread/ParallelLoop.cpp \
diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp
index 65a483e519..6a9e42a829 100644
--- a/android/jni/app-android.cpp
+++ b/android/jni/app-android.cpp
@@ -61,6 +61,7 @@ struct JNIEnv {};
#include "Common/System/Display.h"
#include "Common/System/NativeApp.h"
#include "Common/System/System.h"
+#include "Common/System/Request.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/File/Path.h"
#include "Common/File/DirListing.h"
@@ -175,9 +176,6 @@ static std::atomic renderLoopRunning;
static bool renderer_inited = false;
static std::mutex renderLock;
-static int inputBoxSequence = 1;
-static std::map> inputBoxCallbacks;
-
static bool sustainedPerfSupported = false;
static std::map permissions;
@@ -909,7 +907,6 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
{
std::lock_guard guard(renderLock);
- inputBoxCallbacks.clear();
NativeShutdown();
g_VFS.Clear();
}
@@ -1032,12 +1029,17 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv
}
}
-void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) {
- int seq = inputBoxSequence++;
- inputBoxCallbacks[seq] = cb;
-
- std::string serialized = StringFromFormat("%d:@:%s:@:%s", seq, title.c_str(), defaultValue.c_str());
- System_SendMessage("inputbox", serialized.c_str());
+bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) {
+ switch (type) {
+ case SystemRequestType::INPUT_TEXT_MODAL:
+ {
+ std::string serialized = StringFromFormat("%d:@:%s:@:%s", requestId, param1.c_str(), param2.c_str());
+ PushCommand("inputbox", serialized.c_str());
+ return true;
+ }
+ default:
+ return false;
+ }
}
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendInputBox(JNIEnv *env, jclass, jstring jseqID, jboolean result, jstring jvalue) {
@@ -1058,13 +1060,11 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendInputBox(JNIEnv *en
return;
}
- auto entry = inputBoxCallbacks.find(seq);
- if (entry == inputBoxCallbacks.end()) {
- ERROR_LOG(SYSTEM, "Did not find inputbox callback for %s, shutdown?", seqID.c_str());
- return;
+ if (result) {
+ g_requestManager.PostSystemSuccess(seq, value.c_str());
+ } else {
+ g_requestManager.PostSystemFailure(seq);
}
-
- NativeInputBoxReceived(entry->second, result, value);
}
void LockedNativeUpdateRender() {
diff --git a/headless/Headless.cpp b/headless/Headless.cpp
index 27e0508e64..8d6ae20519 100644
--- a/headless/Headless.cpp
+++ b/headless/Headless.cpp
@@ -116,6 +116,7 @@ bool System_GetPropertyBool(SystemProperty prop) {
}
void System_Notify(SystemNotification notification) {}
void System_SendMessage(const char *command, const char *parameter) {}
+bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; }
void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); }
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
diff --git a/ios/main.mm b/ios/main.mm
index 155bf79995..3caaf93e26 100644
--- a/ios/main.mm
+++ b/ios/main.mm
@@ -219,6 +219,10 @@ void System_SendMessage(const char *command, const char *parameter) {
}
}
+bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) {
+ return false;
+}
+
void System_Toast(const char *text) {}
void System_AskForPermission(SystemPermission permission) {}
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index 3beb711568..83e477f941 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -341,6 +341,7 @@ SOURCES_CXX += \
$(COMMONDIR)/UI/ScrollView.cpp \
$(COMMONDIR)/UI/PopupScreens.cpp \
$(COMMONDIR)/System/Display.cpp \
+ $(COMMONDIR)/System/Request.cpp \
$(COMMONDIR)/ArmCPUDetect.cpp \
$(COMMONDIR)/CPUDetect.cpp \
$(COMMONDIR)/Buffer.cpp \
diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp
index 05b13dcdbf..cdb699bb56 100644
--- a/libretro/libretro.cpp
+++ b/libretro/libretro.cpp
@@ -1874,7 +1874,7 @@ void System_Notify(SystemNotification notification) {
break;
}
}
-
+bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; }
void System_SendMessage(const char *command, const char *parameter) {}
void NativeUpdate() {}
void NativeRender(GraphicsContext *graphicsContext) {}
diff --git a/unittest/JitHarness.cpp b/unittest/JitHarness.cpp
index ebbcdefa39..f730cc44d6 100644
--- a/unittest/JitHarness.cpp
+++ b/unittest/JitHarness.cpp
@@ -42,6 +42,7 @@ void NativeRender(GraphicsContext *graphicsContext) { }
void NativeResized() { }
void System_SendMessage(const char *command, const char *parameter) {}
+bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2) { return false; }
void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); }
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }