Widgets: setTransientParent() when a QMenu is a window
On some platforms, such as X11 and Wayland with some compositors, QMenu could be a popup window, which should be set a transient parent to get relative position, which is requested by Wayland. Added transientParentWindow() for QMenuPrivate like QDialogPrivate. Fixes: QTBUG-68636 Pick-to: 6.2 Change-Id: I6d8880cb008ecf61a4c005898b38e3953379a13d Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
9c05fdac81
commit
493a85a9e4
@ -625,6 +625,29 @@ void QMenuPrivate::hideMenu(QMenu *menu)
|
|||||||
menu->d_func()->causedPopup.widget = nullptr;
|
menu->d_func()->causedPopup.widget = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWindow *QMenuPrivate::transientParentWindow() const
|
||||||
|
{
|
||||||
|
Q_Q(const QMenu);
|
||||||
|
if (const QWidget *parent = q->nativeParentWidget()) {
|
||||||
|
if (parent->windowHandle())
|
||||||
|
return parent->windowHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const QWindow *w = q->windowHandle()) {
|
||||||
|
if (w->transientParent())
|
||||||
|
return w->transientParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (causedPopup.widget) {
|
||||||
|
if (const QWidget *w = causedPopup.widget.data()) {
|
||||||
|
if (const QWidget *ww = w->window())
|
||||||
|
return ww->windowHandle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
|
void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
|
||||||
{
|
{
|
||||||
Q_Q(QMenu);
|
Q_Q(QMenu);
|
||||||
@ -2983,6 +3006,8 @@ bool QMenu::event(QEvent *e)
|
|||||||
d->sloppyState.reset();
|
d->sloppyState.reset();
|
||||||
if (d->currentAction)
|
if (d->currentAction)
|
||||||
d->popupAction(d->currentAction, 0, false);
|
d->popupAction(d->currentAction, 0, false);
|
||||||
|
if (isWindow() && window() && window()->windowHandle() && !window()->windowHandle()->transientParent())
|
||||||
|
window()->windowHandle()->setTransientParent(d->transientParentWindow());
|
||||||
break;
|
break;
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
case QEvent::ToolTip:
|
case QEvent::ToolTip:
|
||||||
|
@ -440,6 +440,7 @@ public:
|
|||||||
QMenuCaused causedPopup;
|
QMenuCaused causedPopup;
|
||||||
void hideUpToMenuBar();
|
void hideUpToMenuBar();
|
||||||
void hideMenu(QMenu *menu);
|
void hideMenu(QMenu *menu);
|
||||||
|
QWindow *transientParentWindow() const;
|
||||||
|
|
||||||
//index mappings
|
//index mappings
|
||||||
inline QAction *actionAt(int i) const { return q_func()->actions().at(i); }
|
inline QAction *actionAt(int i) const { return q_func()->actions().at(i); }
|
||||||
|
@ -118,6 +118,7 @@ private slots:
|
|||||||
void QTBUG_89082_actionTipsHide();
|
void QTBUG_89082_actionTipsHide();
|
||||||
void QTBUG8122_widgetActionCrashOnClose();
|
void QTBUG8122_widgetActionCrashOnClose();
|
||||||
void widgetActionTriggerClosesMenu();
|
void widgetActionTriggerClosesMenu();
|
||||||
|
void transientParent();
|
||||||
|
|
||||||
void QTBUG_10735_crashWithDialog();
|
void QTBUG_10735_crashWithDialog();
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
@ -1588,6 +1589,54 @@ void tst_QMenu::widgetActionTriggerClosesMenu()
|
|||||||
QCOMPARE(actionTriggered, &widgetAction);
|
QCOMPARE(actionTriggered, &widgetAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QMenu::transientParent()
|
||||||
|
{
|
||||||
|
QMainWindow window;
|
||||||
|
window.resize(480, 320);
|
||||||
|
window.menuBar()->setNativeMenuBar(false);
|
||||||
|
centerOnScreen(&window);
|
||||||
|
|
||||||
|
QMenu *fileMenu = new QMenu("&File");
|
||||||
|
QAction *exitAct = new QAction("Exit");
|
||||||
|
fileMenu->addAction(exitAct);
|
||||||
|
|
||||||
|
QMenu *editMenu = new QMenu("&Edit");
|
||||||
|
QAction *undoAct = new QAction("Undo");
|
||||||
|
editMenu->addAction(undoAct);
|
||||||
|
|
||||||
|
QMenuBar *menuBar = new QMenuBar;
|
||||||
|
menuBar->addMenu(fileMenu);
|
||||||
|
menuBar->addMenu(editMenu);
|
||||||
|
window.setMenuBar(menuBar);
|
||||||
|
|
||||||
|
// On Mac, we need to create native key events to test menu
|
||||||
|
// action activation, so skip this part of the test.
|
||||||
|
#if QT_CONFIG(shortcut) && !defined(Q_OS_DARWIN)
|
||||||
|
window.show();
|
||||||
|
QVERIFY(QTest::qWaitForWindowActive(&window));
|
||||||
|
QWindow *topLevel = window.windowHandle();
|
||||||
|
QVERIFY(topLevel);
|
||||||
|
|
||||||
|
QApplication::setActiveWindow(&window);
|
||||||
|
window.setFocus();
|
||||||
|
QVERIFY(QTest::qWaitForWindowActive(&window));
|
||||||
|
QVERIFY(window.hasFocus());
|
||||||
|
|
||||||
|
QTest::keyPress(&window, Qt::Key_F, Qt::AltModifier);
|
||||||
|
QTRY_VERIFY(QTest::qWaitForWindowExposed(fileMenu));
|
||||||
|
if (fileMenu->isWindow() && fileMenu->window() && fileMenu->window()->windowHandle())
|
||||||
|
QVERIFY(fileMenu->window()->windowHandle()->transientParent());
|
||||||
|
QTest::keyRelease(fileMenu, Qt::Key_F, Qt::AltModifier);
|
||||||
|
|
||||||
|
QTest::keyPress(fileMenu, Qt::Key_E, Qt::AltModifier);
|
||||||
|
QTRY_VERIFY(QTest::qWaitForWindowExposed(editMenu));
|
||||||
|
if (editMenu->isWindow() && editMenu->window() && editMenu->window()->windowHandle())
|
||||||
|
QVERIFY(editMenu->window()->windowHandle()->transientParent());
|
||||||
|
QTest::keyRelease(editMenu, Qt::Key_E, Qt::AltModifier);
|
||||||
|
#endif // QT_CONFIG(shortcut) && !Q_OS_DARWIN
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class MyMenu : public QMenu
|
class MyMenu : public QMenu
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user