Fix a particular type of race condition in file dialog requests

It seems to be possible for a user to back out of a screen before
receiving the "dialog completed" callback on Android, in which case
things pointed to by the callback might be gone.

In this case, it's better to simply not call the callback, rather than
crashing.

This is accomplished by assigning "Tokens" to screens that cause
requests, and in ~Screen, invalidate any pending requests belonging to
that token.
This commit is contained in:
Henrik Rydgård 2024-01-18 11:55:39 +01:00
parent b4122ef1f4
commit 1304d04161
24 changed files with 174 additions and 124 deletions

View File

@ -31,13 +31,21 @@ const char *RequestTypeAsString(SystemRequestType type) {
} }
} }
bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, RequestFailedCallback failedCallback, const std::string &param1, const std::string &param2, int param3) { bool RequestManager::MakeSystemRequest(SystemRequestType type, RequesterToken token, RequestCallback callback, RequestFailedCallback failedCallback, const std::string &param1, const std::string &param2, int param3) {
if (token == NO_REQUESTER_TOKEN) {
_dbg_assert_(!callback);
_dbg_assert_(!failedCallback);
}
if (callback || failedCallback) {
_dbg_assert_(token != NO_REQUESTER_TOKEN);
}
int requestId = idCounter_++; int requestId = idCounter_++;
// NOTE: We need to register immediately, in order to support synchronous implementations. // NOTE: We need to register immediately, in order to support synchronous implementations.
if (callback || failedCallback) { if (callback || failedCallback) {
std::lock_guard<std::mutex> guard(callbackMutex_); std::lock_guard<std::mutex> guard(callbackMutex_);
callbackMap_[requestId] = { callback, failedCallback }; callbackMap_[requestId] = { callback, failedCallback, token };
} }
VERBOSE_LOG(SYSTEM, "Making system request %s: id %d", RequestTypeAsString(type), requestId); VERBOSE_LOG(SYSTEM, "Making system request %s: id %d", RequestTypeAsString(type), requestId);
@ -52,6 +60,16 @@ bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback c
return true; return true;
} }
void RequestManager::ForgetRequestsWithToken(RequesterToken token) {
for (auto &iter : callbackMap_) {
if (iter.second.token == token) {
INFO_LOG(SYSTEM, "Forgetting about requester with token %d", token);
iter.second.callback = nullptr;
iter.second.failedCallback = nullptr;
}
}
}
void RequestManager::PostSystemSuccess(int requestId, const char *responseString, int responseValue) { void RequestManager::PostSystemSuccess(int requestId, const char *responseString, int responseValue) {
std::lock_guard<std::mutex> guard(callbackMutex_); std::lock_guard<std::mutex> guard(callbackMutex_);
auto iter = callbackMap_.find(requestId); auto iter = callbackMap_.find(requestId);
@ -82,7 +100,7 @@ void RequestManager::PostSystemFailure(int requestId) {
std::lock_guard<std::mutex> responseGuard(responseMutex_); std::lock_guard<std::mutex> responseGuard(responseMutex_);
PendingFailure response; PendingFailure response;
response.callback = iter->second.failedCallback; response.failedCallback = iter->second.failedCallback;
pendingFailures_.push_back(response); pendingFailures_.push_back(response);
callbackMap_.erase(iter); callbackMap_.erase(iter);
} }
@ -96,8 +114,8 @@ void RequestManager::ProcessRequests() {
} }
pendingSuccesses_.clear(); pendingSuccesses_.clear();
for (auto &iter : pendingFailures_) { for (auto &iter : pendingFailures_) {
if (iter.callback) { if (iter.failedCallback) {
iter.callback(); iter.failedCallback();
} }
} }
pendingFailures_.clear(); pendingFailures_.clear();
@ -113,9 +131,9 @@ void RequestManager::Clear() {
} }
void System_CreateGameShortcut(const Path &path, const std::string &title) { void System_CreateGameShortcut(const Path &path, const std::string &title) {
g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, nullptr, nullptr, path.ToString(), title, 0); g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, NO_REQUESTER_TOKEN, nullptr, nullptr, path.ToString(), title, 0);
} }
void System_ShowFileInFolder(const Path &path) { void System_ShowFileInFolder(const Path &path) {
g_requestManager.MakeSystemRequest(SystemRequestType::SHOW_FILE_IN_FOLDER, nullptr, nullptr, path.ToString(), "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::SHOW_FILE_IN_FOLDER, NO_REQUESTER_TOKEN, nullptr, nullptr, path.ToString(), "", 0);
} }

View File

@ -12,6 +12,10 @@ class Path;
typedef std::function<void(const char *responseString, int responseValue)> RequestCallback; typedef std::function<void(const char *responseString, int responseValue)> RequestCallback;
typedef std::function<void()> RequestFailedCallback; typedef std::function<void()> RequestFailedCallback;
typedef int RequesterToken;
#define NO_REQUESTER_TOKEN -1
#define NON_EPHEMERAL_TOKEN -2
// Platforms often have to process requests asynchronously, on wildly different threads, // Platforms often have to process requests asynchronously, on wildly different threads,
// and then somehow pass a response back to the main thread (especially Android...) // and then somehow pass a response back to the main thread (especially Android...)
// This acts as bridge and buffer. // This acts as bridge and buffer.
@ -23,7 +27,7 @@ public:
// The callback you pass in will be called on the main thread later. // The callback you pass in will be called on the main thread later.
// Params are at the end since it's the part most likely to recieve additions in the future, // Params are at the end since it's the part most likely to recieve additions in the future,
// now that we have both callbacks. // now that we have both callbacks.
bool MakeSystemRequest(SystemRequestType type, RequestCallback callback, RequestFailedCallback failedCallback, const std::string &param1, const std::string &param2, int param3); bool MakeSystemRequest(SystemRequestType type, RequesterToken token, RequestCallback callback, RequestFailedCallback failedCallback, const std::string &param1, const std::string &param2, int param3);
// Called by the platform implementation, when it's finished with a request. // Called by the platform implementation, when it's finished with a request.
void PostSystemSuccess(int requestId, const char *responseString, int responseValue = 0); void PostSystemSuccess(int requestId, const char *responseString, int responseValue = 0);
@ -33,19 +37,21 @@ public:
// This will call the callback of any finished requests. // This will call the callback of any finished requests.
void ProcessRequests(); void ProcessRequests();
RequesterToken GenerateRequesterToken() {
int token = tokenGen_++;
return token;
}
void ForgetRequestsWithToken(RequesterToken token);
// Unclear if we need this... // Unclear if we need this...
void Clear(); void Clear();
private: private:
struct PendingRequest {
SystemRequestType type;
RequestCallback callback;
RequestFailedCallback failedCallback;
};
struct CallbackPair { struct CallbackPair {
RequestCallback callback; RequestCallback callback;
RequestFailedCallback failedCallback; RequestFailedCallback failedCallback;
RequesterToken token;
}; };
std::map<int, CallbackPair> callbackMap_; std::map<int, CallbackPair> callbackMap_;
@ -58,7 +64,7 @@ private:
}; };
struct PendingFailure { struct PendingFailure {
RequestFailedCallback callback; RequestFailedCallback failedCallback;
}; };
// Let's start at 10 to get a recognizably valid ID in logs. // Let's start at 10 to get a recognizably valid ID in logs.
@ -66,6 +72,8 @@ private:
std::vector<PendingSuccess> pendingSuccesses_; std::vector<PendingSuccess> pendingSuccesses_;
std::vector<PendingFailure> pendingFailures_; std::vector<PendingFailure> pendingFailures_;
std::mutex responseMutex_; std::mutex responseMutex_;
RequesterToken tokenGen_ = 20000;
}; };
const char *RequestTypeAsString(SystemRequestType type); const char *RequestTypeAsString(SystemRequestType type);
@ -75,14 +83,14 @@ extern RequestManager g_requestManager;
// Wrappers for easy requests. // Wrappers for easy requests.
// NOTE: Semantics have changed - this no longer calls the callback on cancellation, instead you // NOTE: Semantics have changed - this no longer calls the callback on cancellation, instead you
// can specify a different callback for that. // can specify a different callback for that.
inline void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) { inline void System_InputBoxGetString(RequesterToken token, const std::string &title, const std::string &defaultValue, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::INPUT_TEXT_MODAL, callback, failedCallback, title, defaultValue, 0); g_requestManager.MakeSystemRequest(SystemRequestType::INPUT_TEXT_MODAL, token, callback, failedCallback, title, defaultValue, 0);
} }
// This one will pop up a special image browser if available. You can also pick // This one will pop up a special image browser if available. You can also pick
// images with the file browser below. // images with the file browser below.
inline void System_BrowseForImage(const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) { inline void System_BrowseForImage(RequesterToken token, const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_IMAGE, callback, failedCallback, title, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_IMAGE, token, callback, failedCallback, title, "", 0);
} }
enum class BrowseFileType { enum class BrowseFileType {
@ -95,78 +103,78 @@ enum class BrowseFileType {
ANY, ANY,
}; };
inline void System_BrowseForFile(const std::string &title, BrowseFileType type, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) { inline void System_BrowseForFile(RequesterToken token, const std::string &title, BrowseFileType type, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FILE, callback, failedCallback, title, "", (int)type); g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FILE, token, callback, failedCallback, title, "", (int)type);
} }
inline void System_BrowseForFolder(const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) { inline void System_BrowseForFolder(RequesterToken token, const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FOLDER, callback, failedCallback, title, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FOLDER, token, callback, failedCallback, title, "", 0);
} }
// The returned string is username + '\n' + password. // The returned string is username + '\n' + password.
inline void System_AskUsernamePassword(const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) { inline void System_AskUsernamePassword(RequesterToken token, const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::ASK_USERNAME_PASSWORD, callback, failedCallback, title, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::ASK_USERNAME_PASSWORD, token, callback, failedCallback, title, "", 0);
} }
inline void System_CopyStringToClipboard(const std::string &string) { inline void System_CopyStringToClipboard(const std::string &string) {
g_requestManager.MakeSystemRequest(SystemRequestType::COPY_TO_CLIPBOARD, nullptr, nullptr, string, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::COPY_TO_CLIPBOARD, NO_REQUESTER_TOKEN, nullptr, nullptr, string, "", 0);
} }
inline void System_ExitApp() { inline void System_ExitApp() {
g_requestManager.MakeSystemRequest(SystemRequestType::EXIT_APP, nullptr, nullptr, "", "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::EXIT_APP, NO_REQUESTER_TOKEN, nullptr, nullptr, "", "", 0);
} }
inline void System_RestartApp(const std::string &params) { inline void System_RestartApp(const std::string &params) {
g_requestManager.MakeSystemRequest(SystemRequestType::RESTART_APP, nullptr, nullptr, params, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::RESTART_APP, NO_REQUESTER_TOKEN, nullptr, nullptr, params, "", 0);
} }
inline void System_RecreateActivity() { inline void System_RecreateActivity() {
g_requestManager.MakeSystemRequest(SystemRequestType::RECREATE_ACTIVITY, nullptr, nullptr, "", "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::RECREATE_ACTIVITY, NO_REQUESTER_TOKEN, nullptr, nullptr, "", "", 0);
} }
// The design is a little weird, just a holdover from the old message. Can either toggle or set to on or off. // The design is a little weird, just a holdover from the old message. Can either toggle or set to on or off.
inline void System_ToggleFullscreenState(const std::string &param) { inline void System_ToggleFullscreenState(const std::string &param) {
g_requestManager.MakeSystemRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, nullptr, nullptr, param, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, NO_REQUESTER_TOKEN, nullptr, nullptr, param, "", 0);
} }
inline void System_GraphicsBackendFailedAlert(const std::string &param) { inline void System_GraphicsBackendFailedAlert(const std::string &param) {
g_requestManager.MakeSystemRequest(SystemRequestType::GRAPHICS_BACKEND_FAILED_ALERT, nullptr, nullptr, param, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::GRAPHICS_BACKEND_FAILED_ALERT, NO_REQUESTER_TOKEN, nullptr, nullptr, param, "", 0);
} }
inline void System_CameraCommand(const std::string &command) { inline void System_CameraCommand(const std::string &command) {
g_requestManager.MakeSystemRequest(SystemRequestType::CAMERA_COMMAND, nullptr, nullptr, command, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::CAMERA_COMMAND, NO_REQUESTER_TOKEN, nullptr, nullptr, command, "", 0);
} }
inline void System_GPSCommand(const std::string &command) { inline void System_GPSCommand(const std::string &command) {
g_requestManager.MakeSystemRequest(SystemRequestType::GPS_COMMAND, nullptr, nullptr, command, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::GPS_COMMAND, NO_REQUESTER_TOKEN, nullptr, nullptr, command, "", 0);
} }
inline void System_InfraredCommand(const std::string &command) { inline void System_InfraredCommand(const std::string &command) {
g_requestManager.MakeSystemRequest(SystemRequestType::INFRARED_COMMAND, nullptr, nullptr, command, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::INFRARED_COMMAND, NO_REQUESTER_TOKEN, nullptr, nullptr, command, "", 0);
} }
inline void System_MicrophoneCommand(const std::string &command) { inline void System_MicrophoneCommand(const std::string &command) {
g_requestManager.MakeSystemRequest(SystemRequestType::MICROPHONE_COMMAND, nullptr, nullptr, command, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::MICROPHONE_COMMAND, NO_REQUESTER_TOKEN, nullptr, nullptr, command, "", 0);
} }
inline void System_ShareText(const std::string &text) { inline void System_ShareText(const std::string &text) {
g_requestManager.MakeSystemRequest(SystemRequestType::SHARE_TEXT, nullptr, nullptr, text, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::SHARE_TEXT, NO_REQUESTER_TOKEN, nullptr, nullptr, text, "", 0);
} }
inline void System_NotifyUIState(const std::string &state) { inline void System_NotifyUIState(const std::string &state) {
g_requestManager.MakeSystemRequest(SystemRequestType::NOTIFY_UI_STATE, nullptr, nullptr, state, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::NOTIFY_UI_STATE, NO_REQUESTER_TOKEN, nullptr, nullptr, state, "", 0);
} }
inline void System_SetWindowTitle(const std::string &param) { inline void System_SetWindowTitle(const std::string &param) {
g_requestManager.MakeSystemRequest(SystemRequestType::SET_WINDOW_TITLE, nullptr, nullptr, param, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::SET_WINDOW_TITLE, NO_REQUESTER_TOKEN, nullptr, nullptr, param, "", 0);
} }
inline bool System_SendDebugOutput(const std::string &string) { inline bool System_SendDebugOutput(const std::string &string) {
return g_requestManager.MakeSystemRequest(SystemRequestType::SEND_DEBUG_OUTPUT, nullptr, nullptr, string, "", 0); return g_requestManager.MakeSystemRequest(SystemRequestType::SEND_DEBUG_OUTPUT, NO_REQUESTER_TOKEN, nullptr, nullptr, string, "", 0);
} }
inline void System_SendDebugScreenshot(const std::string &data, int height) { inline void System_SendDebugScreenshot(const std::string &data, int height) {
g_requestManager.MakeSystemRequest(SystemRequestType::SEND_DEBUG_SCREENSHOT, nullptr, nullptr, data, "", height); g_requestManager.MakeSystemRequest(SystemRequestType::SEND_DEBUG_SCREENSHOT, NO_REQUESTER_TOKEN, nullptr, nullptr, data, "", height);
} }
// Non-inline to avoid including Path.h // Non-inline to avoid including Path.h

View File

@ -500,8 +500,8 @@ void SliderFloatPopupScreen::OnCompleted(DialogResult result) {
} }
} }
PopupTextInputChoice::PopupTextInputChoice(std::string *value, const std::string &title, const std::string &placeholder, int maxLen, ScreenManager *screenManager, LayoutParams *layoutParams) PopupTextInputChoice::PopupTextInputChoice(RequesterToken token, std::string *value, const std::string &title, const std::string &placeholder, int maxLen, ScreenManager *screenManager, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(title, layoutParams), screenManager_(screenManager), value_(value), placeHolder_(placeholder), maxLen_(maxLen) { : AbstractChoiceWithValueDisplay(title, layoutParams), screenManager_(screenManager), value_(value), placeHolder_(placeholder), maxLen_(maxLen), token_(token) {
OnClick.Handle(this, &PopupTextInputChoice::HandleClick); OnClick.Handle(this, &PopupTextInputChoice::HandleClick);
} }
@ -510,7 +510,7 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) {
// Choose method depending on platform capabilities. // Choose method depending on platform capabilities.
if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) {
System_InputBoxGetString(text_, *value_ , [=](const std::string &enteredValue, int) { System_InputBoxGetString(token_, text_, *value_ , [=](const std::string &enteredValue, int) {
*value_ = StripSpaces(enteredValue); *value_ = StripSpaces(enteredValue);
EventParams params{}; EventParams params{};
OnChange.Trigger(params); OnChange.Trigger(params);
@ -668,10 +668,10 @@ std::string ChoiceWithValueDisplay::ValueText() const {
return valueText.str(); return valueText.str();
} }
FileChooserChoice::FileChooserChoice(std::string *value, const std::string &text, BrowseFileType fileType, LayoutParams *layoutParams) FileChooserChoice::FileChooserChoice(RequesterToken token, std::string *value, const std::string &text, BrowseFileType fileType, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), fileType_(fileType) { : AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), fileType_(fileType), token_(token) {
OnClick.Add([=](UI::EventParams &) { OnClick.Add([=](UI::EventParams &) {
System_BrowseForFile(text_, fileType, [=](const std::string &returnValue, int) { System_BrowseForFile(token, text_, fileType, [=](const std::string &returnValue, int) {
if (*value_ != returnValue) { if (*value_ != returnValue) {
*value = returnValue; *value = returnValue;
UI::EventParams e{}; UI::EventParams e{};
@ -692,10 +692,10 @@ std::string FileChooserChoice::ValueText() const {
return path.GetFilename(); return path.GetFilename();
} }
FolderChooserChoice::FolderChooserChoice(std::string *value, const std::string &text, LayoutParams *layoutParams) FolderChooserChoice::FolderChooserChoice(RequesterToken token, std::string *value, const std::string &text, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value) { : AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), token_(token) {
OnClick.Add([=](UI::EventParams &) { OnClick.Add([=](UI::EventParams &) {
System_BrowseForFolder(text_, [=](const std::string &returnValue, int) { System_BrowseForFolder(token_, text_, [=](const std::string &returnValue, int) {
if (*value_ != returnValue) { if (*value_ != returnValue) {
*value = returnValue; *value = returnValue;
UI::EventParams e{}; UI::EventParams e{};

View File

@ -360,7 +360,7 @@ private:
// NOTE: This one will defer to a system-native dialog if possible. // NOTE: This one will defer to a system-native dialog if possible.
class PopupTextInputChoice : public AbstractChoiceWithValueDisplay { class PopupTextInputChoice : public AbstractChoiceWithValueDisplay {
public: public:
PopupTextInputChoice(std::string *value, const std::string &title, const std::string &placeholder, int maxLen, ScreenManager *screenManager, LayoutParams *layoutParams = 0); PopupTextInputChoice(RequesterToken token, std::string *value, const std::string &title, const std::string &placeholder, int maxLen, ScreenManager *screenManager, LayoutParams *layoutParams = 0);
Event OnChange; Event OnChange;
@ -370,6 +370,7 @@ protected:
private: private:
EventReturn HandleClick(EventParams &e); EventReturn HandleClick(EventParams &e);
EventReturn HandleChange(EventParams &e); EventReturn HandleChange(EventParams &e);
RequesterToken token_;
ScreenManager *screenManager_; ScreenManager *screenManager_;
std::string *value_; std::string *value_;
std::string placeHolder_; std::string placeHolder_;
@ -405,7 +406,7 @@ enum class FileChooserFileType {
class FileChooserChoice : public AbstractChoiceWithValueDisplay { class FileChooserChoice : public AbstractChoiceWithValueDisplay {
public: public:
FileChooserChoice(std::string *value, const std::string &title, BrowseFileType fileType, LayoutParams *layoutParams = nullptr); FileChooserChoice(RequesterToken token, std::string *value, const std::string &title, BrowseFileType fileType, LayoutParams *layoutParams = nullptr);
std::string ValueText() const override; std::string ValueText() const override;
Event OnChange; Event OnChange;
@ -413,11 +414,12 @@ public:
private: private:
std::string *value_; std::string *value_;
BrowseFileType fileType_; BrowseFileType fileType_;
RequesterToken token_;
}; };
class FolderChooserChoice : public AbstractChoiceWithValueDisplay { class FolderChooserChoice : public AbstractChoiceWithValueDisplay {
public: public:
FolderChooserChoice(std::string *value, const std::string &title, LayoutParams *layoutParams = nullptr); FolderChooserChoice(RequesterToken token, std::string *value, const std::string &title, LayoutParams *layoutParams = nullptr);
std::string ValueText() const override; std::string ValueText() const override;
Event OnChange; Event OnChange;
@ -425,7 +427,7 @@ public:
private: private:
std::string *value_; std::string *value_;
BrowseFileType fileType_; BrowseFileType fileType_;
RequesterToken token_;
}; };
} // namespace UI } // namespace UI

View File

@ -1,4 +1,5 @@
#include "Common/System/Display.h" #include "Common/System/Display.h"
#include "Common/System/Request.h"
#include "Common/Input/InputState.h" #include "Common/Input/InputState.h"
#include "Common/UI/Root.h" #include "Common/UI/Root.h"
#include "Common/UI/Screen.h" #include "Common/UI/Screen.h"
@ -21,6 +22,21 @@ void Screen::focusChanged(ScreenFocusChange focusChange) {
DEBUG_LOG(SYSTEM, "Screen %s got %s", this->tag(), eventName); DEBUG_LOG(SYSTEM, "Screen %s got %s", this->tag(), eventName);
} }
int Screen::GetRequesterToken() {
if (token_ < 0) {
token_ = g_requestManager.GenerateRequesterToken();
}
return token_;
}
Screen::~Screen() {
screenManager_ = nullptr;
if (token_ >= 0) {
// To avoid expired callbacks getting called.
g_requestManager.ForgetRequestsWithToken(token_);
}
}
ScreenManager::~ScreenManager() { ScreenManager::~ScreenManager() {
shutdown(); shutdown();
} }

View File

@ -64,9 +64,7 @@ ENUM_CLASS_BITOPS(ScreenRenderFlags);
class Screen { class Screen {
public: public:
Screen() : screenManager_(nullptr) { } Screen() : screenManager_(nullptr) { }
virtual ~Screen() { virtual ~Screen();
screenManager_ = nullptr;
}
virtual void onFinish(DialogResult reason) {} virtual void onFinish(DialogResult reason) {}
virtual void update() {} virtual void update() {}
@ -100,8 +98,13 @@ public:
virtual TouchInput transformTouch(const TouchInput &touch) { return touch; } virtual TouchInput transformTouch(const TouchInput &touch) { return touch; }
protected:
int GetRequesterToken();
private: private:
ScreenManager *screenManager_; ScreenManager *screenManager_;
int token_ = -1;
DISALLOW_COPY_AND_ASSIGN(Screen); DISALLOW_COPY_AND_ASSIGN(Screen);
}; };

View File

@ -897,7 +897,7 @@ int PSPOskDialog::NativeKeyboard() {
defaultText.assign(u"VALUE"); defaultText.assign(u"VALUE");
// There's already ConvertUCS2ToUTF8 in this file. Should we use that instead of the global ones? // There's already ConvertUCS2ToUTF8 in this file. Should we use that instead of the global ones?
System_InputBoxGetString(::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText), System_InputBoxGetString(NON_EPHEMERAL_TOKEN, ::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText),
[&](const std::string &value, int) { [&](const std::string &value, int) {
// Success callback // Success callback
std::lock_guard<std::mutex> guard(nativeMutex_); std::lock_guard<std::mutex> guard(nativeMutex_);

View File

@ -97,7 +97,7 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) {
sendChat(chat); sendChat(chat);
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("Chat"), "", [](const std::string &value, int) { System_InputBoxGetString(token_, n->T("Chat"), "", [](const std::string &value, int) {
sendChat(value); sendChat(value);
}); });
#endif #endif
@ -180,7 +180,7 @@ void ChatMenu::Update() {
// Could remove the fullscreen check here, it works now. // Could remove the fullscreen check here, it works now.
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
if (promptInput_ && g_Config.bBypassOSKWithKeyboard && !g_Config.UseFullScreen()) { if (promptInput_ && g_Config.bBypassOSKWithKeyboard && !g_Config.UseFullScreen()) {
System_InputBoxGetString(n->T("Chat"), n->T("Chat Here"), [](const std::string &value, int) { System_InputBoxGetString(token_, n->T("Chat"), n->T("Chat Here"), [](const std::string &value, int) {
sendChat(value); sendChat(value);
}); });
promptInput_ = false; promptInput_ = false;

View File

@ -5,7 +5,8 @@
class ChatMenu : public UI::AnchorLayout { class ChatMenu : public UI::AnchorLayout {
public: public:
ChatMenu(const Bounds &screenBounds, UI::LayoutParams *lp = nullptr): UI::AnchorLayout(lp) { ChatMenu(int token, const Bounds &screenBounds, UI::LayoutParams *lp = nullptr)
: UI::AnchorLayout(lp), token_(token) {
CreateSubviews(screenBounds); CreateSubviews(screenBounds);
} }
void Update() override; void Update() override;
@ -41,4 +42,5 @@ private:
int chatChangeID_ = 0; int chatChangeID_ = 0;
bool toBottom_ = true; bool toBottom_ = true;
bool promptInput_ = false; bool promptInput_ = false;
int token_;
}; };

View File

@ -206,7 +206,7 @@ static char *GetLineNoNewline(char *temp, int sz, FILE *fp) {
} }
UI::EventReturn CwCheatScreen::OnImportBrowse(UI::EventParams &params) { UI::EventReturn CwCheatScreen::OnImportBrowse(UI::EventParams &params) {
System_BrowseForFile("Open cheat DB file", BrowseFileType::DB, [&](const std::string &value, int) { System_BrowseForFile(GetRequesterToken(), "Open cheat DB file", BrowseFileType::DB, [&](const std::string &value, int) {
Path path(value); Path path(value);
INFO_LOG(SYSTEM, "Attempting to load cheats from: '%s'", path.ToVisualString().c_str()); INFO_LOG(SYSTEM, "Attempting to load cheats from: '%s'", path.ToVisualString().c_str());
if (ImportCheats(path)) { if (ImportCheats(path)) {

View File

@ -212,7 +212,7 @@ UI::EventReturn DriverManagerScreen::OnCustomDriverUninstall(UI::EventParams &e)
UI::EventReturn DriverManagerScreen::OnCustomDriverInstall(UI::EventParams &e) { UI::EventReturn DriverManagerScreen::OnCustomDriverInstall(UI::EventParams &e) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS); auto gr = GetI18NCategory(I18NCat::GRAPHICS);
System_BrowseForFile(gr->T("Install custom driver..."), BrowseFileType::ZIP, [this](const std::string &value, int) { System_BrowseForFile(GetRequesterToken(), gr->T("Install custom driver..."), BrowseFileType::ZIP, [this](const std::string &value, int) {
if (value.empty()) { if (value.empty()) {
return; return;
} }

View File

@ -1039,7 +1039,7 @@ void EmuScreen::CreateViews() {
root_->Add(btn)->OnClick.Handle(this, &EmuScreen::OnChat); root_->Add(btn)->OnClick.Handle(this, &EmuScreen::OnChat);
chatButton_ = btn; chatButton_ = btn;
} }
chatMenu_ = root_->Add(new ChatMenu(screenManager()->getUIContext()->GetBounds(), new LayoutParams(FILL_PARENT, FILL_PARENT))); chatMenu_ = root_->Add(new ChatMenu(GetRequesterToken(), screenManager()->getUIContext()->GetBounds(), new LayoutParams(FILL_PARENT, FILL_PARENT)));
chatMenu_->SetVisibility(UI::V_GONE); chatMenu_->SetVisibility(UI::V_GONE);
} else { } else {
chatButton_ = nullptr; chatButton_ = nullptr;

View File

@ -805,12 +805,12 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
// Compound view just like the audio file choosers // Compound view just like the audio file choosers
class MacAddressChooser : public UI::LinearLayout { class MacAddressChooser : public UI::LinearLayout {
public: public:
MacAddressChooser(Path gamePath, std::string *value, const std::string &title, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr); MacAddressChooser(RequesterToken token, Path gamePath, std::string *value, const std::string &title, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr);
}; };
static constexpr UI::Size ITEM_HEIGHT = 64.f; static constexpr UI::Size ITEM_HEIGHT = 64.f;
MacAddressChooser::MacAddressChooser(Path gamePath_, std::string *value, const std::string &title, ScreenManager *screenManager, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams) { MacAddressChooser::MacAddressChooser(RequesterToken token, Path gamePath_, std::string *value, const std::string &title, ScreenManager *screenManager, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams) {
using namespace UI; using namespace UI;
SetSpacing(5.0f); SetSpacing(5.0f);
if (!layoutParams) { if (!layoutParams) {
@ -820,7 +820,7 @@ MacAddressChooser::MacAddressChooser(Path gamePath_, std::string *value, const s
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
std::string initialValue = *value; std::string initialValue = *value;
Add(new PopupTextInputChoice(value, title, g_Config.sMACAddress, 17, screenManager, new LinearLayoutParams(1.0f)))->OnChange.Add([=](UI::EventParams &e) { Add(new PopupTextInputChoice(token, value, title, g_Config.sMACAddress, 17, screenManager, new LinearLayoutParams(1.0f)))->OnChange.Add([=](UI::EventParams &e) {
// Validate the chosen address, and restore to initialValue if bad. // Validate the chosen address, and restore to initialValue if bad.
if (g_Config.sMACAddress.size() != 17) { if (g_Config.sMACAddress.size() != 17) {
// TODO: Alert the user // TODO: Alert the user
@ -860,7 +860,7 @@ void GameSettingsScreen::CreateNetworkingSettings(UI::ViewGroup *networkingSetti
networkingSettings->Add(new Choice(n->T("Open PPSSPP Multiplayer Wiki Page")))->OnClick.Handle(this, &GameSettingsScreen::OnAdhocGuides); networkingSettings->Add(new Choice(n->T("Open PPSSPP Multiplayer Wiki Page")))->OnClick.Handle(this, &GameSettingsScreen::OnAdhocGuides);
networkingSettings->Add(new CheckBox(&g_Config.bEnableWlan, n->T("Enable networking", "Enable networking/wlan (beta)"))); networkingSettings->Add(new CheckBox(&g_Config.bEnableWlan, n->T("Enable networking", "Enable networking/wlan (beta)")));
networkingSettings->Add(new MacAddressChooser(gamePath_, &g_Config.sMACAddress, n->T("Change Mac Address"), screenManager())); networkingSettings->Add(new MacAddressChooser(GetRequesterToken(), gamePath_, &g_Config.sMACAddress, n->T("Change Mac Address"), screenManager()));
static const char* wlanChannels[] = { "Auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11" }; static const char* wlanChannels[] = { "Auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11" };
auto wlanChannelChoice = networkingSettings->Add(new PopupMultiChoice(&g_Config.iWlanAdhocChannel, n->T("WLAN Channel"), wlanChannels, 0, ARRAY_SIZE(wlanChannels), I18NCat::NETWORKING, screenManager())); auto wlanChannelChoice = networkingSettings->Add(new PopupMultiChoice(&g_Config.iWlanAdhocChannel, n->T("WLAN Channel"), wlanChannels, 0, ARRAY_SIZE(wlanChannels), I18NCat::NETWORKING, screenManager()));
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -897,11 +897,11 @@ void GameSettingsScreen::CreateNetworkingSettings(UI::ViewGroup *networkingSetti
#endif #endif
#if !defined(MOBILE_DEVICE) && !defined(USING_QT_UI) // TODO: Add all platforms where KEY_CHAR support is added #if !defined(MOBILE_DEVICE) && !defined(USING_QT_UI) // TODO: Add all platforms where KEY_CHAR support is added
PopupTextInputChoice *qc1 = networkingSettings->Add(new PopupTextInputChoice(&g_Config.sQuickChat0, n->T("Quick Chat 1"), "", 32, screenManager())); PopupTextInputChoice *qc1 = networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sQuickChat0, n->T("Quick Chat 1"), "", 32, screenManager()));
PopupTextInputChoice *qc2 = networkingSettings->Add(new PopupTextInputChoice(&g_Config.sQuickChat1, n->T("Quick Chat 2"), "", 32, screenManager())); PopupTextInputChoice *qc2 = networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sQuickChat1, n->T("Quick Chat 2"), "", 32, screenManager()));
PopupTextInputChoice *qc3 = networkingSettings->Add(new PopupTextInputChoice(&g_Config.sQuickChat2, n->T("Quick Chat 3"), "", 32, screenManager())); PopupTextInputChoice *qc3 = networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sQuickChat2, n->T("Quick Chat 3"), "", 32, screenManager()));
PopupTextInputChoice *qc4 = networkingSettings->Add(new PopupTextInputChoice(&g_Config.sQuickChat3, n->T("Quick Chat 4"), "", 32, screenManager())); PopupTextInputChoice *qc4 = networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sQuickChat3, n->T("Quick Chat 4"), "", 32, screenManager()));
PopupTextInputChoice *qc5 = networkingSettings->Add(new PopupTextInputChoice(&g_Config.sQuickChat4, n->T("Quick Chat 5"), "", 32, screenManager())); PopupTextInputChoice *qc5 = networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sQuickChat4, n->T("Quick Chat 5"), "", 32, screenManager()));
#elif defined(USING_QT_UI) #elif defined(USING_QT_UI)
Choice *qc1 = networkingSettings->Add(new Choice(n->T("Quick Chat 1"))); Choice *qc1 = networkingSettings->Add(new Choice(n->T("Quick Chat 1")));
Choice *qc2 = networkingSettings->Add(new Choice(n->T("Quick Chat 2"))); Choice *qc2 = networkingSettings->Add(new Choice(n->T("Quick Chat 2")));
@ -1201,7 +1201,7 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) {
systemSettings->Add(new PopupMultiChoice(&g_Config.iLanguage, psps->T("Game language"), defaultLanguages, -1, ARRAY_SIZE(defaultLanguages), I18NCat::PSPSETTINGS, screenManager())); systemSettings->Add(new PopupMultiChoice(&g_Config.iLanguage, psps->T("Game language"), defaultLanguages, -1, ARRAY_SIZE(defaultLanguages), I18NCat::PSPSETTINGS, screenManager()));
static const char *models[] = { "PSP-1000", "PSP-2000/3000" }; static const char *models[] = { "PSP-1000", "PSP-2000/3000" };
systemSettings->Add(new PopupMultiChoice(&g_Config.iPSPModel, sy->T("PSP Model"), models, 0, ARRAY_SIZE(models), I18NCat::SYSTEM, screenManager()))->SetEnabled(!PSP_IsInited()); systemSettings->Add(new PopupMultiChoice(&g_Config.iPSPModel, sy->T("PSP Model"), models, 0, ARRAY_SIZE(models), I18NCat::SYSTEM, screenManager()))->SetEnabled(!PSP_IsInited());
systemSettings->Add(new PopupTextInputChoice(&g_Config.sNickName, sy->T("Change Nickname"), "", 32, screenManager())); systemSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sNickName, sy->T("Change Nickname"), "", 32, screenManager()));
systemSettings->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, sy->T("Screenshots as PNG"))); systemSettings->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, sy->T("Screenshots as PNG")));
#if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE)) #if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE))
@ -1294,7 +1294,7 @@ UI::EventReturn GameSettingsScreen::OnJitAffectingSetting(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeMemStickDir(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeMemStickDir(UI::EventParams &e) {
#if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) #if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS)
System_BrowseForFolder("", [](const std::string &value, int) { System_BrowseForFolder(GetRequesterToken(), "", [](const std::string &value, int) {
DarwinFileSystemServices::setUserPreferredMemoryStickDirectory(Path(value)); DarwinFileSystemServices::setUserPreferredMemoryStickDirectory(Path(value));
}); });
#else #else
@ -1374,7 +1374,7 @@ UI::EventReturn GameSettingsScreen::OnChangeBackground(UI::EventParams &e) {
RecreateViews(); RecreateViews();
} else { } else {
auto sy = GetI18NCategory(I18NCat::SYSTEM); auto sy = GetI18NCategory(I18NCat::SYSTEM);
System_BrowseForImage(sy->T("Set UI background..."), [=](const std::string &value, int) { System_BrowseForImage(GetRequesterToken(), sy->T("Set UI background..."), [=](const std::string &value, int) {
if (!value.empty()) { if (!value.empty()) {
Path dest = GetSysDirectory(DIRECTORY_SYSTEM) / (endsWithNoCase(value, ".jpg") ? "background.jpg" : "background.png"); Path dest = GetSysDirectory(DIRECTORY_SYSTEM) / (endsWithNoCase(value, ".jpg") ? "background.jpg" : "background.png");
File::Copy(Path(value), dest); File::Copy(Path(value), dest);
@ -1565,7 +1565,7 @@ UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat0(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat0(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("Enter Quick Chat 1"), g_Config.sQuickChat0, [](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), n->T("Enter Quick Chat 1"), g_Config.sQuickChat0, [](const std::string &value, int) {
g_Config.sQuickChat0 = value; g_Config.sQuickChat0 = value;
}); });
#endif #endif
@ -1575,7 +1575,7 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat0(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat1(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat1(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("Enter Quick Chat 2"), g_Config.sQuickChat1, [](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), n->T("Enter Quick Chat 2"), g_Config.sQuickChat1, [](const std::string &value, int) {
g_Config.sQuickChat1 = value; g_Config.sQuickChat1 = value;
}); });
#endif #endif
@ -1585,7 +1585,7 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat1(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat2(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat2(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("Enter Quick Chat 3"), g_Config.sQuickChat2, [](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), n->T("Enter Quick Chat 3"), g_Config.sQuickChat2, [](const std::string &value, int) {
g_Config.sQuickChat2 = value; g_Config.sQuickChat2 = value;
}); });
#endif #endif
@ -1595,7 +1595,7 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat2(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat3(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat3(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("Enter Quick Chat 4"), g_Config.sQuickChat3, [](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), n->T("Enter Quick Chat 4"), g_Config.sQuickChat3, [](const std::string &value, int) {
g_Config.sQuickChat3 = value; g_Config.sQuickChat3 = value;
}); });
#endif #endif
@ -1605,7 +1605,7 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat3(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeQuickChat4(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeQuickChat4(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("Enter Quick Chat 5"), g_Config.sQuickChat4, [](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), n->T("Enter Quick Chat 5"), g_Config.sQuickChat4, [](const std::string &value, int) {
g_Config.sQuickChat4 = value; g_Config.sQuickChat4 = value;
}); });
#endif #endif
@ -1615,7 +1615,7 @@ UI::EventReturn GameSettingsScreen::OnChangeQuickChat4(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("Enter a new PSP nickname"), g_Config.sNickName, [](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), n->T("Enter a new PSP nickname"), g_Config.sNickName, [](const std::string &value, int) {
g_Config.sNickName = StripSpaces(value); g_Config.sNickName = StripSpaces(value);
}); });
#endif #endif
@ -2077,7 +2077,7 @@ UI::EventReturn HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) {
UI::EventReturn HostnameSelectScreen::OnEditClick(UI::EventParams& e) { UI::EventReturn HostnameSelectScreen::OnEditClick(UI::EventParams& e) {
auto n = GetI18NCategory(I18NCat::NETWORKING); auto n = GetI18NCategory(I18NCat::NETWORKING);
System_InputBoxGetString(n->T("proAdhocServer Address:"), addrView_->GetText(), [this](const std::string& value, int) { System_InputBoxGetString(GetRequesterToken(), n->T("proAdhocServer Address:"), addrView_->GetText(), [this](const std::string& value, int) {
addrView_->SetText(value); addrView_->SetText(value);
}); });
return UI::EVENT_DONE; return UI::EVENT_DONE;

View File

@ -510,8 +510,8 @@ void DirButton::Draw(UIContext &dc) {
} }
} }
GameBrowser::GameBrowser(const Path &path, BrowseFlags browseFlags, bool *gridStyle, ScreenManager *screenManager, std::string lastText, std::string lastLink, UI::LayoutParams *layoutParams) GameBrowser::GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool *gridStyle, ScreenManager *screenManager, std::string lastText, std::string lastLink, UI::LayoutParams *layoutParams)
: LinearLayout(UI::ORIENT_VERTICAL, layoutParams), path_(path), gridStyle_(gridStyle), browseFlags_(browseFlags), lastText_(lastText), lastLink_(lastLink), screenManager_(screenManager) { : LinearLayout(UI::ORIENT_VERTICAL, layoutParams), path_(path), gridStyle_(gridStyle), browseFlags_(browseFlags), lastText_(lastText), lastLink_(lastLink), screenManager_(screenManager), token_(token) {
using namespace UI; using namespace UI;
path_.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); path_.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION));
path_.SetRootAlias("ms:", GetSysDirectory(DIRECTORY_MEMSTICK_ROOT).ToVisualString()); path_.SetRootAlias("ms:", GetSysDirectory(DIRECTORY_MEMSTICK_ROOT).ToVisualString());
@ -604,7 +604,7 @@ UI::EventReturn GameBrowser::LastClick(UI::EventParams &e) {
UI::EventReturn GameBrowser::BrowseClick(UI::EventParams &e) { UI::EventReturn GameBrowser::BrowseClick(UI::EventParams &e) {
auto mm = GetI18NCategory(I18NCat::MAINMENU); auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFolder(mm->T("Choose folder"), [this](const std::string &filename, int) { System_BrowseForFolder(token_, mm->T("Choose folder"), [this](const std::string &filename, int) {
this->SetPath(Path(filename)); this->SetPath(Path(filename));
}); });
return UI::EVENT_DONE; return UI::EVENT_DONE;
@ -781,7 +781,7 @@ void GameBrowser::Refresh() {
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_TV) { if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_TV) {
topBar->Add(new Choice(mm->T("Enter Path"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Add([=](UI::EventParams &) { topBar->Add(new Choice(mm->T("Enter Path"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Add([=](UI::EventParams &) {
auto mm = GetI18NCategory(I18NCat::MAINMENU); auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_InputBoxGetString(mm->T("Enter Path"), path_.GetPath().ToString(), [=](const char *responseString, int responseValue) { System_InputBoxGetString(token_, mm->T("Enter Path"), path_.GetPath().ToString(), [=](const char *responseString, int responseValue) {
this->SetPath(Path(responseString)); this->SetPath(Path(responseString));
}); });
return UI::EVENT_DONE; return UI::EVENT_DONE;
@ -1098,7 +1098,7 @@ void MainScreen::CreateViews() {
if (showRecent) { if (showRecent) {
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollRecentGames->SetTag("MainScreenRecentGames"); scrollRecentGames->SetTag("MainScreenRecentGames");
GameBrowser *tabRecentGames = new GameBrowser( GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(),
Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "", Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
scrollRecentGames->Add(tabRecentGames); scrollRecentGames->Add(tabRecentGames);
@ -1118,10 +1118,10 @@ void MainScreen::CreateViews() {
scrollHomebrew->SetTag("MainScreenHomebrew"); scrollHomebrew->SetTag("MainScreenHomebrew");
GameBrowser *tabAllGames = new GameBrowser(Path(g_Config.currentDirectory), BrowseFlags::STANDARD, &g_Config.bGridView2, screenManager(), GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD, &g_Config.bGridView2, screenManager(),
mm->T("How to get games"), "https://www.ppsspp.org/getgames", mm->T("How to get games"), "https://www.ppsspp.org/getgames",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
GameBrowser *tabHomebrew = new GameBrowser(GetSysDirectory(DIRECTORY_GAME), BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, screenManager(), GameBrowser *tabHomebrew = new GameBrowser(GetRequesterToken(), GetSysDirectory(DIRECTORY_GAME), BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, screenManager(),
mm->T("How to get homebrew & demos", "How to get homebrew && demos"), "https://www.ppsspp.org/gethomebrew", mm->T("How to get homebrew & demos", "How to get homebrew && demos"), "https://www.ppsspp.org/gethomebrew",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
@ -1151,7 +1151,7 @@ void MainScreen::CreateViews() {
Path remotePath(FormatRemoteISOUrl(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort, RemoteSubdir().c_str())); Path remotePath(FormatRemoteISOUrl(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort, RemoteSubdir().c_str()));
GameBrowser *tabRemote = new GameBrowser(remotePath, BrowseFlags::NAVIGATE, &g_Config.bGridView3, screenManager(), GameBrowser *tabRemote = new GameBrowser(GetRequesterToken(), remotePath, BrowseFlags::NAVIGATE, &g_Config.bGridView3, screenManager(),
ri->T("Remote disc streaming"), "https://www.ppsspp.org/docs/reference/disc-streaming", ri->T("Remote disc streaming"), "https://www.ppsspp.org/docs/reference/disc-streaming",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
tabRemote->SetHomePath(remotePath); tabRemote->SetHomePath(remotePath);
@ -1330,7 +1330,7 @@ bool MainScreen::key(const KeyInput &touch) {
searchKeyModifier_ = true; searchKeyModifier_ = true;
if (touch.keyCode == NKCODE_F && searchKeyModifier_ && System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { if (touch.keyCode == NKCODE_F && searchKeyModifier_ && System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) {
auto se = GetI18NCategory(I18NCat::SEARCH); auto se = GetI18NCategory(I18NCat::SEARCH);
System_InputBoxGetString(se->T("Search term"), searchFilter_, [&](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), se->T("Search term"), searchFilter_, [&](const std::string &value, int) {
searchFilter_ = StripSpaces(value); searchFilter_ = StripSpaces(value);
searchChanged_ = true; searchChanged_ = true;
}); });
@ -1399,7 +1399,7 @@ void MainScreen::update() {
UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) { UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) {
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) { if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
auto mm = GetI18NCategory(I18NCat::MAINMENU); auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFile(mm->T("Load"), BrowseFileType::BOOTABLE, [](const std::string &value, int) { System_BrowseForFile(GetRequesterToken(), mm->T("Load"), BrowseFileType::BOOTABLE, [](const std::string &value, int) {
System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, value); System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, value);
}); });
} }
@ -1609,7 +1609,7 @@ void UmdReplaceScreen::CreateViews() {
if (g_Config.iMaxRecent > 0) { if (g_Config.iMaxRecent > 0) {
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollRecentGames->SetTag("UmdReplaceRecentGames"); scrollRecentGames->SetTag("UmdReplaceRecentGames");
GameBrowser *tabRecentGames = new GameBrowser( GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(),
Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "", Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
scrollRecentGames->Add(tabRecentGames); scrollRecentGames->Add(tabRecentGames);
@ -1620,7 +1620,7 @@ void UmdReplaceScreen::CreateViews() {
ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollAllGames->SetTag("UmdReplaceAllGames"); scrollAllGames->SetTag("UmdReplaceAllGames");
GameBrowser *tabAllGames = new GameBrowser(Path(g_Config.currentDirectory), BrowseFlags::STANDARD, &g_Config.bGridView2, screenManager(), GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD, &g_Config.bGridView2, screenManager(),
mm->T("How to get games"), "https://www.ppsspp.org/getgames.html", mm->T("How to get games"), "https://www.ppsspp.org/getgames.html",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
@ -1635,7 +1635,7 @@ void UmdReplaceScreen::CreateViews() {
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) { if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
rightColumnItems->Add(new Choice(mm->T("Load", "Load...")))->OnClick.Add([&](UI::EventParams &e) { rightColumnItems->Add(new Choice(mm->T("Load", "Load...")))->OnClick.Add([&](UI::EventParams &e) {
auto mm = GetI18NCategory(I18NCat::MAINMENU); auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFile(mm->T("Load"), BrowseFileType::BOOTABLE, [&](const std::string &value, int) { System_BrowseForFile(GetRequesterToken(), mm->T("Load"), BrowseFileType::BOOTABLE, [&](const std::string &value, int) {
__UmdReplace(Path(value)); __UmdReplace(Path(value));
TriggerFinish(DR_OK); TriggerFinish(DR_OK);
}); });

View File

@ -44,7 +44,7 @@ bool LaunchFile(ScreenManager *screenManager, const Path &path);
class GameBrowser : public UI::LinearLayout { class GameBrowser : public UI::LinearLayout {
public: public:
GameBrowser(const Path &path, BrowseFlags browseFlags, bool *gridStyle, ScreenManager *screenManager, std::string lastText, std::string lastLink, UI::LayoutParams *layoutParams = nullptr); GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool *gridStyle, ScreenManager *screenManager, std::string lastText, std::string lastLink, UI::LayoutParams *layoutParams = nullptr);
UI::Event OnChoice; UI::Event OnChoice;
UI::Event OnHoldChoice; UI::Event OnHoldChoice;
@ -109,6 +109,7 @@ private:
float lastScale_ = 1.0f; float lastScale_ = 1.0f;
bool lastLayoutWasGrid_ = true; bool lastLayoutWasGrid_ = true;
ScreenManager *screenManager_; ScreenManager *screenManager_;
int token_;
}; };
class RemoteISOBrowseScreen; class RemoteISOBrowseScreen;

View File

@ -356,7 +356,7 @@ UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams &params) {
// The old way, from before scoped storage. // The old way, from before scoped storage.
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
auto sy = GetI18NCategory(I18NCat::SYSTEM); auto sy = GetI18NCategory(I18NCat::SYSTEM);
System_InputBoxGetString(sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](const std::string &value, int) { System_InputBoxGetString(GetRequesterToken(), sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](const std::string &value, int) {
auto sy = GetI18NCategory(I18NCat::SYSTEM); auto sy = GetI18NCategory(I18NCat::SYSTEM);
auto di = GetI18NCategory(I18NCat::DIALOG); auto di = GetI18NCategory(I18NCat::DIALOG);
@ -469,7 +469,7 @@ UI::EventReturn MemStickScreen::UseStorageRoot(UI::EventParams &params) {
UI::EventReturn MemStickScreen::Browse(UI::EventParams &params) { UI::EventReturn MemStickScreen::Browse(UI::EventParams &params) {
auto mm = GetI18NCategory(I18NCat::MAINMENU); auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFolder(mm->T("Choose folder"), [=](const std::string &value, int) { System_BrowseForFolder(GetRequesterToken(), mm->T("Choose folder"), [=](const std::string &value, int) {
Path pendingMemStickFolder = Path(value); Path pendingMemStickFolder = Path(value);
INFO_LOG(SYSTEM, "Got folder: '%s'", pendingMemStickFolder.c_str()); INFO_LOG(SYSTEM, "Got folder: '%s'", pendingMemStickFolder.c_str());
// Browse finished. Let's pop up the confirmation dialog. // Browse finished. Let's pop up the confirmation dialog.

View File

@ -530,7 +530,7 @@ void RemoteISOBrowseScreen::CreateViews() {
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollRecentGames->SetTag("RemoteGamesTab"); scrollRecentGames->SetTag("RemoteGamesTab");
GameBrowser *tabRemoteGames = new GameBrowser( GameBrowser *tabRemoteGames = new GameBrowser(GetRequesterToken(),
Path(url_), BrowseFlags::NAVIGATE, &g_Config.bGridView1, screenManager(), "", "", Path(url_), BrowseFlags::NAVIGATE, &g_Config.bGridView1, screenManager(), "", "",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
tabRemoteGames->SetHomePath(Path(url_)); tabRemoteGames->SetHomePath(Path(url_));
@ -601,7 +601,7 @@ void RemoteISOSettingsScreen::CreateViews() {
if (System_GetPropertyBool(SYSPROP_HAS_FOLDER_BROWSER)) { if (System_GetPropertyBool(SYSPROP_HAS_FOLDER_BROWSER)) {
static const char *shareTypes[] = { "Recent files", "Choose directory" }; static const char *shareTypes[] = { "Recent files", "Choose directory" };
remoteisoSettings->Add(new PopupMultiChoice(&g_Config.iRemoteISOShareType, ri->T("Files to share"), shareTypes, 0, ARRAY_SIZE(shareTypes), I18NCat::REMOTEISO, screenManager())); remoteisoSettings->Add(new PopupMultiChoice(&g_Config.iRemoteISOShareType, ri->T("Files to share"), shareTypes, 0, ARRAY_SIZE(shareTypes), I18NCat::REMOTEISO, screenManager()));
FolderChooserChoice *folderChooser = remoteisoSettings->Add(new FolderChooserChoice(&g_Config.sRemoteISOSharedDir, ri->T("Files to share"))); FolderChooserChoice *folderChooser = remoteisoSettings->Add(new FolderChooserChoice(GetRequesterToken(), &g_Config.sRemoteISOSharedDir, ri->T("Files to share")));
folderChooser->SetEnabledFunc([=]() { folderChooser->SetEnabledFunc([=]() {
return g_Config.iRemoteISOShareType == (int)RemoteISOShareType::LOCAL_FOLDER; return g_Config.iRemoteISOShareType == (int)RemoteISOShareType::LOCAL_FOLDER;
}); });
@ -610,7 +610,7 @@ void RemoteISOSettingsScreen::CreateViews() {
g_Config.iRemoteISOShareType = (int)RemoteISOShareType::RECENT; g_Config.iRemoteISOShareType = (int)RemoteISOShareType::RECENT;
} }
UI::Choice *remoteServer = new PopupTextInputChoice(&g_Config.sLastRemoteISOServer, ri->T("Remote Server"), "", 255, screenManager()); UI::Choice *remoteServer = new PopupTextInputChoice(GetRequesterToken(), &g_Config.sLastRemoteISOServer, ri->T("Remote Server"), "", 255, screenManager());
remoteisoSettings->Add(remoteServer); remoteisoSettings->Add(remoteServer);
remoteServer->SetEnabledPtr(&g_Config.bRemoteISOManual); remoteServer->SetEnabledPtr(&g_Config.bRemoteISOManual);
@ -619,7 +619,7 @@ void RemoteISOSettingsScreen::CreateViews() {
UI::Choice *remoteSubdir; UI::Choice *remoteSubdir;
{ {
PopupTextInputChoice *remoteSubdirInput = new PopupTextInputChoice(&g_Config.sRemoteISOSubdir, ri->T("Remote Subdirectory"), "", 255, screenManager()); PopupTextInputChoice *remoteSubdirInput = new PopupTextInputChoice(GetRequesterToken(), &g_Config.sRemoteISOSubdir, ri->T("Remote Subdirectory"), "", 255, screenManager());
remoteSubdirInput->OnChange.Handle(this, &RemoteISOSettingsScreen::OnChangeRemoteISOSubdir); remoteSubdirInput->OnChange.Handle(this, &RemoteISOSettingsScreen::OnChangeRemoteISOSubdir);
remoteSubdir = remoteSubdirInput; remoteSubdir = remoteSubdirInput;
} }

View File

@ -20,14 +20,14 @@ static inline const char *DeNull(const char *ptr) {
// Compound view, creating a FileChooserChoice inside. // Compound view, creating a FileChooserChoice inside.
class AudioFileChooser : public UI::LinearLayout { class AudioFileChooser : public UI::LinearLayout {
public: public:
AudioFileChooser(std::string *value, const std::string &title, UI::UISound sound, UI::LayoutParams *layoutParams = nullptr); AudioFileChooser(RequesterToken token, std::string *value, const std::string &title, UI::UISound sound, UI::LayoutParams *layoutParams = nullptr);
UI::UISound sound_; UI::UISound sound_;
}; };
static constexpr UI::Size ITEM_HEIGHT = 64.f; static constexpr UI::Size ITEM_HEIGHT = 64.f;
AudioFileChooser::AudioFileChooser(std::string *value, const std::string &title, UI::UISound sound, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams), sound_(sound) { AudioFileChooser::AudioFileChooser(RequesterToken token, std::string *value, const std::string &title, UI::UISound sound, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams), sound_(sound) {
using namespace UI; using namespace UI;
SetSpacing(2.0f); SetSpacing(2.0f);
if (!layoutParams) { if (!layoutParams) {
@ -38,7 +38,7 @@ AudioFileChooser::AudioFileChooser(std::string *value, const std::string &title,
g_BackgroundAudio.SFX().Play(sound_, 0.6f); g_BackgroundAudio.SFX().Play(sound_, 0.6f);
return UI::EVENT_DONE; return UI::EVENT_DONE;
}); });
Add(new FileChooserChoice(value, title, BrowseFileType::SOUND_EFFECT, new LinearLayoutParams(1.0f)))->OnChange.Add([=](UI::EventParams &e) { Add(new FileChooserChoice(token, value, title, BrowseFileType::SOUND_EFFECT, new LinearLayoutParams(1.0f)))->OnChange.Add([=](UI::EventParams &e) {
std::string path = e.s; std::string path = e.s;
Sample *sample = Sample::Load(path); Sample *sample = Sample::Load(path);
if (sample) { if (sample) {
@ -299,7 +299,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
}); });
} else if (System_GetPropertyBool(SYSPROP_HAS_LOGIN_DIALOG)) { } else if (System_GetPropertyBool(SYSPROP_HAS_LOGIN_DIALOG)) {
viewGroup->Add(new Choice(di->T("Log in")))->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn { viewGroup->Add(new Choice(di->T("Log in")))->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn {
System_AskUsernamePassword(StringFromFormat("RetroAchievements: %s", di->T("Log in")), [](const std::string &value, int) { System_AskUsernamePassword(GetRequesterToken(), StringFromFormat("RetroAchievements: %s", di->T("Log in")), [](const std::string &value, int) {
std::vector<std::string> parts; std::vector<std::string> parts;
SplitString(value, '\n', parts); SplitString(value, '\n', parts);
if (parts.size() == 2 && !parts[0].empty() && !parts[1].empty()) { if (parts.size() == 2 && !parts[0].empty() && !parts[1].empty()) {
@ -310,8 +310,8 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
}); });
} else { } else {
// Hack up a temporary quick login-form-ish-thing // Hack up a temporary quick login-form-ish-thing
viewGroup->Add(new PopupTextInputChoice(&username_, di->T("Username"), "", 128, screenManager())); viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &username_, di->T("Username"), "", 128, screenManager()));
viewGroup->Add(new PopupTextInputChoice(&password_, di->T("Password"), "", 128, screenManager()))->SetPasswordDisplay(); viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &password_, di->T("Password"), "", 128, screenManager()))->SetPasswordDisplay();
Choice *loginButton = viewGroup->Add(new Choice(di->T("Log in"))); Choice *loginButton = viewGroup->Add(new Choice(di->T("Log in")));
loginButton->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn { loginButton->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn {
if (!username_.empty() && !password_.empty()) { if (!username_.empty() && !password_.empty()) {
@ -357,8 +357,8 @@ void RetroAchievementsSettingsScreen::CreateCustomizeTab(UI::ViewGroup *viewGrou
using namespace UI; using namespace UI;
viewGroup->Add(new ItemHeader(ac->T("Sound Effects"))); viewGroup->Add(new ItemHeader(ac->T("Sound Effects")));
viewGroup->Add(new AudioFileChooser(&g_Config.sAchievementsUnlockAudioFile, ac->T("Achievement unlocked"), UISound::ACHIEVEMENT_UNLOCKED)); viewGroup->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsUnlockAudioFile, ac->T("Achievement unlocked"), UISound::ACHIEVEMENT_UNLOCKED));
viewGroup->Add(new AudioFileChooser(&g_Config.sAchievementsLeaderboardSubmitAudioFile, ac->T("Leaderboard score submission"), UISound::LEADERBOARD_SUBMITTED)); viewGroup->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsLeaderboardSubmitAudioFile, ac->T("Leaderboard score submission"), UISound::LEADERBOARD_SUBMITTED));
static const char *positions[] = { "None", "Bottom Left", "Bottom Center", "Bottom Right", "Top Left", "Top Center", "Top Right", "Center Left", "Center Right" }; static const char *positions[] = { "None", "Bottom Left", "Bottom Center", "Bottom Right", "Top Left", "Top Center", "Top Right", "Center Left", "Center Right" };

View File

@ -674,7 +674,7 @@ UI::EventReturn SavedataScreen::OnSortClick(UI::EventParams &e) {
UI::EventReturn SavedataScreen::OnSearch(UI::EventParams &e) { UI::EventReturn SavedataScreen::OnSearch(UI::EventParams &e) {
if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) {
auto di = GetI18NCategory(I18NCat::DIALOG); auto di = GetI18NCategory(I18NCat::DIALOG);
System_InputBoxGetString(di->T("Filter"), searchFilter_, [](const std::string &value, int ivalue) { System_InputBoxGetString(GetRequesterToken(), di->T("Filter"), searchFilter_, [](const std::string &value, int ivalue) {
System_PostUIMessage(UIMessage::SAVEDATA_SEARCH, value); System_PostUIMessage(UIMessage::SAVEDATA_SEARCH, value);
}); });
} }

View File

@ -84,7 +84,7 @@ void TabbedUIDialogScreenWithGameBackground::CreateViews() {
LinearLayout *searchSettings = AddTab("GameSettingsSearch", ms->T("Search"), true); LinearLayout *searchSettings = AddTab("GameSettingsSearch", ms->T("Search"), true);
searchSettings->Add(new ItemHeader(se->T("Find settings"))); searchSettings->Add(new ItemHeader(se->T("Find settings")));
searchSettings->Add(new PopupTextInputChoice(&searchFilter_, se->T("Filter"), "", 64, screenManager()))->OnChange.Add([=](UI::EventParams &e) { searchSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &searchFilter_, se->T("Filter"), "", 64, screenManager()))->OnChange.Add([=](UI::EventParams &e) {
System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, StripSpaces(searchFilter_)); System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, StripSpaces(searchFilter_));
return UI::EVENT_DONE; return UI::EVENT_DONE;
}); });

View File

@ -321,7 +321,7 @@ namespace MainWindow {
void BrowseAndBootDone(std::string filename); void BrowseAndBootDone(std::string filename);
void BrowseAndBoot(std::string defaultPath, bool browseDirectory) { void BrowseAndBoot(RequesterToken token, std::string defaultPath, bool browseDirectory) {
browsePauseAfter = false; browsePauseAfter = false;
if (GetUIState() == UISTATE_INGAME) { if (GetUIState() == UISTATE_INGAME) {
browsePauseAfter = Core_IsStepping(); browsePauseAfter = Core_IsStepping();
@ -333,11 +333,11 @@ namespace MainWindow {
W32Util::MakeTopMost(GetHWND(), false); W32Util::MakeTopMost(GetHWND(), false);
if (browseDirectory) { if (browseDirectory) {
System_BrowseForFolder(mm->T("Load"), [](const std::string &value, int) { System_BrowseForFolder(token, mm->T("Load"), [](const std::string &value, int) {
BrowseAndBootDone(value); BrowseAndBootDone(value);
}); });
} else { } else {
System_BrowseForFile(mm->T("Load"), BrowseFileType::BOOTABLE, [](const std::string &value, int) { System_BrowseForFile(token, mm->T("Load"), BrowseFileType::BOOTABLE, [](const std::string &value, int) {
BrowseAndBootDone(value); BrowseAndBootDone(value);
}); });
} }
@ -352,9 +352,9 @@ namespace MainWindow {
W32Util::MakeTopMost(GetHWND(), g_Config.bTopMost); W32Util::MakeTopMost(GetHWND(), g_Config.bTopMost);
} }
static void UmdSwitchAction() { static void UmdSwitchAction(RequesterToken token) {
auto mm = GetI18NCategory(I18NCat::MAINMENU); auto mm = GetI18NCategory(I18NCat::MAINMENU);
System_BrowseForFile(mm->T("Switch UMD"), BrowseFileType::BOOTABLE, [](const std::string &value, int) { System_BrowseForFile(token, mm->T("Switch UMD"), BrowseFileType::BOOTABLE, [](const std::string &value, int) {
__UmdReplace(Path(value)); __UmdReplace(Path(value));
}); });
} }
@ -441,15 +441,15 @@ namespace MainWindow {
// Parse the menu selections: // Parse the menu selections:
switch (wmId) { switch (wmId) {
case ID_FILE_LOAD: case ID_FILE_LOAD:
BrowseAndBoot("", false); BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", false);
break; break;
case ID_FILE_LOAD_DIR: case ID_FILE_LOAD_DIR:
BrowseAndBoot("", true); BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", true);
break; break;
case ID_FILE_LOAD_MEMSTICK: case ID_FILE_LOAD_MEMSTICK:
BrowseAndBoot(GetSysDirectory(DIRECTORY_GAME).ToString()); BrowseAndBoot(NON_EPHEMERAL_TOKEN, GetSysDirectory(DIRECTORY_GAME).ToString());
break; break;
case ID_FILE_OPEN_NEW_INSTANCE: case ID_FILE_OPEN_NEW_INSTANCE:
@ -500,7 +500,7 @@ namespace MainWindow {
break; break;
case ID_EMULATION_SWITCH_UMD: case ID_EMULATION_SWITCH_UMD:
UmdSwitchAction(); UmdSwitchAction(NON_EPHEMERAL_TOKEN);
break; break;
case ID_EMULATION_ROTATION_H: g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL; break; case ID_EMULATION_ROTATION_H: g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL; break;

View File

@ -2,12 +2,14 @@
#include "Common/CommonWindows.h" #include "Common/CommonWindows.h"
#include <Windowsx.h> #include <Windowsx.h>
#include "Common/System/Request.h"
#include "Core/System.h" #include "Core/System.h"
namespace MainWindow { namespace MainWindow {
void MainWindowMenu_Process(HWND hWnd, WPARAM wParam); void MainWindowMenu_Process(HWND hWnd, WPARAM wParam);
void TranslateMenus(HWND hWnd, HMENU menu); void TranslateMenus(HWND hWnd, HMENU menu);
void BrowseAndBoot(std::string defaultPath, bool browseDirectory = false); void BrowseAndBoot(RequesterToken token, std::string defaultPath, bool browseDirectory = false);
void setTexScalingMultiplier(int level); void setTexScalingMultiplier(int level);
void SetIngameMenuItemStates(HMENU menu, const GlobalUIState state); void SetIngameMenuItemStates(HMENU menu, const GlobalUIState state);
} }

View File

@ -135,7 +135,6 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
return false; 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) {} void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; } void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; }

View File

@ -1750,7 +1750,6 @@ std::vector<std::string> System_GetCameraDeviceList() { return std::vector<std::
bool System_AudioRecordingIsAvailable() { return false; } bool System_AudioRecordingIsAvailable() { return false; }
bool System_AudioRecordingState() { return false; } bool System_AudioRecordingState() { return false; }
void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function<void(bool, const std::string &)> cb) { cb(false, ""); }
#endif #endif
// TODO: To avoid having to define these here, these should probably be turned into system "requests". // TODO: To avoid having to define these here, these should probably be turned into system "requests".