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 <simon.hausmann@theqtcompany.com>
This commit is contained in:
parent
d83bd9c6f5
commit
beef975f92
@ -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
|
// 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
|
// 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.
|
// 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);
|
e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers);
|
||||||
if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic)
|
if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic)
|
||||||
mouseButtonEvent->flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
mouseButtonEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
|
||||||
QWindowSystemInterfacePrivate::windowSystemEventQueue.prepend(mouseButtonEvent);
|
e->buttons = buttons;
|
||||||
stateChange = Qt::NoButton;
|
processMouseEvent(e);
|
||||||
|
processMouseEvent(&mouseButtonEvent);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWindow *window = e->window.data();
|
QWindow *window = e->window.data();
|
||||||
|
@ -810,8 +810,8 @@ Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPo
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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)
|
||||||
unsigned long timestamp = QWindowSystemInterfacePrivate::eventTime.elapsed();
|
{
|
||||||
QWindowSystemInterfacePrivate::MouseEvent e(w, timestamp, local, global, b, mods, Qt::MouseEventNotSynthesized);
|
QWindowSystemInterfacePrivate::MouseEvent e(w, timestamp, local, global, b, mods, Qt::MouseEventNotSynthesized);
|
||||||
QGuiApplicationPrivate::processWindowSystemEvent(&e);
|
QGuiApplicationPrivate::processWindowSystemEvent(&e);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include <QtTest/qtestspontaneevent.h>
|
#include <QtTest/qtestspontaneevent.h>
|
||||||
#include <QtCore/qpoint.h>
|
#include <QtCore/qpoint.h>
|
||||||
#include <QtCore/qstring.h>
|
#include <QtCore/qstring.h>
|
||||||
|
#include <QtCore/qpointer.h>
|
||||||
#include <QtGui/qevent.h>
|
#include <QtGui/qevent.h>
|
||||||
#include <QtGui/qwindow.h>
|
#include <QtGui/qwindow.h>
|
||||||
|
|
||||||
@ -57,7 +58,7 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
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
|
namespace QTest
|
||||||
{
|
{
|
||||||
@ -84,6 +85,7 @@ namespace QTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Qt::MouseButton lastButton = Qt::NoButton;
|
static Qt::MouseButton lastButton = Qt::NoButton;
|
||||||
|
static int timestamp = 0;
|
||||||
|
|
||||||
if (delay == -1 || delay < defaultMouseDelay())
|
if (delay == -1 || delay < defaultMouseDelay())
|
||||||
delay = defaultMouseDelay();
|
delay = defaultMouseDelay();
|
||||||
@ -93,37 +95,33 @@ namespace QTest
|
|||||||
if (pos.isNull())
|
if (pos.isNull())
|
||||||
pos = window->geometry().center();
|
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);
|
QTEST_ASSERT(uint(stateKey) == 0 || stateKey & Qt::KeyboardModifierMask);
|
||||||
|
|
||||||
stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask);
|
stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask);
|
||||||
|
|
||||||
|
QPointF global = window->mapToGlobal(pos);
|
||||||
|
QPointer<QWindow> w(window);
|
||||||
|
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
|
case MouseDClick:
|
||||||
|
qt_handleMouseEvent(w, pos, global, button, stateKey, timestamp);
|
||||||
|
qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++timestamp);
|
||||||
|
// fall through
|
||||||
case MousePress:
|
case MousePress:
|
||||||
qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey);
|
case MouseClick:
|
||||||
|
qt_handleMouseEvent(w, pos, global, button, stateKey, ++timestamp);
|
||||||
lastButton = button;
|
lastButton = button;
|
||||||
|
if (action == MousePress)
|
||||||
break;
|
break;
|
||||||
|
// fall through
|
||||||
case MouseRelease:
|
case MouseRelease:
|
||||||
qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey);
|
qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++timestamp);
|
||||||
|
timestamp += 500; // avoid double clicks being generated
|
||||||
lastButton = Qt::NoButton;
|
lastButton = Qt::NoButton;
|
||||||
break;
|
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:
|
case MouseMove:
|
||||||
qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),lastButton,stateKey);
|
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
|
// 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.
|
// which is highly undesired here. Tests must avoid relying on QCursor.
|
||||||
break;
|
break;
|
||||||
@ -153,6 +151,15 @@ namespace QTest
|
|||||||
Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
|
Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
|
||||||
{
|
{
|
||||||
QTEST_ASSERT(widget);
|
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();
|
extern int Q_TESTLIB_EXPORT defaultMouseDelay();
|
||||||
|
|
||||||
if (delay == -1 || delay < defaultMouseDelay())
|
if (delay == -1 || delay < defaultMouseDelay())
|
||||||
@ -160,9 +167,6 @@ namespace QTest
|
|||||||
if (delay > 0)
|
if (delay > 0)
|
||||||
QTest::qWait(delay);
|
QTest::qWait(delay);
|
||||||
|
|
||||||
if (pos.isNull())
|
|
||||||
pos = widget->rect().center();
|
|
||||||
|
|
||||||
if (action == MouseClick) {
|
if (action == MouseClick) {
|
||||||
mouseEvent(MousePress, widget, button, stateKey, pos);
|
mouseEvent(MousePress, widget, button, stateKey, pos);
|
||||||
mouseEvent(MouseRelease, 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");
|
QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget");
|
||||||
QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toLatin1().data());
|
QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toLatin1().data());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
|
inline void mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user