From 509c70c6982b6927f5a8d4fb32f9319cbaf0c2ef Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 8 Nov 2023 14:01:00 -0800
Subject: [PATCH] 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
---
src/video/windows/SDL_windowsevents.c | 26 +++++++++++++++++++++
test/testsprite2.c | 33 +++++++++++++++++++++------
2 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 180c1a8eb8d5..66aa8b0b3b64 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/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) {
diff --git a/test/testsprite2.c b/test/testsprite2.c
index 89037fd09c55..01c614883435 100644
--- a/test/testsprite2.c
+++ b/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;