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 <richard.gustavsen@qt.io>
This commit is contained in:
Andy Shaw 2017-12-05 08:46:37 +01:00
parent c8625a3e67
commit 8e5f6e3bed
3 changed files with 31 additions and 14 deletions

View File

@ -2624,7 +2624,7 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint
bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
QWidget *alienWidget, QWidget *nativeWidget, QWidget *alienWidget, QWidget *nativeWidget,
QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
bool spontaneous) bool spontaneous, bool onlyDispatchEnterLeave)
{ {
Q_ASSERT(receiver); Q_ASSERT(receiver);
Q_ASSERT(event); 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 // 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. // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver.
const bool wasLeaveAfterRelease = leaveAfterRelease != 0; const bool wasLeaveAfterRelease = leaveAfterRelease != 0;
bool result; bool result = true;
if (spontaneous) // This code is used for sending the synthetic enter/leave events for cases where it is needed
result = QApplication::sendSpontaneousEvent(receiver, event); // due to other events causing the widget under the mouse to change. However in those cases
else // we do not want to send the mouse event associated with this call, so this enables us to
result = QApplication::sendEvent(receiver, event); // 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 if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease
&& !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) { && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) {
@ -2764,9 +2770,10 @@ void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget)
if (widget->data->in_destructor && qt_button_down == widget) if (widget->data->in_destructor && qt_button_down == widget)
qt_button_down = 0; 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); 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 #else // !QT_NO_CURSOR
Q_UNUSED(widget); Q_UNUSED(widget);
#endif // QT_NO_CURSOR #endif // QT_NO_CURSOR

View File

@ -226,7 +226,7 @@ public:
QWidget *buttonDown, QWidget *alienWidget); QWidget *buttonDown, QWidget *alienWidget);
static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget,
QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
bool spontaneous = true); bool spontaneous = true, bool onlyDispatchEnterLeave = false);
void sendSyntheticEnterLeave(QWidget *widget); void sendSyntheticEnterLeave(QWidget *widget);
static QWindow *windowForWidget(const QWidget *widget) static QWindow *windowForWidget(const QWidget *widget)

View File

@ -9120,7 +9120,8 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave()
void mouseMoveEvent(QMouseEvent *event) void mouseMoveEvent(QMouseEvent *event)
{ {
QCOMPARE(event->button(), Qt::NoButton); QCOMPARE(event->button(), Qt::NoButton);
QCOMPARE(event->buttons(), Qt::MouseButtons(Qt::NoButton)); QCOMPARE(event->buttons(), QApplication::mouseButtons());
QCOMPARE(event->modifiers(), QApplication::keyboardModifiers());
++numMouseMoveEvents; ++numMouseMoveEvents;
} }
void reset() { numEnterEvents = numMouseMoveEvents = 0; } void reset() { numEnterEvents = numMouseMoveEvents = 0; }
@ -9154,11 +9155,11 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave()
child.setMouseTracking(true); child.setMouseTracking(true);
child.show(); 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() // Note that we verify event->button() and event->buttons()
// in SELChild::mouseMoveEvent(). // in SELChild::mouseMoveEvent().
QTRY_COMPARE(child.numEnterEvents, 1); QTRY_COMPARE(child.numEnterEvents, 1);
QCOMPARE(child.numMouseMoveEvents, 1); QCOMPARE(child.numMouseMoveEvents, 0);
// Sending synthetic enter/leave trough the parent's mousePressEvent handler. // Sending synthetic enter/leave trough the parent's mousePressEvent handler.
parent.child = &child; parent.child = &child;
@ -9167,10 +9168,19 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave()
child.reset(); child.reset();
QTest::mouseClick(&parent, Qt::LeftButton); 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); 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.hide();
child.reset(); child.reset();
child.setMouseTracking(false); child.setMouseTracking(false);