diff options
Diffstat (limited to 'src/widgets/widgets/qmenubar.cpp')
-rw-r--r-- | src/widgets/widgets/qmenubar.cpp | 51 |
1 files changed, 35 insertions, 16 deletions
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 01ad37cab0..c9c9191c17 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -281,17 +281,28 @@ 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(); + 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(); - 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()); @@ -596,11 +607,13 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti Qt for \macos also provides a menu bar merging feature to make QMenuBar conform more closely to accepted \macos menu bar layout. - The merging functionality is based on string matching the title of - a QMenu entry. These strings are translated (using QObject::tr()) - in the "QMenuBar" context. If an entry is moved its slots will still - fire as if it was in the original place. The table below outlines - the strings looked for and where the entry is placed if matched: + If an entry is moved its slots will still fire as if it was in the + original place. + + The merging functionality is based on the QAction::menuRole() of + the menu entries. If an item has QAction::TextHeuristicRole, + the role is determined by string matching the title using the + following heuristics: \table \header \li String matches \li Placement \li Notes @@ -618,8 +631,8 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti created to call QCoreApplication::quit() \endtable - You can override this behavior by using the QAction::menuRole() - property. + You can override this behavior by setting the QAction::menuRole() + property to QAction::NoRole. If you want all windows in a Mac application to share one menu bar, you must create a menu bar that does not have a parent. @@ -912,7 +925,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame, this); frame.midLineWidth = 0; style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this); } @@ -1285,7 +1298,12 @@ void QMenuBarPrivate::handleReparent() QList<QPointer<QWidget>> newParents; // Remove event filters on ex-parents, keep them on still-parents // The parents are always ordered in the vector - foreach (const QPointer<QWidget> &w, oldParents) { + // + // Take a copy because this method is called from changeEvent() and eventFilter(), + // which might cause recursion into the class due to event processing, which might + // modify oldParents. + const auto copy = oldParents; + for (const QPointer<QWidget> &w : copy) { if (w) { if (newParent == w) { newParents.append(w); @@ -1356,7 +1374,7 @@ bool QMenuBar::event(QEvent *e) Q_D(QMenuBar); switch (e->type()) { case QEvent::KeyPress: { - QKeyEvent *ke = (QKeyEvent*)e; + QKeyEvent *ke = static_cast<QKeyEvent *>(e); #if 0 if (!d->keyboardState) { //all keypresses.. d->setCurrentAction(0); @@ -1384,7 +1402,7 @@ bool QMenuBar::event(QEvent *e) break; #ifndef QT_NO_SHORTCUT case QEvent::ShortcutOverride: { - QKeyEvent *kev = static_cast<QKeyEvent*>(e); + QKeyEvent *kev = static_cast<QKeyEvent *>(e); //we only filter out escape if there is a current action if (kev->matches(QKeySequence::Cancel) && d->currentAction) { e->accept(); @@ -1772,6 +1790,7 @@ void QMenuBar::setNativeMenuBar(bool nativeMenuBar) if (!nativeMenuBar) { delete d->platformMenuBar; d->platformMenuBar = nullptr; + d->itemsDirty = true; } else { if (!d->platformMenuBar) d->platformMenuBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar(); |