Skip to content

Commit

Permalink
Move QContextMenuEvent synthesis from QWidgetWindow to QWindow
Browse files Browse the repository at this point in the history
...and only if the original mouse event is not accepted. To that end,
QGraphicsView must setAccepted(false) if the graphics scene did not
accept the QGraphicsSceneMouseEvent.

So a widget or a Qt Quick item or handler can handle the mouse events
directly, to provide a consistent context-menu experience across
platforms (for example to handle the press-drag-release gesture),
but the fallback pattern follows the platform behavior.

QWidgetWindow::handleMouseEvent() picks the receiver in its own way:
often a leaf widget. It sets qt_last_mouse_receiver, so
QWidgetWindow::handleContextMenuEvent() can deliver a mouse-originating
QContextMenuEvent to the same receiver. A keyboard-originating
QContextMenuEvent is delivered to the focus widget instead, as before.

As a drive-by: fix an awkward word in qCDebug output.

Task-number: QTBUG-93486
Change-Id: I4c1499120851a899acf2d7d4adaedaf9f42c3126
Reviewed-by: Mitch Curtis <[email protected]>
Reviewed-by: Jan Arve Sæther <[email protected]>
  • Loading branch information
ec1oud committed Dec 7, 2024
1 parent 953b7aa commit 84a5f50
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/gui/kernel/qwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2784,7 +2784,7 @@ void QWindowPrivate::maybeSynthesizeContextMenuEvent(QMouseEvent *event)
&& event->type() == QGuiApplicationPrivate::contextMenuEventType()) {
QContextMenuEvent e(QContextMenuEvent::Mouse, event->scenePosition().toPoint(),
event->globalPosition().toPoint(), event->modifiers());
qCDebug(lcPopup) << "synthesized QContextMenuEvent after un-accepted" << event->type() << ":" << &e;
qCDebug(lcPopup) << "synthesized QContextMenuEvent after ignored" << event->type() << ":" << &e;
QGuiApplication::sendEvent(q_func(), &e);
}
#endif
Expand Down
3 changes: 2 additions & 1 deletion src/widgets/graphicsview/qgraphicsview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3354,8 +3354,9 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event)
else
QCoreApplication::sendEvent(d->scene, &mouseEvent);

// Update the last mouse event selected state.
// Update the last and current mouse events' accepted state.
d->lastMouseEvent.setAccepted(mouseEvent.isAccepted());
event->setAccepted(mouseEvent.isAccepted());

#ifndef QT_NO_CURSOR
if (mouseEvent.isAccepted() && mouseEvent.buttons() == 0 && viewport()->testAttribute(Qt::WA_SetCursor)) {
Expand Down
63 changes: 32 additions & 31 deletions src/widgets/kernel/qwidgetwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e)

void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
{
Q_D(QWidgetWindow);
if (auto *activePopupWidget = QApplication::activePopupWidget()) {
QPointF mapped = event->position();
if (activePopupWidget != m_widget)
Expand Down Expand Up @@ -647,7 +648,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
if (!receiver)
return;

if (d_func()->isPopup() && receiver->window()->windowHandle() != this) {
if (d->isPopup() && receiver->window()->windowHandle() != this) {
receiver = widget;
mapped = event->position().toPoint();
}
Expand All @@ -664,16 +665,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
&qt_button_down, qt_last_mouse_receiver);
event->setAccepted(translated.isAccepted());
}
#ifndef QT_NO_CONTEXTMENU
if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
&& event->button() == Qt::RightButton
&& m_widget->rect().contains(event->position().toPoint())) {
QContextMenuEvent e(QContextMenuEvent::Mouse, mapped.toPoint(), event->globalPosition().toPoint(), event->modifiers());
QGuiApplication::forwardEvent(receiver, &e, event);
if (e.isAccepted())
event->accept();
}
#endif

d->maybeSynthesizeContextMenuEvent(event);
}

void QWidgetWindow::handleTouchEvent(QTouchEvent *event)
Expand Down Expand Up @@ -1165,28 +1158,36 @@ void QWidgetWindow::handleGestureEvent(QNativeGestureEvent *e)
#ifndef QT_NO_CONTEXTMENU
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;

QWidget *fw = QWidget::keyboardGrabber();
if (!fw) {
if (QApplication::activePopupWidget()) {
fw = (QApplication::activePopupWidget()->focusWidget()
? QApplication::activePopupWidget()->focusWidget()
: QApplication::activePopupWidget());
} else if (QApplication::focusWidget()) {
fw = QApplication::focusWidget();
} else {
fw = m_widget;
QWidget *receiver = qt_last_mouse_receiver.get();
QPoint pos = e->pos();
QPoint globalPos = e->globalPos();

// Keyboard-originating context menu events are delivered to the focus widget,
// independently of event position.
if (e->reason() == QContextMenuEvent::Keyboard) {
receiver = QWidget::keyboardGrabber();
if (!receiver) {
if (QApplication::activePopupWidget()) {
receiver = (QApplication::activePopupWidget()->focusWidget()
? QApplication::activePopupWidget()->focusWidget()
: QApplication::activePopupWidget());
} else if (QApplication::focusWidget()) {
receiver = QApplication::focusWidget();
} else {
receiver = m_widget;
}
}
if (Q_LIKELY(receiver)) {
pos = receiver->inputMethodQuery(Qt::ImCursorRectangle).toRect().center();
globalPos = receiver->mapToGlobal(pos);
}
} else if (Q_LIKELY(receiver)) {
pos = receiver->mapFromGlobal(e->globalPos());
}
if (fw && fw->isEnabled()) {
QPoint pos = fw->inputMethodQuery(Qt::ImCursorRectangle).toRect().center();
QContextMenuEvent widgetEvent(QContextMenuEvent::Keyboard, pos, fw->mapToGlobal(pos),
e->modifiers());
QGuiApplication::forwardEvent(fw, &widgetEvent, e);

if (receiver && receiver->isEnabled()) {
QContextMenuEvent widgetEvent(e->reason(), pos, globalPos, e->modifiers());
QGuiApplication::forwardEvent(receiver, &widgetEvent, e);
}
}
#endif // QT_NO_CONTEXTMENU
Expand Down

0 comments on commit 84a5f50

Please sign in to comment.