summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Klokkhammer Helsing <johan.helsing@qt.io>2016-08-01 09:43:59 +0200
committerJohan Helsing <johan.helsing@qt.io>2016-08-02 07:11:26 +0000
commitda364484aa51ce7c73d39ce0ca444169ce69588e (patch)
treef0f7a16975b43dec9f521e1d5ebaee8139ca9c0a
parent798127e5c9a107ddd8cc1c04495ce39b64513bdb (diff)
Fix crash when dragging with touch without first having pointer focus
Also add drag-and-drop tests for both touch and mouse. Task-number: QTBUG-54756 Change-Id: Ibfff48b1f2377022a8624e28e9f638076187ddca Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
-rw-r--r--src/client/qwaylanddatadevice.cpp3
-rw-r--r--tests/auto/client/mockcompositor.cpp42
-rw-r--r--tests/auto/client/mockcompositor.h15
-rw-r--r--tests/auto/client/mockinput.cpp121
-rw-r--r--tests/auto/client/mockinput.h18
-rw-r--r--tests/auto/client/tst_client.cpp86
6 files changed, 285 insertions, 0 deletions
diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
index 8130578b5..255b13f4c 100644
--- a/src/client/qwaylanddatadevice.cpp
+++ b/src/client/qwaylanddatadevice.cpp
@@ -107,7 +107,10 @@ void QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
{
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
+
QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus();
+ if (!origin)
+ origin = m_display->currentInputDevice()->touchFocus();
start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial());
}
diff --git a/tests/auto/client/mockcompositor.cpp b/tests/auto/client/mockcompositor.cpp
index 7eb683191..83dd52ba2 100644
--- a/tests/auto/client/mockcompositor.cpp
+++ b/tests/auto/client/mockcompositor.cpp
@@ -150,6 +150,47 @@ void MockCompositor::sendTouchFrame(const QSharedPointer<MockSurface> &surface)
processCommand(command);
}
+void MockCompositor::sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceDataOffer, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint& position)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceEnter, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << QVariant::fromValue(position);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceMotion(const QPoint &position)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceMotion, m_compositor);
+ command.parameters << QVariant::fromValue(position);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceDrop, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceLeave, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::waitForStartDrag()
+{
+ Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor);
+ processCommand(command);
+}
+
QSharedPointer<MockSurface> MockCompositor::surface()
{
QSharedPointer<MockSurface> result;
@@ -228,6 +269,7 @@ namespace Impl {
Compositor::Compositor()
: m_display(wl_display_create())
+ , m_startDragSeen(false)
, m_time(0)
{
wl_list_init(&m_outputResources);
diff --git a/tests/auto/client/mockcompositor.h b/tests/auto/client/mockcompositor.h
index 8731949c0..2f0df4a0f 100644
--- a/tests/auto/client/mockcompositor.h
+++ b/tests/auto/client/mockcompositor.h
@@ -85,6 +85,15 @@ public:
static void sendTouchUp(void *data, const QList<QVariant> &parameters);
static void sendTouchMotion(void *data, const QList<QVariant> &parameters);
static void sendTouchFrame(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceDataOffer(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceEnter(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceMotion(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceDrop(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceLeave(void *data, const QList<QVariant> &parameters);
+ static void waitForStartDrag(void *data, const QList<QVariant> &parameters);
+
+public:
+ bool m_startDragSeen;
private:
static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id);
@@ -156,6 +165,12 @@ public:
void sendTouchMotion(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id);
void sendTouchUp(const QSharedPointer<MockSurface> &surface, int id);
void sendTouchFrame(const QSharedPointer<MockSurface> &surface);
+ void sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface);
+ void sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint &position);
+ void sendDataDeviceMotion(const QPoint &position);
+ void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface);
+ void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
+ void waitForStartDrag();
QSharedPointer<MockSurface> surface();
diff --git a/tests/auto/client/mockinput.cpp b/tests/auto/client/mockinput.cpp
index dd0512e76..05df8604b 100644
--- a/tests/auto/client/mockinput.cpp
+++ b/tests/auto/client/mockinput.cpp
@@ -144,6 +144,70 @@ void Compositor::sendTouchFrame(void *data, const QList<QVariant> &parameters)
compositor->m_touch->sendFrame(surface);
}
+void Compositor::sendDataDeviceDataOffer(void *data, const QList<QVariant> &parameters)
+{
+ Compositor *compositor = static_cast<Compositor *>(data);
+ Surface *surface = resolveSurface(parameters.first());
+
+ Q_ASSERT(compositor);
+ Q_ASSERT(surface);
+
+ compositor->m_data_device_manager->dataDevice()->sendDataOffer(surface->resource()->client());
+}
+
+void Compositor::sendDataDeviceEnter(void *data, const QList<QVariant> &parameters)
+{
+ Compositor *compositor = static_cast<Compositor *>(data);
+ Surface *surface = resolveSurface(parameters.first());
+ QPoint position = parameters.at(1).toPoint();
+
+ Q_ASSERT(compositor);
+ Q_ASSERT(surface);
+
+ compositor->m_data_device_manager->dataDevice()->sendEnter(surface, position);
+}
+
+void Compositor::sendDataDeviceMotion(void *data, const QList<QVariant> &parameters)
+{
+ Compositor *compositor = static_cast<Compositor *>(data);
+ Q_ASSERT(compositor);
+ QPoint position = parameters.first().toPoint();
+ compositor->m_data_device_manager->dataDevice()->sendMotion(position);
+}
+
+void Compositor::sendDataDeviceDrop(void *data, const QList<QVariant> &parameters)
+{
+ Compositor *compositor = static_cast<Compositor *>(data);
+ Surface *surface = resolveSurface(parameters.first());
+
+ Q_ASSERT(compositor);
+ Q_ASSERT(surface);
+
+ compositor->m_data_device_manager->dataDevice()->sendDrop(surface);
+}
+
+void Compositor::sendDataDeviceLeave(void *data, const QList<QVariant> &parameters)
+{
+ Compositor *compositor = static_cast<Compositor *>(data);
+ Surface *surface = resolveSurface(parameters.first());
+
+ Q_ASSERT(compositor);
+ Q_ASSERT(surface);
+
+ compositor->m_data_device_manager->dataDevice()->sendLeave(surface);
+}
+
+void Compositor::waitForStartDrag(void *data, const QList<QVariant> &parameters)
+{
+ Compositor *compositor = static_cast<Compositor *>(data);
+ Q_ASSERT(compositor);
+ while (!compositor->m_startDragSeen) {
+ wl_display_flush_clients(compositor->m_display);
+ wl_event_loop_dispatch(compositor->m_loop, 100);
+ }
+ compositor->m_startDragSeen = false;
+}
+
Seat::Seat(Compositor *compositor, struct ::wl_display *display)
: wl_seat(display, 2)
, m_compositor(compositor)
@@ -312,11 +376,53 @@ void Touch::sendFrame(Surface *surface)
wl_touch_send_frame(resource->handle);
}
+DataOffer::DataOffer()
+ : wl_data_offer()
+{
+
+}
+
DataDevice::DataDevice(Compositor *compositor)
: wl_data_device()
, m_compositor(compositor)
+ , m_dataOffer(nullptr)
+ , m_focus(nullptr)
+{
+
+}
+
+void DataDevice::sendDataOffer(wl_client *client)
+{
+ m_dataOffer = new QtWaylandServer::wl_data_offer(client, 0, 1);
+ Resource *resource = resourceMap().value(client);
+ send_data_offer(resource->handle, m_dataOffer->resource()->handle);
+}
+
+void DataDevice::sendEnter(Surface *surface, const QPoint& position)
+{
+ uint serial = m_compositor->nextSerial();
+ m_focus = surface;
+ Resource *resource = resourceMap().value(surface->resource()->client());
+ send_enter(resource->handle, serial, surface->resource()->handle, position.x(), position.y(), m_dataOffer->resource()->handle);
+}
+
+void DataDevice::sendMotion(const QPoint &position)
+{
+ uint32_t time = m_compositor->time();
+ Resource *resource = resourceMap().value(m_focus->resource()->client());
+ send_motion(resource->handle, time, position.x(), position.y());
+}
+
+void DataDevice::sendDrop(Surface *surface)
{
+ Resource *resource = resourceMap().value(surface->resource()->client());
+ send_drop(resource->handle);
+}
+void DataDevice::sendLeave(Surface *surface)
+{
+ Resource *resource = resourceMap().value(surface->resource()->client());
+ send_leave(resource->handle);
}
DataDevice::~DataDevice()
@@ -324,6 +430,11 @@ DataDevice::~DataDevice()
}
+void DataDevice::data_device_start_drag(QtWaylandServer::wl_data_device::Resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial)
+{
+ m_compositor->m_startDragSeen = true;
+}
+
DataDeviceManager::DataDeviceManager(Compositor *compositor, wl_display *display)
: wl_data_device_manager(display, 1)
, m_compositor(compositor)
@@ -336,6 +447,11 @@ DataDeviceManager::~DataDeviceManager()
}
+DataDevice *DataDeviceManager::dataDevice() const
+{
+ return m_data_device.data();
+}
+
void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat)
{
if (!m_data_device)
@@ -343,4 +459,9 @@ void DataDeviceManager::data_device_manager_get_data_device(Resource *resource,
m_data_device->add(resource->client(), id, 1);
}
+void DataDeviceManager::data_device_manager_create_data_source(QtWaylandServer::wl_data_device_manager::Resource *resource, uint32_t id)
+{
+ new QtWaylandServer::wl_data_source(resource->client(), id, 1);
+}
+
}
diff --git a/tests/auto/client/mockinput.h b/tests/auto/client/mockinput.h
index 61c507077..d98328a66 100644
--- a/tests/auto/client/mockinput.h
+++ b/tests/auto/client/mockinput.h
@@ -127,14 +127,30 @@ private:
Compositor *m_compositor;
};
+class DataOffer : public QtWaylandServer::wl_data_offer
+{
+public:
+ DataOffer();
+};
+
class DataDevice : public QtWaylandServer::wl_data_device
{
public:
DataDevice(Compositor *compositor);
+ void sendDataOffer(wl_client *client);
+ void sendEnter(Surface *surface, const QPoint &position);
+ void sendMotion(const QPoint &position);
+ void sendDrop(Surface *surface);
+ void sendLeave(Surface *surface);
~DataDevice();
+protected:
+ void data_device_start_drag(Resource *resource, struct ::wl_resource *source, struct ::wl_resource *origin, struct ::wl_resource *icon, uint32_t serial) override;
+
private:
Compositor *m_compositor;
+ QtWaylandServer::wl_data_offer *m_dataOffer;
+ Surface* m_focus;
};
class DataDeviceManager : public QtWaylandServer::wl_data_device_manager
@@ -142,9 +158,11 @@ class DataDeviceManager : public QtWaylandServer::wl_data_device_manager
public:
DataDeviceManager(Compositor *compositor, struct ::wl_display *display);
~DataDeviceManager();
+ DataDevice *dataDevice() const;
protected:
void data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) Q_DECL_OVERRIDE;
+ void data_device_manager_create_data_source(Resource *resource, uint32_t id) override;
private:
Compositor *m_compositor;
diff --git a/tests/auto/client/tst_client.cpp b/tests/auto/client/tst_client.cpp
index 3fde258d1..5a1143220 100644
--- a/tests/auto/client/tst_client.cpp
+++ b/tests/auto/client/tst_client.cpp
@@ -36,6 +36,10 @@
#include <QBackingStore>
#include <QPainter>
#include <QScreen>
+#include <QWindow>
+#include <QMimeData>
+#include <QPixmap>
+#include <QDrag>
#include <QtTest/QtTest>
@@ -141,6 +145,8 @@ private slots:
void createDestroyWindow();
void events();
void backingStore();
+ void touchDrag();
+ void mouseDrag();
private:
MockCompositor *compositor;
@@ -251,6 +257,86 @@ void tst_WaylandClient::backingStore()
QTRY_VERIFY(surface->image.isNull());
}
+class DndWindow : public QWindow
+{
+ Q_OBJECT
+
+public:
+ DndWindow(QWindow *parent = 0)
+ : QWindow(parent)
+ , dragStarted(false)
+ {
+ QImage cursorImage(64,64,QImage::Format_ARGB32);
+ cursorImage.fill(Qt::blue);
+ m_dragIcon = QPixmap::fromImage(cursorImage);
+ }
+ ~DndWindow(){}
+ bool dragStarted;
+
+protected:
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE
+ {
+ if (dragStarted)
+ return;
+ dragStarted = true;
+
+ QByteArray dataBytes;
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setData("application/x-dnditemdata", dataBytes);
+ QDrag *drag = new QDrag(this);
+ drag->setMimeData(mimeData);
+ drag->setPixmap(m_dragIcon);
+ drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
+ }
+private:
+ QPixmap m_dragIcon;
+};
+
+void tst_WaylandClient::touchDrag()
+{
+ DndWindow window;
+ window.show();
+
+ QSharedPointer<MockSurface> surface;
+ QTRY_VERIFY(surface = compositor->surface());
+
+ compositor->setKeyboardFocus(surface);
+ QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
+
+ const int id = 0;
+ compositor->sendTouchDown(surface, QPoint(10, 10), id);
+ compositor->sendTouchMotion(surface, QPoint(20, 20), id);
+ compositor->sendTouchFrame(surface);
+ compositor->waitForStartDrag();
+ compositor->sendDataDeviceDataOffer(surface);
+ compositor->sendDataDeviceEnter(surface, QPoint(20, 20));
+ compositor->sendDataDeviceMotion( QPoint(21, 21));
+ compositor->sendDataDeviceDrop(surface);
+ compositor->sendDataDeviceLeave(surface);
+ QTRY_VERIFY(window.dragStarted);
+}
+
+void tst_WaylandClient::mouseDrag()
+{
+ DndWindow window;
+ window.show();
+
+ QSharedPointer<MockSurface> surface;
+ QTRY_VERIFY(surface = compositor->surface());
+
+ compositor->setKeyboardFocus(surface);
+ QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
+
+ compositor->sendMousePress(surface, QPoint(10, 10));
+ compositor->sendDataDeviceDataOffer(surface);
+ compositor->sendDataDeviceEnter(surface, QPoint(20, 20));
+ compositor->sendDataDeviceMotion( QPoint(21, 21));
+ compositor->waitForStartDrag();
+ compositor->sendDataDeviceDrop(surface);
+ compositor->sendDataDeviceLeave(surface);
+ QTRY_VERIFY(window.dragStarted);
+}
+
int main(int argc, char **argv)
{
setenv("XDG_RUNTIME_DIR", ".", 1);