From beef975f92e42143c464d68afa6b8cd4f7ef7389 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 2 Jun 2015 08:43:17 +0200 Subject: Cleanup the mouse event handling in testlib Calling QCursor::setPos() to emulate mouse move events is a rather bad idea, as it creates round trips through the server, leading to timing issues etc. In addition, we should not call qapp->notify(), but rather route the events through the proper QPA interface. This is required to properly generate all other events such as enter/leave etc. As this breaks existing tests, put the new behavior behind an #ifdef for now. Like this, we can fix tests one by one, and then turn on the define by default for 5.6 (with a changelog message). We emulate timestamps to avoid creating double clicks by mistake. In addition, fix QGuiApplication::processMouseEvent to not push events back into the QPA event queue (as this is a bad hack and breaks the new testing system). Change-Id: I71774cb56674d7fb66b9a7cf1e1ada1629536408 Reviewed-by: Simon Hausmann --- src/gui/kernel/qguiapplication.cpp | 10 +++-- src/gui/kernel/qwindowsysteminterface.cpp | 4 +- src/testlib/qtestmouse.h | 72 ++++++++++++++++--------------- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 4146ddd8ba..024578ccdd 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1695,12 +1695,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo // A mouse event should not change both position and buttons at the same time. Instead we // should first send a move event followed by a button changed event. Since this is not the case // with the current event, we split it in two. - QWindowSystemInterfacePrivate::MouseEvent *mouseButtonEvent = new QWindowSystemInterfacePrivate::MouseEvent( + QWindowSystemInterfacePrivate::MouseEvent mouseButtonEvent( e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers); if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic) - mouseButtonEvent->flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; - QWindowSystemInterfacePrivate::windowSystemEventQueue.prepend(mouseButtonEvent); - stateChange = Qt::NoButton; + mouseButtonEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; + e->buttons = buttons; + processMouseEvent(e); + processMouseEvent(&mouseButtonEvent); + return; } QWindow *window = e->window.data(); diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index de8e5fbe64..823387b702 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -810,8 +810,8 @@ Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPo } #endif -Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier) { - unsigned long timestamp = QWindowSystemInterfacePrivate::eventTime.elapsed(); +Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp) +{ QWindowSystemInterfacePrivate::MouseEvent e(w, timestamp, local, global, b, mods, Qt::MouseEventNotSynthesized); QGuiApplicationPrivate::processWindowSystemEvent(&e); } diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index 2cf84a7ea0..5f69463867 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -57,7 +58,7 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier); +Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp); namespace QTest { @@ -83,7 +84,8 @@ namespace QTest QTest::qWarn("Mouse event occurs outside of target window."); } - static Qt::MouseButton lastButton = Qt::NoButton; + static Qt::MouseButton lastButton = Qt::NoButton; + static int timestamp = 0; if (delay == -1 || delay < defaultMouseDelay()) delay = defaultMouseDelay(); @@ -93,42 +95,38 @@ namespace QTest if (pos.isNull()) pos = window->geometry().center(); - if (action == MouseClick) { - mouseEvent(MousePress, window, button, stateKey, pos); - mouseEvent(MouseRelease, window, button, stateKey, pos); - return; - } QTEST_ASSERT(uint(stateKey) == 0 || stateKey & Qt::KeyboardModifierMask); stateKey &= static_cast(Qt::KeyboardModifierMask); + QPointF global = window->mapToGlobal(pos); + QPointer w(window); switch (action) { - case MousePress: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey); - lastButton = button; - break; - case MouseRelease: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey); - lastButton = Qt::NoButton; + case MouseDClick: + qt_handleMouseEvent(w, pos, global, button, stateKey, timestamp); + qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++timestamp); + // fall through + case MousePress: + case MouseClick: + qt_handleMouseEvent(w, pos, global, button, stateKey, ++timestamp); + lastButton = button; + if (action == MousePress) break; - case MouseDClick: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey); - qWait(10); - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey); - qWait(20); - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey); - qWait(10); - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey); - break; - case MouseMove: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),lastButton,stateKey); - // No QCursor::setPos() call here. That could potentially result in mouse events sent by the windowing system - // which is highly undesired here. Tests must avoid relying on QCursor. - break; - default: - QTEST_ASSERT(false); + // fall through + case MouseRelease: + qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++timestamp); + timestamp += 500; // avoid double clicks being generated + lastButton = Qt::NoButton; + break; + case MouseMove: + qt_handleMouseEvent(w, pos, global, lastButton, stateKey, ++timestamp); + // No QCursor::setPos() call here. That could potentially result in mouse events sent by the windowing system + // which is highly undesired here. Tests must avoid relying on QCursor. + break; + default: + QTEST_ASSERT(false); } waitForEvents(); } @@ -153,6 +151,15 @@ namespace QTest Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1) { QTEST_ASSERT(widget); + + if (pos.isNull()) + pos = widget->rect().center(); + +#ifdef QTEST_QPA_MOUSE_HANDLING + QWindow *w = widget->window()->windowHandle(); + QTEST_ASSERT(w); + mouseEvent(action, w, button, stateKey, w->mapFromGlobal(widget->mapToGlobal(pos)), delay); +#else extern int Q_TESTLIB_EXPORT defaultMouseDelay(); if (delay == -1 || delay < defaultMouseDelay()) @@ -160,9 +167,6 @@ namespace QTest if (delay > 0) QTest::qWait(delay); - if (pos.isNull()) - pos = widget->rect().center(); - if (action == MouseClick) { mouseEvent(MousePress, widget, button, stateKey, pos); mouseEvent(MouseRelease, widget, button, stateKey, pos); @@ -203,7 +207,7 @@ namespace QTest QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget"); QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast(action)])).toLatin1().data()); } - +#endif } inline void mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, -- cgit v1.2.3