Fix excess enter events when showing modal dialog on button press
QApplicationPrivate::leaveAfterRelease was not properly cleared when mouse event handling was interrupted by a modal dialog, which caused every mouse move over the modal dialog to trigger enter event to the widget under cursor. Fixed by clearing QApplicationPrivate::leaveAfterRelease if mouse event without any buttons pressed is handled. Task-number: QTBUG-27643 Change-Id: I4f31daa656bc643c88e5338282a671ae2077e255 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Oliver Wolff <oliver.wolff@digia.com> Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>bb10
parent
6dcfbe552a
commit
dde3f6a934
|
|
@ -2482,6 +2482,12 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
|
|||
|
||||
bool widgetUnderMouse = QRectF(receiver->rect()).contains(event->localPos());
|
||||
|
||||
// Clear the obsolete leaveAfterRelease value, if mouse button has been released but
|
||||
// leaveAfterRelease has not been updated.
|
||||
// This happens e.g. when modal dialog or popup is shown as a response to button click.
|
||||
if (leaveAfterRelease && !*buttonDown && !event->buttons())
|
||||
leaveAfterRelease = 0;
|
||||
|
||||
if (*buttonDown) {
|
||||
if (!graphicsWidget) {
|
||||
// Register the widget that shall receive a leave event
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ private slots:
|
|||
void syntheticEnterLeave();
|
||||
void taskQTBUG_4055_sendSyntheticEnterLeave();
|
||||
void underMouse();
|
||||
void taskQTBUG_27643_enterEvents();
|
||||
#endif
|
||||
void windowFlags();
|
||||
void initialPosForDontShowOnScreenWidgets();
|
||||
|
|
@ -9854,6 +9855,99 @@ void tst_QWidget::underMouse()
|
|||
QCOMPARE(childWidget2.enters, 0);
|
||||
QCOMPARE(childWidget2.leaves, 0);
|
||||
}
|
||||
|
||||
class EnterTestModalDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EnterTestModalDialog() : QDialog(), button(0)
|
||||
{
|
||||
setGeometry(100, 300, 150, 100);
|
||||
button = new QPushButton(this);
|
||||
button->setGeometry(10, 10, 50, 30);
|
||||
}
|
||||
|
||||
QPushButton *button;
|
||||
};
|
||||
|
||||
class EnterTestMainDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EnterTestMainDialog() : QDialog(), modal(0), enters(0) {}
|
||||
|
||||
public slots:
|
||||
void buttonPressed()
|
||||
{
|
||||
qApp->installEventFilter(this);
|
||||
modal = new EnterTestModalDialog();
|
||||
QTimer::singleShot(2000, modal, SLOT(close())); // Failsafe
|
||||
QTimer::singleShot(100, this, SLOT(doMouseMoves()));
|
||||
modal->exec();
|
||||
delete modal;
|
||||
}
|
||||
|
||||
void doMouseMoves()
|
||||
{
|
||||
QPoint point1(15, 15);
|
||||
QPoint point2(15, 20);
|
||||
QPoint point3(20, 20);
|
||||
QWindow *window = modal->windowHandle();
|
||||
QWindowSystemInterface::handleEnterEvent(window);
|
||||
QTest::mouseMove(window, point1);
|
||||
QTest::mouseMove(window, point2);
|
||||
QTest::mouseMove(window, point3);
|
||||
modal->close();
|
||||
}
|
||||
|
||||
bool eventFilter(QObject *o, QEvent *e)
|
||||
{
|
||||
if (modal && modal->button && o == modal->button) {
|
||||
switch (e->type()) {
|
||||
case QEvent::Enter:
|
||||
enters++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QDialog::eventFilter(o, e);
|
||||
}
|
||||
|
||||
public:
|
||||
EnterTestModalDialog *modal;
|
||||
int enters;
|
||||
};
|
||||
|
||||
// A modal dialog launched by clicking a button should not trigger excess enter events
|
||||
// when mousing over it.
|
||||
void tst_QWidget::taskQTBUG_27643_enterEvents()
|
||||
{
|
||||
// Move the mouse cursor to a safe location so it won't interfere
|
||||
QCursor::setPos(0,0);
|
||||
|
||||
EnterTestMainDialog dialog;
|
||||
QPushButton button(&dialog);
|
||||
|
||||
connect(&button, SIGNAL(clicked()), &dialog, SLOT(buttonPressed()));
|
||||
|
||||
dialog.setGeometry(100, 100, 150, 100);
|
||||
button.setGeometry(10, 10, 100, 50);
|
||||
dialog.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
|
||||
|
||||
QWindow *window = dialog.windowHandle();
|
||||
QPoint overButton(25, 25);
|
||||
|
||||
QWindowSystemInterface::handleEnterEvent(window);
|
||||
QTest::mouseMove(window, overButton);
|
||||
QTest::mouseClick(window, Qt::LeftButton, 0, overButton, 0);
|
||||
|
||||
// Modal dialog opened in EnterTestMainDialog::buttonPressed()...
|
||||
|
||||
// Must only register only single enter on modal dialog's button after all said and done
|
||||
QCOMPARE(dialog.enters, 1);
|
||||
}
|
||||
#endif // QTEST_NO_CURSOR
|
||||
|
||||
QTEST_MAIN(tst_QWidget)
|
||||
|
|
|
|||
Loading…
Reference in New Issue