Merge pull request #18723 from hrydgard/requester-tokens

Fix a particular type of race condition in file dialog requests
This commit is contained in:
Henrik Rydgård 2024-01-18 14:53:39 +01:00 committed by GitHub
commit 7918e49a24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
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_++;
// NOTE: We need to register immediately, in order to support synchronous implementations.
if (callback || failedCallback) {
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);
@ -52,6 +60,16 @@ bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback c
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) {
std::lock_guard<std::mutex> guard(callbackMutex_);
auto iter = callbackMap_.find(requestId);
@ -82,7 +100,7 @@ void RequestManager::PostSystemFailure(int requestId) {
std::lock_guard<std::mutex> responseGuard(responseMutex_);
PendingFailure response;
response.callback = iter->second.failedCallback;
response.failedCallback = iter->second.failedCallback;
pendingFailures_.push_back(response);
callbackMap_.erase(iter);
}
@ -96,8 +114,8 @@ void RequestManager::ProcessRequests() {
}
pendingSuccesses_.clear();
for (auto &iter : pendingFailures_) {
if (iter.callback) {
iter.callback();
if (iter.failedCallback) {
iter.failedCallback();
}
}
pendingFailures_.clear();
@ -113,9 +131,9 @@ void RequestManager::Clear() {
}
void System_CreateGameShortcut(const Path &path, const std::string &title) {
g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, nullptr, nullptr, path.ToString(), title, 0);
g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, NO_REQUESTER_TOKEN, nullptr, nullptr, path.ToString(), title, 0);
}
void System_ShowFileInFolder(const Path &path) {
g_requestManager.MakeSystemRequest(SystemRequestType::SHOW_FILE_IN_FOLDER, nullptr, nullptr, path.ToString(), "", 0);
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()> 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,
// and then somehow pass a response back to the main thread (especially Android...)
// This acts as bridge and buffer.
@ -23,7 +27,7 @@ public:
// 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,
// 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.
void PostSystemSuccess(int requestId, const char *responseString, int responseValue = 0);
@ -33,19 +37,21 @@ public:
// This will call the callback of any finished requests.
void ProcessRequests();
RequesterToken GenerateRequesterToken() {
int token = tokenGen_++;
return token;
}
void ForgetRequestsWithToken(RequesterToken token);
// Unclear if we need this...
void Clear();
private:
struct PendingRequest {
SystemRequestType type;
RequestCallback callback;
RequestFailedCallback failedCallback;
};
struct CallbackPair {
RequestCallback callback;
RequestFailedCallback failedCallback;
RequesterToken token;
};
std::map<int, CallbackPair> callbackMap_;
@ -58,7 +64,7 @@ private:
};
struct PendingFailure {
RequestFailedCallback callback;
RequestFailedCallback failedCallback;
};
// Let's start at 10 to get a recognizably valid ID in logs.
@ -66,6 +72,8 @@ private:
std::vector<PendingSuccess> pendingSuccesses_;
std::vector<PendingFailure> pendingFailures_;
std::mutex responseMutex_;
RequesterToken tokenGen_ = 20000;
};
const char *RequestTypeAsString(SystemRequestType type);
@ -75,14 +83,14 @@ extern RequestManager g_requestManager;
// Wrappers for easy requests.
// NOTE: Semantics have changed - this no longer calls the callback on cancellation, instead you
// can specify a different callback for that.
inline void System_InputBoxGetString(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);
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, token, callback, failedCallback, title, defaultValue, 0);
}
// This one will pop up a special image browser if available. You can also pick
// images with the file browser below.
inline void System_BrowseForImage(const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_IMAGE, callback, failedCallback, title, "", 0);
inline void System_BrowseForImage(RequesterToken token, const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_IMAGE, token, callback, failedCallback, title, "", 0);
}
enum class BrowseFileType {
@ -95,78 +103,78 @@ enum class BrowseFileType {
ANY,
};
inline void System_BrowseForFile(const std::string &title, BrowseFileType type, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FILE, callback, failedCallback, title, "", (int)type);
inline void System_BrowseForFile(RequesterToken token, const std::string &title, BrowseFileType type, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
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) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FOLDER, callback, failedCallback, title, "", 0);
inline void System_BrowseForFolder(RequesterToken token, const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FOLDER, token, callback, failedCallback, title, "", 0);
}
// The returned string is username + '\n' + password.
inline void System_AskUsernamePassword(const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::ASK_USERNAME_PASSWORD, callback, failedCallback, title, "", 0);
inline void System_AskUsernamePassword(RequesterToken token, const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::ASK_USERNAME_PASSWORD, token, callback, failedCallback, title, "", 0);
}
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() {
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) {
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() {
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.
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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

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)
: AbstractChoiceWithValueDisplay(title, layoutParams), screenManager_(screenManager), value_(value), placeHolder_(placeholder), maxLen_(maxLen) {
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), token_(token) {
OnClick.Handle(this, &PopupTextInputChoice::HandleClick);
}
@ -510,7 +510,7 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) {
// Choose method depending on platform capabilities.
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);
EventParams params{};
OnChange.Trigger(params);
@ -668,10 +668,10 @@ std::string ChoiceWithValueDisplay::ValueText() const {
return valueText.str();
}
FileChooserChoice::FileChooserChoice(std::string *value, const std::string &text, BrowseFileType fileType, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), fileType_(fileType) {
FileChooserChoice::FileChooserChoice(RequesterToken token, std::string *value, const std::string &text, BrowseFileType fileType, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), fileType_(fileType), token_(token) {
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) {
*value = returnValue;
UI::EventParams e{};
@ -692,10 +692,10 @@ std::string FileChooserChoice::ValueText() const {
return path.GetFilename();
}
FolderChooserChoice::FolderChooserChoice(std::string *value, const std::string &text, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value) {
FolderChooserChoice::FolderChooserChoice(RequesterToken token, std::string *value, const std::string &text, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), token_(token) {
OnClick.Add([=](UI::EventParams &) {
System_BrowseForFolder(text_, [=](const std::string &returnValue, int) {
System_BrowseForFolder(token_, text_, [=](const std::string &returnValue, int) {
if (*value_ != returnValue) {
*value = returnValue;
UI::EventParams e{};

View File

@ -360,7 +360,7 @@ private:
// NOTE: This one will defer to a system-native dialog if possible.
class PopupTextInputChoice : public AbstractChoiceWithValueDisplay {
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;
@ -370,6 +370,7 @@ protected:
private:
EventReturn HandleClick(EventParams &e);
EventReturn HandleChange(EventParams &e);
RequesterToken token_;
ScreenManager *screenManager_;
std::string *value_;
std::string placeHolder_;
@ -405,7 +406,7 @@ enum class FileChooserFileType {
class FileChooserChoice : public AbstractChoiceWithValueDisplay {
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;
Event OnChange;
@ -413,11 +414,12 @@ public:
private:
std::string *value_;
BrowseFileType fileType_;
RequesterToken token_;
};
class FolderChooserChoice : public AbstractChoiceWithValueDisplay {
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;
Event OnChange;
@ -425,7 +427,7 @@ public:
private:
std::string *value_;
BrowseFileType fileType_;
RequesterToken token_;
};
} // namespace UI

View File

@ -1,4 +1,5 @@
#include "Common/System/Display.h"
#include "Common/System/Request.h"
#include "Common/Input/InputState.h"
#include "Common/UI/Root.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);
}
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() {
shutdown();
}

View File

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

View File

@ -897,7 +897,7 @@ 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),
System_InputBoxGetString(NON_EPHEMERAL_TOKEN, ::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText),
[&](const std::string &value, int) {
// Success callback
std::lock_guard<std::mutex> guard(nativeMutex_);

View File

@ -97,7 +97,7 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) {
sendChat(chat);
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
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);
});
#endif
@ -180,7 +180,7 @@ void ChatMenu::Update() {
// Could remove the fullscreen check here, it works now.
auto n = GetI18NCategory(I18NCat::NETWORKING);
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);
});
promptInput_ = false;

View File

@ -5,7 +5,8 @@
class ChatMenu : public UI::AnchorLayout {
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);
}
void Update() override;
@ -41,4 +42,5 @@ private:
int chatChangeID_ = 0;
bool toBottom_ = true;
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) {
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);
INFO_LOG(SYSTEM, "Attempting to load cheats from: '%s'", path.ToVisualString().c_str());
if (ImportCheats(path)) {

View File

@ -212,7 +212,7 @@ UI::EventReturn DriverManagerScreen::OnCustomDriverUninstall(UI::EventParams &e)
UI::EventReturn DriverManagerScreen::OnCustomDriverInstall(UI::EventParams &e) {
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()) {
return;
}

View File

@ -1039,7 +1039,7 @@ void EmuScreen::CreateViews() {
root_->Add(btn)->OnClick.Handle(this, &EmuScreen::OnChat);
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);
} else {
chatButton_ = nullptr;

View File

@ -805,12 +805,12 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
// Compound view just like the audio file choosers
class MacAddressChooser : public UI::LinearLayout {
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;
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;
SetSpacing(5.0f);
if (!layoutParams) {
@ -820,7 +820,7 @@ MacAddressChooser::MacAddressChooser(Path gamePath_, std::string *value, const s
auto n = GetI18NCategory(I18NCat::NETWORKING);
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.
if (g_Config.sMACAddress.size() != 17) {
// 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 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" };
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++) {
@ -897,11 +897,11 @@ void GameSettingsScreen::CreateNetworkingSettings(UI::ViewGroup *networkingSetti
#endif
#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 *qc2 = networkingSettings->Add(new PopupTextInputChoice(&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 *qc4 = networkingSettings->Add(new PopupTextInputChoice(&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 *qc1 = networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sQuickChat0, n->T("Quick Chat 1"), "", 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(GetRequesterToken(), &g_Config.sQuickChat2, n->T("Quick Chat 3"), "", 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(GetRequesterToken(), &g_Config.sQuickChat4, n->T("Quick Chat 5"), "", 32, screenManager()));
#elif defined(USING_QT_UI)
Choice *qc1 = networkingSettings->Add(new Choice(n->T("Quick Chat 1")));
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()));
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 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")));
#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) {
#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));
});
#else
@ -1374,7 +1374,7 @@ UI::EventReturn GameSettingsScreen::OnChangeBackground(UI::EventParams &e) {
RecreateViews();
} else {
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()) {
Path dest = GetSysDirectory(DIRECTORY_SYSTEM) / (endsWithNoCase(value, ".jpg") ? "background.jpg" : "background.png");
File::Copy(Path(value), dest);
@ -1565,7 +1565,7 @@ 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) || PPSSPP_PLATFORM(SWITCH)
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;
});
#endif
@ -1575,7 +1575,7 @@ 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) || PPSSPP_PLATFORM(SWITCH)
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;
});
#endif
@ -1585,7 +1585,7 @@ 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) || PPSSPP_PLATFORM(SWITCH)
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;
});
#endif
@ -1595,7 +1595,7 @@ 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) || PPSSPP_PLATFORM(SWITCH)
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;
});
#endif
@ -1605,7 +1605,7 @@ 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) || PPSSPP_PLATFORM(SWITCH)
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;
});
#endif
@ -1615,7 +1615,7 @@ 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) || PPSSPP_PLATFORM(SWITCH)
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);
});
#endif
@ -2077,7 +2077,7 @@ UI::EventReturn HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) {
UI::EventReturn HostnameSelectScreen::OnEditClick(UI::EventParams& e) {
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);
});
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)
: LinearLayout(UI::ORIENT_VERTICAL, layoutParams), path_(path), gridStyle_(gridStyle), browseFlags_(browseFlags), lastText_(lastText), lastLink_(lastLink), screenManager_(screenManager) {
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), token_(token) {
using namespace UI;
path_.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION));
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) {
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));
});
return UI::EVENT_DONE;
@ -781,7 +781,7 @@ void GameBrowser::Refresh() {
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 &) {
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));
});
return UI::EVENT_DONE;
@ -1098,7 +1098,7 @@ void MainScreen::CreateViews() {
if (showRecent) {
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollRecentGames->SetTag("MainScreenRecentGames");
GameBrowser *tabRecentGames = new GameBrowser(
GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(),
Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
scrollRecentGames->Add(tabRecentGames);
@ -1118,10 +1118,10 @@ void MainScreen::CreateViews() {
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",
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",
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()));
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",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
tabRemote->SetHomePath(remotePath);
@ -1330,7 +1330,7 @@ bool MainScreen::key(const KeyInput &touch) {
searchKeyModifier_ = true;
if (touch.keyCode == NKCODE_F && searchKeyModifier_ && System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) {
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);
searchChanged_ = true;
});
@ -1399,7 +1399,7 @@ void MainScreen::update() {
UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) {
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
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);
});
}
@ -1609,7 +1609,7 @@ void UmdReplaceScreen::CreateViews() {
if (g_Config.iMaxRecent > 0) {
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
scrollRecentGames->SetTag("UmdReplaceRecentGames");
GameBrowser *tabRecentGames = new GameBrowser(
GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(),
Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
scrollRecentGames->Add(tabRecentGames);
@ -1620,7 +1620,7 @@ void UmdReplaceScreen::CreateViews() {
ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
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",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
@ -1635,7 +1635,7 @@ void UmdReplaceScreen::CreateViews() {
if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) {
rightColumnItems->Add(new Choice(mm->T("Load", "Load...")))->OnClick.Add([&](UI::EventParams &e) {
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));
TriggerFinish(DR_OK);
});

View File

@ -44,7 +44,7 @@ bool LaunchFile(ScreenManager *screenManager, const Path &path);
class GameBrowser : public UI::LinearLayout {
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 OnHoldChoice;
@ -109,6 +109,7 @@ private:
float lastScale_ = 1.0f;
bool lastLayoutWasGrid_ = true;
ScreenManager *screenManager_;
int token_;
};
class RemoteISOBrowseScreen;

View File

@ -356,7 +356,7 @@ UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams &params) {
// The old way, from before scoped storage.
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
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 di = GetI18NCategory(I18NCat::DIALOG);
@ -469,7 +469,7 @@ UI::EventReturn MemStickScreen::UseStorageRoot(UI::EventParams &params) {
UI::EventReturn MemStickScreen::Browse(UI::EventParams &params) {
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);
INFO_LOG(SYSTEM, "Got folder: '%s'", pendingMemStickFolder.c_str());
// 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));
scrollRecentGames->SetTag("RemoteGamesTab");
GameBrowser *tabRemoteGames = new GameBrowser(
GameBrowser *tabRemoteGames = new GameBrowser(GetRequesterToken(),
Path(url_), BrowseFlags::NAVIGATE, &g_Config.bGridView1, screenManager(), "", "",
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
tabRemoteGames->SetHomePath(Path(url_));
@ -601,7 +601,7 @@ void RemoteISOSettingsScreen::CreateViews() {
if (System_GetPropertyBool(SYSPROP_HAS_FOLDER_BROWSER)) {
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()));
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([=]() {
return g_Config.iRemoteISOShareType == (int)RemoteISOShareType::LOCAL_FOLDER;
});
@ -610,7 +610,7 @@ void RemoteISOSettingsScreen::CreateViews() {
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);
remoteServer->SetEnabledPtr(&g_Config.bRemoteISOManual);
@ -619,7 +619,7 @@ void RemoteISOSettingsScreen::CreateViews() {
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);
remoteSubdir = remoteSubdirInput;
}

View File

@ -20,14 +20,14 @@ static inline const char *DeNull(const char *ptr) {
// Compound view, creating a FileChooserChoice inside.
class AudioFileChooser : public UI::LinearLayout {
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_;
};
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;
SetSpacing(2.0f);
if (!layoutParams) {
@ -38,7 +38,7 @@ AudioFileChooser::AudioFileChooser(std::string *value, const std::string &title,
g_BackgroundAudio.SFX().Play(sound_, 0.6f);
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;
Sample *sample = Sample::Load(path);
if (sample) {
@ -299,7 +299,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
});
} else if (System_GetPropertyBool(SYSPROP_HAS_LOGIN_DIALOG)) {
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;
SplitString(value, '\n', parts);
if (parts.size() == 2 && !parts[0].empty() && !parts[1].empty()) {
@ -310,8 +310,8 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
});
} else {
// Hack up a temporary quick login-form-ish-thing
viewGroup->Add(new PopupTextInputChoice(&username_, di->T("Username"), "", 128, screenManager()));
viewGroup->Add(new PopupTextInputChoice(&password_, di->T("Password"), "", 128, screenManager()))->SetPasswordDisplay();
viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &username_, di->T("Username"), "", 128, screenManager()));
viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &password_, di->T("Password"), "", 128, screenManager()))->SetPasswordDisplay();
Choice *loginButton = viewGroup->Add(new Choice(di->T("Log in")));
loginButton->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn {
if (!username_.empty() && !password_.empty()) {
@ -357,8 +357,8 @@ void RetroAchievementsSettingsScreen::CreateCustomizeTab(UI::ViewGroup *viewGrou
using namespace UI;
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(&g_Config.sAchievementsLeaderboardSubmitAudioFile, ac->T("Leaderboard score submission"), UISound::LEADERBOARD_SUBMITTED));
viewGroup->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsUnlockAudioFile, ac->T("Achievement unlocked"), UISound::ACHIEVEMENT_UNLOCKED));
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" };

View File

@ -674,7 +674,7 @@ UI::EventReturn SavedataScreen::OnSortClick(UI::EventParams &e) {
UI::EventReturn SavedataScreen::OnSearch(UI::EventParams &e) {
if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_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);
});
}

