summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
authorMorten Sørvig <morten.sorvig@qt.io>2024-03-12 13:42:54 +0100
committerMorten Sørvig <morten.sorvig@qt.io>2024-03-25 19:52:04 +0100
commit6272dddaddafa7f1b555dc8b2d374387fda70b15 (patch)
treeb76d36519c46eeca6f3ea73fa932be2a97c17166 /src/widgets
parent36e65785ec997b0e38aa84ebc3288b7c6d033137 (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.cpp11
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());