diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-11-08 22:23:00 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-03-08 20:51:31 +0000 |
commit | 19792c38ed43a6d9a8cbd6c842ac8b794bad58c4 (patch) | |
tree | 8d959b47397a468544a1c278f60073fe73d3ed3c | |
parent | e853c2058cc1a1009f92fc53b4d8ff5e91761e66 (diff) |
Fix menu size in multiscreen setups
During QMenuPrivate::popup() and QMenuBarPrivate::popupAction(),
QMenuPrivate::popupGeometry() is called from updateActionRects() with
screen = 0 several times (from sizeHint() and various event handlers
triggered), which causes it to return the primary screen geometry
always.
To fix this for the non-QGraphicsView case, use the screen of
the menu when it is visible or the screen stored in a newly introduced
popupScreen member variable, which is set from a few places
in QMenuPrivate::popup().
Fixes: QTBUG-118434
Pick-to: 6.5
Change-Id: I6b18593d313719d628b0856004197ac59f46c270
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 8cd7a3d4723ca414f3fe544704a0ccb752da94b8)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 60d91acc0ab6a2ffde42617923fa81dc7fd3ffee)
-rw-r--r-- | src/widgets/widgets/qmenu.cpp | 12 | ||||
-rw-r--r-- | src/widgets/widgets/qmenu_p.h | 5 | ||||
-rw-r--r-- | src/widgets/widgets/qmenubar.cpp | 12 |
3 files changed, 25 insertions, 4 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index d0e8ef732c..3edebb388d 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -292,6 +292,13 @@ inline bool QMenuPrivate::useFullScreenForPopup() const QRect QMenuPrivate::popupGeometry(QScreen *screen) const { Q_Q(const QMenu); + if (screen == nullptr +#if QT_CONFIG(graphicsview) + && q->graphicsProxyWidget() == nullptr +#endif + ) { + screen = q->isVisible() ? q->screen() : popupScreen.data(); + } if (useFullScreenForPopup()) return screen ? screen->geometry() : QWidgetPrivate::screenGeometry(q); @@ -2309,6 +2316,9 @@ void QMenu::popup(const QPoint &p, QAction *atAction) void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction positionFunction) { Q_Q(QMenu); + popupScreen = QGuiApplication::screenAt(p); + QScopeGuard popupScreenGuard([this](){ popupScreen.clear(); }); + if (scroll) { // reset scroll state from last popup if (scroll->scrollOffset) itemsDirty = 1; // sizeHint will be incorrect if there is previous scroll @@ -2384,6 +2394,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition(); else pos = p; + popupScreen = QGuiApplication::screenAt(pos); const QSize menuSizeHint(q->sizeHint()); QSize size = menuSizeHint; @@ -2522,6 +2533,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po } } } + popupScreen = QGuiApplication::screenAt(pos); q->setGeometry(QRect(pos, size)); #if QT_CONFIG(effects) int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index 0d849e5eed..93ca1fedf5 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -471,6 +471,11 @@ public: mutable quint8 ncols = 0; // "255cols ought to be enough for anybody." + // Contains the screen of the popup point during popup(QPoint). + // This is to make sure the screen is remembered, + // when the menu contains many items on multiple screens + QPointer<QScreen> popupScreen; + mutable bool itemsDirty : 1; mutable bool hasCheckableItems : 1; bool lastContextMenu : 1; diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 3a5f19efdc..cfa975e0af 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -281,17 +281,21 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) if (action->isEnabled() && action->menu()->isEnabled()) { closePopupMode = 0; activeMenu = action->menu(); - activeMenu->d_func()->causedPopup.widget = q; - activeMenu->d_func()->causedPopup.action = action; + auto *activeMenuPriv = activeMenu->d_func(); + activeMenuPriv->causedPopup.widget = q; + activeMenuPriv->causedPopup.action = action; QRect adjustedActionRect = actionRect(action); QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1))); - QSize popup_size = activeMenu->sizeHint(); //we put the popup menu on the screen containing the bottom-center of the action rect QScreen *menubarScreen = q->window()->windowHandle()->screen(); - QScreen *popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0)); + QPointer<QScreen> popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0)); if (!popupScreen) popupScreen = menubarScreen; + std::swap(popupScreen, activeMenuPriv->popupScreen); + const QSize popup_size = activeMenu->sizeHint(); + std::swap(popupScreen, activeMenuPriv->popupScreen); + QRect screenRect = popupScreen->geometry(); pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y())); const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top()); |