x11: Don't move the window when restoring and ensure that resize and position events are sent when entering or leaving fullscreen

Account for the border sizes when restoring the window and only turn off resize events when entering or leaving fullscreen until the frame extents are changed, and only if they are, or previously were, non-zero.

This necessitated further refinement to the sync algorithm as well, but as a result, the sync function no longer occasionally times out if creating a window and immediately recreating it when initializing a renderer, and some rare, spurious size and position failures in the centered window and state automated tests seem to be fixed.
main
Frank Praznik 2023-12-16 19:13:31 -05:00
parent 08a7ca4d53
commit 1745289b1b
3 changed files with 72 additions and 57 deletions

View File

@ -1326,36 +1326,36 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
if (xevent->xconfigure.x != data->last_xconfigure.x ||
xevent->xconfigure.y != data->last_xconfigure.y) {
SDL_Window *w;
int x = xevent->xconfigure.x;
int y = xevent->xconfigure.y;
if (!data->disable_size_position_events) {
SDL_Window *w;
int x = xevent->xconfigure.x;
int y = xevent->xconfigure.y;
data->pending_operation &= ~X11_PENDING_OP_MOVE;
SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
data->pending_operation &= ~X11_PENDING_OP_MOVE;
SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
#ifdef SDL_USE_IME
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
/* Update IME candidate list position */
SDL_IME_UpdateTextRect(NULL);
}
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
/* Update IME candidate list position */
SDL_IME_UpdateTextRect(NULL);
}
#endif
for (w = data->window->first_child; w; w = w->next_sibling) {
/* Don't update hidden child windows, their relative position doesn't change */
if (!(w->flags & SDL_WINDOW_HIDDEN)) {
X11_UpdateWindowPosition(w, SDL_TRUE);
for (w = data->window->first_child; w; w = w->next_sibling) {
/* Don't update hidden child windows, their relative position doesn't change */
if (!(w->flags & SDL_WINDOW_HIDDEN)) {
X11_UpdateWindowPosition(w, SDL_TRUE);
}
}
}
}
if (xevent->xconfigure.width != data->last_xconfigure.width ||
xevent->xconfigure.height != data->last_xconfigure.height) {
if (!data->skip_size_count) {
if (!data->disable_size_position_events) {
data->pending_operation &= ~X11_PENDING_OP_RESIZE;
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED,
xevent->xconfigure.width,
xevent->xconfigure.height);
} else {
data->skip_size_count--;
}
}
@ -1653,9 +1653,28 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
SDL_UpdateFullscreenMode(data->window, SDL_FALSE, SDL_TRUE);
}
if (!(data->window->flags & SDL_WINDOW_BORDERLESS)) {
/* Skip the first resize event if the borders are being turned on/off. */
data->skip_size_count = 1;
if ((flags & SDL_WINDOW_FULLSCREEN) &&
(data->border_top || data->border_left || data->border_bottom || data->border_right)) {
/* If the window is entering fullscreen and the borders are
* non-zero sized, turn off size events until the borders are
* shut off to avoid bogus window sizes and positions, and
* note that the old borders were non-zero for restoration.
*/
data->disable_size_position_events = SDL_TRUE;
data->previous_borders_nonzero = SDL_TRUE;
} else if (!(flags & SDL_WINDOW_FULLSCREEN) &&
data->previous_borders_nonzero &&
(!data->border_top && !data->border_left && !data->border_bottom && !data->border_right)) {
/* If the window is leaving fullscreen and the current borders
* are zero sized, but weren't when entering fullscreen, turn
* off size events until the borders come back to avoid bogus
* window sizes and positions.
*/
data->disable_size_position_events = SDL_TRUE;
data->previous_borders_nonzero = SDL_FALSE;
} else {
data->disable_size_position_events = SDL_FALSE;
data->previous_borders_nonzero = SDL_FALSE;
}
}
if ((changed & SDL_WINDOW_MAXIMIZED) && ((flags & SDL_WINDOW_MAXIMIZED) && !(flags & SDL_WINDOW_MINIMIZED))) {
@ -1678,11 +1697,11 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
/* Restore the last known floating state if leaving maximized mode */
if (!(flags & SDL_WINDOW_FULLSCREEN)) {
data->pending_operation |= X11_PENDING_OP_MOVE | X11_PENDING_OP_RESIZE;
data->expected.x = data->window->floating.x;
data->expected.y = data->window->floating.y;
data->expected.x = data->window->floating.x - data->border_left;
data->expected.y = data->window->floating.y - data->border_top;
data->expected.w = data->window->floating.w;
data->expected.h = data->window->floating.h;
X11_XMoveWindow(display, data->xwindow, data->window->floating.x, data->window->floating.y);
X11_XMoveWindow(display, data->xwindow, data->window->floating.x - data->border_left, data->window->floating.y - data->border_top);
X11_XResizeWindow(display, data->xwindow, data->window->floating.w, data->window->floating.h);
}
}
@ -1699,18 +1718,23 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
right approach, but it seems to work. */
X11_UpdateKeymap(_this, SDL_TRUE);
} else if (xevent->xproperty.atom == videodata->_NET_FRAME_EXTENTS) {
/* Re-enable size events if they were turned off waiting for the borders to come back
* when leaving fullscreen.
*/
data->disable_size_position_events = SDL_FALSE;
X11_GetBorderValues(data);
if (data->border_top != 0 || data->border_left != 0 || data->border_right != 0 || data->border_bottom != 0) {
/* Adjust if the window size changed to accommodate the borders. */
/* Adjust if the window size/position changed to accommodate the borders. */
if (data->window->flags & SDL_WINDOW_MAXIMIZED) {
data->pending_operation |= X11_PENDING_OP_RESIZE;
data->expected.w = data->window->windowed.w;
data->expected.h = data->window->windowed.h;
X11_XResizeWindow(display, data->xwindow, data->window->windowed.w, data->window->windowed.h);
} else {
data->pending_operation |= X11_PENDING_OP_RESIZE;
data->pending_operation |= X11_PENDING_OP_RESIZE | X11_PENDING_OP_MOVE;
data->expected.w = data->window->floating.w;
data->expected.h = data->window->floating.h;
X11_XMoveWindow(display, data->xwindow, data->window->floating.x - data->border_left, data->window->floating.y - data->border_top);
X11_XResizeWindow(display, data->xwindow, data->window->floating.w, data->window->floating.h);
}
}

View File

@ -856,6 +856,7 @@ static int X11_SyncWindowTimeout(SDL_VideoDevice *_this, SDL_Window *window, int
int (*prev_handler)(Display *, XErrorEvent *);
Uint64 timeout = 0;
int ret = 0;
SDL_bool force_exit = SDL_FALSE;
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
@ -868,11 +869,25 @@ static int X11_SyncWindowTimeout(SDL_VideoDevice *_this, SDL_Window *window, int
X11_XSync(display, False);
X11_PumpEvents(_this);
if ((!(data->pending_operation & X11_PENDING_OP_MOVE) || (window->x == data->expected.x && window->y == data->expected.y)) &&
(!(data->pending_operation & X11_PENDING_OP_RESIZE) || (window->w == data->expected.w && window->h == data->expected.h)) &&
(data->pending_operation & ~(X11_PENDING_OP_MOVE | X11_PENDING_OP_RESIZE)) == X11_PENDING_OP_NONE) {
/* The window is where it is wanted and nothing is pending. Done. */
break;
if ((data->pending_operation & X11_PENDING_OP_MOVE) && (window->x == data->expected.x && window->y == data->expected.y)) {
data->pending_operation &= ~X11_PENDING_OP_MOVE;
}
if ((data->pending_operation & X11_PENDING_OP_RESIZE) && (window->w == data->expected.w && window->h == data->expected.h)) {
data->pending_operation &= ~X11_PENDING_OP_RESIZE;
}
if (data->pending_operation == X11_PENDING_OP_NONE) {
if (force_exit ||
(window->x == data->expected.x && window->y == data->expected.y &&
window->w == data->expected.w && window->h == data->expected.h)) {
/* The window is in the expected state and nothing is pending. Done. */
break;
}
/* No operations are pending, but the window still isn't in the expected state.
* Try one more time before exiting.
*/
force_exit = SDL_TRUE;
}
if (SDL_GetTicks() >= timeout) {
@ -1310,15 +1325,9 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
}
/* Get some valid border values, if we haven't them yet */
/* Get some valid border values, if we haven't received them yet */
if (data->border_left == 0 && data->border_right == 0 && data->border_top == 0 && data->border_bottom == 0) {
X11_GetBorderValues(data);
if (!data->initial_border_adjustment) {
data->expected.x += data->border_left;
data->expected.y += data->border_top;
data->initial_border_adjustment = SDL_TRUE;
}
}
}
@ -1591,24 +1600,6 @@ static int X11_SetWindowFullscreenViaWM(SDL_VideoDevice *_this, SDL_Window *wind
e.xclient.data.l[3] = 0l;
X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
SubstructureNotifyMask | SubstructureRedirectMask, &e);
if (!data->window_was_maximized) {
/* Attempt to move the window back to where it was. */
SDL_RelativeToGlobalForWindow(window,
window->floating.x - data->border_left, window->floating.y - data->border_top,
&data->expected.x, &data->expected.y);
data->expected.w = window->floating.w;
data->expected.h = window->floating.h;
data->pending_operation |= X11_PENDING_OP_MOVE;
X11_XMoveWindow(display, data->xwindow, data->expected.x, data->expected.y);
/* If the window is bordered, the size will be set when the borders turn themselves back on. */
if (window->flags & SDL_WINDOW_BORDERLESS) {
data->pending_operation |= X11_PENDING_OP_RESIZE;
X11_XResizeWindow(display, data->xwindow, data->expected.w, data->expected.h);
}
}
}
} else {
Uint32 flags;

View File

@ -93,9 +93,9 @@ struct SDL_WindowData
X11_PENDING_OP_RESIZE = 0x20
} pending_operation;
SDL_bool initial_border_adjustment;
SDL_bool window_was_maximized;
int skip_size_count;
SDL_bool disable_size_position_events;
SDL_bool previous_borders_nonzero;
SDL_HitTestResult hit_test_result;
};