Replace the inputbox queue with a more generic RequestManager.

This commit is contained in:
Henrik Rydgård 2023-03-22 12:26:14 +01:00
parent 3852d4f698
commit de064e210e
23 changed files with 198 additions and 205 deletions

View file

@ -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

View file

@ -550,7 +550,7 @@
<ClInclude Include="Swap.h" />
<ClInclude Include="SysError.h" />
<ClInclude Include="System\Display.h" />
<ClInclude Include="System\Message.h" />
<ClInclude Include="System\Request.h" />
<ClInclude Include="System\NativeApp.h" />
<ClInclude Include="System\System.h" />
<ClInclude Include="Thread\Barrier.h" />
@ -1006,7 +1006,7 @@
<ClCompile Include="OSVersion.cpp" />
<ClCompile Include="StringUtils.cpp" />
<ClCompile Include="System\Display.cpp" />
<ClCompile Include="System\Message.cpp" />
<ClCompile Include="System\Request.cpp" />
<ClCompile Include="Thread\ParallelLoop.cpp" />
<ClCompile Include="Thread\ThreadManager.cpp" />
<ClCompile Include="Thread\ThreadUtil.cpp" />

View file

@ -494,7 +494,7 @@
<ClInclude Include="..\ext\basis_universal\basisu_transcoder_uastc.h">
<Filter>ext\basis_universal</Filter>
</ClInclude>
<ClInclude Include="System\Message.h">
<ClInclude Include="System\Request.h">
<Filter>System</Filter>
</ClInclude>
</ItemGroup>
@ -923,7 +923,7 @@
<ClCompile Include="..\ext\basis_universal\basisu_transcoder.cpp">
<Filter>ext\basis_universal</Filter>
</ClCompile>
<ClCompile Include="System\Message.cpp">
<ClCompile Include="System\Request.cpp">
<Filter>System</Filter>
</ClCompile>
</ItemGroup>

View file

@ -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<void(bool, const std::string &)> 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.

View file

