Fix logic for figuring out what ConfigureNotify positions can be trusted
authorOwen W. Taylor <otaylor@fishsoup.net>
Mon, 17 Oct 2011 21:27:43 +0000 (17:27 -0400)
committerDmitry Shachnev <mitya57@debian.org>
Fri, 12 Apr 2019 20:10:28 +0000 (21:10 +0100)
When reading ahead in the queue for ConfigureNotify events, it's necessary
to look for intermediate ReparentNotify events as well, since they will
determine whether the position in the event can be trusted or not.

Bug: https://bugreports.qt.nokia.com/browse/QTBUG-21900

Gbp-Pq: Name QTBUG-21900_Buttons_in_Qt_applications_not_clickable_when_run_under_gnome-shell.patch

src/gui/kernel/qapplication_x11.cpp

index 400b99d440654e72032c82c6aedafb1fa376b24a..2e666ce83b1da8fa1d0f5a0ec391d685bafaf720 100644 (file)
@@ -819,6 +819,27 @@ static Bool qt_sync_request_scanner(Display*, XEvent *event, XPointer arg)
 #endif
 #endif // QT_NO_XSYNC
 
+struct qt_configure_event_data
+{
+    WId window;
+    WId parent;
+};
+
+static Bool qt_configure_event_scanner(Display*, XEvent *event, XPointer arg)
+{
+    qt_configure_event_data *data =
+        reinterpret_cast<qt_configure_event_data*>(arg);
+    if (event->type == ConfigureNotify &&
+        event->xconfigure.window == data->window) {
+        return true;
+    } else if (event->type == ReparentNotify &&
+               event->xreparent.window == data->window) {
+        data->parent = event->xreparent.parent;
+    }
+
+    return false;
+}
+
 static void qt_x11_create_intern_atoms()
 {
     const char *names[QX11Data::NAtoms];
@@ -5310,8 +5331,11 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
         if (d->extra->compress_events) {
             // ConfigureNotify compression for faster opaque resizing
             XEvent otherEvent;
-            while (XCheckTypedWindowEvent(X11->display, internalWinId(), ConfigureNotify,
-                                          &otherEvent)) {
+            qt_configure_event_data configureData;
+            configureData.window = internalWinId();
+            configureData.parent = d->topData()->parentWinId;
+            while (XCheckIfEvent(X11->display, &otherEvent,
+                                 &qt_configure_event_scanner, (XPointer)&configureData)) {
                 if (qt_x11EventFilter(&otherEvent))
                     continue;
 
@@ -5324,13 +5348,19 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
                 newSize.setWidth(otherEvent.xconfigure.width);
                 newSize.setHeight(otherEvent.xconfigure.height);
 
+                trust = isVisible()
+                        && (configureData.parent == XNone ||
+                            configureData.parent == QX11Info::appRootWindow());
+
                 if (otherEvent.xconfigure.send_event || trust) {
                     newCPos.rx() = otherEvent.xconfigure.x +
                                    otherEvent.xconfigure.border_width;
                     newCPos.ry() = otherEvent.xconfigure.y +
                                    otherEvent.xconfigure.border_width;
                     isCPos = true;
-                }
+                } else {
+                    isCPos = false;
+               }
             }
 #ifndef QT_NO_XSYNC
             qt_sync_request_event_data sync_event;
@@ -5343,9 +5373,14 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
         }
 
         if (!isCPos) {
-            // we didn't get an updated position of the toplevel.
-            // either we haven't moved or there is a bug in the window manager.
-            // anyway, let's query the position to be certain.
+            // If the last configure event didn't have a trustable position,
+            // it's necessary to query, see ICCCM 4.24:
+            //
+            // Any real ConfigureNotify event on a top-level window implies
+            // that the window position on the root may have changed, even
+            // though the event reports that the window position in its
+            // parent is unchanged because the window may have been reparented.
+
             int x, y;
             Window child;
             XTranslateCoordinates(X11->display, internalWinId(),