Browse Source

Allow the application to draw while Windows is in a modal move/resize loop

SDL will send an SDL_EVENT_WINDOW_EXPOSED event for your window during the modal interaction and you can use an event watcher to redraw your window directly from the callback.

Fixes https://github.com/libsdl-org/SDL/issues/1059
Closes https://github.com/libsdl-org/SDL/pull/4836
Sam Lantinga 1 year ago
parent
commit
509c70c698
2 changed files with 52 additions and 7 deletions
  1. 26 0
      src/video/windows/SDL_windowsevents.c
  2. 26 7
      test/testsprite2.c

+ 26 - 0
src/video/windows/SDL_windowsevents.c

@@ -110,6 +110,10 @@
 #define IS_SURROGATE_PAIR(h, l) (IS_HIGH_SURROGATE(h) && IS_LOW_SURROGATE(l))
 #endif
 
+#ifndef USER_TIMER_MINIMUM
+#define USER_TIMER_MINIMUM 0x0000000A
+#endif
+
 static SDL_Scancode VKeytoScancodeFallback(WPARAM vkey)
 {
     switch (vkey) {
@@ -675,6 +679,7 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
 LRESULT CALLBACK
 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
+    static SDL_bool s_ModalMoveResizeLoop;
     SDL_WindowData *data;
     LRESULT returnCode = -1;
 
@@ -1253,6 +1258,27 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         }
     } break;
 
+    case WM_ENTERSIZEMOVE:
+    case WM_ENTERMENULOOP:
+    {
+        SetTimer(hwnd, (UINT_PTR)&s_ModalMoveResizeLoop, USER_TIMER_MINIMUM, NULL);
+    } break;
+
+    case WM_TIMER:
+    {
+        if (wParam == (UINT_PTR)&s_ModalMoveResizeLoop) {
+            // Send an expose event so the application can redraw
+            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
+            return 0;
+        }
+    } break;
+
+    case WM_EXITSIZEMOVE:
+    case WM_EXITMENULOOP:
+    {
+        KillTimer(hwnd, (UINT_PTR)&s_ModalMoveResizeLoop);
+    } break;
+
     case WM_SIZE:
     {
         switch (wParam) {

+ 26 - 7
test/testsprite2.c

@@ -392,22 +392,30 @@ void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite)
     SDL_RenderPresent(renderer);
 }
 
-void loop()
+static void MoveAllSprites()
 {
-    Uint32 now;
     int i;
-    SDL_Event event;
 
-    /* Check for events */
-    while (SDL_PollEvent(&event)) {
-        SDLTest_CommonEvent(state, &event, &done);
-    }
     for (i = 0; i < state->num_windows; ++i) {
         if (state->windows[i] == NULL) {
             continue;
         }
         MoveSprites(state->renderers[i], sprites[i]);
     }
+}
+
+void loop()
+{
+    Uint32 now;
+    SDL_Event event;
+
+    /* Check for events */
+    while (SDL_PollEvent(&event)) {
+        SDLTest_CommonEvent(state, &event, &done);
+    }
+
+    MoveAllSprites();
+
 #ifdef __EMSCRIPTEN__
     if (done) {
         emscripten_cancel_main_loop();
@@ -426,6 +434,14 @@ void loop()
     }
 }
 
+static int SDLCALL ExposeEventWatcher(void *userdata, SDL_Event *event)
+{
+    if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_EXPOSED) {
+        MoveAllSprites();
+    }
+    return 0;
+}
+
 int main(int argc, char *argv[])
 {
     int i;
@@ -568,6 +584,9 @@ int main(int argc, char *argv[])
         }
     }
 
+    /* Add an event watcher to redraw from within modal window resize/move loops */
+    SDL_AddEventWatch(ExposeEventWatcher, NULL);
+
     /* Main render loop */
     frames = 0;
     next_fps_check = SDL_GetTicks() + fps_check_delay;