From 8e5f6e3bed6e123cc603f12d785c47eeee495f94 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 5 Dec 2017 08:46:37 +0100 Subject: [PATCH] Don't send a mouse move when we just need to do a synthetic enter/leave [ChangeLog][QtWidgets] QApplication no longer sends a mouse move event to the entered widget if it sends synthetic enter and leave events. Task-number: QTBUG-67736 Change-Id: I75daaffd53f1ddc2bc4d7df67382cbc22d3eb6fc Reviewed-by: Richard Moe Gustavsen --- src/widgets/kernel/qapplication.cpp | 23 ++++++++++++------- src/widgets/kernel/qapplication_p.h | 2 +- .../widgets/kernel/qwidget/tst_qwidget.cpp | 20 ++++++++++++---- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index c9933aff8a..8e9ce286de 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -2624,7 +2624,7 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *nativeWidget, QWidget **buttonDown, QPointer &lastMouseReceiver, - bool spontaneous) + bool spontaneous, bool onlyDispatchEnterLeave) { Q_ASSERT(receiver); Q_ASSERT(event); @@ -2685,11 +2685,17 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, // We need this quard in case someone opens a modal dialog / popup. If that's the case // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver. const bool wasLeaveAfterRelease = leaveAfterRelease != 0; - bool result; - if (spontaneous) - result = QApplication::sendSpontaneousEvent(receiver, event); - else - result = QApplication::sendEvent(receiver, event); + bool result = true; + // This code is used for sending the synthetic enter/leave events for cases where it is needed + // due to other events causing the widget under the mouse to change. However in those cases + // we do not want to send the mouse event associated with this call, so this enables us to + // not send the unneeded mouse event + if (!onlyDispatchEnterLeave) { + if (spontaneous) + result = QApplication::sendSpontaneousEvent(receiver, event); + else + result = QApplication::sendEvent(receiver, event); + } if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) { @@ -2764,9 +2770,10 @@ void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget) if (widget->data->in_destructor && qt_button_down == widget) qt_button_down = 0; - // Send enter/leave events followed by a mouse move on the entered widget. + // A mouse move is not actually sent, but we utilize the sendMouseEvent() call to send the + // enter/leave events as appropriate QMouseEvent e(QEvent::MouseMove, pos, windowPos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier); - sendMouseEvent(widgetUnderCursor, &e, widgetUnderCursor, tlw, &qt_button_down, qt_last_mouse_receiver); + sendMouseEvent(widgetUnderCursor, &e, widgetUnderCursor, tlw, &qt_button_down, qt_last_mouse_receiver, true, true); #else // !QT_NO_CURSOR Q_UNUSED(widget); #endif // QT_NO_CURSOR diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 019fad3fc3..21ba47caa3 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -226,7 +226,7 @@ public: QWidget *buttonDown, QWidget *alienWidget); static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *native, QWidget **buttonDown, QPointer &lastMouseReceiver, - bool spontaneous = true); + bool spontaneous = true, bool onlyDispatchEnterLeave = false); void sendSyntheticEnterLeave(QWidget *widget); static QWindow *windowForWidget(const QWidget *widget) diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 823a52ce70..e1c4019fba 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -9120,7 +9120,8 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave() void mouseMoveEvent(QMouseEvent *event) { QCOMPARE(event->button(), Qt::NoButton); - QCOMPARE(event->buttons(), Qt::MouseButtons(Qt::NoButton)); + QCOMPARE(event->buttons(), QApplication::mouseButtons()); + QCOMPARE(event->modifiers(), QApplication::keyboardModifiers()); ++numMouseMoveEvents; } void reset() { numEnterEvents = numMouseMoveEvents = 0; } @@ -9154,11 +9155,11 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave() child.setMouseTracking(true); child.show(); - // Make sure the child gets enter event and mouse move event. + // Make sure the child gets enter event. // Note that we verify event->button() and event->buttons() // in SELChild::mouseMoveEvent(). QTRY_COMPARE(child.numEnterEvents, 1); - QCOMPARE(child.numMouseMoveEvents, 1); + QCOMPARE(child.numMouseMoveEvents, 0); // Sending synthetic enter/leave trough the parent's mousePressEvent handler. parent.child = &child; @@ -9167,10 +9168,19 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave() child.reset(); QTest::mouseClick(&parent, Qt::LeftButton); - // Make sure the child gets enter event and one mouse move event. + // Make sure the child gets enter event. QTRY_COMPARE(child.numEnterEvents, 1); - QCOMPARE(child.numMouseMoveEvents, 1); + QCOMPARE(child.numMouseMoveEvents, 0); + child.hide(); + child.reset(); + QTest::keyPress(&parent, Qt::Key_Shift); + QTest::mouseClick(&parent, Qt::LeftButton); + + // Make sure the child gets enter event + QTRY_COMPARE(child.numEnterEvents, 1); + QCOMPARE(child.numMouseMoveEvents, 0); + QTest::keyRelease(&child, Qt::Key_Shift); child.hide(); child.reset(); child.setMouseTracking(false);