View File

@ -84,7 +84,7 @@ void TabbedUIDialogScreenWithGameBackground::CreateViews() {
LinearLayout *searchSettings = AddTab("GameSettingsSearch", ms->T("Search"), true);
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_));
return UI::EVENT_DONE;
});

View File

@ -321,7 +321,7 @@ namespace MainWindow {
void BrowseAndBootDone(std::string filename);
void BrowseAndBoot(std::string defaultPath, bool browseDirectory) {
void BrowseAndBoot(RequesterToken token, std::string defaultPath, bool browseDirectory) {
browsePauseAfter = false;
if (GetUIState() == UISTATE_INGAME) {
browsePauseAfter = Core_IsStepping();
@ -333,11 +333,11 @@ namespace MainWindow {
W32Util::MakeTopMost(GetHWND(), false);
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);
});
} 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);
});
}
@ -352,9 +352,9 @@ namespace MainWindow {
W32Util::MakeTopMost(GetHWND(), g_Config.bTopMost);
}
static void UmdSwitchAction() {
static void UmdSwitchAction(RequesterToken token) {
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));
});
}
@ -441,15 +441,15 @@ namespace MainWindow {
// Parse the menu selections:
switch (wmId) {
case ID_FILE_LOAD:
BrowseAndBoot("", false);
BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", false);
break;
case ID_FILE_LOAD_DIR:
BrowseAndBoot("", true);
BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", true);
break;
case ID_FILE_LOAD_MEMSTICK:
BrowseAndBoot(GetSysDirectory(DIRECTORY_GAME).ToString());
BrowseAndBoot(NON_EPHEMERAL_TOKEN, GetSysDirectory(DIRECTORY_GAME).ToString());
break;
case ID_FILE_OPEN_NEW_INSTANCE:
@ -500,7 +500,7 @@ namespace MainWindow {
break;
case ID_EMULATION_SWITCH_UMD:
UmdSwitchAction();
UmdSwitchAction(NON_EPHEMERAL_TOKEN);
break;
case ID_EMULATION_ROTATION_H: g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL; break;

View File

@ -2,12 +2,14 @@
#include "Common/CommonWindows.h"
#include <Windowsx.h>
#include "Common/System/Request.h"
#include "Core/System.h"
namespace MainWindow {
void MainWindowMenu_Process(HWND hWnd, WPARAM wParam);
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 SetIngameMenuItemStates(HMENU menu, const GlobalUIState state);
}

View File

@ -135,7 +135,6 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
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; }
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_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
// TODO: To avoid having to define these here, these should probably be turned into system "requests".