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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Q_Q(QMenu);
|
||||
@ -2983,6 +3006,8 @@ bool QMenu::event(QEvent *e)
|
||||
d->sloppyState.reset();
|
||||
if (d->currentAction)
|
||||
d->popupAction(d->currentAction, 0, false);
|
||||
if (isWindow() && window() && window()->windowHandle() && !window()->windowHandle()->transientParent())
|
||||
window()->windowHandle()->setTransientParent(d->transientParentWindow());
|
||||
break;
|
||||
#if QT_CONFIG(tooltip)
|
||||
case QEvent::ToolTip:
|
||||
|
@ -440,6 +440,7 @@ public:
|
||||
QMenuCaused causedPopup;
|
||||
void hideUpToMenuBar();
|
||||
void hideMenu(QMenu *menu);
|
||||
QWindow *transientParentWindow() const;
|
||||
|
||||
//index mappings
|
||||
inline QAction *actionAt(int i) const { return q_func()->actions().at(i); }
|
||||
|
@ -118,6 +118,7 @@ private slots:
|
||||
void QTBUG_89082_actionTipsHide();
|
||||
void QTBUG8122_widgetActionCrashOnClose();
|
||||
void widgetActionTriggerClosesMenu();
|
||||
void transientParent();
|
||||
|
||||
void QTBUG_10735_crashWithDialog();
|
||||
#ifdef Q_OS_MAC
|
||||
@ -1588,6 +1589,54 @@ void tst_QMenu::widgetActionTriggerClosesMenu()
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
Loading…
x
Reference in New Issue
Block a user