src/core/winrt/SDL_winrtapp_direct3d.cpp
changeset 8666 20d52dc1a24a
parent 8665 b987c561c218
child 8678 7149b02f106b
     1.1 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp	Sun Mar 23 08:56:52 2014 -0400
     1.2 +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp	Sun Mar 23 11:04:47 2014 -0400
     1.3 @@ -418,16 +418,62 @@
     1.4      }
     1.5  }
     1.6  
     1.7 +static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)
     1.8 +{
     1.9 +    SDL_Event events[128];
    1.10 +    const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
    1.11 +    for (int i = 0; i < count; ++i) {
    1.12 +        if (events[i].window.event == windowEventID) {
    1.13 +            return true;
    1.14 +        }
    1.15 +    }
    1.16 +    return false;
    1.17 +}
    1.18 +
    1.19 +bool SDL_WinRTApp::ShouldWaitForAppResumeEvents()
    1.20 +{
    1.21 +    /* Don't wait if the app is visible: */
    1.22 +    if (m_windowVisible) {
    1.23 +        return false;
    1.24 +    }
    1.25 +    
    1.26 +    /* Don't wait until the window-hide events finish processing.
    1.27 +     * Do note that if an app-suspend event is sent (as indicated
    1.28 +     * by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND
    1.29 +     * events), then this code may be a moot point, as WinRT's
    1.30 +     * own event pump (aka ProcessEvents()) will pause regardless
    1.31 +     * of what we do here.  This happens on Windows Phone 8, to note.
    1.32 +     * Windows 8.x apps, on the other hand, may get a chance to run
    1.33 +     * these.
    1.34 +     */
    1.35 +    if (IsSDLWindowEventPending(SDL_WINDOWEVENT_HIDDEN)) {
    1.36 +        return false;
    1.37 +    } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_FOCUS_LOST)) {
    1.38 +        return false;
    1.39 +    } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_MINIMIZED)) {
    1.40 +        return false;
    1.41 +    }
    1.42 +
    1.43 +    return true;
    1.44 +}
    1.45 +
    1.46  void SDL_WinRTApp::PumpEvents()
    1.47  {
    1.48 -    if (!m_windowClosed)
    1.49 -    {
    1.50 -        if (m_windowVisible)
    1.51 -        {
    1.52 +    if (!m_windowClosed) {
    1.53 +        if (!ShouldWaitForAppResumeEvents()) {
    1.54 +            /* This is the normal way in which events should be pumped.
    1.55 +             * 'ProcessAllIfPresent' will make ProcessEvents() process anywhere
    1.56 +             * from zero to N events, and will then return.
    1.57 +             */
    1.58              CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
    1.59 -        }
    1.60 -        else
    1.61 -        {
    1.62 +        } else {
    1.63 +            /* This style of event-pumping, with 'ProcessOneAndAllPending',
    1.64 +             * will cause anywhere from one to N events to be processed.  If
    1.65 +             * at least one event is processed, the call will return.  If
    1.66 +             * no events are pending, then the call will wait until one is
    1.67 +             * available, and will not return (to the caller) until this
    1.68 +             * happens!  This should only occur when the app is hidden.
    1.69 +             */
    1.70              CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
    1.71          }
    1.72      }
    1.73 @@ -511,8 +557,12 @@
    1.74  
    1.75          if (args->Visible) {
    1.76              SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
    1.77 +            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
    1.78 +            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0);
    1.79          } else {
    1.80              SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
    1.81 +            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
    1.82 +            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    1.83          }
    1.84  
    1.85          // HACK: Prevent SDL's window-hide handling code, which currently
    1.86 @@ -538,26 +588,6 @@
    1.87      CoreWindow::GetForCurrentThread()->Activate();
    1.88  }
    1.89  
    1.90 -static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event)
    1.91 -{
    1.92 -    if (event->type == SDL_WINDOWEVENT)
    1.93 -    {
    1.94 -        switch (event->window.event)
    1.95 -        {
    1.96 -            case SDL_WINDOWEVENT_MINIMIZED:
    1.97 -            case SDL_WINDOWEVENT_RESTORED:
    1.98 -                // Return 0 to indicate that the event should be removed from the
    1.99 -                // event queue:
   1.100 -                return 0;
   1.101 -            default:
   1.102 -                break;
   1.103 -        }
   1.104 -    }
   1.105 -
   1.106 -    // Return 1 to indicate that the event should stay in the event queue:
   1.107 -    return 1;
   1.108 -}
   1.109 -
   1.110  void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
   1.111  {
   1.112      // Save app state asynchronously after requesting a deferral. Holding a deferral
   1.113 @@ -577,24 +607,13 @@
   1.114      SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
   1.115      create_task([this, deferral]()
   1.116      {
   1.117 -        // Send a window-minimized event immediately to observers.
   1.118 +        // Send an app did-enter-background event immediately to observers.
   1.119          // CoreDispatcher::ProcessEvents, which is the backbone on which
   1.120          // SDL_WinRTApp::PumpEvents is built, will not return to its caller
   1.121          // once it sends out a suspend event.  Any events posted to SDL's
   1.122          // event queue won't get received until the WinRT app is resumed.
   1.123          // SDL_AddEventWatch() may be used to receive app-suspend events on
   1.124          // WinRT.
   1.125 -        //
   1.126 -        // In order to prevent app-suspend events from being received twice:
   1.127 -        // first via a callback passed to SDL_AddEventWatch, and second via
   1.128 -        // SDL's event queue, the event will be sent to SDL, then immediately
   1.129 -        // removed from the queue.
   1.130 -        if (WINRT_GlobalSDLWindow)
   1.131 -        {
   1.132 -            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0);   // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
   1.133 -            SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
   1.134 -        }
   1.135 -
   1.136          SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
   1.137  
   1.138          deferral->Complete();
   1.139 @@ -603,24 +622,11 @@
   1.140  
   1.141  void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
   1.142  {
   1.143 +    // Restore any data or state that was unloaded on suspend. By default, data
   1.144 +    // and state are persisted when resuming from suspend. Note that these events
   1.145 +    // do not occur if the app was previously terminated.
   1.146      SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
   1.147      SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
   1.148 -
   1.149 -    // Restore any data or state that was unloaded on suspend. By default, data
   1.150 -    // and state are persisted when resuming from suspend. Note that this event
   1.151 -    // does not occur if the app was previously terminated.
   1.152 -    if (WINRT_GlobalSDLWindow)
   1.153 -    {
   1.154 -        SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0);    // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
   1.155 -
   1.156 -        // Remove the app-resume event from the queue, as is done with the
   1.157 -        // app-suspend event.
   1.158 -        //
   1.159 -        // TODO, WinRT: consider posting this event to the queue even though
   1.160 -        // its counterpart, the app-suspend event, effectively has to be
   1.161 -        // processed immediately.
   1.162 -        SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
   1.163 -    }
   1.164  }
   1.165  
   1.166  void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)