Prechádzať zdrojové kódy

x11: Handle size/position events arriving before state events

Xfce, unlike every other window manager in existence, sends ConfigureNotify events before PropertyNotify events when toggling the fullscreen and maximized window state. Check the window state when handling ConfigureNotify events, and defer emitting SDL size/position events until the corresponding PropertyNotify event arrives, since SDL and clients expect to get the window state before the new size and position.

(cherry picked from commit 11a3296a42594da107ef3913c6bb6df8b1d63f4d)
Frank Praznik 4 mesiacov pred
rodič
commit
3b4472ecf7
2 zmenil súbory, kde vykonal 54 pridanie a 32 odobranie
  1. 52 32
      src/video/x11/SDL_x11events.c
  2. 2 0
      src/video/x11/SDL_x11window.h

+ 52 - 32
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;
-
-                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);
+        /* 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;
+        }
 
-                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);

+ 2 - 0
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;