@ -1,8 +1,8 @@
#include "Common/System/Message.h"
#include "Common/System/Request.h"
#include "Common/System/System.h"
#include "Common/Log.h"
RequestManager g_RequestManager;
RequestManager g_requestManager;
const char *RequestTypeAsString(SystemRequestType type) {
switch (type) {
@ -11,7 +11,7 @@ const char *RequestTypeAsString(SystemRequestType type) {
}
}
bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, const char *param1, const char *param2) {
bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, const std::string &param1, const std::string &param2) {
int requestId = idCounter_++;
if (!System_MakeRequest(type, requestId, param1, param2)) {
return false;
@ -27,12 +27,11 @@ bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback c
return true;
}
void RequestManager::PostSystemResponse(int requestId, const char *responseString, int responseValue) {
void RequestManager::PostSystemSuccess(int requestId, const char *responseString, int responseValue) {
std::lock_guard<std::mutex> guard(callbackMutex_);
auto iter = callbackMap_.find(requestId);
if (iter == callbackMap_.end()) {
// Unexpected!
ERROR_LOG(SYSTEM, "PostSystemResponse: Unexpected request ID %d for %s (responseString=%s)", requestId, responseString);
ERROR_LOG(SYSTEM, "PostSystemSuccess: Unexpected request ID %d (responseString=%s)", requestId, responseString);
return;
}
@ -44,6 +43,16 @@ void RequestManager::PostSystemResponse(int requestId, const char *responseStrin
pendingResponses_.push_back(response);
}
void RequestManager::PostSystemFailure(int requestId) {
std::lock_guard<std::mutex> 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<std::mutex> guard(responseMutex_);
for (auto &iter : pendingResponses_) {
@ -53,3 +62,11 @@ void RequestManager::ProcessRequests() {
}
pendingResponses_.clear();
}
void RequestManager::Clear() {
std::lock_guard<std::mutex> guard(callbackMutex_);
std::lock_guard<std::mutex> responseGuard(responseMutex_);
pendingResponses_.clear();
callbackMap_.clear();
}

View file

@ -16,15 +16,19 @@ class RequestManager {
public:
// These requests are to be handled by platform implementations.
// The callback you pass in will be called on the main thread later.
bool MakeSystemRequest(SystemRequestType type, RequestCallback callback, const char *param1, const char *param2);
bool MakeSystemRequest(SystemRequestType type, RequestCallback callback, const std::string &param1, const std::string &param2);
// Called by the platform implementation, when it's finished with a request.
void PostSystemResponse(int requestId, const char *responseString, int responseValue);
void PostSystemSuccess(int requestId, const char *responseString, int responseValue = 0);
void PostSystemFailure(int requestId);
// This must be called every frame from the beginning of NativeUpdate().
// This will call the callback of any finished requests.
void ProcessRequests();
// Unclear if we need this...
void Clear();
private:
struct PendingRequest {
SystemRequestType type;
@ -47,4 +51,10 @@ private:
const char *RequestTypeAsString(SystemRequestType type);
extern RequestManager g_RequestManager;
extern RequestManager g_requestManager;
// Wrappers for easy requests.
// NOTE: Semantics have changed - this no longer calls the callback on cancellation.
inline void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, RequestCallback callback) {
g_requestManager.MakeSystemRequest(SystemRequestType::INPUT_TEXT_MODAL, callback, title, defaultValue);
}

View file

@ -50,8 +50,20 @@ enum class LaunchUrlType {
void System_Vibrate(int length_ms);
void System_ShowFileInFolder(const char *path);
void System_LaunchUrl(LaunchUrlType urlType, const char *url);
void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function<void(bool, const std::string &)> cb);
enum class SystemRequestType {
INPUT_TEXT_MODAL,
};
// Implementations are supposed to process the request, and post the response to the g_RequestManager (see Message.h).
// This is not to be used directly by applications, instead use the g_RequestManager to make the requests.
// This can return false if it's known that the platform doesn't support the request, the app is supposed to handle
// or ignore that cleanly.
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2);
// TODO: To be separated into requests, see Request.h, and a way to post "UI messages".
void System_SendMessage(const char *command, const char *parameter);
PermissionStatus System_GetPermissionStatus(SystemPermission permission);
void System_AskForPermission(SystemPermission permission);
@ -146,16 +158,6 @@ enum class SystemNotification {
SWITCH_UMD_UPDATED,
};
enum class SystemRequestType {
INPUT_TEXT_MODAL,
};
// Implementations are supposed to process the request, and post the response to the g_RequestManager (see Message.h).
// This is not to be used directly by applications, instead use the g_RequestManager to make the requests.
// This can return false if it's known that the platform doesn't support the request, the app is supposed to handle
// or ignore that cleanly.
bool System_MakeRequest(SystemRequestType type, int requestId, const char *param1, const char *param2);
std::string System_GetProperty(SystemProperty prop);
std::vector<std::string> System_GetPropertyStringVec(SystemProperty prop);
int System_GetPropertyInt(SystemProperty prop);

View file

@ -22,7 +22,7 @@
#include "Common/Math/math_util.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/System/System.h"
#include "Common/System/Request.h"
#include "Common/Serialize/Serializer.h"
#include "Core/Dialog/PSPOskDialog.h"
@ -892,14 +892,14 @@ int PSPOskDialog::NativeKeyboard() {
defaultText.assign(u"VALUE");
// There's already ConvertUCS2ToUTF8 in this file. Should we use that instead of the global ones?
System_InputBoxGetString(::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText), [&](bool result, const std::string &value) {
System_InputBoxGetString(::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText), [&](const std::string &value, int iValue) {
std::lock_guard<std::mutex> guard(nativeMutex_);
if (nativeStatus_ != PSPOskNativeStatus::WAITING) {
return;
}
nativeValue_ = value;
nativeStatus_ = result ? PSPOskNativeStatus::SUCCESS : PSPOskNativeStatus::FAILURE;
nativeStatus_ = iValue ? PSPOskNativeStatus::SUCCESS : PSPOskNativeStatus::FAILURE;
});
} else if (nativeStatus_ == PSPOskNativeStatus::SUCCESS) {
inputChars = ConvertUTF8ToUCS2(nativeValue_);

View file

@ -273,6 +273,8 @@ void System_Notify(SystemNotification notification) {
}
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2) { return false; }
void System_SendMessage(const char *command, const char *parameter) {
if (!strcmp(command, "finish")) {
qApp->exit(0);

View file

@ -166,6 +166,8 @@ void System_Vibrate(int length_ms) {
// Ignore on PC
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2) { return false; }
void System_SendMessage(const char *command, const char *parameter) {
if (!strcmp(command, "toggle_fullscreen")) {
g_ToggleFullScreenNextFrame = true;

View file

@ -10,7 +10,7 @@
#include "Common/Data/Text/I18n.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/System/System.h"
#include "Common/System/Request.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "Core/HLE/proAdhoc.h"
@ -97,7 +97,7 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) {
sendChat(chat);
#elif PPSSPP_PLATFORM(ANDROID)
auto n = GetI18NCategory("Networking");
System_InputBoxGetString(n->T("Chat"), "", [](bool result, const std::string &value) {
System_InputBoxGetString(n->T("Chat"), "", [](const std::string &value, int) {
sendChat(value);
});
#endif
@ -181,10 +181,8 @@ void ChatMenu::Update() {
#if defined(USING_WIN_UI)
// Could remove the fullscreen check here, it works now.
if (promptInput_ && g_Config.bBypassOSKWithKeyboard && !g_Config.UseFullScreen()) {
System_InputBoxGetString(n->T("Chat"), n->T("Chat Here"), [](bool result, const std::string &value) {
if (result) {
sendChat(value);
}
System_InputBoxGetString(n->T("Chat"), n->T("Chat Here"), [](const std::string &value, int) {
sendChat(value);
});
promptInput_ = false;
}

View file

@ -30,7 +30,7 @@
#include "Common/VR/PPSSPPVR.h"
#include "Common/System/Display.h" // Only to check screen aspect ratio with pixel_yres/pixel_xres
#include "Common/System/System.h"
#include "Common/System/Request.h"
#include "Common/Battery/Battery.h"
#include "Common/System/NativeApp.h"
#include "Common/Data/Color/RGBAUtil.h"
@ -1564,10 +1564,8 @@ UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat0(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
auto n = GetI18NCategory("Networking");
System_InputBoxGetString(n->T("Enter Quick Chat 1"), g_Config.sQuickChat0, [](bool result, const std::string &value) {
if (result) {
g_Config.sQuickChat0 = value;
}
System_InputBoxGetString(n->T("Enter Quick Chat 1"), g_Config.sQuickChat0, [](const std::string &value, int) {
g_Config.sQuickChat0 = value;
});
#endif
return UI::EVENT_DONE;
@ -1576,10 +1574,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat0(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat1(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
auto n = GetI18NCategory("Networking");
System_InputBoxGetString(n->T("Enter Quick Chat 2"), g_Config.sQuickChat1, [](bool result, const std::string &value) {
if (result) {
g_Config.sQuickChat1 = value;
}
System_InputBoxGetString(n->T("Enter Quick Chat 2"), g_Config.sQuickChat1, [](const std::string &value, int) {
g_Config.sQuickChat1 = value;
});
#endif
return UI::EVENT_DONE;
@ -1588,10 +1584,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat1(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat2(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
auto n = GetI18NCategory("Networking");
System_InputBoxGetString(n->T("Enter Quick Chat 3"), g_Config.sQuickChat2, [](bool result, const std::string &value) {
if (result) {
g_Config.sQuickChat2 = value;
}
System_InputBoxGetString(n->T("Enter Quick Chat 3"), g_Config.sQuickChat2, [](const std::string &value, int) {
g_Config.sQuickChat2 = value;
});
#endif
return UI::EVENT_DONE;
@ -1600,10 +1594,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat2(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat3(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
auto n = GetI18NCategory("Networking");
System_InputBoxGetString(n->T("Enter Quick Chat 4"), g_Config.sQuickChat3, [](bool result, const std::string &value) {
if (result) {
g_Config.sQuickChat3 = value;
}
System_InputBoxGetString(n->T("Enter Quick Chat 4"), g_Config.sQuickChat3, [](const std::string &value, int) {
g_Config.sQuickChat3 = value;
});
#endif
return UI::EVENT_DONE;
@ -1612,10 +1604,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat3(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat4(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
auto n = GetI18NCategory("Networking");
System_InputBoxGetString(n->T("Enter Quick Chat 5"), g_Config.sQuickChat4, [](bool result, const std::string &value) {
if (result) {
g_Config.sQuickChat4 = value;
}
System_InputBoxGetString(n->T("Enter Quick Chat 5"), g_Config.sQuickChat4, [](const std::string &value, int) {
g_Config.sQuickChat4 = value;
});
#endif
return UI::EVENT_DONE;
@ -1624,10 +1614,8 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat4(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
auto n = GetI18NCategory("Networking");
System_InputBoxGetString(n->T("Enter a new PSP nickname"), g_Config.sNickName, [](bool result, const std::string &value) {
if (result) {
g_Config.sNickName = StripSpaces(value);
}
System_InputBoxGetString(n->T("Enter a new PSP nickname"), g_Config.sNickName, [](const std::string &value, int) {
g_Config.sNickName = StripSpaces(value);
});
#endif
return UI::EVENT_DONE;
@ -1723,10 +1711,8 @@ UI::EventReturn GameSettingsScreen::OnSysInfo(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeSearchFilter(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__)
auto se = GetI18NCategory("Search");
System_InputBoxGetString(se->T("Search term"), searchFilter_, [](bool result, const std::string &value) {
if (result) {
NativeMessageReceived("gameSettings_search", StripSpaces(value).c_str());
}
System_InputBoxGetString(se->T("Search term"), searchFilter_, [](const std::string &value, int) {
NativeMessageReceived("gameSettings_search", StripSpaces(value).c_str());
});
#else
if (!System_GetPropertyBool(SYSPROP_HAS_KEYBOARD))
@ -2098,10 +2084,8 @@ UI::EventReturn HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) {
UI::EventReturn HostnameSelectScreen::OnEditClick(UI::EventParams& e) {
auto n = GetI18NCategory("Networking");
#if PPSSPP_PLATFORM(ANDROID)
System_InputBoxGetString(n->T("proAdhocServer Address:"), addrView_->GetText(), [this](bool result, const std::string& value) {
if (result) {
addrView_->SetText(value);
}
System_InputBoxGetString(n->T("proAdhocServer Address:"), addrView_->GetText(), [this](const std::string& value, int) {
addrView_->SetText(value);
});
#endif
return UI::EVENT_DONE;

View file

@ -26,6 +26,7 @@
#include "Common/StringUtils.h"
#include "Common/System/System.h"
#include "Common/System/Request.h"
#include "Common/System/NativeApp.h"
#include "Common/System/Display.h"
#include "Common/Data/Text/I18n.h"
@ -336,64 +337,62 @@ UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams &params) {
// The old way, from before scoped storage.
#if PPSSPP_PLATFORM(ANDROID)
auto sy = GetI18NCategory("System");
System_InputBoxGetString(sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](bool result, const std::string &value) {
System_InputBoxGetString(sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](const std::string &value, int) {
auto sy = GetI18NCategory("System");
auto di = GetI18NCategory("Dialog");
if (result) {
std::string newPath = value;
size_t pos = newPath.find_last_not_of("/");
// Gotta have at least something but a /, and also needs to start with a /.
if (newPath.empty() || pos == newPath.npos || newPath[0] != '/') {
settingInfo_->Show(sy->T("ChangingMemstickPathInvalid", "That path couldn't be used to save Memory Stick files."), nullptr);
return;
}
if (pos != newPath.size() - 1) {
newPath = newPath.substr(0, pos + 1);
}
std::string newPath = value;
size_t pos = newPath.find_last_not_of("/");
// Gotta have at least something but a /, and also needs to start with a /.
if (newPath.empty() || pos == newPath.npos || newPath[0] != '/') {
settingInfo_->Show(sy->T("ChangingMemstickPathInvalid", "That path couldn't be used to save Memory Stick files."), nullptr);
return;
}
if (pos != newPath.size() - 1) {
newPath = newPath.substr(0, pos + 1);
}
if (newPath.empty()) {
// Reuse below message instead of adding yet another string.
System_Toast(sy->T("Path does not exist!"));
return;
}
if (newPath.empty()) {
// Reuse below message instead of adding yet another string.
System_Toast(sy->T("Path does not exist!"));
return;
}
Path pendingMemStickFolder(newPath);
Path pendingMemStickFolder(newPath);
if (!File::Exists(pendingMemStickFolder)) {
// Try to fix the path string, apparently some users got used to leaving out the /.
if (newPath[0] != '/') {
newPath = "/" + newPath;
}
if (!File::Exists(pendingMemStickFolder)) {
// Try to fix the path string, apparently some users got used to leaving out the /.
if (newPath[0] != '/') {
newPath = "/" + newPath;
}
pendingMemStickFolder = Path(newPath);
}
pendingMemStickFolder = Path(newPath);
}
if (!File::Exists(pendingMemStickFolder) && pendingMemStickFolder.Type() == PathType::NATIVE) {
// Still no path? Try to automatically fix the case.
std::string oldNewPath = newPath;
FixPathCase(Path(""), newPath, FixPathCaseBehavior::FPC_FILE_MUST_EXIST);
if (oldNewPath != newPath) {
NOTICE_LOG(IO, "Fixed path case: %s -> %s", oldNewPath.c_str(), newPath.c_str());
pendingMemStickFolder = Path(newPath);
} else {
NOTICE_LOG(IO, "Failed to fix case of path %s (result: %s)", newPath.c_str(), oldNewPath.c_str());
}
}
if (!File::Exists(pendingMemStickFolder) && pendingMemStickFolder.Type() == PathType::NATIVE) {
// Still no path? Try to automatically fix the case.
std::string oldNewPath = newPath;
FixPathCase(Path(""), newPath, FixPathCaseBehavior::FPC_FILE_MUST_EXIST);
if (oldNewPath != newPath) {
NOTICE_LOG(IO, "Fixed path case: %s -> %s", oldNewPath.c_str(), newPath.c_str());
pendingMemStickFolder = Path(newPath);
} else {
NOTICE_LOG(IO, "Failed to fix case of path %s (result: %s)", newPath.c_str(), oldNewPath.c_str());
}
}
if (pendingMemStickFolder == g_Config.memStickDirectory) {
// Same directory as before - all good. Nothing to do.
TriggerFinish(DialogResult::DR_OK);
return;
}
if (pendingMemStickFolder == g_Config.memStickDirectory) {
// Same directory as before - all good. Nothing to do.
TriggerFinish(DialogResult::DR_OK);
return;
}
if (!File::Exists(pendingMemStickFolder)) {
System_Toast(sy->T("Path does not exist!"));
return;
}
if (!File::Exists(pendingMemStickFolder)) {
System_Toast(sy->T("Path does not exist!"));
return;
}
screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder, false));
}
screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder, false));
});
#endif
return UI::EVENT_DONE;

View file

@ -58,8 +58,10 @@
#include "android/jni/app-android.h"
#include "Common/System/Display.h"
#include "Common/System/Request.h"
#include "Common/System/System.h"
#include "Common/System/NativeApp.h"
#include "Common/Data/Text/I18n.h"
#include "Common/Input/InputState.h"
#include "Common/Math/math_util.h"
@ -164,15 +166,8 @@ struct PendingMessage {
std::string value;
};
struct PendingInputBox {
std::function<void(bool, const std::string &)> cb;
bool result;
std::string value;
};
static std::mutex pendingMutex;
static std::vector<PendingMessage> pendingMessages;
static std::vector<PendingInputBox> pendingInputBoxes;
static Draw::DrawContext *g_draw;
static Draw::Pipeline *colorPipeline;
static Draw::Pipeline *texColorPipeline;
@ -443,7 +438,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
setlocale( LC_ALL, "C" );
std::string user_data_path = savegame_dir;
pendingMessages.clear();
pendingInputBoxes.clear();
g_requestManager.Clear();
// external_dir has all kinds of meanings depending on platform.
// on iOS it's even the path to bundled app assets. It's a mess.
@ -1248,22 +1243,18 @@ void NativeUpdate() {
PROFILE_END_FRAME();
std::vector<PendingMessage> toProcess;
std::vector<PendingInputBox> inputToProcess;
{
std::lock_guard<std::mutex> lock(pendingMutex);
toProcess = std::move(pendingMessages);
inputToProcess = std::move(pendingInputBoxes);
pendingMessages.clear();
pendingInputBoxes.clear();
}
for (const auto &item : toProcess) {
HandleGlobalMessage(item.msg, item.value);
g_screenManager->sendMessage(item.msg.c_str(), item.value.c_str());
}
for (const auto &item : inputToProcess) {
item.cb(item.result, item.value);
}
g_requestManager.ProcessRequests();
g_DownloadManager.Update();
g_screenManager->update();
@ -1396,15 +1387,6 @@ void NativeMessageReceived(const char *message, const char *value) {
pendingMessages.push_back(pendingMessage);
}
void NativeInputBoxReceived(std::function<void(bool, const std::string &)> cb, bool result, const std::string &value) {
std::lock_guard<std::mutex> lock(pendingMutex);
PendingInputBox pendingMessage;
pendingMessage.cb = cb;
pendingMessage.result = result;
pendingMessage.value = value;
pendingInputBoxes.push_back(pendingMessage);
}
void NativeResized() {
// NativeResized can come from any thread so we just set a flag, then process it later.
VERBOSE_LOG(G3D, "NativeResized - setting flag");

View file

@ -31,6 +31,7 @@
#include "Common/Net/Resolve.h"
#include "Common/Net/URL.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/System/Request.h"
#include "Common/File/PathBrowser.h"
#include "Common/Data/Format/JSONReader.h"
@ -38,7 +39,6 @@
#include "Common/Common.h"
#include "Common/Log.h"
#include "Common/StringUtils.h"
#include "Common/System/System.h"
#include "Common/TimeUtil.h"
#include "Core/Config.h"
#include "Core/System.h"
@ -643,7 +643,7 @@ void RemoteISOSettingsScreen::CreateViews() {
UI::EventReturn RemoteISOSettingsScreen::OnClickRemoteServer(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__)
auto ri = GetI18NCategory("RemoteISO");
System_InputBoxGetString(ri->T("Remote Server"), g_Config.sLastRemoteISOServer, [](bool result, const std::string &value) {
System_InputBoxGetString(ri->T("Remote Server"), g_Config.sLastRemoteISOServer, [](const std::string &value, int) {
g_Config.sLastRemoteISOServer = value;
});
#endif
@ -663,7 +663,7 @@ static void CleanupRemoteISOSubdir() {
UI::EventReturn RemoteISOSettingsScreen::OnClickRemoteISOSubdir(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__)
auto ri = GetI18NCategory("RemoteISO");
System_InputBoxGetString(ri->T("Remote Subdirectory"), g_Config.sRemoteISOSubdir, [](bool result, const std::string &value) {
System_InputBoxGetString(ri->T("Remote Subdirectory"), g_Config.sRemoteISOSubdir, [](const std::string &value, int) {
g_Config.sRemoteISOSubdir = value;
// Apply the cleanup logic, too.
CleanupRemoteISOSubdir();

View file

@ -24,7 +24,7 @@
#include "Common/Data/Text/I18n.h"
#include "Common/Math/curves.h"
#include "Common/System/NativeApp.h"
#include "Common/System/System.h"
#include "Common/System/Request.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/UI/Context.h"
#include "Common/UI/View.h"
@ -674,8 +674,8 @@ UI::EventReturn SavedataScreen::OnSortClick(UI::EventParams &e) {
UI::EventReturn SavedataScreen::OnSearch(UI::EventParams &e) {
auto di = GetI18NCategory("Dialog");
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || defined(__ANDROID__)
System_InputBoxGetString(di->T("Filter"), searchFilter_, [](bool result, const std::string &value) {
if (result) {
System_InputBoxGetString(di->T("Filter"), searchFilter_, [](const std::string &value, int ivalue) {
if (ivalue) {
NativeMessageReceived("savedatascreen_search", value.c_str());
}
});

View file

@ -443,6 +443,8 @@ void System_Notify(SystemNotification notification) {
}
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2) { return false; }
void System_SendMessage(const char *command, const char *parameter) {
using namespace concurrency;

View file

@ -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 &param1, const std::string &param2) {
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,42 +521,6 @@ void EnableCrashingOnCrashes() {
FreeLibrary(kernel32);
}
void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function<void(bool, const std::string &)> 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, "");
}
});
}
bool System_PerformRequest(SystemRequestType type, int requestId, const char *param1, const char *param2) {
switch (type) {
case SystemRequestType::INPUT_TEXT_MODAL:
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);
@ -639,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();

View file

@ -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<bool> renderLoopRunning;
static bool renderer_inited = false;
static std::mutex renderLock;
static int inputBoxSequence = 1;
static std::map<int, std::function<void(bool, const std::string &)>> inputBoxCallbacks;
static bool sustainedPerfSupported = false;
static std::map<SystemPermission, PermissionStatus> permissions;
@ -909,7 +907,6 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
{
std::lock_guard<std::mutex> 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<void(bool, const std::string &)> 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 &param1, const std::string &param2) {
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() {

View file

@ -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 &param1, const std::string &param2) { return false; }
void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function<void(bool, const std::string &)> cb) { cb(false, ""); }
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }

View file

@ -219,6 +219,10 @@ void System_SendMessage(const char *command, const char *parameter) {
}
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2) {
return false;
}
void System_Toast(const char *text) {}
void System_AskForPermission(SystemPermission permission) {}

View file

@ -1874,7 +1874,7 @@ void System_Notify(SystemNotification notification) {
break;
}
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2) { return false; }
void System_SendMessage(const char *command, const char *parameter) {}
void NativeUpdate() {}
void NativeRender(GraphicsContext *graphicsContext) {}

View file

@ -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 &param1, const std::string &param2) { return false; }
void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function<void(bool, const std::string &)> cb) { cb(false, ""); }
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }