Skip to content

Commit

Permalink
Allow the application to draw while Windows is in a modal move/resize…
Browse files Browse the repository at this point in the history
… loop

If you're using the application main callbacks, your SDL_AppIterate() function will be called while Windows is moving and resizing your window. If not, then SDL will send an SDL_EVENT_WINDOW_EXPOSED event for your window and you can use an event watcher to redraw your window directly from the callback.

Fixes #1059
Closes #4836
  • Loading branch information
slouken committed Nov 8, 2023
1 parent 1934417 commit 02f3564
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 9 deletions.
24 changes: 18 additions & 6 deletions src/main/SDL_main_callbacks.c
Expand Up @@ -80,6 +80,14 @@ static int SDLCALL SDL_MainCallbackEventWatcher(void *userdata, SDL_Event *event
return 0;
}

SDL_bool SDL_HasMainCallbacks()
{
if (SDL_main_iteration_callback) {
return SDL_TRUE;
}
return SDL_FALSE;
}

int SDL_InitMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
SDL_main_iteration_callback = appiter;
Expand All @@ -104,16 +112,20 @@ int SDL_InitMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_
return SDL_AtomicGet(&apprc);
}

int SDL_IterateMainCallbacks(void)
int SDL_IterateMainCallbacks(SDL_bool pump_events)
{
SDL_PumpEvents();
if (pump_events) {
SDL_PumpEvents();
}
SDL_DispatchMainCallbackEvents();

int rc = SDL_main_iteration_callback();
if (!SDL_AtomicCAS(&apprc, 0, rc)) {
rc = SDL_AtomicGet(&apprc); // something else already set a quit result, keep that.
int rc = SDL_AtomicGet(&apprc);
if (rc == 0) {
rc = SDL_main_iteration_callback();
if (!SDL_AtomicCAS(&apprc, 0, rc)) {
rc = SDL_AtomicGet(&apprc); // something else already set a quit result, keep that.
}
}

return rc;
}

Expand Down
5 changes: 3 additions & 2 deletions src/main/SDL_main_callbacks.h
Expand Up @@ -22,8 +22,9 @@
#ifndef SDL_main_callbacks_h_
#define SDL_main_callbacks_h_

int SDL_InitMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func _appiter, SDL_AppEvent_func _appevent, SDL_AppQuit_func _appquit);
int SDL_IterateMainCallbacks(void);
SDL_bool SDL_HasMainCallbacks();
int SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func _appiter, SDL_AppEvent_func _appevent, SDL_AppQuit_func _appquit);
int SDL_IterateMainCallbacks(SDL_bool pump_events);
void SDL_QuitMainCallbacks(void);

#endif // SDL_main_callbacks_h_
Expand Down
2 changes: 1 addition & 1 deletion src/main/generic/SDL_sysmain_callbacks.c
Expand Up @@ -45,7 +45,7 @@ int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit,

Uint64 next_iteration = callback_rate_increment ? (SDL_GetTicksNS() + callback_rate_increment) : 0;

while ((rc = SDL_IterateMainCallbacks()) == 0) {
while ((rc = SDL_IterateMainCallbacks(SDL_TRUE)) == 0) {
// !!! FIXME: this can be made more complicated if we decide to
// !!! FIXME: optionally hand off callback responsibility to the
// !!! FIXME: video subsystem (for example, if Wayland has a
Expand Down
30 changes: 30 additions & 0 deletions src/video/windows/SDL_windowsevents.c
Expand Up @@ -28,6 +28,7 @@
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_touch_c.h"
#include "../../events/scancodes_windows.h"
#include "../../main/SDL_main_callbacks.h"

/* Dropfile support */
#include <shellapi.h>
Expand Down Expand Up @@ -106,6 +107,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

/* Used to compare Windows message timestamps */
#define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0)

Expand Down Expand Up @@ -1283,6 +1288,31 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
} break;

case WM_ENTERSIZEMOVE:
case WM_ENTERMENULOOP:
{
SetTimer(hwnd, (UINT_PTR)SDL_IterateMainCallbacks, USER_TIMER_MINIMUM, NULL);
} break;

case WM_TIMER:
{
if (wParam == (UINT_PTR)SDL_IterateMainCallbacks) {
if (SDL_HasMainCallbacks()) {
SDL_IterateMainCallbacks(SDL_FALSE);
} else {
// Send an expose event so the application can redraw
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_EXPOSED, 0, 0);
}
return 0;
}
} break;

case WM_EXITSIZEMOVE:
case WM_EXITMENULOOP:
{
KillTimer(hwnd, (UINT_PTR)SDL_IterateMainCallbacks);
} break;

case WM_SIZE:
{
switch (wParam) {
Expand Down

0 comments on commit 02f3564

Please sign in to comment.