summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qmenu.cpp')
-rw-r--r--src/widgets/widgets/qmenu.cpp828
1 files changed, 420 insertions, 408 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index fc7e2dbbcb..db00f8a650 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -1,59 +1,21 @@
-/****************************************************************************
-**
-** 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"
#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include <QtWidgets/private/qwidgetwindow_p.h>
+#include "qactiongroup.h"
#include "qdebug.h"
#include "qstyle.h"
#include "qevent.h"
#include "qtimer.h"
#include "qlayout.h"
-#include "qpainter.h"
+#include "qstylepainter.h"
#include <qpa/qplatformtheme.h>
-#ifdef Q_OS_OSX
-#include "qmacnativewidget_mac.h"
-#endif
#include "qapplication.h"
-#include "qdesktopwidget.h"
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
# include "qaccessible.h"
#endif
#if QT_CONFIG(effects)
@@ -72,13 +34,14 @@
#include "qtoolbutton.h"
#endif
#include "qpushbutton.h"
+#if QT_CONFIG(tooltip)
#include "qtooltip.h"
+#endif
#include <qwindow.h>
#include <private/qpushbutton_p.h>
#include <private/qaction_p.h>
#include <private/qguiapplication_p.h>
#include <qpa/qplatformtheme.h>
-#include <private/qdesktopwidget_p.h>
#include <private/qstyle_p.h>
QT_BEGIN_NAMESPACE
@@ -105,7 +68,7 @@ class QTornOffMenu : public QMenu
Q_Q(QTornOffMenu);
QSize size = menuSize;
const QPoint p = (!initialized) ? causedMenu->pos() : q->pos();
- QRect screen = popupGeometry(QDesktopWidgetPrivate::screenNumber(p));
+ const QRect screen = popupGeometry(QGuiApplication::screenAt(p));
const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, nullptr, q);
const int titleBarHeight = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, nullptr, q);
if (scroll && (size.height() > screen.height() - titleBarHeight || size.width() > screen.width())) {
@@ -118,9 +81,9 @@ class QTornOffMenu : public QMenu
q->setFixedSize(size);
}
- QVector<QPointer<QWidget> > calcCausedStack() const override { return causedStack; }
+ QList<QPointer<QWidget>> calcCausedStack() const override { return causedStack; }
QPointer<QMenu> causedMenu;
- QVector<QPointer<QWidget> > causedStack;
+ QList<QPointer<QWidget>> causedStack;
bool initialized;
};
@@ -130,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);
@@ -147,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;
@@ -155,7 +120,7 @@ public:
void syncWithMenu(QMenu *menu, QActionEvent *act)
{
Q_D(QTornOffMenu);
- if(menu != d->causedMenu)
+ if (menu != d->causedMenu)
return;
auto action = static_cast<QAction *>(act->action());
if (act->type() == QEvent::ActionAdded) {
@@ -198,8 +163,9 @@ void QMenuPrivate::init()
#endif
q->setAttribute(Qt::WA_X11NetWmWindowTypePopupMenu);
defaultMenuAction = menuAction = new QAction(q);
- menuAction->d_func()->menu = q;
- QObject::connect(menuAction, &QAction::changed, [this] {
+ menuAction->setMenu(q); // this calls setOverrideMenuAction
+ setOverrideMenuAction(nullptr);
+ QObject::connect(menuAction, &QAction::changed, q, [this] {
if (!tornPopup.isNull())
tornPopup->updateWindowTitle();
});
@@ -251,15 +217,23 @@ 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.init(w);
+ opt.initFrom(w);
item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w));
} else {
QStyleOption opt;
@@ -305,7 +279,7 @@ QPlatformMenuItem * QMenuPrivate::insertActionInPlatformMenu(const QAction *acti
int QMenuPrivate::scrollerHeight() const
{
Q_Q(const QMenu);
- return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, nullptr, q));
+ return q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, nullptr, q);
}
// Windows and KDE allow menus to cover the taskbar, while GNOME and macOS
@@ -315,24 +289,26 @@ inline bool QMenuPrivate::useFullScreenForPopup() const
return !tornoff && QStylePrivate::useFullScreenForPopup();
}
-QRect QMenuPrivate::popupGeometry() const
+QRect QMenuPrivate::popupGeometry(QScreen *screen) const
{
Q_Q(const QMenu);
- return useFullScreenForPopup()
- ? QDesktopWidgetPrivate::screenGeometry(q)
- : QDesktopWidgetPrivate::availableGeometry(q);
-}
-
-QRect QMenuPrivate::popupGeometry(int screen) const
-{
- return useFullScreenForPopup()
- ? QDesktopWidgetPrivate::screenGeometry(screen)
- : QDesktopWidgetPrivate::availableGeometry(screen);
+ 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);
+ return screen ? screen->availableGeometry()
+ : QWidgetPrivate::availableScreenGeometry(q);
}
-QVector<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
+QList<QPointer<QWidget>> QMenuPrivate::calcCausedStack() const
{
- QVector<QPointer<QWidget> > ret;
+ QList<QPointer<QWidget>> ret;
for(QWidget *widget = causedPopup.widget; widget; ) {
ret.append(widget);
if (QTornOffMenu *qtmenu = qobject_cast<QTornOffMenu*>(widget))
@@ -347,7 +323,11 @@ QVector<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
bool QMenuPrivate::isContextMenu() const
{
+#if QT_CONFIG(menubar)
return qobject_cast<const QMenuBar *>(topCausedWidget()) == nullptr;
+#else
+ return true;
+#endif
}
void QMenuPrivate::updateActionRects() const
@@ -364,14 +344,14 @@ 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();
QStyle *style = q->style();
QStyleOption opt;
- opt.init(q);
+ opt.initFrom(q);
const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q),
vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q),
icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q);
@@ -389,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;
@@ -433,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);
@@ -473,8 +453,8 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const
}
max_column_width += tabWidth; //finally add in the tab width
- if (!tornoff || (tornoff && scroll)) { // exclude non-scrollable tear-off menu since the tear-off menu has a fixed size
- const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width();
+ if (!tornoff || scroll) { // exclude non-scrollable tear-off menu since the tear-off menu has a fixed size
+ const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QSize(0, 0), q).width();
const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin));
max_column_width = qMax(min_column_width, max_column_width);
}
@@ -483,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;
@@ -508,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()) {
@@ -566,20 +546,59 @@ void QMenuPrivate::hideMenu(QMenu *menu)
{
if (!menu)
return;
+
+ // See two execs below. They may trigger an akward situation
+ // when 'menu' (also known as 'q' or 'this' in the many functions
+ // around) to become a dangling pointer if the loop manages
+ // to execute 'deferred delete' ... posted while executing
+ // this same loop. Not good!
+ struct Reposter : QObject
+ {
+ Reposter(QMenu *menu) : q(menu)
+ {
+ Q_ASSERT(q);
+ q->installEventFilter(this);
+ }
+ ~Reposter()
+ {
+ if (deleteLater)
+ q->deleteLater();
+ }
+ bool eventFilter(QObject *obj, QEvent *event) override
+ {
+ if (obj == q && event->type() == QEvent::DeferredDelete)
+ return deleteLater = true;
+
+ return QObject::eventFilter(obj, event);
+ }
+ QMenu *q = nullptr;
+ bool deleteLater = false;
+ };
+
#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;
QAction *activeAction = currentAction;
menu->setActiveAction(nullptr);
+ const Reposter deleteDeleteLate(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()));
@@ -587,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);
@@ -619,7 +667,7 @@ void QMenuPrivate::setSyncAction()
{
Q_Q(QMenu);
QAction *current = currentAction;
- if(current && (!current->isEnabled() || current->menu() || current->isSeparator()))
+ if (current && (!current->isEnabled() || current->menu() || current->isSeparator()))
current = nullptr;
for(QWidget *caused = q; caused;) {
if (QMenu *m = qobject_cast<QMenu*>(caused)) {
@@ -637,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;
@@ -874,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);
}
@@ -929,7 +977,7 @@ void QMenuPrivate::drawScroller(QPainter *painter, QMenuPrivate::ScrollerTearOff
menuOpt.state = QStyle::State_None;
menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
menuOpt.maxIconWidth = 0;
- menuOpt.tabWidth = 0;
+ menuOpt.reservedShortcutWidth = 0;
menuOpt.rect = rect;
menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
menuOpt.state |= QStyle::State_Enabled;
@@ -954,7 +1002,7 @@ void QMenuPrivate::drawTearOff(QPainter *painter, const QRect &rect)
menuOpt.state = QStyle::State_None;
menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
menuOpt.maxIconWidth = 0;
- menuOpt.tabWidth = 0;
+ menuOpt.reservedShortcutWidth = 0;
menuOpt.rect = rect;
menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
if (tearoffHighlighted)
@@ -969,7 +1017,7 @@ QRect QMenuPrivate::rect() const
Q_Q(const QMenu);
QStyle *style = q->style();
QStyleOption opt(0);
- opt.init(q);
+ opt.initFrom(q);
const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q);
const int vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q);
const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q);
@@ -1024,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
@@ -1075,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;
@@ -1083,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)
@@ -1093,7 +1151,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
break;
}
}
- if(newOffset)
+ if (newOffset)
newOffset -= fw * 2;
}
@@ -1102,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;
@@ -1129,9 +1187,9 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
QRect geom = q->geometry();
if (newOffset > scroll->scrollOffset && (scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollUp)) { //scroll up
const int newHeight = geom.height()-(newOffset-scroll->scrollOffset);
- if(newHeight > geom.height())
+ if (newHeight > geom.height())
geom.setHeight(newHeight);
- } else if(scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollDown) {
+ } else if (scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollDown) {
int newTop = geom.top() + (newOffset-scroll->scrollOffset);
if (newTop < desktopFrame+screen.top())
newTop = desktopFrame+screen.top();
@@ -1159,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 &current = actionRects[i];
current.moveTop(current.top() + delta);
@@ -1180,7 +1238,7 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool activ
{
Q_Q(QMenu);
updateActionRects();
- if(location == QMenuScroller::ScrollBottom) {
+ if (location == QMenuScroller::ScrollBottom) {
for(int i = actions.size()-1; i >= 0; --i) {
QAction *act = actions.at(i);
if (actionRects.at(i).isNull())
@@ -1188,14 +1246,14 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool activ
if (!act->isSeparator() &&
(q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, nullptr, q)
|| act->isEnabled())) {
- if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
+ if (scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollBottom, active);
- else if(active)
+ else if (active)
setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
break;
}
}
- } else if(location == QMenuScroller::ScrollTop) {
+ } else if (location == QMenuScroller::ScrollTop) {
for(int i = 0; i < actions.size(); ++i) {
QAction *act = actions.at(i);
if (actionRects.at(i).isNull())
@@ -1203,9 +1261,9 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool activ
if (!act->isSeparator() &&
(q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, nullptr, q)
|| act->isEnabled())) {
- if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ if (scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollTop, active);
- else if(active)
+ else if (active)
setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
break;
}
@@ -1226,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);
@@ -1235,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;
@@ -1252,7 +1310,7 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool pag
break;
}
}
- if(!scrolled) {
+ if (!scrolled) {
scroll->scrollFlags &= ~QMenuScroller::ScrollDown;
q->update();
}
@@ -1264,11 +1322,11 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool pag
bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
{
Q_Q(QMenu);
- QPoint pos = q->mapFromGlobal(e->globalPos());
+ QPoint pos = q->mapFromGlobal(e->globalPosition().toPoint());
QStyle *style = q->style();
QStyleOption opt(0);
- opt.init(q);
+ opt.initFrom(q);
const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q);
const int vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q);
const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q);
@@ -1303,7 +1361,7 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
tearRect.translate(0, scrollerHeight());
q->update(tearRect);
- if (tearRect.contains(pos) && hasMouseMoved(e->globalPos())) {
+ if (tearRect.contains(pos) && hasMouseMoved(e->globalPosition().toPoint())) {
setCurrentAction(nullptr);
tearoffHighlighted = 1;
if (e->type() == QEvent::MouseButtonRelease) {
@@ -1318,26 +1376,27 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
tearoffHighlighted = 0;
}
- if (q->frameGeometry().contains(e->globalPos()))
+ if (q->frameGeometry().contains(e->globalPosition().toPoint()))
return false; //otherwise if the event is in our rect we want it..
for(QWidget *caused = causedPopup.widget; caused;) {
bool passOnEvent = false;
QWidget *next_widget = nullptr;
- QPoint cpos = caused->mapFromGlobal(e->globalPos());
+ QPointF cpos = caused->mapFromGlobal(e->globalPosition());
#if QT_CONFIG(menubar)
if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
- passOnEvent = mb->rect().contains(cpos);
+ passOnEvent = mb->rect().contains(cpos.toPoint());
} else
#endif
if (QMenu *m = qobject_cast<QMenu*>(caused)) {
- passOnEvent = m->rect().contains(cpos);
+ passOnEvent = m->rect().contains(cpos.toPoint());
next_widget = m->d_func()->causedPopup.widget;
}
if (passOnEvent) {
if (e->type() != QEvent::MouseButtonRelease || mouseDown == caused) {
- QMouseEvent new_e(e->type(), cpos, caused->mapTo(caused->topLevelWidget(), cpos), e->screenPos(),
- e->button(), e->buttons(), e->modifiers(), e->source());
+ QMouseEvent new_e(e->type(), cpos, caused->mapTo(caused->topLevelWidget(), cpos), e->globalPosition(),
+ e->button(), e->buttons(), e->modifiers(),
+ e->source(), e->pointingDevice());
QCoreApplication::sendEvent(caused, &new_e);
return true;
}
@@ -1349,11 +1408,21 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
return false;
}
-void QMenuPrivate::activateCausedStack(const QVector<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self)
+void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget>> &causedStack, QAction *action,
+ QAction::ActionEvent action_e, bool self)
{
- QBoolBlocker guard(activationRecursionGuard);
- if(self)
+ 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);
@@ -1397,7 +1466,7 @@ void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e
/* I have to save the caused stack here because it will be undone after popup execution (ie in the hide).
Then I iterate over the list to actually send the events. --Sam
*/
- const QVector<QPointer<QWidget> > causedStack = calcCausedStack();
+ const QList<QPointer<QWidget>> causedStack = calcCausedStack();
if (action_e == QAction::Trigger) {
#if QT_CONFIG(whatsthis)
if (!inWhatsThisMode)
@@ -1409,7 +1478,7 @@ void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e
} else {
for(QWidget *widget = QApplication::activePopupWidget(); widget; ) {
if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
- if(qmenu == q)
+ if (qmenu == q)
hideUpToMenuBar();
widget = qmenu->d_func()->causedPopup.widget;
} else {
@@ -1429,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);
@@ -1459,7 +1529,7 @@ void QMenuPrivate::_q_actionTriggered()
if (!activationRecursionGuard && actionGuard) {
//in case the action has not been activated by the mouse
//we check the parent hierarchy
- QVector< QPointer<QWidget> > list;
+ QList<QPointer<QWidget>> list;
for(QWidget *widget = q->parentWidget(); widget; ) {
if (qobject_cast<QMenu*>(widget)
#if QT_CONFIG(menubar)
@@ -1473,6 +1543,9 @@ void QMenuPrivate::_q_actionTriggered()
}
}
activateCausedStack(list, action, QAction::Trigger, false);
+ // if a widget action fires, we need to hide the menu explicitly
+ if (qobject_cast<QWidgetAction*>(action))
+ hideUpToMenuBar();
}
}
}
@@ -1491,7 +1564,7 @@ void QMenuPrivate::_q_platformMenuAboutToShow()
emit q->aboutToShow();
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
if (platformMenu) {
const auto actions = q->actions();
for (QAction *action : actions) {
@@ -1570,14 +1643,14 @@ 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;
- option->tabWidth = d->tabWidth;
+ option->reservedShortcutWidth = d->tabWidth;
option->maxIconWidth = d->maxIconWidth;
option->menuRect = rect();
}
@@ -1620,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.
@@ -1640,13 +1713,13 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action)
Widgets can be inserted into menus with the QWidgetAction class.
Instances of this class are used to hold widgets, and are inserted
- into menus with the addAction() overload that takes a QAction.
-
- Conversely, actions can be added to widgets with the addAction(),
- addActions() and insertAction() functions.
+ into menus with the addAction() overload that takes a QAction. If the
+ QWidgetAction fires the triggered() signal, the menu will close.
\warning To make QMenu visible on the screen, exec() or popup() should be
- used instead of show().
+ used instead of show() or setVisible(). To hide or disable the menu in the
+ menubar, or in another menu to which it was added as a submenu, use the
+ respective properties of menuAction() instead.
\section1 QMenu on \macos with Qt Build Against Cocoa
@@ -1659,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},
- {Application Example}, {Menus Example}
+ \sa QMenuBar, {Menus Example}
*/
@@ -1725,162 +1797,75 @@ QMenu::~QMenu()
hideTearOffMenu();
}
+#if QT_DEPRECATED_SINCE(6, 4)
/*!
- This convenience function creates a new action with \a text.
- The function adds the newly created action to the menu's
- list of actions, and returns it.
+ \fn QAction *QMenu::addAction(const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut)
+ \obsolete
- QMenu takes ownership of the returned QAction.
-
- \sa QWidget::addAction()
+ Use \c{QWidget::addAction(text, shortcut, receiver, member)} instead.
*/
-QAction *QMenu::addAction(const QString &text)
-{
- QAction *ret = new QAction(text, this);
- addAction(ret);
- return ret;
-}
-
-/*!
- \overload
-
- This convenience function creates a new action with an \a icon
- and some \a text. The function adds the newly created action to
- the menu's list of actions, and returns it.
-
- QMenu takes ownership of the returned QAction.
-
- \sa QWidget::addAction()
-*/
-QAction *QMenu::addAction(const QIcon &icon, const QString &text)
-{
- QAction *ret = new QAction(icon, text, this);
- addAction(ret);
- return ret;
-}
-
-/*!
- \overload
-
- This convenience function creates a new action with the text \a
- text and an optional shortcut \a shortcut. The action's
- \l{QAction::triggered()}{triggered()} signal is connected to the
- \a receiver's \a member slot. The function adds the newly created
- action to the menu's list of actions and returns it.
-
- QMenu takes ownership of the returned QAction.
-
- \sa QWidget::addAction()
-*/
-QAction *QMenu::addAction(const QString &text, const QObject *receiver, const char* member
#if QT_CONFIG(shortcut)
- , const QKeySequence &shortcut
-#endif
- )
+QAction *QMenu::addAction(const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut)
{
- QAction *action = new QAction(text, this);
-#if QT_CONFIG(shortcut)
- action->setShortcut(shortcut);
-#endif
- QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
- addAction(action);
- return action;
+ return QWidget::addAction(text, shortcut, receiver, member);
}
+#endif
-/*!\fn template<typename Functor> QAction *QMenu::addAction(const QString &text, Functor functor, const QKeySequence &shortcut = 0)
+/*!
+ \fn template<typename Functor> QAction *QMenu::addAction(const QString &text, Functor functor, const QKeySequence &shortcut)
\since 5.6
+ \obsolete
- \overload
-
- This convenience function creates a new action with the text \a
- text and an optional shortcut \a shortcut. The action's
- \l{QAction::triggered()}{triggered()} signal is connected to the
- \a functor. The function adds the newly created
- action to the menu's list of actions and returns it.
-
- QMenu takes ownership of the returned QAction.
+ Use QWidget::addAction(text, shortcut, functor) instead.
*/
-/*!\fn template<typename Functor> QAction *QMenu::addAction(const QString &text, const QObject *context, Functor functor, const QKeySequence &shortcut)
+/*!
+ \fn template<typename Functor> QAction *QMenu::addAction(const QString &text, const QObject *context, Functor functor, const QKeySequence &shortcut)
\since 5.6
+ \obsolete
- \overload
-
- This convenience function creates a new action with the text \a
- text and an optional shortcut \a shortcut. The action's
- \l{QAction::triggered()}{triggered()} signal is connected to the
- \a functor. The functor can be a pointer to a member function of
- the \a context object. The newly created action is added to the
- menu's list of actions and a pointer to it is returned.
-
- If the \a context object is destroyed, the functor will not be called.
-
- QMenu takes ownership of the returned QAction.
+ Use QWidget::addAction(text, shortcut, context, functor) instead.
*/
-/*!\fn template<typename Functor> QAction *QMenu::addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut = 0)
+/*!
+ \fn template<typename Functor> QAction *QMenu::addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
\since 5.6
+ \obsolete
- \overload
-
- This convenience function creates a new action with an \a icon
- and some \a text and an optional shortcut \a shortcut. The action's
- \l{QAction::triggered()}{triggered()} signal is connected to the
- \a functor. The function adds the newly created
- action to the menu's list of actions and returns it.
-
- QMenu takes ownership of the returned QAction.
+ Use QWidget::addAction(icon, text, shortcut, functor) instead.
*/
-/*!\fn template<typename Functor> QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *context, Functor functor, const QKeySequence &shortcut)
+/*!
+ \fn template<typename Functor> QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *context, Functor functor, const QKeySequence &shortcut)
\since 5.6
+ \obsolete
- \overload
-
- This convenience function creates a new action with an \a icon
- and some \a text and an optional shortcut \a shortcut. The action's
- \l{QAction::triggered()}{triggered()} signal is connected to the
- \a functor. The \a functor can be a pointer to a member function
- of the \a context object. The newly created action is added to the
- menu's list of actions and a pointer to it is returned.
-
- If \a context is destroyed, the functor will not be called.
-
- QMenu takes ownership of the returned QAction.
+ Use QWidget::addAction(icon, text, shortcut, context, functor) instead.
*/
/*!
- \overload
+ \fn QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut)
- This convenience function creates a new action with an \a icon and
- some \a text and an optional shortcut \a shortcut. The action's
- \l{QAction::triggered()}{triggered()} signal is connected to the
- \a member slot of the \a receiver object. The function adds the
- newly created action to the menu's list of actions, and returns it.
+ \obsolete
- QMenu takes ownership of the returned QAction.
-
- \sa QWidget::addAction()
+ Use QWidget::addAction(icon, text, shortcut, receiver, member) instead.
*/
-QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *receiver,
- const char* member
#if QT_CONFIG(shortcut)
- , const QKeySequence &shortcut
-#endif
- )
+QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *receiver,
+ const char* member, const QKeySequence &shortcut)
{
QAction *action = new QAction(icon, text, this);
-#if QT_CONFIG(shortcut)
action->setShortcut(shortcut);
-#endif
QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
addAction(action);
return action;
}
+#endif
+#endif // QT_DEPRECATED_SINCE(6, 4)
/*!
This convenience function adds \a menu as a submenu to this menu.
@@ -2196,7 +2181,7 @@ void QMenu::setActiveAction(QAction *act)
{
Q_D(QMenu);
d->setCurrentAction(act, 0);
- if (d->scroll)
+ if (d->scroll && act)
d->scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollCenter);
}
@@ -2222,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;
@@ -2243,7 +2228,7 @@ void QMenu::clear()
for(int i = 0; i < acts.size(); i++) {
removeAction(acts[i]);
- if (acts[i]->parent() == this && acts[i]->d_func()->widgets.isEmpty())
+ if (acts[i]->parent() == this && acts[i]->d_func()->associatedObjects.isEmpty())
delete acts[i];
}
}
@@ -2287,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;
@@ -2300,13 +2285,12 @@ QSize QMenu::sizeHint() const
// the top and left margins, so we only need to add margins for
// the bottom and right.
QStyleOption opt(0);
- opt.init(this);
+ opt.initFrom(this);
const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this);
s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this) + fw + d->rightmargin;
s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) + fw + d->bottommargin;
- return style()->sizeFromContents(QStyle::CT_Menu, &opt,
- s.expandedTo(QApplication::globalStrut()), this);
+ return style()->sizeFromContents(QStyle::CT_Menu, &opt, s, this);
}
/*!
@@ -2326,76 +2310,105 @@ QSize QMenu::sizeHint() const
void QMenu::popup(const QPoint &p, QAction *atAction)
{
Q_D(QMenu);
- if (d->scroll) { // reset scroll state from last popup
- if (d->scroll->scrollOffset)
- d->itemsDirty = 1; // sizeHint will be incorrect if there is previous scroll
- d->scroll->scrollOffset = 0;
- d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
+ d->popup(p, 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
+ scroll->scrollOffset = 0;
+ scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
}
- d->tearoffHighlighted = 0;
- d->motions = 0;
- d->doChildEffects = true;
- d->updateLayoutDirection();
+ tearoffHighlighted = 0;
+ motions = 0;
+ doChildEffects = true;
+ updateLayoutDirection();
+
+ q->ensurePolished(); // Get the right font
// Ensure that we get correct sizeHints by placing this window on the correct screen.
- // However if the QMenu was constructed with a QDesktopScreenWidget as its parent,
+ // However if the QMenu was constructed with a Qt::Desktop widget as its parent,
// then initialScreenIndex was set, so we should respect that for the lifetime of this menu.
- // Use d->popupScreen to remember, because initialScreenIndex will be reset after the first showing.
// However if eventLoop exists, then exec() already did this by calling createWinId(); so leave it alone. (QTBUG-76162)
- if (!d->eventLoop) {
- const int screenIndex = d->topData()->initialScreenIndex;
- if (screenIndex >= 0)
- d->popupScreen = screenIndex;
- if (auto s = QGuiApplication::screens().value(d->popupScreen)) {
- if (d->setScreen(s))
- d->itemsDirty = true;
- } else if (d->setScreenForPoint(p)) {
- d->itemsDirty = true;
- }
+ if (!eventLoop) {
+ bool screenSet = false;
+ QScreen *screen = topData()->initialScreen;
+ if (screen) {
+ if (setScreen(screen))
+ itemsDirty = true;
+ screenSet = true;
+ } else if (QMenu *parentMenu = qobject_cast<QMenu *>(parent)) {
+ // a submenu is always opened from an open parent menu,
+ // so show it on the same screen where the parent is. (QTBUG-76162)
+ if (setScreen(parentMenu->screen()))
+ itemsDirty = true;
+ screenSet = true;
+ }
+ if (!screenSet && setScreenForPoint(p))
+ itemsDirty = true;
+ }
+
+ const bool contextMenu = isContextMenu();
+ if (lastContextMenu != contextMenu) {
+ itemsDirty = true;
+ lastContextMenu = contextMenu;
}
- const bool contextMenu = d->isContextMenu();
- if (d->lastContextMenu != contextMenu) {
- d->itemsDirty = true;
- d->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
- setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(d->topCausedWidget()) != 0);
+ q->setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(topCausedWidget()) != nullptr);
#endif
- ensurePolished(); // Get the right font
- emit aboutToShow();
- const bool actionListChanged = d->itemsDirty;
+ emit q->aboutToShow();
+ const bool actionListChanged = itemsDirty;
QRect screen;
#if QT_CONFIG(graphicsview)
- bool isEmbedded = !bypassGraphicsProxyWidget(this) && QMenuPrivate::nearestGraphicsProxyWidget(this);
+ bool isEmbedded = !bypassGraphicsProxyWidget(q) && QMenuPrivate::nearestGraphicsProxyWidget(q);
if (isEmbedded)
- screen = d->popupGeometry();
+ screen = popupGeometry();
else
#endif
- screen = d->popupGeometry(QDesktopWidgetPrivate::screenNumber(p));
- d->updateActionRects(screen);
+ screen = popupGeometry(QGuiApplication::screenAt(p));
+ updateActionRects(screen);
QPoint pos;
- QPushButton *causedButton = qobject_cast<QPushButton*>(d->causedPopup.widget);
+ QPushButton *causedButton = qobject_cast<QPushButton*>(causedPopup.widget);
if (actionListChanged && causedButton)
pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
else
pos = p;
+ popupScreen = QGuiApplication::screenAt(pos);
- const QSize menuSizeHint(sizeHint());
+ const QSize menuSizeHint(q->sizeHint());
QSize size = menuSizeHint;
- const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, nullptr, this);
- bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen);
+
+ if (positionFunction)
+ pos = positionFunction(menuSizeHint);
+
+ const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, nullptr, q);
+ bool adjustToDesktop = !q->window()->testAttribute(Qt::WA_DontShowOnScreen);
// if the screens have very different geometries and the menu is too big, we have to recalculate
if ((size.height() > screen.height() || size.width() > screen.width()) ||
// Layout is not right, we might be able to save horizontal space
- (d->ncols >1 && size.height() < screen.height())) {
+ (ncols >1 && size.height() < screen.height())) {
size.setWidth(qMin(menuSizeHint.width(), screen.width() - desktopFrame * 2));
size.setHeight(qMin(menuSizeHint.height(), screen.height() - desktopFrame * 2));
adjustToDesktop = true;
@@ -2404,61 +2417,61 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
#ifdef QT_KEYPAD_NAVIGATION
if (!atAction && QApplicationPrivate::keypadNavigationEnabled()) {
// Try to have one item activated
- if (d->defaultAction && d->defaultAction->isEnabled()) {
- atAction = d->defaultAction;
+ if (defaultAction && defaultAction->isEnabled()) {
+ atAction = defaultAction;
// TODO: This works for first level menus, not yet sub menus
} else {
- for (QAction *action : qAsConst(d->actions))
+ for (QAction *action : std::as_const(actions))
if (action->isEnabled()) {
atAction = action;
break;
}
}
- d->currentAction = atAction;
+ currentAction = atAction;
}
#endif
- if (d->ncols > 1) {
+ if (ncols > 1) {
pos.setY(screen.top() + desktopFrame);
} else if (atAction) {
- for (int i = 0, above_height = 0; i < d->actions.count(); i++) {
- QAction *action = d->actions.at(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;
- if (d->scroll && newY < desktopFrame) {
- d->scroll->scrollFlags = d->scroll->scrollFlags
+ if (scroll && newY < desktopFrame) {
+ scroll->scrollFlags = scroll->scrollFlags
| QMenuPrivate::QMenuScroller::ScrollUp;
- d->scroll->scrollOffset = newY;
+ scroll->scrollOffset = newY;
newY = desktopFrame;
}
pos.setY(newY);
- if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
- && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, nullptr, this)) {
- int below_height = above_height + d->scroll->scrollOffset;
- for (int i2 = i; i2 < d->actionRects.count(); i2++)
- below_height += d->actionRects.at(i2).height();
+ 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.size(); i2++)
+ below_height += actionRects.at(i2).height();
size.setHeight(below_height);
}
break;
} else {
- above_height += d->actionRects.at(i).height();
+ above_height += actionRects.at(i).height();
}
}
}
QPoint mouse = QCursor::pos();
- d->mousePopupPos = mouse;
- const bool snapToMouse = !d->causedPopup.widget && (QRect(p.x() - 3, p.y() - 3, 6, 6).contains(mouse));
+ mousePopupPos = mouse;
+ const bool snapToMouse = !causedPopup.widget && (QRect(p.x() - 3, p.y() - 3, 6, 6).contains(mouse));
if (adjustToDesktop) {
// handle popup falling "off screen"
- if (isRightToLeft()) {
+ if (q->isRightToLeft()) {
if (snapToMouse) // position flowing left from the mouse
pos.setX(mouse.x() - size.width());
#if QT_CONFIG(menubar)
// if the menu is in a menubar or is a submenu, it should be right-aligned
- if (qobject_cast<QMenuBar*>(d->causedPopup.widget) || qobject_cast<QMenu*>(d->causedPopup.widget))
+ if (qobject_cast<QMenuBar*>(causedPopup.widget) || qobject_cast<QMenu*>(causedPopup.widget))
pos.rx() -= size.width();
#endif // QT_CONFIG(menubar)
@@ -2473,7 +2486,7 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
pos.setX(screen.left() + desktopFrame);
}
if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
- if(snapToMouse)
+ if (snapToMouse)
pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
else
pos.setY(qMax(p.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
@@ -2482,8 +2495,8 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
if (pos.y() < screen.top() + desktopFrame)
pos.setY(screen.top() + desktopFrame);
if (pos.y() + menuSizeHint.height() - 1 > screen.bottom() - desktopFrame) {
- if (d->scroll) {
- d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
+ if (scroll) {
+ scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
int y = qMax(screen.y(),pos.y());
size.setHeight(screen.bottom() - (desktopFrame * 2) - y);
} else {
@@ -2492,13 +2505,13 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
}
}
}
- const int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, nullptr, this);
- QMenu *caused = qobject_cast<QMenu*>(d_func()->causedPopup.widget);
+ const int subMenuOffset = q->style()->pixelMetric(QStyle::PM_SubMenuOverlap, nullptr, q);
+ QMenu *caused = qobject_cast<QMenu*>(causedPopup.widget);
if (caused && caused->geometry().width() + menuSizeHint.width() + subMenuOffset < screen.width()) {
QRect parentActionRect(caused->d_func()->actionRect(caused->d_func()->currentAction));
const QPoint actionTopLeft = caused->mapToGlobal(parentActionRect.topLeft());
parentActionRect.moveTopLeft(actionTopLeft);
- if (isRightToLeft()) {
+ if (q->isRightToLeft()) {
if ((pos.x() + menuSizeHint.width() > parentActionRect.left() - subMenuOffset)
&& (pos.x() < parentActionRect.right()))
{
@@ -2520,61 +2533,62 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
}
}
}
- setGeometry(QRect(pos, size));
+ popupScreen = QGuiApplication::screenAt(pos);
+ q->setGeometry(QRect(pos, size));
#if QT_CONFIG(effects)
- int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
+ int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
int vGuess = QEffects::DownScroll;
- if (isRightToLeft()) {
+ if (q->isRightToLeft()) {
if ((snapToMouse && (pos.x() + size.width() / 2 > mouse.x())) ||
- (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 > d->causedPopup.widget->x()))
+ (qobject_cast<QMenu*>(causedPopup.widget) && pos.x() + size.width() / 2 > causedPopup.widget->x()))
hGuess = QEffects::RightScroll;
} else {
if ((snapToMouse && (pos.x() + size.width() / 2 < mouse.x())) ||
- (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 < d->causedPopup.widget->x()))
+ (qobject_cast<QMenu*>(causedPopup.widget) && pos.x() + size.width() / 2 < causedPopup.widget->x()))
hGuess = QEffects::LeftScroll;
}
#if QT_CONFIG(menubar)
if ((snapToMouse && (pos.y() + size.height() / 2 < mouse.y())) ||
- (qobject_cast<QMenuBar*>(d->causedPopup.widget) &&
- pos.y() + size.width() / 2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y()))
+ (qobject_cast<QMenuBar*>(causedPopup.widget) &&
+ pos.y() + size.width() / 2 < causedPopup.widget->mapToGlobal(causedPopup.widget->pos()).y()))
vGuess = QEffects::UpScroll;
#endif
if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) {
bool doChildEffects = true;
#if QT_CONFIG(menubar)
- if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) {
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(causedPopup.widget)) {
doChildEffects = mb->d_func()->doChildEffects;
mb->d_func()->doChildEffects = false;
} else
#endif
- if (QMenu *m = qobject_cast<QMenu*>(d->causedPopup.widget)) {
+ if (QMenu *m = qobject_cast<QMenu*>(causedPopup.widget)) {
doChildEffects = m->d_func()->doChildEffects;
m->d_func()->doChildEffects = false;
}
if (doChildEffects) {
if (QApplication::isEffectEnabled(Qt::UI_FadeMenu))
- qFadeEffect(this);
- else if (d->causedPopup.widget)
- qScrollEffect(this, qobject_cast<QMenu*>(d->causedPopup.widget) ? hGuess : vGuess);
+ qFadeEffect(q);
+ else if (causedPopup.widget)
+ qScrollEffect(q, qobject_cast<QMenu*>(causedPopup.widget) ? hGuess : vGuess);
else
- qScrollEffect(this, hGuess | vGuess);
+ qScrollEffect(q, hGuess | vGuess);
} else {
// kill any running effect
qFadeEffect(nullptr);
qScrollEffect(nullptr);
- show();
+ q->show();
}
} else
#endif
{
- show();
+ q->show();
}
-#ifndef QT_NO_ACCESSIBILITY
- QAccessibleEvent event(this, QAccessible::PopupMenuStart);
+#if QT_CONFIG(accessibility)
+ QAccessibleEvent event(q, QAccessible::PopupMenuStart);
QAccessible::updateAccessibility(&event);
#endif
}
@@ -2640,20 +2654,27 @@ QAction *QMenu::exec()
QAction *QMenu::exec(const QPoint &p, QAction *action)
{
Q_D(QMenu);
- ensurePolished();
- createWinId();
- QEventLoop eventLoop;
- d->eventLoop = &eventLoop;
- popup(p, action);
-
- QPointer<QObject> guard = this;
- (void) eventLoop.exec();
+ return d->exec(p, action);
+}
+
+QAction *QMenuPrivate::exec(const QPoint &p, QAction *action, PositionFunction positionFunction)
+{
+ Q_Q(QMenu);
+ q->ensurePolished();
+ q->createWinId();
+ QEventLoop evtLoop;
+ eventLoop = &evtLoop;
+ popup(p, action, positionFunction);
+
+ QPointer<QObject> guard = q;
+ (void) evtLoop.exec();
if (guard.isNull())
return nullptr;
- action = d->syncAction;
- d->syncAction = nullptr;
- d->eventLoop = nullptr;
+ action = syncAction;
+ syncAction = nullptr;
+ eventLoop = nullptr;
+ popupScreen.clear();
return action;
}
@@ -2679,11 +2700,7 @@ QAction *QMenu::exec(const QPoint &p, QAction *action)
\sa popup(), QWidget::mapToGlobal()
*/
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
QAction *QMenu::exec(const QList<QAction *> &actions, const QPoint &pos, QAction *at, QWidget *parent)
-#else
-QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at, QWidget *parent)
-#endif
{
QMenu menu(parent);
menu.addActions(actions);
@@ -2700,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
@@ -2726,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;
@@ -2734,8 +2751,8 @@ void QMenu::paintEvent(QPaintEvent *e)
menuOpt.state = QStyle::State_None;
menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
menuOpt.maxIconWidth = 0;
- menuOpt.tabWidth = 0;
- style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this);
+ menuOpt.reservedShortcutWidth = 0;
+ p.drawPrimitive(QStyle::PE_PanelMenu, menuOpt);
//calculate the scroll up / down rect
const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, this);
@@ -2767,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)
@@ -2803,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);
@@ -2835,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.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
@@ -2847,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)
@@ -2875,9 +2892,9 @@ void QMenu::mousePressEvent(QMouseEvent *e)
// and mouse clicks on second screen, e->pos() is QPoint(0,0) and the menu doesn't hide. This trick makes
// possible to hide the menu when mouse clicks on another screen (e->screenPos() returns correct value).
// Only when mouse clicks in QPoint(0,0) on second screen, the menu doesn't hide.
- if ((e->pos().isNull() && !e->screenPos().isNull()) || !rect().contains(e->pos())) {
+ if ((e->position().toPoint().isNull() && !e->globalPosition().isNull()) || !rect().contains(e->position().toPoint())) {
if (d->noReplayFor
- && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPos()))
+ && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPosition().toPoint()))
setAttribute(Qt::WA_NoMouseReplay);
if (d->eventLoop) // synchronous operation
d->syncAction = nullptr;
@@ -2886,7 +2903,7 @@ void QMenu::mousePressEvent(QMouseEvent *e)
}
QMenuPrivate::mouseDown = this;
- QAction *action = d->actionAt(e->pos());
+ QAction *action = d->actionAt(e->position().toPoint());
d->setCurrentAction(action, 20);
update();
}
@@ -2906,17 +2923,17 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e)
QMenuPrivate::mouseDown = nullptr;
d->setSyncAction();
- QAction *action = d->actionAt(e->pos());
+ QAction *action = d->actionAt(e->position().toPoint());
if (action && action == d->currentAction) {
- if (!action->menu()){
+ if (!action->menu()) {
#if defined(Q_OS_WIN)
//On Windows only context menus can be activated with the right button
if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
#endif
d->activateAction(action, QAction::Trigger);
}
- } else if ((!action || action->isEnabled()) && d->hasMouseMoved(e->globalPos())) {
+ } else if ((!action || action->isEnabled()) && d->hasMouseMoved(e->globalPosition().toPoint())) {
d->hideUpToMenuBar();
}
}
@@ -2954,8 +2971,7 @@ void QMenu::changeEvent(QEvent *e)
/*!
\reimp
*/
-bool
-QMenu::event(QEvent *e)
+bool QMenu::event(QEvent *e)
{
Q_D(QMenu);
switch (e->type()) {
@@ -2963,7 +2979,7 @@ 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
@@ -2977,7 +2993,7 @@ 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;
@@ -3010,8 +3026,10 @@ 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;
-#ifndef QT_NO_TOOLTIP
+#if QT_CONFIG(tooltip)
case QEvent::ToolTip:
if (d->toolTipsVisible) {
const QHelpEvent *ev = static_cast<const QHelpEvent*>(e);
@@ -3019,11 +3037,13 @@ QMenu::event(QEvent *e)
const QString toolTip = action->d_func()->tooltip;
if (!toolTip.isEmpty())
QToolTip::showText(ev->globalPos(), toolTip, this);
+ else
+ QToolTip::hideText();
return true;
}
}
break;
-#endif // QT_NO_TOOLTIP
+#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(whatsthis)
case QEvent::QueryWhatsThis:
e->setAccepted(d->whatsThis.size());
@@ -3086,7 +3106,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
case Qt::Key_PageUp:
key_consumed = true;
if (d->currentAction && d->scroll) {
- if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollUp, true, true);
else
d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
@@ -3095,7 +3115,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
case Qt::Key_PageDown:
key_consumed = true;
if (d->currentAction && d->scroll) {
- if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
+ if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollDown, true, true);
else
d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
@@ -3107,8 +3127,8 @@ void QMenu::keyPressEvent(QKeyEvent *e)
QAction *nextAction = nullptr;
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) {
+ if (key == Qt::Key_Down) {
+ for(int i = 0; i < d->actions.size(); ++i) {
QAction *act = d->actions.at(i);
if (d->actionRects.at(i).isNull())
continue;
@@ -3120,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;
@@ -3133,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) {
@@ -3143,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)
@@ -3169,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)
@@ -3326,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()) {
@@ -3340,10 +3360,10 @@ void QMenu::keyPressEvent(QKeyEvent *e)
QAction *act = d->actions.at(i);
const QString act_text = act->text();
for(int c = 0; c < d->searchBuffer.size(); ++c) {
- if(act_text.indexOf(d->searchBuffer.at(c), 0, Qt::CaseInsensitive) != -1)
+ if (act_text.indexOf(d->searchBuffer.at(c), 0, Qt::CaseInsensitive) != -1)
++match_count;
}
- if(match_count > best_match_count) {
+ if (match_count > best_match_count) {
best_match_count = match_count;
nextAction = act;
}
@@ -3359,7 +3379,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
continue;
QAction *act = d->actions.at(i);
QKeySequence sequence = QKeySequence::mnemonic(act->text());
- int key = sequence[0] & 0xffff;
+ int key = sequence[0].toCombined() & 0xffff; // suspicious
if (key == c.unicode()) {
clashCount++;
if (!first)
@@ -3382,7 +3402,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
#endif
if (nextAction) {
key_consumed = true;
- if(d->scroll)
+ if (d->scroll)
d->scrollMenu(nextAction, QMenuPrivate::QMenuScroller::ScrollCenter, false);
d->setCurrentAction(nextAction, 0, QMenuPrivate::SelectedFromElsewhere, true);
if (!nextAction->menu() && activateAction) {
@@ -3423,12 +3443,12 @@ void QMenu::mouseMoveEvent(QMouseEvent *e)
return;
d->motions++;
- if (d->motions == 0)
+ if (!d->hasMouseMoved(e->globalPosition().toPoint()))
return;
- d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos());
+ d->hasHadMouse = d->hasHadMouse || rect().contains(e->position().toPoint());
- QAction *action = d->actionAt(e->pos());
+ QAction *action = d->actionAt(e->position().toPoint());
if ((!action || action->isSeparator()) && !d->sloppyState.enabled()) {
if (d->hasHadMouse
|| (!d->currentAction || !d->currentAction->menu() || !d->currentAction->menu()->isVisible())) {
@@ -3443,7 +3463,7 @@ void QMenu::mouseMoveEvent(QMouseEvent *e)
if (d->activeMenu)
d->activeMenu->d_func()->setCurrentAction(nullptr);
- QMenuSloppyState::MouseEventResult sloppyEventResult = d->sloppyState.processMouseEvent(e->localPos(), action, d->currentAction);
+ QMenuSloppyState::MouseEventResult sloppyEventResult = d->sloppyState.processMouseEvent(e->position(), action, d->currentAction);
if (sloppyEventResult == QMenuSloppyState::EventShouldBePropagated) {
d->setCurrentAction(action, d->mousePopupDelay);
} else if (sloppyEventResult == QMenuSloppyState::EventDiscardsSloppyState) {
@@ -3455,7 +3475,7 @@ void QMenu::mouseMoveEvent(QMouseEvent *e)
/*!
\reimp
*/
-void QMenu::enterEvent(QEvent *)
+void QMenu::enterEvent(QEnterEvent *)
{
Q_D(QMenu);
d->hasReceievedEnter = true;
@@ -3493,7 +3513,7 @@ QMenu::timerEvent(QTimerEvent *e)
internalDelayedPopup();
} else if (d->sloppyState.isTimerId(e->timerId())) {
d->sloppyState.timeout();
- } else if(d->searchBufferTimer.timerId() == e->timerId()) {
+ } else if (d->searchBufferTimer.timerId() == e->timerId()) {
d->searchBuffer.clear();
}
}
@@ -3511,7 +3531,10 @@ void QMenu::actionEvent(QActionEvent *e)
if (e->type() == QEvent::ActionAdded) {
if (!d->tornoff
- && !qobject_cast<QMenuBar*>(e->action()->parent())) {
+#if QT_CONFIG(menubar)
+ && !qobject_cast<QMenuBar*>(e->action()->parent())
+#endif
+ ) {
// Only connect if the action was not directly added by QMenuBar::addAction(const QString &text)
// to avoid the signal being emitted twice
connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()), Qt::UniqueConnection);
@@ -3536,19 +3559,8 @@ void QMenu::actionEvent(QActionEvent *e)
if (e->action() == d->currentAction)
d->currentAction = nullptr;
if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
- if (QWidget *widget = d->widgetItems.value(wa)) {
-#ifdef Q_OS_OSX
- QWidget *p = widget->parentWidget();
- if (p != this && qobject_cast<QMacNativeWidget *>(p)) {
- // This widget was reparented into a native Mac view
- // (see QMenuPrivate::moveWidgetToPlatformItem).
- // Reset the parent and delete the native widget.
- widget->setParent(this);
- p->deleteLater();
- }
-#endif
+ if (QWidget *widget = d->widgetItems.value(wa))
wa->releaseWidget(widget);
- }
}
d->widgetItems.remove(static_cast<QAction *>(e->action()));
}
@@ -3609,13 +3621,13 @@ void QMenu::internalDelayedPopup()
screen = d->popupGeometry();
else
#endif
- screen = d->popupGeometry(QDesktopWidgetPrivate::screenNumber(pos()));
+ screen = d->popupGeometry(QGuiApplication::screenAt(pos()));
int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, nullptr, this);
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()) {