2023-06-20 13:23:45 +00:00
|
|
|
#include <cstring>
|
|
|
|
|
2023-03-22 11:26:14 +00:00
|
|
|
#include "Common/System/Request.h"
|
2023-03-22 10:34:48 +00:00
|
|
|
#include "Common/System/System.h"
|
|
|
|
#include "Common/Log.h"
|
2023-03-24 19:05:48 +00:00
|
|
|
#include "Common/File/Path.h"
|
2023-06-20 12:40:46 +00:00
|
|
|
#include "Common/TimeUtil.h"
|
2023-03-22 10:34:48 +00:00
|
|
|
|
2023-03-22 11:26:14 +00:00
|
|
|
RequestManager g_requestManager;
|
2023-06-20 12:40:46 +00:00
|
|
|
OnScreenDisplay g_OSD;
|
|
|
|
|
|
|
|
void OnScreenDisplay::Update() {
|
|
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
|
|
|
|
|
|
double now = time_now_d();
|
2023-06-20 13:07:01 +00:00
|
|
|
for (auto iter = entries_.begin(); iter != entries_.end(); ) {
|
2023-06-20 12:40:46 +00:00
|
|
|
if (now >= iter->endTime) {
|
2023-06-20 13:07:01 +00:00
|
|
|
iter = entries_.erase(iter);
|
2023-06-20 12:40:46 +00:00
|
|
|
} else {
|
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-20 13:07:01 +00:00
|
|
|
std::vector<OnScreenDisplay::Entry> OnScreenDisplay::Entries() {
|
2023-06-20 12:40:46 +00:00
|
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
2023-06-20 13:07:01 +00:00
|
|
|
return entries_; // makes a copy.
|
2023-06-20 12:40:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OnScreenDisplay::Show(OSDType type, const std::string &text, float duration_s, const char *id) {
|
|
|
|
// Automatic duration based on type.
|
|
|
|
if (duration_s <= 0.0f) {
|
|
|
|
switch (type) {
|
|
|
|
case OSDType::MESSAGE_ERROR:
|
|
|
|
case OSDType::MESSAGE_WARNING:
|
|
|
|
duration_s = 3.0f;
|
|
|
|
break;
|
|
|
|
case OSDType::MESSAGE_FILE_LINK:
|
|
|
|
duration_s = 5.0f;
|
|
|
|
break;
|
|
|
|
case OSDType::MESSAGE_SUCCESS:
|
|
|
|
duration_s = 2.0f;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
duration_s = 1.5f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double now = time_now_d();
|
|
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
|
|
if (id) {
|
2023-06-20 13:07:01 +00:00
|
|
|
for (auto iter = entries_.begin(); iter != entries_.end(); ++iter) {
|
2023-06-20 12:40:46 +00:00
|
|
|
if (iter->id && !strcmp(iter->id, id)) {
|
2023-06-20 13:07:01 +00:00
|
|
|
Entry msg = *iter;
|
2023-06-20 12:40:46 +00:00
|
|
|
msg.endTime = now + duration_s;
|
|
|
|
msg.text = text;
|
2023-06-20 13:07:01 +00:00
|
|
|
entries_.erase(iter);
|
|
|
|
entries_.insert(entries_.begin(), msg);
|
2023-06-20 12:40:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-20 13:07:01 +00:00
|
|
|
Entry msg;
|
2023-06-20 12:40:46 +00:00
|
|
|
msg.text = text;
|
|
|
|
msg.endTime = now + duration_s;
|
|
|
|
msg.id = id;
|
2023-06-20 13:07:01 +00:00
|
|
|
entries_.insert(entries_.begin(), msg);
|
2023-06-20 12:40:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float duration_s) {
|
|
|
|
// TODO: translate "on" and "off"? Or just get rid of this whole thing?
|
|
|
|
Show(OSDType::MESSAGE_INFO, message + ": " + (on ? "on" : "off"), duration_s);
|
|
|
|
}
|
|
|
|
|
2023-03-22 10:34:48 +00:00
|
|
|
const char *RequestTypeAsString(SystemRequestType type) {
|
|
|
|
switch (type) {
|
|
|
|
case SystemRequestType::INPUT_TEXT_MODAL: return "INPUT_TEXT_MODAL";
|
2023-03-22 13:14:15 +00:00
|
|
|
case SystemRequestType::BROWSE_FOR_IMAGE: return "BROWSE_FOR_IMAGE";
|
2023-03-22 15:09:33 +00:00
|
|
|
case SystemRequestType::BROWSE_FOR_FILE: return "BROWSE_FOR_FILE";
|
|
|
|
case SystemRequestType::BROWSE_FOR_FOLDER: return "BROWSE_FOR_FOLDER";
|
2023-03-22 10:34:48 +00:00
|
|
|
default: return "N/A";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-25 17:48:50 +00:00
|
|
|
bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, RequestFailedCallback failedCallback, const std::string ¶m1, const std::string ¶m2, int param3) {
|
2023-03-22 10:34:48 +00:00
|
|
|
int requestId = idCounter_++;
|
2023-03-22 16:39:45 +00:00
|
|
|
|
|
|
|
// NOTE: We need to register immediately, in order to support synchronous implementations.
|
2023-03-25 23:26:10 +00:00
|
|
|
if (callback || failedCallback) {
|
2023-03-22 16:39:45 +00:00
|
|
|
std::lock_guard<std::mutex> guard(callbackMutex_);
|
2023-03-25 17:48:50 +00:00
|
|
|
callbackMap_[requestId] = { callback, failedCallback };
|
2023-03-22 16:39:45 +00:00
|
|
|
}
|
|
|
|
|
2023-03-25 23:27:22 +00:00
|
|
|
DEBUG_LOG(SYSTEM, "Making system request %s: id %d", RequestTypeAsString(type), requestId);
|
2023-03-22 14:21:03 +00:00
|
|
|
if (!System_MakeRequest(type, requestId, param1, param2, param3)) {
|
2023-03-25 23:26:10 +00:00
|
|
|
if (callback || failedCallback) {
|
2023-03-22 16:39:45 +00:00
|
|
|
std::lock_guard<std::mutex> guard(callbackMutex_);
|
|
|
|
callbackMap_.erase(requestId);
|
|
|
|
}
|
2023-03-22 10:34:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-03-22 11:26:14 +00:00
|
|
|
void RequestManager::PostSystemSuccess(int requestId, const char *responseString, int responseValue) {
|
2023-03-22 10:34:48 +00:00
|
|
|
std::lock_guard<std::mutex> guard(callbackMutex_);
|
|
|
|
auto iter = callbackMap_.find(requestId);
|
|
|
|
if (iter == callbackMap_.end()) {
|
2023-03-22 11:26:14 +00:00
|
|
|
ERROR_LOG(SYSTEM, "PostSystemSuccess: Unexpected request ID %d (responseString=%s)", requestId, responseString);
|
2023-03-22 10:34:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::lock_guard<std::mutex> responseGuard(responseMutex_);
|
2023-03-25 17:48:50 +00:00
|
|
|
PendingSuccess response;
|
|
|
|
response.callback = iter->second.callback;
|
2023-03-22 10:34:48 +00:00
|
|
|
response.responseString = responseString;
|
|
|
|
response.responseValue = responseValue;
|
2023-03-25 17:48:50 +00:00
|
|
|
pendingSuccesses_.push_back(response);
|
2023-03-25 23:27:22 +00:00
|
|
|
DEBUG_LOG(SYSTEM, "PostSystemSuccess: Request %d (%s, %d)", requestId, responseString, responseValue);
|
2023-03-25 17:48:50 +00:00
|
|
|
callbackMap_.erase(iter);
|
2023-03-22 10:34:48 +00:00
|
|
|
}
|
|
|
|
|
2023-03-22 11:26:14 +00:00
|
|
|
void RequestManager::PostSystemFailure(int requestId) {
|
|
|
|
std::lock_guard<std::mutex> guard(callbackMutex_);
|
|
|
|
auto iter = callbackMap_.find(requestId);
|
|
|
|
if (iter == callbackMap_.end()) {
|
|
|
|
ERROR_LOG(SYSTEM, "PostSystemFailure: Unexpected request ID %d", requestId);
|
|
|
|
return;
|
|
|
|
}
|
2023-03-25 17:48:50 +00:00
|
|
|
|
2023-03-25 23:27:22 +00:00
|
|
|
WARN_LOG(SYSTEM, "PostSystemFailure: Request %d failed", requestId);
|
2023-03-25 17:48:50 +00:00
|
|
|
|
|
|
|
std::lock_guard<std::mutex> responseGuard(responseMutex_);
|
|
|
|
PendingFailure response;
|
|
|
|
response.callback = iter->second.failedCallback;
|
|
|
|
pendingFailures_.push_back(response);
|
2023-03-22 11:26:14 +00:00
|
|
|
callbackMap_.erase(iter);
|
|
|
|
}
|
|
|
|
|
2023-03-22 10:34:48 +00:00
|
|
|
void RequestManager::ProcessRequests() {
|
|
|
|
std::lock_guard<std::mutex> guard(responseMutex_);
|
2023-03-25 17:48:50 +00:00
|
|
|
for (auto &iter : pendingSuccesses_) {
|
2023-03-22 10:34:48 +00:00
|
|
|
if (iter.callback) {
|
|
|
|
iter.callback(iter.responseString.c_str(), iter.responseValue);
|
|
|
|
}
|
|
|
|
}
|
2023-03-25 17:48:50 +00:00
|
|
|
pendingSuccesses_.clear();
|
|
|
|
for (auto &iter : pendingFailures_) {
|
|
|
|
if (iter.callback) {
|
|
|
|
iter.callback();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pendingFailures_.clear();
|
2023-03-22 10:34:48 +00:00
|
|
|
}
|
2023-03-22 11:26:14 +00:00
|
|
|
|
|
|
|
void RequestManager::Clear() {
|
|
|
|
std::lock_guard<std::mutex> guard(callbackMutex_);
|
|
|
|
std::lock_guard<std::mutex> responseGuard(responseMutex_);
|
|
|
|
|
2023-03-25 17:48:50 +00:00
|
|
|
pendingSuccesses_.clear();
|
|
|
|
pendingFailures_.clear();
|
2023-03-22 11:26:14 +00:00
|
|
|
callbackMap_.clear();
|
|
|
|
}
|
2023-03-24 19:05:48 +00:00
|
|
|
|
|
|
|
void System_CreateGameShortcut(const Path &path, const std::string &title) {
|
2023-03-25 17:48:50 +00:00
|
|
|
g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, nullptr, nullptr, path.ToString(), title, 0);
|
2023-03-24 19:05:48 +00:00
|
|
|
}
|