mirror of
https://github.com/Relintai/sdl2_frt.git
synced 2024-12-29 20:27:12 +01:00
WinRT: Miscellaneous app-backgrounding/restoring event fixes and additions
SDL_WINDOWEVENT_FOCUS_LOST is now sent when an app's native window is hidden. Likewise, SDL_WINDOWEVENT_FOCUS_GAINED is sent when an app's window is shown. This mimicks behavior seen on iOS and Android. SDL_WINDOWEVENT_MINIMIZED and SDL_WINDOWEVENT_RESTORED are now sent when the app's native window is hidden and shown. Previously, these were sent when an app was suspended and resumed. On Windows 8.x/RT, an app may be sent to the background without being suspended, which previously meant that SDL_WINDOWEVENT_MINIMIZED might never have been sent. (On Windows Phone 8, however, this seems to be different, whereby apps sent to the background appear to always get suspended.)
This commit is contained in:
parent
50ee99ecb2
commit
c2243092d7
@ -418,16 +418,62 @@ void SDL_WinRTApp::Run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)
|
||||||
|
{
|
||||||
|
SDL_Event events[128];
|
||||||
|
const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
if (events[i].window.event == windowEventID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDL_WinRTApp::ShouldWaitForAppResumeEvents()
|
||||||
|
{
|
||||||
|
/* Don't wait if the app is visible: */
|
||||||
|
if (m_windowVisible) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't wait until the window-hide events finish processing.
|
||||||
|
* Do note that if an app-suspend event is sent (as indicated
|
||||||
|
* by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND
|
||||||
|
* events), then this code may be a moot point, as WinRT's
|
||||||
|
* own event pump (aka ProcessEvents()) will pause regardless
|
||||||
|
* of what we do here. This happens on Windows Phone 8, to note.
|
||||||
|
* Windows 8.x apps, on the other hand, may get a chance to run
|
||||||
|
* these.
|
||||||
|
*/
|
||||||
|
if (IsSDLWindowEventPending(SDL_WINDOWEVENT_HIDDEN)) {
|
||||||
|
return false;
|
||||||
|
} else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_FOCUS_LOST)) {
|
||||||
|
return false;
|
||||||
|
} else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_MINIMIZED)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SDL_WinRTApp::PumpEvents()
|
void SDL_WinRTApp::PumpEvents()
|
||||||
{
|
{
|
||||||
if (!m_windowClosed)
|
if (!m_windowClosed) {
|
||||||
{
|
if (!ShouldWaitForAppResumeEvents()) {
|
||||||
if (m_windowVisible)
|
/* This is the normal way in which events should be pumped.
|
||||||
{
|
* 'ProcessAllIfPresent' will make ProcessEvents() process anywhere
|
||||||
|
* from zero to N events, and will then return.
|
||||||
|
*/
|
||||||
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
|
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
|
||||||
}
|
} else {
|
||||||
else
|
/* This style of event-pumping, with 'ProcessOneAndAllPending',
|
||||||
{
|
* will cause anywhere from one to N events to be processed. If
|
||||||
|
* at least one event is processed, the call will return. If
|
||||||
|
* no events are pending, then the call will wait until one is
|
||||||
|
* available, and will not return (to the caller) until this
|
||||||
|
* happens! This should only occur when the app is hidden.
|
||||||
|
*/
|
||||||
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
|
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -511,8 +557,12 @@ void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEven
|
|||||||
|
|
||||||
if (args->Visible) {
|
if (args->Visible) {
|
||||||
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
|
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
|
||||||
|
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
|
||||||
|
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
|
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
|
||||||
|
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
|
||||||
|
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: Prevent SDL's window-hide handling code, which currently
|
// HACK: Prevent SDL's window-hide handling code, which currently
|
||||||
@ -538,26 +588,6 @@ void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedE
|
|||||||
CoreWindow::GetForCurrentThread()->Activate();
|
CoreWindow::GetForCurrentThread()->Activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event)
|
|
||||||
{
|
|
||||||
if (event->type == SDL_WINDOWEVENT)
|
|
||||||
{
|
|
||||||
switch (event->window.event)
|
|
||||||
{
|
|
||||||
case SDL_WINDOWEVENT_MINIMIZED:
|
|
||||||
case SDL_WINDOWEVENT_RESTORED:
|
|
||||||
// Return 0 to indicate that the event should be removed from the
|
|
||||||
// event queue:
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return 1 to indicate that the event should stay in the event queue:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
|
void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
|
||||||
{
|
{
|
||||||
// Save app state asynchronously after requesting a deferral. Holding a deferral
|
// Save app state asynchronously after requesting a deferral. Holding a deferral
|
||||||
@ -577,24 +607,13 @@ void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ a
|
|||||||
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
|
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
|
||||||
create_task([this, deferral]()
|
create_task([this, deferral]()
|
||||||
{
|
{
|
||||||
// Send a window-minimized event immediately to observers.
|
// Send an app did-enter-background event immediately to observers.
|
||||||
// CoreDispatcher::ProcessEvents, which is the backbone on which
|
// CoreDispatcher::ProcessEvents, which is the backbone on which
|
||||||
// SDL_WinRTApp::PumpEvents is built, will not return to its caller
|
// SDL_WinRTApp::PumpEvents is built, will not return to its caller
|
||||||
// once it sends out a suspend event. Any events posted to SDL's
|
// once it sends out a suspend event. Any events posted to SDL's
|
||||||
// event queue won't get received until the WinRT app is resumed.
|
// event queue won't get received until the WinRT app is resumed.
|
||||||
// SDL_AddEventWatch() may be used to receive app-suspend events on
|
// SDL_AddEventWatch() may be used to receive app-suspend events on
|
||||||
// WinRT.
|
// WinRT.
|
||||||
//
|
|
||||||
// In order to prevent app-suspend events from being received twice:
|
|
||||||
// first via a callback passed to SDL_AddEventWatch, and second via
|
|
||||||
// SDL's event queue, the event will be sent to SDL, then immediately
|
|
||||||
// removed from the queue.
|
|
||||||
if (WINRT_GlobalSDLWindow)
|
|
||||||
{
|
|
||||||
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
|
|
||||||
SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
|
SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
|
||||||
|
|
||||||
deferral->Complete();
|
deferral->Complete();
|
||||||
@ -603,24 +622,11 @@ void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ a
|
|||||||
|
|
||||||
void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
|
void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
|
||||||
{
|
{
|
||||||
|
// Restore any data or state that was unloaded on suspend. By default, data
|
||||||
|
// and state are persisted when resuming from suspend. Note that these events
|
||||||
|
// do not occur if the app was previously terminated.
|
||||||
SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
|
SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
|
||||||
SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
|
SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
|
||||||
|
|
||||||
// Restore any data or state that was unloaded on suspend. By default, data
|
|
||||||
// and state are persisted when resuming from suspend. Note that this event
|
|
||||||
// does not occur if the app was previously terminated.
|
|
||||||
if (WINRT_GlobalSDLWindow)
|
|
||||||
{
|
|
||||||
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
|
|
||||||
|
|
||||||
// Remove the app-resume event from the queue, as is done with the
|
|
||||||
// app-suspend event.
|
|
||||||
//
|
|
||||||
// TODO, WinRT: consider posting this event to the queue even though
|
|
||||||
// its counterpart, the app-suspend event, effectively has to be
|
|
||||||
// processed immediately.
|
|
||||||
SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
|
void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
|
||||||
|
@ -39,6 +39,8 @@ internal:
|
|||||||
void PumpEvents();
|
void PumpEvents();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool ShouldWaitForAppResumeEvents();
|
||||||
|
|
||||||
// Event Handlers.
|
// Event Handlers.
|
||||||
|
|
||||||
#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps)
|
#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps)
|
||||||
|
Loading…
Reference in New Issue
Block a user