x11: Wait for mode switches to complete when synchronizing a window

Otherwise, the sync can timeout due to mode switching taking several seconds.
main
Frank Praznik 2024-04-17 10:40:36 -04:00
parent e632ed23ad
commit bed6c5b81f
2 changed files with 17 additions and 5 deletions

View File

@ -921,7 +921,7 @@ int X11_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SD
viddata->last_mode_change_deadline = SDL_GetTicks() + (PENDING_FOCUS_TIME * 2); viddata->last_mode_change_deadline = SDL_GetTicks() + (PENDING_FOCUS_TIME * 2);
if (mode != &sdl_display->desktop_mode) { if (sdl_display->current_mode != mode) {
data->mode_switch_deadline_ns = SDL_GetTicksNS() + MODE_SWITCH_TIMEOUT_NS; data->mode_switch_deadline_ns = SDL_GetTicksNS() + MODE_SWITCH_TIMEOUT_NS;
} else { } else {
data->mode_switch_deadline_ns = 0; data->mode_switch_deadline_ns = 0;

View File

@ -875,7 +875,7 @@ static int X11_CatchAnyError(Display *d, XErrorEvent *e)
/* Wait a brief time, or not, to see if the window manager decided to move/resize the window. /* Wait a brief time, or not, to see if the window manager decided to move/resize the window.
* Send MOVED and RESIZED window events */ * Send MOVED and RESIZED window events */
static int X11_SyncWindowTimeout(SDL_VideoDevice *_this, SDL_Window *window, int param_timeout) static int X11_SyncWindowTimeout(SDL_VideoDevice *_this, SDL_Window *window, Uint64 param_timeout)
{ {
SDL_WindowData *data = window->driverdata; SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display; Display *display = data->videodata->display;
@ -888,7 +888,7 @@ static int X11_SyncWindowTimeout(SDL_VideoDevice *_this, SDL_Window *window, int
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError); prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
if (param_timeout) { if (param_timeout) {
timeout = SDL_GetTicks() + param_timeout; timeout = SDL_GetTicksNS() + param_timeout;
} }
while (SDL_TRUE) { while (SDL_TRUE) {
@ -916,7 +916,7 @@ static int X11_SyncWindowTimeout(SDL_VideoDevice *_this, SDL_Window *window, int
force_exit = SDL_TRUE; force_exit = SDL_TRUE;
} }
if (SDL_GetTicks() >= timeout) { if (SDL_GetTicksNS() >= timeout) {
/* Timed out without the expected values. Update the requested data so future sync calls won't block. */ /* Timed out without the expected values. Update the requested data so future sync calls won't block. */
data->expected.x = window->x; data->expected.x = window->x;
data->expected.y = window->y; data->expected.y = window->y;
@ -2024,10 +2024,22 @@ void X11_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
int X11_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window) int X11_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window)
{ {
const Uint64 current_time = SDL_GetTicksNS();
Uint64 timeout = 0;
/* Allow time for any pending mode switches to complete. */
for (int i = 0; i < _this->num_displays; ++i) {
if (_this->displays[i]->driverdata->mode_switch_deadline_ns &&
current_time < _this->displays[i]->driverdata->mode_switch_deadline_ns) {
timeout = SDL_max(_this->displays[i]->driverdata->mode_switch_deadline_ns - current_time, timeout);
}
}
/* 100ms is fine for most cases, but, for some reason, maximizing /* 100ms is fine for most cases, but, for some reason, maximizing
* a window can take a very long time. * a window can take a very long time.
*/ */
const int timeout = window->driverdata->pending_operation & SDL_WINDOW_MAXIMIZED ? 1000 : 100; timeout += window->driverdata->pending_operation & X11_PENDING_OP_MAXIMIZE ? SDL_MS_TO_NS(1000) : SDL_MS_TO_NS(100);
return X11_SyncWindowTimeout(_this, window, timeout); return X11_SyncWindowTimeout(_this, window, timeout);
} }