mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 03:46:53 +02:00
Keep sign-in dialogs active until user dismissal through shared system presentation
This commit is contained in:
@@ -29,9 +29,9 @@ namespace Libs::Graphics {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
namespace CoreIme = Libs::Ime;
|
namespace CoreIme = Libs::Ime;
|
||||||
namespace DialogIme = Libs::Dialog::ImeDialog;
|
namespace DialogIme = Libs::Dialog::ImeDialog;
|
||||||
namespace ErrorDialog = Libs::Dialog::ErrorDialog;
|
namespace SystemDialog = Libs::Dialog::SystemDialog;
|
||||||
|
|
||||||
namespace Ime {
|
namespace Ime {
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ bool HostQueueExternalInput(uint64_t generation, ExternalInput input) {
|
|||||||
|
|
||||||
} // namespace Ime
|
} // namespace Ime
|
||||||
|
|
||||||
enum class OverlayKind : uint8_t { None, Ime, Error };
|
enum class OverlayKind : uint8_t { None, Ime, Dialog };
|
||||||
|
|
||||||
struct OverlaySession {
|
struct OverlaySession {
|
||||||
OverlayKind kind = OverlayKind::None;
|
OverlayKind kind = OverlayKind::None;
|
||||||
@@ -114,14 +114,14 @@ struct OverlaySession {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct OverlaySnapshot {
|
struct OverlaySnapshot {
|
||||||
OverlaySession session;
|
OverlaySession session;
|
||||||
Ime::HostSnapshot ime;
|
Ime::HostSnapshot ime;
|
||||||
ErrorDialog::HostSnapshot error;
|
SystemDialog::HostSnapshot dialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool GetOverlaySnapshot(OverlaySnapshot* snapshot) {
|
bool GetOverlaySnapshot(OverlaySnapshot* snapshot) {
|
||||||
if (ErrorDialog::GetHostSnapshot(&snapshot->error)) {
|
if (SystemDialog::GetHostSnapshot(&snapshot->dialog)) {
|
||||||
snapshot->session = {OverlayKind::Error, snapshot->error.generation};
|
snapshot->session = {OverlayKind::Dialog, snapshot->dialog.generation};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (Ime::GetHostSnapshot(&snapshot->ime)) {
|
if (Ime::GetHostSnapshot(&snapshot->ime)) {
|
||||||
@@ -234,7 +234,7 @@ void RefreshVisibility() {
|
|||||||
bool capture_keyboard = false;
|
bool capture_keyboard = false;
|
||||||
bool text_input = false;
|
bool text_input = false;
|
||||||
bool multiline = false;
|
bool multiline = false;
|
||||||
if (snapshot.session.kind == OverlayKind::Error) {
|
if (snapshot.session.kind == OverlayKind::Dialog) {
|
||||||
capture_controller = true;
|
capture_controller = true;
|
||||||
capture_keyboard = true;
|
capture_keyboard = true;
|
||||||
} else if (snapshot.session.kind == OverlayKind::Ime) {
|
} else if (snapshot.session.kind == OverlayKind::Ime) {
|
||||||
@@ -429,14 +429,14 @@ void InitializeSystemOverlayInput(SDL_Window* window) {
|
|||||||
}
|
}
|
||||||
CoreIme::SetVisibilityCallback(OnCoreVisibilityChanged);
|
CoreIme::SetVisibilityCallback(OnCoreVisibilityChanged);
|
||||||
DialogIme::SetVisibilityCallback(OnDialogVisibilityChanged);
|
DialogIme::SetVisibilityCallback(OnDialogVisibilityChanged);
|
||||||
ErrorDialog::SetVisibilityCallback(RefreshVisibility);
|
SystemDialog::SetVisibilityCallback(RefreshVisibility);
|
||||||
RefreshVisibility();
|
RefreshVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownSystemOverlayInput() {
|
void ShutdownSystemOverlayInput() {
|
||||||
CoreIme::SetVisibilityCallback(nullptr);
|
CoreIme::SetVisibilityCallback(nullptr);
|
||||||
DialogIme::SetVisibilityCallback(nullptr);
|
DialogIme::SetVisibilityCallback(nullptr);
|
||||||
ErrorDialog::SetVisibilityCallback(nullptr);
|
SystemDialog::SetVisibilityCallback(nullptr);
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(g_visibility_mutex);
|
std::scoped_lock lock(g_visibility_mutex);
|
||||||
g_input_lifecycle_active = false;
|
g_input_lifecycle_active = false;
|
||||||
@@ -466,9 +466,9 @@ void ShutdownSystemOverlayInput() {
|
|||||||
SystemOverlayVisualState GetSystemOverlayVisualState() noexcept {
|
SystemOverlayVisualState GetSystemOverlayVisualState() noexcept {
|
||||||
const auto core = CoreIme::GetVisualState();
|
const auto core = CoreIme::GetVisualState();
|
||||||
const auto dialog = DialogIme::GetVisualState();
|
const auto dialog = DialogIme::GetVisualState();
|
||||||
const auto error = ErrorDialog::GetVisualState();
|
const auto system = SystemDialog::GetVisualState();
|
||||||
return {core.active || dialog.active || error.active,
|
return {core.active || dialog.active || system.active,
|
||||||
core.revision + dialog.revision + error.revision};
|
core.revision + dialog.revision + system.revision};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessSystemOverlayInput(const SDL_Event& event) {
|
bool ProcessSystemOverlayInput(const SDL_Event& event) {
|
||||||
@@ -521,10 +521,11 @@ bool ProcessSystemOverlayInput(const SDL_Event& event) {
|
|||||||
if (keyboard_event && !g_input_keyboard) {
|
if (keyboard_event && !g_input_keyboard) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (keyboard_event && session.kind == OverlayKind::Error) {
|
if (keyboard_event && session.kind == OverlayKind::Dialog) {
|
||||||
if (event.type == SDL_EVENT_KEY_DOWN && !event.key.repeat &&
|
if (event.type == SDL_EVENT_KEY_DOWN && !event.key.repeat &&
|
||||||
(event.key.key == SDLK_RETURN || event.key.key == SDLK_KP_ENTER)) {
|
(event.key.key == SDLK_RETURN || event.key.key == SDLK_KP_ENTER ||
|
||||||
ErrorDialog::HostAccept(generation);
|
event.key.key == SDLK_ESCAPE)) {
|
||||||
|
SystemDialog::HostClose(generation);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -904,7 +905,7 @@ struct SystemOverlay::Impl {
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawError(const ErrorDialog::HostSnapshot& snapshot, vk::Extent2D extent) {
|
void DrawDialog(const SystemDialog::HostSnapshot& snapshot, vk::Extent2D extent) {
|
||||||
const ImVec2 display(static_cast<float>(extent.width), static_cast<float>(extent.height));
|
const ImVec2 display(static_cast<float>(extent.width), static_cast<float>(extent.height));
|
||||||
const float scale = std::max(std::min(display.x / 1280.0f, display.y / 720.0f), 0.5f);
|
const float scale = std::max(std::min(display.x / 1280.0f, display.y / 720.0f), 0.5f);
|
||||||
ImGui::GetBackgroundDrawList()->AddRectFilled({0.0f, 0.0f}, display,
|
ImGui::GetBackgroundDrawList()->AddRectFilled({0.0f, 0.0f}, display,
|
||||||
@@ -922,17 +923,23 @@ struct SystemOverlay::Impl {
|
|||||||
constexpr ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
|
constexpr ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
|
||||||
ImGuiWindowFlags_NoSavedSettings |
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
ImGuiWindowFlags_AlwaysAutoResize;
|
ImGuiWindowFlags_AlwaysAutoResize;
|
||||||
ImGui::Begin("##SystemError", nullptr, flags);
|
const bool signin = snapshot.kind == SystemDialog::Kind::Signin;
|
||||||
ImGui::TextUnformatted("Error");
|
ImGui::Begin("##SystemDialog", nullptr, flags);
|
||||||
|
ImGui::TextUnformatted(signin ? "Sign in to PlayStation Network" : "Error");
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
const auto error_code = static_cast<uint32_t>(snapshot.error_code);
|
const auto error_code = static_cast<uint32_t>(snapshot.error_code);
|
||||||
ImGui::TextWrapped("%s", error_code == 0x80550006u
|
ImGui::TextWrapped("%s", signin ? "PlayStation Network sign-in is unavailable."
|
||||||
|
: error_code == 0x80550006u
|
||||||
? "You are not signed in to PlayStation Network."
|
? "You are not signed in to PlayStation Network."
|
||||||
: "An error has occurred.");
|
: "An error has occurred.");
|
||||||
ImGui::TextDisabled("Error code: 0x%08X", error_code);
|
if (!signin) {
|
||||||
|
ImGui::TextDisabled("Error code: 0x%08X", error_code);
|
||||||
|
}
|
||||||
const float button_width = std::min(140.0f * scale, ImGui::GetContentRegionAvail().x);
|
const float button_width = std::min(140.0f * scale, ImGui::GetContentRegionAvail().x);
|
||||||
ImGui::SetCursorPosX((ImGui::GetWindowSize().x - button_width) * 0.5f);
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x - button_width) * 0.5f);
|
||||||
const bool accepted = ImGui::Button("OK", {button_width, 44.0f * scale});
|
const bool accepted =
|
||||||
|
ImGui::Button(signin ? "Cancel" : "OK", {button_width, 44.0f * scale}) ||
|
||||||
|
(signin && ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false));
|
||||||
if (focus_pending) {
|
if (focus_pending) {
|
||||||
ImGui::SetItemDefaultFocus();
|
ImGui::SetItemDefaultFocus();
|
||||||
focus_pending = false;
|
focus_pending = false;
|
||||||
@@ -941,7 +948,7 @@ struct SystemOverlay::Impl {
|
|||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
ImGui::PopStyleVar(2);
|
ImGui::PopStyleVar(2);
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
ErrorDialog::HostAccept(snapshot.generation);
|
SystemDialog::HostClose(snapshot.generation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -955,7 +962,8 @@ struct SystemOverlay::Impl {
|
|||||||
if (session != snapshot.session) {
|
if (session != snapshot.session) {
|
||||||
session = snapshot.session;
|
session = snapshot.session;
|
||||||
focus_pending = true;
|
focus_pending = true;
|
||||||
shift = (snapshot.ime.option & Ime::OPTION_NO_AUTO_CAPITALIZE) == 0;
|
shift = session.kind == OverlayKind::Ime &&
|
||||||
|
(snapshot.ime.option & Ime::OPTION_NO_AUTO_CAPITALIZE) == 0;
|
||||||
symbol_mode = false;
|
symbol_mode = false;
|
||||||
panel_offset = {};
|
panel_offset = {};
|
||||||
right_stick = {};
|
right_stick = {};
|
||||||
@@ -981,8 +989,8 @@ struct SystemOverlay::Impl {
|
|||||||
ImGui::EndFrame();
|
ImGui::EndFrame();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (snapshot.session.kind == OverlayKind::Error) {
|
if (snapshot.session.kind == OverlayKind::Dialog) {
|
||||||
DrawError(snapshot.error, frame_extent);
|
DrawDialog(snapshot.dialog, frame_extent);
|
||||||
} else {
|
} else {
|
||||||
DrawIme(snapshot.ime, frame_extent);
|
DrawIme(snapshot.ime, frame_extent);
|
||||||
}
|
}
|
||||||
|
|||||||
+122
-88
@@ -14,6 +14,81 @@
|
|||||||
// NOLINTNEXTLINE(modernize-concat-nested-namespaces)
|
// NOLINTNEXTLINE(modernize-concat-nested-namespaces)
|
||||||
namespace Libs::Dialog {
|
namespace Libs::Dialog {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr int DIALOG_STATUS_RUNNING = 2;
|
||||||
|
constexpr int DIALOG_STATUS_FINISHED = 3;
|
||||||
|
|
||||||
|
struct DialogState {
|
||||||
|
int status = 0;
|
||||||
|
uint64_t generation = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::mutex g_dialog_mutex;
|
||||||
|
DialogState g_error;
|
||||||
|
DialogState g_signin;
|
||||||
|
uint64_t g_dialog_generation = 0;
|
||||||
|
uint64_t g_dialog_revision = 0;
|
||||||
|
int32_t g_error_code = 0;
|
||||||
|
void (*g_dialog_visibility_callback)() = nullptr;
|
||||||
|
|
||||||
|
void SetDialogStatus(DialogState& dialog, int status, std::unique_lock<std::mutex>& lock) {
|
||||||
|
const bool visibility_changed =
|
||||||
|
(dialog.status == DIALOG_STATUS_RUNNING) != (status == DIALOG_STATUS_RUNNING);
|
||||||
|
dialog.status = status;
|
||||||
|
if (visibility_changed) {
|
||||||
|
g_dialog_revision++;
|
||||||
|
if (status == DIALOG_STATUS_RUNNING) {
|
||||||
|
dialog.generation = ++g_dialog_generation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto callback = visibility_changed ? g_dialog_visibility_callback : nullptr;
|
||||||
|
lock.unlock();
|
||||||
|
if (callback != nullptr) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace SystemDialog {
|
||||||
|
|
||||||
|
bool GetHostSnapshot(HostSnapshot* snapshot) {
|
||||||
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
|
if (g_signin.status == DIALOG_STATUS_RUNNING) {
|
||||||
|
*snapshot = {Kind::Signin, g_signin.generation, 0};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (g_error.status == DIALOG_STATUS_RUNNING) {
|
||||||
|
*snapshot = {Kind::Error, g_error.generation, g_error_code};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualState GetVisualState() noexcept {
|
||||||
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
|
const bool signin = g_signin.status == DIALOG_STATUS_RUNNING;
|
||||||
|
return {g_error.status == DIALOG_STATUS_RUNNING || signin, signin, g_dialog_revision};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVisibilityCallback(void (*callback)()) {
|
||||||
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
|
g_dialog_visibility_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HostClose(uint64_t generation) {
|
||||||
|
std::unique_lock lock(g_dialog_mutex);
|
||||||
|
auto& dialog = g_signin.status == DIALOG_STATUS_RUNNING ? g_signin : g_error;
|
||||||
|
if (dialog.status != DIALOG_STATUS_RUNNING || generation != dialog.generation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetDialogStatus(dialog, DIALOG_STATUS_FINISHED, lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SystemDialog
|
||||||
|
|
||||||
namespace CommonDialog {
|
namespace CommonDialog {
|
||||||
|
|
||||||
LIB_NAME("CommonDialog", "CommonDialog");
|
LIB_NAME("CommonDialog", "CommonDialog");
|
||||||
@@ -207,6 +282,7 @@ constexpr int SIGNIN_ERROR_NOT_INITIALIZED = static_cast<int>(0x81350001u);
|
|||||||
constexpr int SIGNIN_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x81350002u);
|
constexpr int SIGNIN_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x81350002u);
|
||||||
constexpr int SIGNIN_ERROR_PARAM_INVALID = static_cast<int>(0x81350003u);
|
constexpr int SIGNIN_ERROR_PARAM_INVALID = static_cast<int>(0x81350003u);
|
||||||
constexpr int SIGNIN_ERROR_INVALID_STATE = static_cast<int>(0x81350005u);
|
constexpr int SIGNIN_ERROR_INVALID_STATE = static_cast<int>(0x81350005u);
|
||||||
|
constexpr int SIGNIN_ERROR_INVALID_USER_ID = static_cast<int>(0x81350007u);
|
||||||
|
|
||||||
struct SigninDialogResult {
|
struct SigninDialogResult {
|
||||||
int32_t result;
|
int32_t result;
|
||||||
@@ -222,70 +298,78 @@ struct SigninDialogParam {
|
|||||||
static_assert(sizeof(SigninDialogResult) == 16);
|
static_assert(sizeof(SigninDialogResult) == 16);
|
||||||
static_assert(sizeof(SigninDialogParam) == 16);
|
static_assert(sizeof(SigninDialogParam) == 16);
|
||||||
|
|
||||||
static int g_signin_status = SIGNIN_STATUS_NONE;
|
|
||||||
|
|
||||||
int KYTY_SYSV_ABI SigninDialogInitialize() {
|
int KYTY_SYSV_ABI SigninDialogInitialize() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
if (g_signin_status != SIGNIN_STATUS_NONE) {
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
|
if (g_signin.status != SIGNIN_STATUS_NONE) {
|
||||||
return SIGNIN_ERROR_ALREADY_INITIALIZED;
|
return SIGNIN_ERROR_ALREADY_INITIALIZED;
|
||||||
}
|
}
|
||||||
g_signin_status = SIGNIN_STATUS_INITIALIZED;
|
g_signin.status = SIGNIN_STATUS_INITIALIZED;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI SigninDialogTerminate() {
|
int KYTY_SYSV_ABI SigninDialogTerminate() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
if (g_signin_status == SIGNIN_STATUS_NONE) {
|
std::unique_lock lock(g_dialog_mutex);
|
||||||
|
if (g_signin.status == SIGNIN_STATUS_NONE) {
|
||||||
return SIGNIN_ERROR_NOT_INITIALIZED;
|
return SIGNIN_ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
g_signin_status = SIGNIN_STATUS_NONE;
|
SetDialogStatus(g_signin, SIGNIN_STATUS_NONE, lock);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI SigninDialogOpen(const void* param) {
|
int KYTY_SYSV_ABI SigninDialogOpen(const void* param) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
if (g_signin_status != SIGNIN_STATUS_INITIALIZED && g_signin_status != SIGNIN_STATUS_FINISHED) {
|
std::unique_lock lock(g_dialog_mutex);
|
||||||
|
if (g_signin.status == SIGNIN_STATUS_NONE) {
|
||||||
|
return SIGNIN_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (g_signin.status != SIGNIN_STATUS_INITIALIZED && g_signin.status != SIGNIN_STATUS_FINISHED) {
|
||||||
return SIGNIN_ERROR_INVALID_STATE;
|
return SIGNIN_ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
if (param == nullptr ||
|
if (param == nullptr) {
|
||||||
static_cast<const SigninDialogParam*>(param)->size != sizeof(SigninDialogParam)) {
|
|
||||||
return SIGNIN_ERROR_PARAM_INVALID;
|
return SIGNIN_ERROR_PARAM_INVALID;
|
||||||
}
|
}
|
||||||
g_signin_status = SIGNIN_STATUS_RUNNING;
|
const auto* p = static_cast<const SigninDialogParam*>(param);
|
||||||
|
if (p->size != sizeof(SigninDialogParam) || p->reserved[0] != 0 || p->reserved[1] != 0) {
|
||||||
|
return SIGNIN_ERROR_PARAM_INVALID;
|
||||||
|
}
|
||||||
|
if (p->user_id != Config::GetUserId()) {
|
||||||
|
return SIGNIN_ERROR_INVALID_USER_ID;
|
||||||
|
}
|
||||||
|
SetDialogStatus(g_signin, SIGNIN_STATUS_RUNNING, lock);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI SigninDialogClose() {
|
int KYTY_SYSV_ABI SigninDialogClose() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
if (g_signin_status == SIGNIN_STATUS_NONE) {
|
std::unique_lock lock(g_dialog_mutex);
|
||||||
|
if (g_signin.status == SIGNIN_STATUS_NONE) {
|
||||||
return SIGNIN_ERROR_NOT_INITIALIZED;
|
return SIGNIN_ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
if (g_signin_status != SIGNIN_STATUS_RUNNING && g_signin_status != SIGNIN_STATUS_FINISHED) {
|
SetDialogStatus(g_signin, SIGNIN_STATUS_FINISHED, lock);
|
||||||
return SIGNIN_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
g_signin_status = SIGNIN_STATUS_FINISHED;
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI SigninDialogUpdateStatus() {
|
int KYTY_SYSV_ABI SigninDialogUpdateStatus() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
if (g_signin_status == SIGNIN_STATUS_RUNNING) {
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
g_signin_status = SIGNIN_STATUS_FINISHED;
|
return g_signin.status;
|
||||||
}
|
|
||||||
return g_signin_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI SigninDialogGetStatus() {
|
int KYTY_SYSV_ABI SigninDialogGetStatus() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
return g_signin_status;
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
|
return g_signin.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI SigninDialogGetResult(void* result) {
|
int KYTY_SYSV_ABI SigninDialogGetResult(void* result) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
if (g_signin_status == SIGNIN_STATUS_NONE) {
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
|
if (g_signin.status == SIGNIN_STATUS_NONE) {
|
||||||
return SIGNIN_ERROR_NOT_INITIALIZED;
|
return SIGNIN_ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
if (g_signin_status != SIGNIN_STATUS_FINISHED) {
|
if (g_signin.status != SIGNIN_STATUS_FINISHED) {
|
||||||
return SIGNIN_ERROR_INVALID_STATE;
|
return SIGNIN_ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
@@ -661,64 +745,15 @@ struct ErrorDialogParam {
|
|||||||
|
|
||||||
static_assert(sizeof(ErrorDialogParam) == 16);
|
static_assert(sizeof(ErrorDialogParam) == 16);
|
||||||
|
|
||||||
static std::mutex g_error_mutex;
|
|
||||||
static int g_error_status = STATUS_NONE;
|
|
||||||
static uint64_t g_error_generation = 0;
|
|
||||||
static uint64_t g_error_revision = 0;
|
|
||||||
static int32_t g_error_code = 0;
|
|
||||||
static void (*g_error_visibility_callback)() = nullptr;
|
|
||||||
|
|
||||||
static void SetStatus(int status, std::unique_lock<std::mutex>& lock) {
|
|
||||||
const bool visibility_changed =
|
|
||||||
(g_error_status == STATUS_RUNNING) != (status == STATUS_RUNNING);
|
|
||||||
g_error_status = status;
|
|
||||||
if (visibility_changed) {
|
|
||||||
g_error_revision++;
|
|
||||||
}
|
|
||||||
const auto callback = visibility_changed ? g_error_visibility_callback : nullptr;
|
|
||||||
lock.unlock();
|
|
||||||
if (callback != nullptr) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetHostSnapshot(HostSnapshot* snapshot) {
|
|
||||||
std::scoped_lock lock(g_error_mutex);
|
|
||||||
if (g_error_status != STATUS_RUNNING) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*snapshot = {g_error_generation, g_error_code};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VisualState GetVisualState() noexcept {
|
|
||||||
std::scoped_lock lock(g_error_mutex);
|
|
||||||
return {g_error_status == STATUS_RUNNING, g_error_revision};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVisibilityCallback(void (*callback)()) {
|
|
||||||
std::scoped_lock lock(g_error_mutex);
|
|
||||||
g_error_visibility_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HostAccept(uint64_t generation) {
|
|
||||||
std::unique_lock lock(g_error_mutex);
|
|
||||||
if (g_error_status != STATUS_RUNNING || generation != g_error_generation) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
SetStatus(STATUS_FINISHED, lock);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int KYTY_SYSV_ABI ErrorDialogInitialize() {
|
int KYTY_SYSV_ABI ErrorDialogInitialize() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
std::scoped_lock lock(g_error_mutex);
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
if (g_error_status != STATUS_NONE) {
|
if (g_error.status != STATUS_NONE) {
|
||||||
return ERROR_ALREADY_INITIALIZED;
|
return ERROR_ALREADY_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_error_status = STATUS_INITIALIZED;
|
g_error.status = STATUS_INITIALIZED;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -726,8 +761,8 @@ int KYTY_SYSV_ABI ErrorDialogInitialize() {
|
|||||||
int KYTY_SYSV_ABI ErrorDialogOpen(const void* param) {
|
int KYTY_SYSV_ABI ErrorDialogOpen(const void* param) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
std::unique_lock lock(g_error_mutex);
|
std::unique_lock lock(g_dialog_mutex);
|
||||||
if (g_error_status != STATUS_INITIALIZED && g_error_status != STATUS_FINISHED) {
|
if (g_error.status != STATUS_INITIALIZED && g_error.status != STATUS_FINISHED) {
|
||||||
return ERROR_INVALID_STATE;
|
return ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
if (param == nullptr) {
|
if (param == nullptr) {
|
||||||
@@ -745,8 +780,7 @@ int KYTY_SYSV_ABI ErrorDialogOpen(const void* param) {
|
|||||||
p->size, static_cast<uint32_t>(p->error_code), p->user_id);
|
p->size, static_cast<uint32_t>(p->error_code), p->user_id);
|
||||||
|
|
||||||
g_error_code = p->error_code;
|
g_error_code = p->error_code;
|
||||||
g_error_generation++;
|
SetDialogStatus(g_error, STATUS_RUNNING, lock);
|
||||||
SetStatus(STATUS_RUNNING, lock);
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -754,12 +788,12 @@ int KYTY_SYSV_ABI ErrorDialogOpen(const void* param) {
|
|||||||
int KYTY_SYSV_ABI ErrorDialogClose() {
|
int KYTY_SYSV_ABI ErrorDialogClose() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
std::unique_lock lock(g_error_mutex);
|
std::unique_lock lock(g_dialog_mutex);
|
||||||
if (g_error_status != STATUS_RUNNING) {
|
if (g_error.status != STATUS_RUNNING) {
|
||||||
return ERROR_INVALID_STATE;
|
return ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetStatus(STATUS_FINISHED, lock);
|
SetDialogStatus(g_error, STATUS_FINISHED, lock);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -767,12 +801,12 @@ int KYTY_SYSV_ABI ErrorDialogClose() {
|
|||||||
int KYTY_SYSV_ABI ErrorDialogTerminate() {
|
int KYTY_SYSV_ABI ErrorDialogTerminate() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
std::unique_lock lock(g_error_mutex);
|
std::unique_lock lock(g_dialog_mutex);
|
||||||
if (g_error_status == STATUS_NONE) {
|
if (g_error.status == STATUS_NONE) {
|
||||||
return ERROR_NOT_INITIALIZED;
|
return ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetStatus(STATUS_NONE, lock);
|
SetDialogStatus(g_error, STATUS_NONE, lock);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -780,15 +814,15 @@ int KYTY_SYSV_ABI ErrorDialogTerminate() {
|
|||||||
int KYTY_SYSV_ABI ErrorDialogUpdateStatus() {
|
int KYTY_SYSV_ABI ErrorDialogUpdateStatus() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
std::scoped_lock lock(g_error_mutex);
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
return g_error_status;
|
return g_error.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI ErrorDialogGetStatus() {
|
int KYTY_SYSV_ABI ErrorDialogGetStatus() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
std::scoped_lock lock(g_error_mutex);
|
std::scoped_lock lock(g_dialog_mutex);
|
||||||
return g_error_status;
|
return g_error.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ErrorDialog
|
} // namespace ErrorDialog
|
||||||
|
|||||||
+10
-2
@@ -68,22 +68,30 @@ int KYTY_SYSV_ABI MsgDialogProgressBarSetMsg(int target, const char* msg);
|
|||||||
|
|
||||||
} // namespace MsgDialog
|
} // namespace MsgDialog
|
||||||
|
|
||||||
namespace ErrorDialog {
|
namespace SystemDialog {
|
||||||
|
|
||||||
|
enum class Kind { Error, Signin };
|
||||||
|
|
||||||
struct HostSnapshot {
|
struct HostSnapshot {
|
||||||
|
Kind kind;
|
||||||
uint64_t generation;
|
uint64_t generation;
|
||||||
int32_t error_code;
|
int32_t error_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VisualState {
|
struct VisualState {
|
||||||
bool active;
|
bool active;
|
||||||
|
bool background;
|
||||||
uint64_t revision;
|
uint64_t revision;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool GetHostSnapshot(HostSnapshot* snapshot);
|
bool GetHostSnapshot(HostSnapshot* snapshot);
|
||||||
VisualState GetVisualState() noexcept;
|
VisualState GetVisualState() noexcept;
|
||||||
void SetVisibilityCallback(void (*callback)());
|
void SetVisibilityCallback(void (*callback)());
|
||||||
bool HostAccept(uint64_t generation);
|
bool HostClose(uint64_t generation);
|
||||||
|
|
||||||
|
} // namespace SystemDialog
|
||||||
|
|
||||||
|
namespace ErrorDialog {
|
||||||
|
|
||||||
int KYTY_SYSV_ABI ErrorDialogInitialize();
|
int KYTY_SYSV_ABI ErrorDialogInitialize();
|
||||||
int KYTY_SYSV_ABI ErrorDialogOpen(const void* param);
|
int KYTY_SYSV_ABI ErrorDialogOpen(const void* param);
|
||||||
|
|||||||
@@ -163,8 +163,10 @@ static int KYTY_SYSV_ABI SystemServiceGetStatus(SystemServiceStatus* status) {
|
|||||||
return SYSTEM_SERVICE_ERROR_PARAMETER;
|
return SYSTEM_SERVICE_ERROR_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
*status = SystemServiceStatus();
|
const auto dialog = Dialog::SystemDialog::GetVisualState();
|
||||||
status->is_system_ui_overlaid = Dialog::ErrorDialog::GetVisualState().active;
|
*status = SystemServiceStatus();
|
||||||
|
status->is_system_ui_overlaid = dialog.active;
|
||||||
|
status->is_in_background_execution = dialog.background;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -977,6 +977,7 @@ void Require(const char *shader_name, const char *stage, bool value,
|
|||||||
|
|
||||||
void CheckErrorDialogLifecycle() {
|
void CheckErrorDialogLifecycle() {
|
||||||
namespace ErrorDialog = Libs::Dialog::ErrorDialog;
|
namespace ErrorDialog = Libs::Dialog::ErrorDialog;
|
||||||
|
namespace SystemDialog = Libs::Dialog::SystemDialog;
|
||||||
struct Param {
|
struct Param {
|
||||||
int32_t size = 16;
|
int32_t size = 16;
|
||||||
int32_t error_code = static_cast<int32_t>(0x80550006u);
|
int32_t error_code = static_cast<int32_t>(0x80550006u);
|
||||||
@@ -986,27 +987,27 @@ void CheckErrorDialogLifecycle() {
|
|||||||
static_assert(sizeof(Param) == 16);
|
static_assert(sizeof(Param) == 16);
|
||||||
constexpr int invalid_state = static_cast<int>(0x80ed0005u);
|
constexpr int invalid_state = static_cast<int>(0x80ed0005u);
|
||||||
constexpr int invalid_param = static_cast<int>(0x80ed0003u);
|
constexpr int invalid_param = static_cast<int>(0x80ed0003u);
|
||||||
static std::vector<ErrorDialog::VisualState> notifications;
|
static std::vector<SystemDialog::VisualState> notifications;
|
||||||
notifications.clear();
|
notifications.clear();
|
||||||
ErrorDialog::SetVisibilityCallback([] {
|
SystemDialog::SetVisibilityCallback([] {
|
||||||
const auto visual = ErrorDialog::GetVisualState();
|
const auto visual = SystemDialog::GetVisualState();
|
||||||
ErrorDialog::HostSnapshot snapshot{};
|
SystemDialog::HostSnapshot snapshot{};
|
||||||
Require("ErrorDialog", "callback reentry",
|
Require("ErrorDialog", "callback reentry",
|
||||||
ErrorDialog::GetHostSnapshot(&snapshot) == visual.active &&
|
SystemDialog::GetHostSnapshot(&snapshot) == visual.active &&
|
||||||
(ErrorDialog::ErrorDialogGetStatus() == 2) == visual.active,
|
(ErrorDialog::ErrorDialogGetStatus() == 2) == visual.active,
|
||||||
"visibility callback observed inconsistent dialog state");
|
"visibility callback observed inconsistent dialog state");
|
||||||
notifications.push_back(visual);
|
notifications.push_back(visual);
|
||||||
});
|
});
|
||||||
const auto initial_revision = ErrorDialog::GetVisualState().revision;
|
const auto initial_revision = SystemDialog::GetVisualState().revision;
|
||||||
const auto check_state = [&](const char *stage, int status,
|
const auto check_state = [&](const char *stage, int status,
|
||||||
size_t visibility_changes) {
|
size_t visibility_changes) {
|
||||||
const auto visual = ErrorDialog::GetVisualState();
|
const auto visual = SystemDialog::GetVisualState();
|
||||||
ErrorDialog::HostSnapshot snapshot{};
|
SystemDialog::HostSnapshot snapshot{};
|
||||||
Require("ErrorDialog", stage,
|
Require("ErrorDialog", stage,
|
||||||
ErrorDialog::ErrorDialogGetStatus() == status &&
|
ErrorDialog::ErrorDialogGetStatus() == status &&
|
||||||
ErrorDialog::ErrorDialogUpdateStatus() == status &&
|
ErrorDialog::ErrorDialogUpdateStatus() == status &&
|
||||||
visual.active == (status == 2) &&
|
visual.active == (status == 2) && !visual.background &&
|
||||||
ErrorDialog::GetHostSnapshot(&snapshot) == visual.active &&
|
SystemDialog::GetHostSnapshot(&snapshot) == visual.active &&
|
||||||
visual.revision == initial_revision + visibility_changes &&
|
visual.revision == initial_revision + visibility_changes &&
|
||||||
notifications.size() == visibility_changes &&
|
notifications.size() == visibility_changes &&
|
||||||
(notifications.empty() ||
|
(notifications.empty() ||
|
||||||
@@ -1036,9 +1037,9 @@ void CheckErrorDialogLifecycle() {
|
|||||||
check_state("failed open preserves initialized state", 1, 0);
|
check_state("failed open preserves initialized state", 1, 0);
|
||||||
Require("ErrorDialog", "open", ErrorDialog::ErrorDialogOpen(¶m) == 0,
|
Require("ErrorDialog", "open", ErrorDialog::ErrorDialogOpen(¶m) == 0,
|
||||||
"valid error dialog did not open");
|
"valid error dialog did not open");
|
||||||
ErrorDialog::HostSnapshot first{};
|
SystemDialog::HostSnapshot first{};
|
||||||
Require("ErrorDialog", "copied error code",
|
Require("ErrorDialog", "copied error code",
|
||||||
ErrorDialog::GetHostSnapshot(&first) &&
|
SystemDialog::GetHostSnapshot(&first) &&
|
||||||
first.error_code == param.error_code,
|
first.error_code == param.error_code,
|
||||||
"host dialog did not expose the guest error code");
|
"host dialog did not expose the guest error code");
|
||||||
param.error_code = static_cast<int32_t>(0x8055000au);
|
param.error_code = static_cast<int32_t>(0x8055000au);
|
||||||
@@ -1048,31 +1049,31 @@ void CheckErrorDialogLifecycle() {
|
|||||||
Require(
|
Require(
|
||||||
"ErrorDialog", "running failures",
|
"ErrorDialog", "running failures",
|
||||||
ErrorDialog::ErrorDialogOpen(¶m) == invalid_state &&
|
ErrorDialog::ErrorDialogOpen(¶m) == invalid_state &&
|
||||||
!ErrorDialog::HostAccept(first.generation + 1),
|
!SystemDialog::HostClose(first.generation + 1),
|
||||||
"an invalid open or stale acknowledgement replaced the active dialog");
|
"an invalid open or stale acknowledgement replaced the active dialog");
|
||||||
ErrorDialog::HostSnapshot current{};
|
SystemDialog::HostSnapshot current{};
|
||||||
Require("ErrorDialog", "failed open preserves active dialog",
|
Require("ErrorDialog", "failed open preserves active dialog",
|
||||||
ErrorDialog::GetHostSnapshot(¤t) &&
|
SystemDialog::GetHostSnapshot(¤t) &&
|
||||||
current.generation == first.generation &&
|
current.generation == first.generation &&
|
||||||
current.error_code == first.error_code,
|
current.error_code == first.error_code,
|
||||||
"active error code or generation changed after a failed open");
|
"active error code or generation changed after a failed open");
|
||||||
check_state("failed operations preserve running state", 2, 1);
|
check_state("failed operations preserve running state", 2, 1);
|
||||||
Require("ErrorDialog", "acknowledge",
|
Require("ErrorDialog", "acknowledge",
|
||||||
ErrorDialog::HostAccept(first.generation),
|
SystemDialog::HostClose(first.generation),
|
||||||
"current host acknowledgement did not finish the dialog");
|
"current host acknowledgement did not finish the dialog");
|
||||||
check_state("acknowledged", 3, 2);
|
check_state("acknowledged", 3, 2);
|
||||||
Require("ErrorDialog", "finished operations",
|
Require("ErrorDialog", "finished operations",
|
||||||
!ErrorDialog::HostAccept(first.generation) &&
|
!SystemDialog::HostClose(first.generation) &&
|
||||||
ErrorDialog::ErrorDialogClose() == invalid_state &&
|
ErrorDialog::ErrorDialogClose() == invalid_state &&
|
||||||
ErrorDialog::ErrorDialogOpen(&invalid) == invalid_param,
|
ErrorDialog::ErrorDialogOpen(&invalid) == invalid_param,
|
||||||
"finished dialog accepted duplicate completion or an invalid open");
|
"finished dialog accepted duplicate completion or an invalid open");
|
||||||
check_state("failed operations preserve finished state", 3, 2);
|
check_state("failed operations preserve finished state", 3, 2);
|
||||||
Require("ErrorDialog", "reopen and stale acknowledgement",
|
Require("ErrorDialog", "reopen and stale acknowledgement",
|
||||||
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
||||||
ErrorDialog::GetHostSnapshot(¤t) &&
|
SystemDialog::GetHostSnapshot(¤t) &&
|
||||||
current.generation != first.generation &&
|
current.generation != first.generation &&
|
||||||
current.error_code == param.error_code &&
|
current.error_code == param.error_code &&
|
||||||
!ErrorDialog::HostAccept(first.generation),
|
!SystemDialog::HostClose(first.generation),
|
||||||
"reopened dialog accepted acknowledgement from its predecessor");
|
"reopened dialog accepted acknowledgement from its predecessor");
|
||||||
check_state("reopened", 2, 3);
|
check_state("reopened", 2, 3);
|
||||||
Require("ErrorDialog", "guest close", ErrorDialog::ErrorDialogClose() == 0,
|
Require("ErrorDialog", "guest close", ErrorDialog::ErrorDialogClose() == 0,
|
||||||
@@ -1080,15 +1081,15 @@ void CheckErrorDialogLifecycle() {
|
|||||||
check_state("closed", 3, 4);
|
check_state("closed", 3, 4);
|
||||||
Require("ErrorDialog", "terminate running dialog",
|
Require("ErrorDialog", "terminate running dialog",
|
||||||
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
||||||
ErrorDialog::GetHostSnapshot(¤t) &&
|
SystemDialog::GetHostSnapshot(¤t) &&
|
||||||
ErrorDialog::ErrorDialogTerminate() == 0 &&
|
ErrorDialog::ErrorDialogTerminate() == 0 &&
|
||||||
!ErrorDialog::HostAccept(current.generation),
|
!SystemDialog::HostClose(current.generation),
|
||||||
"termination failed to remove the active dialog");
|
"termination failed to remove the active dialog");
|
||||||
check_state("terminated", 0, 6);
|
check_state("terminated", 0, 6);
|
||||||
Require("ErrorDialog", "reinitialize and stale acknowledgement",
|
Require("ErrorDialog", "reinitialize and stale acknowledgement",
|
||||||
ErrorDialog::ErrorDialogInitialize() == 0 &&
|
ErrorDialog::ErrorDialogInitialize() == 0 &&
|
||||||
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
||||||
!ErrorDialog::HostAccept(current.generation),
|
!SystemDialog::HostClose(current.generation),
|
||||||
"reinitialization reused an old dialog generation");
|
"reinitialization reused an old dialog generation");
|
||||||
check_state("reinitialized", 2, 7);
|
check_state("reinitialized", 2, 7);
|
||||||
Require("ErrorDialog", "final termination",
|
Require("ErrorDialog", "final termination",
|
||||||
@@ -1097,20 +1098,131 @@ void CheckErrorDialogLifecycle() {
|
|||||||
static_cast<int>(0x80ed0001u),
|
static_cast<int>(0x80ed0001u),
|
||||||
"termination did not restore the uninitialized state");
|
"termination did not restore the uninitialized state");
|
||||||
check_state("final state", 0, 8);
|
check_state("final state", 0, 8);
|
||||||
ErrorDialog::SetVisibilityCallback(nullptr);
|
SystemDialog::SetVisibilityCallback(nullptr);
|
||||||
Require("ErrorDialog", "lifecycle without a visibility listener",
|
Require("ErrorDialog", "lifecycle without a visibility listener",
|
||||||
ErrorDialog::ErrorDialogInitialize() == 0 &&
|
ErrorDialog::ErrorDialogInitialize() == 0 &&
|
||||||
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
ErrorDialog::ErrorDialogOpen(¶m) == 0 &&
|
||||||
ErrorDialog::ErrorDialogClose() == 0 &&
|
ErrorDialog::ErrorDialogClose() == 0 &&
|
||||||
ErrorDialog::ErrorDialogTerminate() == 0 &&
|
ErrorDialog::ErrorDialogTerminate() == 0 &&
|
||||||
ErrorDialog::ErrorDialogGetStatus() == 0 &&
|
ErrorDialog::ErrorDialogGetStatus() == 0 &&
|
||||||
!ErrorDialog::GetVisualState().active &&
|
!SystemDialog::GetVisualState().active &&
|
||||||
ErrorDialog::GetVisualState().revision == initial_revision + 10 &&
|
SystemDialog::GetVisualState().revision ==
|
||||||
|
initial_revision + 10 &&
|
||||||
notifications.size() == 8,
|
notifications.size() == 8,
|
||||||
"guest lifecycle depended on a registered host visibility listener");
|
"guest lifecycle depended on a registered host visibility listener");
|
||||||
std::printf("[host] %-32s ok\n", "ErrorDialogLifecycle");
|
std::printf("[host] %-32s ok\n", "ErrorDialogLifecycle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckSigninDialogLifecycle() {
|
||||||
|
namespace Signin = Libs::Dialog::SigninDialog;
|
||||||
|
namespace Error = Libs::Dialog::ErrorDialog;
|
||||||
|
namespace Host = Libs::Dialog::SystemDialog;
|
||||||
|
struct Param {
|
||||||
|
int32_t size = 16;
|
||||||
|
int32_t user_id = Config::GetUserId();
|
||||||
|
int32_t reserved[2] = {};
|
||||||
|
} param;
|
||||||
|
struct Result {
|
||||||
|
int32_t result = -1;
|
||||||
|
int32_t reserved[3] = {-1, -1, -1};
|
||||||
|
} result;
|
||||||
|
constexpr int not_initialized = static_cast<int>(0x81350001u);
|
||||||
|
constexpr int already_initialized = static_cast<int>(0x81350002u);
|
||||||
|
constexpr int invalid_param = static_cast<int>(0x81350003u);
|
||||||
|
constexpr int invalid_state = static_cast<int>(0x81350005u);
|
||||||
|
Require("SigninDialog", "uninitialized",
|
||||||
|
Signin::SigninDialogOpen(¶m) == not_initialized &&
|
||||||
|
Signin::SigninDialogClose() == not_initialized &&
|
||||||
|
Signin::SigninDialogGetResult(&result) == not_initialized,
|
||||||
|
"uninitialized operations returned the wrong error");
|
||||||
|
Require("SigninDialog", "initialize and close",
|
||||||
|
Signin::SigninDialogInitialize() == 0 &&
|
||||||
|
Signin::SigninDialogClose() == 0 &&
|
||||||
|
Signin::SigninDialogUpdateStatus() == 3,
|
||||||
|
"close must also succeed from INITIALIZED");
|
||||||
|
Param invalid = param;
|
||||||
|
invalid.reserved[0] = 1;
|
||||||
|
Require("SigninDialog", "parameter validation",
|
||||||
|
Signin::SigninDialogOpen(nullptr) == invalid_param &&
|
||||||
|
Signin::SigninDialogOpen(&invalid) == invalid_param,
|
||||||
|
"invalid parameters were accepted");
|
||||||
|
invalid = param;
|
||||||
|
invalid.user_id = -1;
|
||||||
|
Require("SigninDialog", "user validation",
|
||||||
|
Signin::SigninDialogOpen(&invalid) == static_cast<int>(0x81350007u),
|
||||||
|
"an invalid user was accepted");
|
||||||
|
Host::SetVisibilityCallback([] {
|
||||||
|
const auto visual = Host::GetVisualState();
|
||||||
|
Require("SigninDialog", "callback reentry",
|
||||||
|
visual.background == (Signin::SigninDialogGetStatus() == 2),
|
||||||
|
"foreground state did not follow the dialog lifetime");
|
||||||
|
});
|
||||||
|
Require("SigninDialog", "open", Signin::SigninDialogOpen(¶m) == 0,
|
||||||
|
"valid sign-in dialog did not open");
|
||||||
|
Host::HostSnapshot first{};
|
||||||
|
Require(
|
||||||
|
"SigninDialog", "visible and backgrounded",
|
||||||
|
Host::GetHostSnapshot(&first) && first.kind == Host::Kind::Signin &&
|
||||||
|
Host::GetVisualState().active && Host::GetVisualState().background,
|
||||||
|
"sign-in dialog was not visible or did not background the application");
|
||||||
|
for (int poll = 0; poll < 8; ++poll) {
|
||||||
|
Require(
|
||||||
|
"SigninDialog", "polling waits for the user",
|
||||||
|
Signin::SigninDialogUpdateStatus() == 2 &&
|
||||||
|
Signin::SigninDialogGetStatus() == 2 &&
|
||||||
|
Signin::SigninDialogInitialize() == already_initialized &&
|
||||||
|
Signin::SigninDialogGetResult(&result) == invalid_state,
|
||||||
|
"polling silently finished sign-in or lost the active initialization");
|
||||||
|
}
|
||||||
|
Require(
|
||||||
|
"SigninDialog", "user cancellation",
|
||||||
|
Host::HostClose(first.generation) &&
|
||||||
|
Signin::SigninDialogGetResult(&result) == 0 && result.result == 1 &&
|
||||||
|
result.reserved[0] == 0 && result.reserved[1] == 0 &&
|
||||||
|
result.reserved[2] == 0 && !Host::GetVisualState().background &&
|
||||||
|
!Host::GetVisualState().active && Signin::SigninDialogClose() == 0,
|
||||||
|
"user cancellation did not finish sign-in and restore the foreground");
|
||||||
|
const int32_t error_param[4] = {16, static_cast<int32_t>(0x80550006u), 1, 0};
|
||||||
|
Host::HostSnapshot error{};
|
||||||
|
Require("SigninDialog", "shared presentation generations",
|
||||||
|
Error::ErrorDialogInitialize() == 0 &&
|
||||||
|
Error::ErrorDialogOpen(error_param) == 0 &&
|
||||||
|
Host::GetHostSnapshot(&error) &&
|
||||||
|
error.kind == Host::Kind::Error &&
|
||||||
|
error.generation != first.generation &&
|
||||||
|
!Host::HostClose(first.generation),
|
||||||
|
"an old sign-in action affected an error dialog");
|
||||||
|
Host::HostSnapshot overlay{};
|
||||||
|
Require("SigninDialog", "overlapping dialogs",
|
||||||
|
Signin::SigninDialogOpen(¶m) == 0 &&
|
||||||
|
Host::GetHostSnapshot(&overlay) &&
|
||||||
|
overlay.kind == Host::Kind::Signin &&
|
||||||
|
!Host::HostClose(error.generation) &&
|
||||||
|
Host::HostClose(overlay.generation) &&
|
||||||
|
Host::GetHostSnapshot(&overlay) &&
|
||||||
|
overlay.kind == Host::Kind::Error &&
|
||||||
|
overlay.generation == error.generation &&
|
||||||
|
!Host::GetVisualState().background &&
|
||||||
|
Host::HostClose(error.generation) &&
|
||||||
|
Error::ErrorDialogTerminate() == 0,
|
||||||
|
"closing sign-in did not restore the pending error dialog");
|
||||||
|
Host::HostSnapshot reopened{};
|
||||||
|
Require(
|
||||||
|
"SigninDialog", "reopen and abort",
|
||||||
|
Signin::SigninDialogOpen(¶m) == 0 &&
|
||||||
|
Host::GetHostSnapshot(&reopened) &&
|
||||||
|
!Host::HostClose(first.generation) &&
|
||||||
|
!Host::HostClose(error.generation) &&
|
||||||
|
Signin::SigninDialogTerminate() == 0 &&
|
||||||
|
!Host::HostClose(reopened.generation) &&
|
||||||
|
!Host::GetVisualState().active &&
|
||||||
|
!Host::GetVisualState().background &&
|
||||||
|
Signin::SigninDialogTerminate() == not_initialized,
|
||||||
|
"abort did not remove the dialog or a stale host action was accepted");
|
||||||
|
Host::SetVisibilityCallback(nullptr);
|
||||||
|
std::printf("[host] %-32s ok\n", "SigninDialogLifecycle");
|
||||||
|
}
|
||||||
|
|
||||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||||
template <typename Function>
|
template <typename Function>
|
||||||
void ExpectFatal(const char *name, Function function) {
|
void ExpectFatal(const char *name, Function function) {
|
||||||
@@ -37149,8 +37261,9 @@ int main(int argc, char **argv) {
|
|||||||
vulkan.CheckPackedTextureComponents();
|
vulkan.CheckPackedTextureComponents();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--error-dialog-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--system-dialog-only") == 0) {
|
||||||
CheckErrorDialogLifecycle();
|
CheckErrorDialogLifecycle();
|
||||||
|
CheckSigninDialogLifecycle();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--fmask-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--fmask-only") == 0) {
|
||||||
@@ -37716,6 +37829,7 @@ int main(int argc, char **argv) {
|
|||||||
CheckClipControlDepthClipState();
|
CheckClipControlDepthClipState();
|
||||||
CheckReferenceClockScale();
|
CheckReferenceClockScale();
|
||||||
CheckErrorDialogLifecycle();
|
CheckErrorDialogLifecycle();
|
||||||
|
CheckSigninDialogLifecycle();
|
||||||
CheckVulkan13FeatureRequirements();
|
CheckVulkan13FeatureRequirements();
|
||||||
CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer());
|
CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer());
|
||||||
CheckPm4SyntheticOcclusionCounterDump(vulkan.RuntimeRenderer());
|
CheckPm4SyntheticOcclusionCounterDump(vulkan.RuntimeRenderer());
|
||||||
|
|||||||
Reference in New Issue
Block a user