#include "SDL_internal.h"
extern "C" {
#include "../windows/SDL_windows.h"
#include "../../events/SDL_events_c.h"
}
#include <XGameRuntime.h>
#include <xsapi-c/services_c.h>
#include <appnotify.h>
static XTaskQueueHandle GDK_GlobalTaskQueue;
PAPPSTATE_REGISTRATION hPLM = {};
PAPPCONSTRAIN_REGISTRATION hCPLM = {};
HANDLE plmSuspendComplete = nullptr;
extern "C"
bool SDL_GetGDKTaskQueue(XTaskQueueHandle *outTaskQueue)
{
if (!GDK_GlobalTaskQueue) {
HRESULT hr;
hr = XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool,
XTaskQueueDispatchMode::Manual,
&GDK_GlobalTaskQueue);
if (FAILED(hr)) {
return SDL_SetError("[GDK] Could not create global task queue");
}
*outTaskQueue = GDK_GlobalTaskQueue;
} else {
if (FAILED(XTaskQueueDuplicateHandle(GDK_GlobalTaskQueue, outTaskQueue))) {
return SDL_SetError("[GDK] Unable to acquire global task queue");
}
}
return true;
}
extern "C"
void GDK_DispatchTaskQueue(void)
{
if (GDK_GlobalTaskQueue) {
while (XTaskQueueDispatch(GDK_GlobalTaskQueue, XTaskQueuePort::Completion, 0))
;
}
}
extern "C"
bool GDK_RegisterChangeNotifications(void)
{
plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
if (!plmSuspendComplete) {
return SDL_SetError("[GDK] Unable to create plmSuspendComplete event");
}
auto rascn = [](BOOLEAN quiesced, PVOID context) {
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppStateChangeNotification handler");
if (quiesced) {
ResetEvent(plmSuspendComplete);
SDL_SendAppEvent(SDL_EVENT_DID_ENTER_BACKGROUND);
(void)WaitForSingleObject(plmSuspendComplete, INFINITE);
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppStateChangeNotification handler: plmSuspendComplete event signaled.");
} else {
SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_FOREGROUND);
}
};
if (RegisterAppStateChangeNotification(rascn, NULL, &hPLM)) {
return SDL_SetError("[GDK] Unable to call RegisterAppStateChangeNotification");
}
auto raccn = [](BOOLEAN constrained, PVOID context) {
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppConstrainedChangeNotification handler");
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this) {
if (constrained && !((_this->windows) && _this->windows->text_input_active)) {
SDL_SetKeyboardFocus(NULL);
} else {
SDL_SetKeyboardFocus(_this->windows);
}
}
};
if (RegisterAppConstrainedChangeNotification(raccn, NULL, &hCPLM)) {
return SDL_SetError("[GDK] Unable to call RegisterAppConstrainedChangeNotification");
}
return true;
}
extern "C"
void GDK_UnregisterChangeNotifications(void)
{
UnregisterAppStateChangeNotification(hPLM);
CloseHandle(plmSuspendComplete);
UnregisterAppConstrainedChangeNotification(hCPLM);
}
extern "C"
void SDL_GDKSuspendComplete()
{
if (plmSuspendComplete) {
SetEvent(plmSuspendComplete);
}
}
extern "C"
bool SDL_GetGDKDefaultUser(XUserHandle *outUserHandle)
{
XAsyncBlock block = { 0 };
HRESULT result;
if (FAILED(result = XUserAddAsync(XUserAddOptions::AddDefaultUserAllowingUI, &block))) {
return WIN_SetErrorFromHRESULT("XUserAddAsync", result);
}
do {
result = XUserAddResult(&block, outUserHandle);
} while (result == E_PENDING);
if (FAILED(result)) {
return WIN_SetErrorFromHRESULT("XUserAddResult", result);
}
return true;
}