diff options
Diffstat (limited to 'src/widgets/widgets/qmenu.cpp')
-rw-r--r-- | src/widgets/widgets/qmenu.cpp | 241 |
1 files changed, 148 insertions, 93 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index c418f6dc7d..db00f8a650 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qmenu.h" @@ -48,10 +12,10 @@ #include "qevent.h" #include "qtimer.h" #include "qlayout.h" -#include "qpainter.h" +#include "qstylepainter.h" #include <qpa/qplatformtheme.h> #include "qapplication.h" -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) # include "qaccessible.h" #endif #if QT_CONFIG(effects) @@ -129,7 +93,9 @@ public: Q_D(QTornOffMenu); // make the torn-off menu a sibling of p (instead of a child) QWidget *parentWidget = d->causedStack.isEmpty() ? p : d->causedStack.constLast(); - if (parentWidget->parentWidget()) + if (!parentWidget && p) + parentWidget = p; + if (parentWidget && parentWidget->parentWidget()) parentWidget = parentWidget->parentWidget(); setParent(parentWidget, Qt::Window | Qt::Tool); setAttribute(Qt::WA_DeleteOnClose, true); @@ -146,7 +112,7 @@ public: //QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(onTrigger(QAction*))); //QObject::connect(this, SIGNAL(hovered(QAction*)), this, SLOT(onHovered(QAction*))); QList<QAction*> items = p->actions(); - for(int i = 0; i < items.count(); i++) + for(int i = 0; i < items.size(); i++) addAction(items.at(i)); d->setMenuSize(sizeHint()); d->initialized = true; @@ -199,7 +165,7 @@ void QMenuPrivate::init() defaultMenuAction = menuAction = new QAction(q); menuAction->setMenu(q); // this calls setOverrideMenuAction setOverrideMenuAction(nullptr); - QObject::connect(menuAction, &QAction::changed, [this] { + QObject::connect(menuAction, &QAction::changed, q, [this] { if (!tornPopup.isNull()) tornPopup->updateWindowTitle(); }); @@ -251,13 +217,21 @@ void QMenuPrivate::syncPlatformMenu() platformMenu->setEnabled(q->isEnabled()); } +static QWidget *getParentWidget(const QAction *action) +{ + auto result = action->parent(); + while (result && !qobject_cast<QWidget *>(result)) + result = result->parent(); + return static_cast<QWidget *>(result); +} + void QMenuPrivate::copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item) { item->setText(action->text()); item->setIsSeparator(action->isSeparator()); if (action->isIconVisibleInMenu()) { item->setIcon(action->icon()); - if (QWidget *w = action->parentWidget()) { + if (QWidget *w = getParentWidget(action)) { QStyleOption opt; opt.initFrom(w); item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w)); @@ -318,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); @@ -363,7 +344,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const q->ensurePolished(); //let's reinitialize the buffer - actionRects.resize(actions.count()); + actionRects.resize(actions.size()); actionRects.fill(QRect()); int lastVisibleAction = getLastVisibleAction(); @@ -388,7 +369,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const hasCheckableItems = false; ncols = 1; - for (int i = 0; i < actions.count(); ++i) { + for (int i = 0; i < actions.size(); ++i) { QAction *action = actions.at(i); if (action->isSeparator() || !action->isVisible() || widgetItems.contains(action)) continue; @@ -432,7 +413,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const sz = QSize(2, 2); } else { QString s = action->text(); - int t = s.indexOf(QLatin1Char('\t')); + qsizetype t = s.indexOf(u'\t'); if (t != -1) { tabWidth = qMax(int(tabWidth), qfm.horizontalAdvance(s.mid(t+1))); s = s.left(t); @@ -482,7 +463,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const int x = hmargin + fw + leftmargin; y = base_y; - for(int i = 0; i < actions.count(); i++) { + for(int i = 0; i < actions.size(); i++) { QRect &rect = actionRects[i]; if (rect.isNull()) continue; @@ -507,7 +488,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const int QMenuPrivate::getLastVisibleAction() const { //let's try to get the last visible action - int lastVisibleAction = actions.count() - 1; + int lastVisibleAction = actions.size() - 1; for (;lastVisibleAction >= 0; --lastVisibleAction) { const QAction *action = actions.at(lastVisibleAction); if (action->isVisible()) { @@ -595,10 +576,16 @@ void QMenuPrivate::hideMenu(QMenu *menu) }; #if QT_CONFIG(effects) - QSignalBlocker blocker(menu); + // If deleteLater has been called and the event loop spins, while waiting + // for visual effects to happen, menu might become stale. + // To prevent a QSignalBlocker from restoring a stale object, block and restore signals manually. + QPointer<QMenu> stillAlive(menu); + const bool signalsBlocked = menu->signalsBlocked(); + menu->blockSignals(true); + aboutToHide = true; // Flash item which is about to trigger (if any). - if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem) + if (menu && menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem) && currentAction && currentAction == actionAboutToTrigger && menu->actions().contains(currentAction)) { QEventLoop eventLoop; @@ -609,6 +596,9 @@ void QMenuPrivate::hideMenu(QMenu *menu) QTimer::singleShot(60, &eventLoop, SLOT(quit())); eventLoop.exec(); + if (!stillAlive) + return; + // Select and wait 20 ms. menu->setActiveAction(activeAction); QTimer::singleShot(20, &eventLoop, SLOT(quit())); @@ -616,15 +606,44 @@ void QMenuPrivate::hideMenu(QMenu *menu) } aboutToHide = false; - blocker.unblock(); + + if (stillAlive) + menu->blockSignals(signalsBlocked); + else + return; + #endif // QT_CONFIG(effects) if (activeMenu == menu) activeMenu = nullptr; + menu->d_func()->causedPopup.action = nullptr; menu->close(); 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); @@ -666,7 +685,7 @@ void QMenuPrivate::setFirstActionActive() { Q_Q(QMenu); updateActionRects(); - for(int i = 0, saccum = 0; i < actions.count(); i++) { + for(int i = 0, saccum = 0; i < actions.size(); i++) { const QRect &rect = actionRects.at(i); if (rect.isNull()) continue; @@ -903,7 +922,7 @@ QAction *QMenuPrivate::actionAt(QPoint p) const if (!rect().contains(p)) //sanity check return nullptr; - for(int i = 0; i < actionRects.count(); i++) { + for(int i = 0; i < actionRects.size(); i++) { if (actionRects.at(i).contains(p)) return actions.at(i); } @@ -1053,6 +1072,16 @@ QAction *QMenu::menuAction() const } /*! + \fn static QMenu *QMenu::menuInAction(const QAction *action) + + Returns the menu contained by \a action, or \nullptr if \a action does not + contain a menu. + + In widget applications, actions that contain menus can be used to create menu + items with submenus, or inserted into toolbars to create buttons with popup menus. +*/ + +/*! \property QMenu::title \brief The title of the menu @@ -1104,7 +1133,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, q); if (location == QMenuScroller::ScrollTop) { - for(int i = 0, saccum = 0; i < actions.count(); i++) { + for(int i = 0, saccum = 0; i < actions.size(); i++) { if (actions.at(i) == action) { newOffset = topScroll - saccum; break; @@ -1112,7 +1141,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc saccum += actionRects.at(i).height(); } } else { - for(int i = 0, saccum = 0; i < actions.count(); i++) { + for(int i = 0, saccum = 0; i < actions.size(); i++) { saccum += actionRects.at(i).height(); if (actions.at(i) == action) { if (location == QMenuScroller::ScrollCenter) @@ -1131,7 +1160,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc if (newOffset < 0) //easy and cheap one newScrollFlags |= QMenuScroller::ScrollUp; int saccum = newOffset; - for(int i = 0; i < actionRects.count(); i++) { + for(int i = 0; i < actionRects.size(); i++) { saccum += actionRects.at(i).height(); if (saccum > q->height()) { newScrollFlags |= QMenuScroller::ScrollDown; @@ -1188,7 +1217,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc const int delta = qMin(0, newOffset) - scroll->scrollOffset; //make sure the new offset is always negative if (!itemsDirty && delta) { //we've scrolled so we need to update the action rects - for (int i = 0; i < actionRects.count(); ++i) { + for (int i = 0; i < actionRects.size(); ++i) { QRect ¤t = actionRects[i]; current.moveTop(current.top() + delta); @@ -1255,7 +1284,7 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool pag const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, q); const int offset = topScroll ? topScroll-vmargin : 0; if (direction == QMenuScroller::ScrollUp) { - for(int i = 0, saccum = 0; i < actions.count(); i++) { + for(int i = 0, saccum = 0; i < actions.size(); i++) { saccum -= actionRects.at(i).height(); if (saccum <= scroll->scrollOffset-offset) { scrollMenu(actions.at(i), page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active); @@ -1264,13 +1293,13 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool pag } } else if (direction == QMenuScroller::ScrollDown) { bool scrolled = false; - for(int i = 0, saccum = 0; i < actions.count(); i++) { + for(int i = 0, saccum = 0; i < actions.size(); i++) { const int iHeight = actionRects.at(i).height(); saccum -= iHeight; if (saccum <= scroll->scrollOffset-offset) { const int scrollerArea = q->height() - botScroll - fw*2; int visible = (scroll->scrollOffset-offset) - saccum; - for(i++ ; i < actions.count(); i++) { + for(i++ ; i < actions.size(); i++) { visible += actionRects.at(i).height(); if (visible > scrollerArea - topScroll) { scrolled = true; @@ -1382,9 +1411,18 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e) void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget>> &causedStack, QAction *action, QAction::ActionEvent action_e, bool self) { - QBoolBlocker guard(activationRecursionGuard); + Q_Q(QMenu); + // can't use QBoolBlocker here + const bool activationRecursionGuardReset = activationRecursionGuard; + activationRecursionGuard = true; + QPointer<QMenu> guard(q); if (self) action->activate(action_e); + if (!guard) + return; + auto boolBlocker = qScopeGuard([this, activationRecursionGuardReset]{ + activationRecursionGuard = activationRecursionGuardReset; + }); for(int i = 0; i < causedStack.size(); ++i) { QPointer<QWidget> widget = causedStack.at(i); @@ -1460,12 +1498,13 @@ void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e #endif } - + QPointer<QMenu> thisGuard(q); activateCausedStack(causedStack, action, action_e, self); - + if (!thisGuard) + return; if (action_e == QAction::Hover) { -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) if (QAccessible::isActive()) { int actionIndex = indexOf(action); QAccessibleEvent focusEvent(q, QAccessible::Focus); @@ -1604,10 +1643,10 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) QString textAndAccel = action->text(); #ifndef QT_NO_SHORTCUT if ((action->isShortcutVisibleInContextMenu() || !d->isContextMenu()) - && textAndAccel.indexOf(QLatin1Char('\t')) == -1) { + && textAndAccel.indexOf(u'\t') == -1) { QKeySequence seq = action->shortcut(); if (!seq.isEmpty()) - textAndAccel += QLatin1Char('\t') + seq.toString(QKeySequence::NativeText); + textAndAccel += u'\t' + seq.toString(QKeySequence::NativeText); } #endif option->text = textAndAccel; @@ -1654,7 +1693,7 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) and all other items are considered action items. When inserting action items you usually specify a receiver and a - slot. The receiver will be notifed whenever the item is + slot. The receiver will be notified whenever the item is \l{QAction::triggered()}{triggered()}. In addition, QMenu provides two signals, triggered() and hovered(), which signal the QAction that was triggered from the menu. @@ -1693,8 +1732,7 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) \b{Important inherited functions:} addAction(), removeAction(), clear(), addSeparator(), and addMenu(). - \sa QMenuBar, {fowler}{GUI Design Handbook: Menu, Drop-Down and Pop-Up}, - {Qt Widgets - Application Example}, {Menus Example} + \sa QMenuBar, {Menus Example} */ @@ -2169,7 +2207,7 @@ QAction *QMenu::activeAction() const bool QMenu::isEmpty() const { bool ret = true; - for(int i = 0; ret && i < actions().count(); ++i) { + for(int i = 0; ret && i < actions().size(); ++i) { const QAction *action = actions().at(i); if (!action->isSeparator() && action->isVisible()) { ret = false; @@ -2234,7 +2272,7 @@ QSize QMenu::sizeHint() const d->updateActionRects(); QSize s; - for (int i = 0; i < d->actionRects.count(); ++i) { + for (int i = 0; i < d->actionRects.size(); ++i) { const QRect &rect = d->actionRects.at(i); if (rect.isNull()) continue; @@ -2278,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 @@ -2319,6 +2360,15 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po lastContextMenu = contextMenu; } + // Until QWidget::metric accepts the screen set on a widget (without having a window handle) + // we need to make sure we get a window handle. This must be done near here because + // we want the screen to be correctly set and items to be marked dirty. + // (and screen set could 'fail' on oldscreen == newScreen if created before causing the + // itemsDirty not to be set though needed to get the correct size on first show). + if (!windowHandle()) { + createWinId(); + } + #if QT_CONFIG(menubar) // if this menu is part of a chain attached to a QMenuBar, set the // _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type @@ -2344,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; @@ -2370,7 +2421,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po atAction = defaultAction; // TODO: This works for first level menus, not yet sub menus } else { - for (QAction *action : qAsConst(actions)) + for (QAction *action : std::as_const(actions)) if (action->isEnabled()) { atAction = action; break; @@ -2382,7 +2433,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po if (ncols > 1) { pos.setY(screen.top() + desktopFrame); } else if (atAction) { - for (int i = 0, above_height = 0; i < actions.count(); i++) { + for (int i = 0, above_height = 0; i < actions.size(); i++) { QAction *action = actions.at(i); if (action == atAction) { int newY = pos.y() - above_height; @@ -2397,7 +2448,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po if (scroll && scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone && !q->style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, nullptr, q)) { int below_height = above_height + scroll->scrollOffset; - for (int i2 = i; i2 < actionRects.count(); i2++) + for (int i2 = i; i2 < actionRects.size(); i2++) below_height += actionRects.at(i2).height(); size.setHeight(below_height); } @@ -2482,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; @@ -2535,7 +2587,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po q->show(); } -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) QAccessibleEvent event(q, QAccessible::PopupMenuStart); QAccessible::updateAccessibility(&event); #endif @@ -2622,6 +2674,7 @@ QAction *QMenuPrivate::exec(const QPoint &p, QAction *action, PositionFunction p action = syncAction; syncAction = nullptr; eventLoop = nullptr; + popupScreen.clear(); return action; } @@ -2664,7 +2717,7 @@ void QMenu::hideEvent(QHideEvent *) if (d->eventLoop) d->eventLoop->exit(); d->setCurrentAction(nullptr); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) QAccessibleEvent event(this, QAccessible::PopupMenuEnd); QAccessible::updateAccessibility(&event); #endif @@ -2690,7 +2743,7 @@ void QMenu::paintEvent(QPaintEvent *e) { Q_D(QMenu); d->updateActionRects(); - QPainter p(this); + QStylePainter p(this); QRegion emptyArea = QRegion(rect()); QStyleOptionMenuItem menuOpt; @@ -2699,7 +2752,7 @@ void QMenu::paintEvent(QPaintEvent *e) menuOpt.checkType = QStyleOptionMenuItem::NotCheckable; menuOpt.maxIconWidth = 0; menuOpt.reservedShortcutWidth = 0; - style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this); + p.drawPrimitive(QStyle::PE_PanelMenu, menuOpt); //calculate the scroll up / down rect const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, this); @@ -2731,7 +2784,7 @@ void QMenu::paintEvent(QPaintEvent *e) //draw the items that need updating.. QRect scrollUpTearOffRect = scrollUpRect.united(tearOffRect); - for (int i = 0; i < d->actions.count(); ++i) { + for (int i = 0; i < d->actions.size(); ++i) { QAction *action = d->actions.at(i); QRect actionRect = d->actionRects.at(i); if (!e->rect().intersects(actionRect) @@ -2767,7 +2820,7 @@ void QMenu::paintEvent(QPaintEvent *e) QStyleOptionMenuItem opt; initStyleOption(&opt, action); opt.rect = actionRect; - style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this); + p.drawControl(QStyle::CE_MenuItem, opt); } emptyArea -= QRegion(scrollUpTearOffRect); @@ -2799,9 +2852,9 @@ void QMenu::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame, this); frame.midLineWidth = 0; - style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this); + p.drawPrimitive(QStyle::PE_FrameMenu, frame); } //finally the rest of the spaces @@ -2811,7 +2864,7 @@ void QMenu::paintEvent(QPaintEvent *e) menuOpt.checkType = QStyleOptionMenuItem::NotCheckable; menuOpt.rect = rect(); menuOpt.menuRect = rect(); - style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this); + p.drawControl(QStyle::CE_MenuEmptyArea, menuOpt); } #if QT_CONFIG(wheelevent) @@ -2926,7 +2979,7 @@ bool QMenu::event(QEvent *e) d->updateLayoutDirection(); break; case QEvent::ShortcutOverride: { - QKeyEvent *kev = static_cast<QKeyEvent*>(e); + QKeyEvent *kev = static_cast<QKeyEvent *>(e); if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down || kev->key() == Qt::Key_Left || kev->key() == Qt::Key_Right || kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return @@ -2940,7 +2993,7 @@ bool QMenu::event(QEvent *e) } break; case QEvent::KeyPress: { - QKeyEvent *ke = (QKeyEvent*)e; + QKeyEvent *ke = static_cast<QKeyEvent *>(e); if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { keyPressEvent(ke); return true; @@ -2973,6 +3026,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: @@ -3073,7 +3128,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) QMenuPrivate::QMenuScroller::ScrollLocation scroll_loc = QMenuPrivate::QMenuScroller::ScrollStay; if (!d->currentAction) { if (key == Qt::Key_Down) { - for(int i = 0; i < d->actions.count(); ++i) { + for(int i = 0; i < d->actions.size(); ++i) { QAction *act = d->actions.at(i); if (d->actionRects.at(i).isNull()) continue; @@ -3085,7 +3140,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) } } } else { - for(int i = d->actions.count()-1; i >= 0; --i) { + for(int i = d->actions.size()-1; i >= 0; --i) { QAction *act = d->actions.at(i); if (d->actionRects.at(i).isNull()) continue; @@ -3098,7 +3153,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) } } } else { - for(int i = 0, y = 0; !nextAction && i < d->actions.count(); i++) { + for(int i = 0, y = 0; !nextAction && i < d->actions.size(); i++) { QAction *act = d->actions.at(i); if (act == d->currentAction) { if (key == Qt::Key_Up) { @@ -3108,7 +3163,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) break; if (d->scroll) scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom; - next_i = d->actionRects.count()-1; + next_i = d->actionRects.size()-1; } QAction *next = d->actions.at(next_i); if (next == d->currentAction) @@ -3134,7 +3189,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) } else { y += d->actionRects.at(i).height(); for(int next_i = i+1; true; next_i++) { - if (next_i == d->actionRects.count()) { + if (next_i == d->actionRects.size()) { if (!style()->styleHint(QStyle::SH_Menu_SelectionWrap, nullptr, this)) break; if (d->scroll) @@ -3291,7 +3346,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) if (!key_consumed) { // send to menu bar if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) && - e->text().length()==1) { + e->text().size()==1) { bool activateAction = false; QAction *nextAction = nullptr; if (style()->styleHint(QStyle::SH_Menu_KeyboardSearch, nullptr, this) && !e->modifiers()) { @@ -3572,7 +3627,7 @@ void QMenu::internalDelayedPopup() const QRect actionRect(d->actionRect(d->currentAction)); QPoint subMenuPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top()))); if (subMenuPos.x() > screen.right()) - subMenuPos.setX(QCursor::pos().x()); + subMenuPos.setX(geometry().left()); const auto &subMenuActions = d->activeMenu->actions(); if (!subMenuActions.isEmpty()) { |