From fb69a09a2490102ad0c3f6015e04942bb5df7505 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Date: Tue, 24 Nov 2015 13:49:44 +0100
Subject: [PATCH] QWidget::mapTo/FromGlobal(): Avoid calling QWindow helpers
 until shown.

The platform window geometry can be misleading until it has
been properly positioned and
QWindowPrivate::resizeEventPending has been cleared.

Task-number: QTBUG-49588
Task-number: QTBUG-48396
Change-Id: Ie065f62478fc8522a9ad51391bb897510afa5aad
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
---
 src/widgets/kernel/qwidget.cpp                | 10 +++-
 .../auto/widgets/widgets/qmenu/tst_qmenu.cpp  | 56 +++++++++++++++++++
 2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index b8b8640cea3..229cfc0f858 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -12327,6 +12327,12 @@ QPaintEngine *QWidget::paintEngine() const
     return 0; //##### @@@
 }
 
+// Do not call QWindow::mapToGlobal() until QPlatformWindow is properly showing.
+static inline bool canMapPosition(QWindow *window)
+{
+    return window->handle() && !qt_window_private(window)->resizeEventPending;
+}
+
 /*!
     \fn QPoint QWidget::mapToGlobal(const QPoint &pos) const
 
@@ -12354,7 +12360,7 @@ QPoint QWidget::mapToGlobal(const QPoint &pos) const
 #endif // !QT_NO_GRAPHICSVIEW
 
         QWindow *window = w->windowHandle();
-        if (window && window->handle())
+        if (window && canMapPosition(window))
             return window->mapToGlobal(QPoint(x, y));
 
         x += w->data->crect.x();
@@ -12390,7 +12396,7 @@ QPoint QWidget::mapFromGlobal(const QPoint &pos) const
 #endif // !QT_NO_GRAPHICSVIEW
 
         QWindow *window = w->windowHandle();
-        if (window && window->handle())
+        if (window && canMapPosition(window))
             return window->mapFromGlobal(QPoint(x, y));
 
         x -= w->data->crect.x();
diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
index 5ae07339652..b3f9c54f24f 100644
--- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
+++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
@@ -94,6 +94,7 @@ private slots:
 
     void task208001_stylesheet();
     void activeSubMenuPosition();
+    void activeSubMenuPositionExec();
     void task242454_sizeHint();
     void task176201_clear();
     void task250673_activeMultiColumnSubMenuPosition();
@@ -694,6 +695,61 @@ void tst_QMenu::activeSubMenuPosition()
 #endif
 }
 
+// QTBUG-49588, QTBUG-48396: activeSubMenuPositionExec() is the same as
+// activeSubMenuPosition(), but uses QMenu::exec(), which produces a different
+// sequence of events. Verify that the sub menu is positioned to the right of the
+// main menu.
+class SubMenuPositionExecMenu : public QMenu
+{
+    Q_OBJECT
+public:
+    SubMenuPositionExecMenu() : QMenu("Menu-Title"), m_timerId(-1), m_timerTick(0)
+    {
+        addAction("Item 1");
+        m_subMenu = addMenu("Submenu");
+        m_subAction = m_subMenu->addAction("Sub-Item1");
+        setActiveAction(m_subMenu->menuAction());
+    }
+
+protected:
+    void showEvent(QShowEvent *e) Q_DECL_OVERRIDE
+    {
+        QVERIFY(m_subMenu->isVisible());
+        QVERIFY2(m_subMenu->x() > x(),
+                 (QByteArray::number(m_subMenu->x()) + ' ' + QByteArray::number(x())).constData());
+        m_timerId = startTimer(50);
+        QMenu::showEvent(e);
+    }
+
+    void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE
+    {
+        if (e->timerId() == m_timerId) {
+            switch (m_timerTick++) {
+            case 0:
+                m_subMenu->close();
+                break;
+            case 1:
+                close();
+                break;
+            }
+        }
+    }
+
+private:
+    int m_timerId;
+    int m_timerTick;
+    QMenu *m_subMenu;
+    QAction *m_subAction;
+};
+
+void tst_QMenu::activeSubMenuPositionExec()
+{
+#ifndef Q_OS_WINCE
+    SubMenuPositionExecMenu menu;
+    menu.exec(QGuiApplication::primaryScreen()->availableGeometry().center());
+#endif // !Q_OS_WINCE
+}
+
 void tst_QMenu::task242454_sizeHint()
 {
     QMenu menu;
-- 
GitLab