diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 764bfa8e97..26f5e060a5 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -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); } } diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 5a2de89d94..24aa08c090 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -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; diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 11977a57b9..01fd049995 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -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; };