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
|
||||
// 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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <QtTest/qtestspontaneevent.h>
|
||||
#include <QtCore/qpoint.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
|
||||
@ -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<unsigned int>(Qt::KeyboardModifierMask);
|
||||
|
||||
QPointF global = window->mapToGlobal(pos);
|
||||
QPointer<QWindow> w(window);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MousePress:
|
||||
qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey);
|
||||
lastButton = button;
|
||||
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 MouseRelease:
|
||||
qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey);
|
||||
lastButton = Qt::NoButton;
|
||||
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<int>(action)])).toLatin1().data());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
|
||||
|
Loading…
x
Reference in New Issue
Block a user