diff options
author | Morten Sørvig <morten.sorvig@qt.io> | 2024-03-12 13:42:54 +0100 |
---|---|---|
committer | Morten Sørvig <morten.sorvig@qt.io> | 2024-03-25 19:52:04 +0100 |
commit | 6272dddaddafa7f1b555dc8b2d374387fda70b15 (patch) | |
tree | b76d36519c46eeca6f3ea73fa932be2a97c17166 /src/widgets | |
parent | 36e65785ec997b0e38aa84ebc3288b7c6d033137 (diff) |
Fix multiscreen menu popup positioning corner case
A QMenuBar may span multiple screens. Its menus will
then open on the screen which the bottom middle of
the action rect is at, and will snap to that screen's
geometry if needed.
However it can happen that the bottomLeft() of the action
rect is on a different screen from the selected popup
screen, in which case mapping this point to global
coordinates can give incorrect coordinates if the screens
have different scale factors.
The x value will be corrected by the screen snapping
if needed. Use the y from the screen test point, which
will be correct for the selected screen.
Task-number: QTBUG-73231
Change-Id: If9a39f6b832a64f2f701868f2be0d3a6468fe553
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/widgets/qmenubar.cpp | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 1ffe82835d..c9c9191c17 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -286,16 +286,23 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) activeMenuPriv->causedPopup.action = action; QRect adjustedActionRect = actionRect(action); - QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1))); + QPoint popupPos = adjustedActionRect.bottomLeft() + QPoint(0, 1); + //we put the popup menu on the screen containing the bottom-center of the action rect QScreen *menubarScreen = q->window()->windowHandle()->screen(); - QPointer<QScreen> popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0)); + QPoint screenTestPos = q->mapToGlobal(popupPos + QPoint(adjustedActionRect.width() / 2, 0)); + QPointer<QScreen> popupScreen = menubarScreen->virtualSiblingAt(screenTestPos); if (!popupScreen) popupScreen = menubarScreen; std::swap(popupScreen, activeMenuPriv->popupScreen); const QSize popup_size = activeMenu->sizeHint(); std::swap(popupScreen, activeMenuPriv->popupScreen); + // Use screenTestPos.y() for the popup y position. This is the correct global y + // consistent with the selected screen in cases where the action rect spans + // multiple screens with different scale factors. + QPoint pos(q->mapToGlobal(popupPos).x(), screenTestPos.y()); + 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()); |