Always send QContextMenuEvent after the contextMenuEventType event

Both widgets and Qt Quick Controls are unable to avoid accepting the
right-click events (press and/or release) in at least some cases.
In the Windows UI pattern of allowing the user to select something by
pressing (and maybe dragging) with the right button and then getting
a QContextMenuEvent afterwards, it's sensible for the code that does
the selection to accept the mouse events, because that code is only
concerned with selection, not the context menu. And in Controls,
Pane is accepting all mouse events just to prevent propagation to
other controls underneath. (That might not be so great, but we don't
have a better way yet.) In legacy Qt Quick, accepting the event results
in an exclusive grab; so in fact, Pane gets the grab, so we can't use
that either, as a way to distinguish "stop propagation" from "this item
is handling it completely, nothing more needs to be done". So it
doesn't make sense for QWindowPrivate::maybeSynthesizeContextMenuEvent
to check the grabber either.

Amends 357c64a99607456133bfabf86d6b67162717cb29 and
84a5f50c7766c99f62b22bb4388137e0aa8dd13d

Task-number: QTBUG-67331
Task-number: QTBUG-93486
Task-number: QTBUG-132066
Fixes: QTBUG-132073
Change-Id: I822cada05cfef27afe6a44faf170585f027061f7
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
(cherry picked from commit 70c61b12efe9d1faf24063b63cf5a69414d45cea)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Shawn Rutledge 2024-12-11 13:08:33 +01:00 committed by Qt Cherry-pick Bot
parent 835475873b
commit 019feea9b1

View File

@ -2750,21 +2750,27 @@ bool QWindow::event(QEvent *ev)
} }
/*! \internal /*! \internal
Synthesize and send a QContextMenuEvent if the given \a event is a Synthesize and send a QContextMenuEvent if the given \a event is a suitable
suitable mouse event (a right-button press or release, depending on mouse event (a right-button press or release, depending on
QStyleHints::contextMenuTrigger()) that *isn't* exclusively grabbed. QStyleHints::contextMenuTrigger()). On most platforms, it's done on mouse
On most platforms, it's done on mouse release; on press; on Windows, it's done on release, because of the potential to
Windows, it's done on press, because of the potential to support support right-button clicks and drags to select or lasso items, and then
right-button clicks and drags to select or lasso items, and then still still getting a context menu at the end of that gesture. (That is in
getting a context menu at the end of that gesture. (That is in conflict conflict with supporting the press-drag-release gesture to select menu
with supporting the press-drag-release gesture to select menu items on the items on the context menus themselves. Context menus can be implemented
context menus themselves. Context menus can be implemented that way by that way by handling the separate press, move and release events.)
handling the separate press, move and release events.) Any time the
\a event was already handled in some way, it *should* be accepted, to Any time the \a event was already handled in some way, it *should* be
indicate that it's not necessary to synthesize a QContextMenuEvent here. accepted, but mere acceptance of the mouse event cannot be taken to
However, there's enough legacy widget code that doesn't call ignore() indicate that it's not necessary to synthesize a QContextMenuEvent here,
on unhandled mouse events, that in QWidgetWindow, we put off requiring because the Windows use case requires doing one thing (selecting items)
the event to be ignored. Hopefully we can begin requiring it in Qt 7. with the mouse events, and then doing something completely different with
the QContextMenuEvent. In other words, QContextMenuEvent is very different
from other kinds of optional followup events synthesized from unhandled
events (like the way we synthesize a QMouseEvent only if a QTabletEvent was
not handled). Furthermore, there's enough legacy widget code that doesn't
call ignore() on unhandled mouse events. So it's uncertain whether this can
change in Qt 7.
The QContextMenuEvent occurs at the scenePosition(). The position() The QContextMenuEvent occurs at the scenePosition(). The position()
was likely already "localized" during the previous delivery. was likely already "localized" during the previous delivery.
@ -2784,7 +2790,7 @@ bool QWindow::event(QEvent *ev)
void QWindowPrivate::maybeSynthesizeContextMenuEvent(QMouseEvent *event) void QWindowPrivate::maybeSynthesizeContextMenuEvent(QMouseEvent *event)
{ {
#ifndef QT_NO_CONTEXTMENU #ifndef QT_NO_CONTEXTMENU
if (!event->exclusivePointGrabber() && event->button() == Qt::RightButton if (event->button() == Qt::RightButton
&& event->type() == QGuiApplicationPrivate::contextMenuEventType()) { && event->type() == QGuiApplicationPrivate::contextMenuEventType()) {
QContextMenuEvent e(QContextMenuEvent::Mouse, event->scenePosition().toPoint(), QContextMenuEvent e(QContextMenuEvent::Mouse, event->scenePosition().toPoint(),
event->globalPosition().toPoint(), event->modifiers()); event->globalPosition().toPoint(), event->modifiers());