diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 8f0ecc9b1d..dcc6c878c6 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -1108,6 +1108,41 @@ void X11_GetBorderValues(SDL_WindowData *data) } } +void X11_EmitConfigureNotifyEvents(SDL_WindowData *data, XConfigureEvent *xevent) +{ + if (xevent->x != data->last_xconfigure.x || + xevent->y != data->last_xconfigure.y) { + if (!data->size_move_event_flags) { + SDL_Window *w; + int x = xevent->x; + int y = xevent->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); + + for (w = data->window->first_child; w; w = w->next_sibling) { + // Don't update hidden child popup windows, their relative position doesn't change + if (SDL_WINDOW_IS_POPUP(w) && !(w->flags & SDL_WINDOW_HIDDEN)) { + X11_UpdateWindowPosition(w, true); + } + } + } + } + + if (xevent->width != data->last_xconfigure.width || + xevent->height != data->last_xconfigure.height) { + if (!data->size_move_event_flags) { + data->pending_operation &= ~X11_PENDING_OP_RESIZE; + SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED, + xevent->width, + xevent->height); + } + } + + SDL_copyp(&data->last_xconfigure, xevent); +} + static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) { SDL_VideoData *videodata = _this->internal; @@ -1459,9 +1494,8 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) xevent->xconfigure.x, xevent->xconfigure.y, xevent->xconfigure.width, xevent->xconfigure.height); #endif - // Real configure notify events are relative to the parent, synthetic events are absolute. - if (!xevent->xconfigure.send_event) - { + // Real configure notify events are relative to the parent, synthetic events are absolute. + if (!xevent->xconfigure.send_event) { unsigned int NumChildren; Window ChildReturn, Root, Parent; Window *Children; @@ -1474,41 +1508,23 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) &ChildReturn); } - if (xevent->xconfigure.x != data->last_xconfigure.x || - xevent->xconfigure.y != data->last_xconfigure.y) { - if (!data->size_move_event_flags) { - SDL_Window *w; - int x = xevent->xconfigure.x; - int y = xevent->xconfigure.y; + /* Xfce sends ConfigureNotify before PropertyNotify when toggling fullscreen and maximized, which + * is backwards from every other window manager, as well as what is expected by SDL and its clients. + * Defer emitting the size/move events until the corresponding PropertyNotify arrives. + */ + const Uint32 changed = X11_GetNetWMState(_this, data->window, xevent->xproperty.window) ^ data->window->flags; + if (changed & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) { + SDL_copyp(&data->pending_xconfigure, &xevent->xconfigure); + data->emit_size_move_after_property_notify = true; + } - 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); - - for (w = data->window->first_child; w; w = w->next_sibling) { - // Don't update hidden child popup windows, their relative position doesn't change - if (SDL_WINDOW_IS_POPUP(w) && !(w->flags & SDL_WINDOW_HIDDEN)) { - X11_UpdateWindowPosition(w, true); - } - } - } + if (!data->emit_size_move_after_property_notify) { + X11_EmitConfigureNotifyEvents(data, &xevent->xconfigure); } #ifdef SDL_VIDEO_DRIVER_X11_XSYNC X11_HandleConfigure(data->window, &xevent->xconfigure); #endif /* SDL_VIDEO_DRIVER_X11_XSYNC */ - - if (xevent->xconfigure.width != data->last_xconfigure.width || - xevent->xconfigure.height != data->last_xconfigure.height) { - if (!data->size_move_event_flags) { - data->pending_operation &= ~X11_PENDING_OP_RESIZE; - SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED, - xevent->xconfigure.width, - xevent->xconfigure.height); - } - } - - data->last_xconfigure = xevent->xconfigure; } break; // Have we been requested to quit (or another client message?) @@ -1906,6 +1922,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) } } } + if (data->emit_size_move_after_property_notify) { + X11_EmitConfigureNotifyEvents(data, &data->pending_xconfigure); + data->emit_size_move_after_property_notify = false; + } if ((flags & SDL_WINDOW_INPUT_FOCUS)) { if (data->pending_move) { DispatchWindowMove(_this, data, &data->pending_move_point); diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 2d7b3239d3..ce90ed3061 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -68,6 +68,7 @@ struct SDL_WindowData bool pending_move; SDL_Point pending_move_point; XConfigureEvent last_xconfigure; + XConfigureEvent pending_xconfigure; struct SDL_VideoData *videodata; unsigned long user_time; Atom xdnd_req; @@ -116,6 +117,7 @@ struct SDL_WindowData bool toggle_borders; bool fullscreen_borders_forced_on; bool was_shown; + bool emit_size_move_after_property_notify; SDL_HitTestResult hit_test_result; XPoint xim_spot;