Details
-
Task
-
Resolution: Unresolved
-
P3: Somewhat important
-
None
-
6.2
-
None
-
4585cacaa (dev)
Description
It is platform specific when QContextMenuEvents are triggered, but the actual logic doesn't live in the platform plugins today. Instead, QPlatformTheme::themeHint reports for QPlatformTheme::ContextMenuOnMouseRelease which mouse button triggers the context menu event.
On all platforms we synthesize the event ourselves depending on that trigger info, at the end of the already insanely complex QWidgetWindow::event:
#ifndef QT_NO_CONTEXTMENU
if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton
&& m_widget->rect().contains(event->position().toPoint())) {
QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers());
QGuiApplication::forwardEvent(receiver, &e, event);
}
#endif
On Windows, we handle WM_CONTEXTMENU to generate a QContextMenuEvent which we deliver via handleContextMenuEvent. However, that message is only generated by the DefWindowProc for WM_RBUTTONUP, which we only call if Qt didn't handle the event at all, and it's practically impossible to achive that even for QWindow (reimplementing event, ignoring the event and returning false is not enough!).
So even though we never get a WM_CONTEXTMENU-originating QContextMenuEvent with Mouse trigger, in QWidgetWindow and in QGuieApplicationPrivate, we then ignore mouse-triggered context menu events. This at any rate avoids that we get both the platform-triggered event, and the synthesized event:
void QWidgetWindow::handleContextMenuEvent(QContextMenuEvent *e) { // We are only interested in keyboard originating context menu events here, // mouse originated context menu events for widgets are generated in mouse handling methods. if (e->reason() != QContextMenuEvent::Keyboard) return;
void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e) { // Widgets do not care about mouse triggered context menu events. Also, do not forward event // to a window blocked by a modal window. if (!e->window || e->mouseTriggered || e->window->d_func()->blockedByModalWindow) return; [...]
This is all very messy, and we should clean this up.
Perhaps we could obsolete the theme hint and let each platform plugin decide when and how to synthesize QContextMenuEvent, and then deliver those events as usual to any QWindow (as of the fix for QTBUG-59988 in https://codereview.qt-project.org/c/qt/qtbase/+/347659, QWindow also synthesizes the event). No special logic would be needed there or in QWidgetWindow.
Note: as of right now the mouse event triggering the context menu (either press or release) is always delivered before the context menu event, both for widgets and (with the change mentioned above) windows. This is consistent with how Windows does it - only generate the WM_CONTEXTMENU if the WM_RBUTTONUP is ignored - and generally not something we should change, even though it would perhaps be nicer to inverse the order.
Attachments
Issue Links
- relates to
-
QTBUG-47007 mousePressEvent of QWidget gets called even though QTabletEvent was accepted [Qt 5.4.2]
- Closed
-
QTBUG-67331 Make it possible to react to context menu events
- In Progress
Gerrit Reviews
For Gerrit Dashboard: QTBUG-93486 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
555514,6 | QWindow: move context menu synthesis code into private virtual | dev | qt/qtbase | Status: NEW | 0 | 0 |
347659,4 | QWindow: synthesize a QContextMenuEvent from relevant mouse events | dev | qt/qtbase | Status: MERGED | +2 | 0 |
559332,13 | Add way to override when to show context menu | dev | qt/qtbase | Status: MERGED | +2 | 0 |