Commit 78486bb5 authored by Martin Flöser's avatar Martin Flöser
Browse files

Handle DataDeviceInterface selection in SeatInterface

The selection is supposed to be sent to the DataDeviceInterface just
before getting keyboard focus. In order to do that the SeatInterface
keeps track of the DataDeviceInterface which is the current selection
and the DataDeviceInterface of the focused keyboard client.

SeatInterface friends DataDeviceManagerInterface so that the latter
can register each created DataDevice for the SeatInterface.
parent 9d2cfd12
......@@ -238,7 +238,7 @@ void TestDataSource::testRequestSend()
QVERIFY(sendRequestedSpy.wait());
QCOMPARE(sendRequestedSpy.count(), 1);
QCOMPARE(sendRequestedSpy.first().first().toString(), plain);
QVERIFY(sendRequestedSpy.first().last().value<qint32>() != file.handle());
QCOMPARE(sendRequestedSpy.first().last().value<qint32>(), file.handle());
QVERIFY(sendRequestedSpy.first().last().value<qint32>() != -1);
QFile writeFile;
......
......@@ -22,6 +22,9 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
// KWin
#include "../../src/client/compositor.h"
#include "../../src/client/connection_thread.h"
#include "../../src/client/datadevice.h"
#include "../../src/client/datadevicemanager.h"
#include "../../src/client/datasource.h"
#include "../../src/client/event_queue.h"
#include "../../src/client/keyboard.h"
#include "../../src/client/pointer.h"
......@@ -31,6 +34,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "../../src/client/shm_pool.h"
#include "../../src/server/buffer_interface.h"
#include "../../src/server/compositor_interface.h"
#include "../../src/server/datadevicemanager_interface.h"
#include "../../src/server/display.h"
#include "../../src/server/keyboard_interface.h"
#include "../../src/server/pointer_interface.h"
......@@ -59,6 +63,7 @@ private Q_SLOTS:
void testKeyboard();
void testCast();
void testDestroy();
void testSelection();
// TODO: add test for keymap
private:
......@@ -678,5 +683,80 @@ void TestWaylandSeat::testDestroy()
p->destroy();
}
void TestWaylandSeat::testSelection()
{
using namespace KWayland::Client;
using namespace KWayland::Server;
QScopedPointer<DataDeviceManagerInterface> ddmi(m_display->createDataDeviceManager());
ddmi->create();
Registry registry;
QSignalSpy dataDeviceManagerSpy(&registry, SIGNAL(dataDeviceManagerAnnounced(quint32,quint32)));
QVERIFY(dataDeviceManagerSpy.isValid());
registry.setEventQueue(m_queue);
registry.create(m_connection->display());
QVERIFY(registry.isValid());
registry.setup();
QVERIFY(dataDeviceManagerSpy.wait());
QScopedPointer<DataDeviceManager> ddm(registry.createDataDeviceManager(dataDeviceManagerSpy.first().first().value<quint32>(),
dataDeviceManagerSpy.first().last().value<quint32>()));
QVERIFY(ddm->isValid());
QScopedPointer<DataDevice> dd1(ddm->getDataDevice(m_seat));
QVERIFY(dd1->isValid());
QSignalSpy selectionSpy(dd1.data(), SIGNAL(selectionOffered(KWayland::Client::DataOffer*)));
QVERIFY(selectionSpy.isValid());
QSignalSpy selectionClearedSpy(dd1.data(), SIGNAL(selectionCleared()));
QVERIFY(selectionClearedSpy.isValid());
QSignalSpy surfaceCreatedSpy(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(surfaceCreatedSpy.isValid());
QScopedPointer<Surface> surface(m_compositor->createSurface());
QVERIFY(surface->isValid());
QVERIFY(surfaceCreatedSpy.wait());
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
QVERIFY(!m_seatInterface->focusedKeyboard());
serverSurface->client()->flush();
QCoreApplication::processEvents();
QCoreApplication::processEvents();
QVERIFY(selectionSpy.isEmpty());
QVERIFY(selectionClearedSpy.isEmpty());
// now let's try to set a selection - we have keyboard focus, so it should be sent to us
QScopedPointer<DataSource> ds(ddm->createDataSource());
QVERIFY(ds->isValid());
ds->offer(QStringLiteral("text/plain"));
dd1->setSelection(0, ds.data());
QVERIFY(selectionSpy.wait());
QCOMPARE(selectionSpy.count(), 1);
QVERIFY(selectionClearedSpy.isEmpty());
auto df = selectionSpy.first().first().value<DataOffer*>();
QCOMPARE(df->offeredMimeTypes().count(), 1);
QCOMPARE(df->offeredMimeTypes().first().name(), QStringLiteral("text/plain"));
// try to clear
dd1->setSelection(0);
QVERIFY(selectionClearedSpy.wait());
QCOMPARE(selectionClearedSpy.count(), 1);
QCOMPARE(selectionSpy.count(), 1);
// unset the keyboard focus
m_seatInterface->setFocusedKeyboardSurface(nullptr);
QVERIFY(!m_seatInterface->focusedKeyboardSurface());
QVERIFY(!m_seatInterface->focusedKeyboard());
serverSurface->client()->flush();
QCoreApplication::processEvents();
QCoreApplication::processEvents();
// try to set Selection
dd1->setSelection(0, ds.data());
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCoreApplication::processEvents();
QCOMPARE(selectionSpy.count(), 1);
}
QTEST_GUILESS_MAIN(TestWaylandSeat)
#include "test_wayland_seat.moc"
......@@ -177,6 +177,12 @@ void DataDeviceInterface::sendSelection(DataDeviceInterface *other)
wl_data_device_send_selection(d->resource, r->resource());
}
void DataDeviceInterface::sendClearSelection()
{
Q_D();
wl_data_device_send_selection(d->resource, nullptr);
}
DataDeviceInterface::Private *DataDeviceInterface::d_func() const
{
return reinterpret_cast<DataDeviceInterface::Private*>(d.data());
......
......@@ -50,6 +50,7 @@ public:
DataSourceInterface *selection() const;
void sendSelection(DataDeviceInterface *other);
void sendClearSelection();
Q_SIGNALS:
void dragStarted();
......
......@@ -20,7 +20,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "datadevicemanager_interface.h"
#include "global_p.h"
#include "display.h"
#include "seat_interface.h"
#include "seat_interface_p.h"
// Wayland
#include <wayland-server.h>
......@@ -104,12 +104,15 @@ void DataDeviceManagerInterface::Private::getDataDeviceCallback(wl_client *clien
void DataDeviceManagerInterface::Private::getDataDevice(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat)
{
DataDeviceInterface *dataDevice = new DataDeviceInterface(SeatInterface::get(seat), q, resource);
SeatInterface *s = SeatInterface::get(seat);
Q_ASSERT(s);
DataDeviceInterface *dataDevice = new DataDeviceInterface(s, q, resource);
dataDevice->create(display->getConnection(client), wl_resource_get_version(resource), id);
if (!dataDevice->resource()) {
wl_resource_post_no_memory(resource);
return;
}
s->d_func()->registerDataDevice(dataDevice);
emit q->dataDeviceCreated(dataDevice);
}
......
......@@ -20,6 +20,8 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "seat_interface.h"
#include "seat_interface_p.h"
#include "display.h"
#include "datadevice_interface.h"
#include "datasource_interface.h"
#include "keyboard_interface.h"
#include "pointer_interface.h"
#include "surface_interface.h"
......@@ -183,6 +185,70 @@ KeyboardInterface *SeatInterface::Private::keyboardForSurface(SurfaceInterface *
return interfaceForSurface(surface, keyboards);
}
DataDeviceInterface *SeatInterface::Private::dataDeviceForSurface(SurfaceInterface *surface) const
{
return interfaceForSurface(surface, dataDevices);
}
void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice)
{
Q_ASSERT(dataDevice->seat() == q);
dataDevices << dataDevice;
QObject::connect(dataDevice, &QObject::destroyed, q,
[this, dataDevice] {
dataDevices.removeAt(dataDevices.indexOf(dataDevice));
if (keys.focus.selection == dataDevice) {
keys.focus.selection = nullptr;
}
if (currentSelection == dataDevice) {
// current selection is cleared
currentSelection = nullptr;
if (keys.focus.selection) {
keys.focus.selection->sendClearSelection();
}
}
}
);
QObject::connect(dataDevice, &DataDeviceInterface::selectionChanged, q,
[this, dataDevice] {
updateSelection(dataDevice, true);
}
);
QObject::connect(dataDevice, &DataDeviceInterface::selectionCleared, q,
[this, dataDevice] {
updateSelection(dataDevice, false);
}
);
// is the new DataDevice for the current keyoard focus?
if (keys.focus.surface && !keys.focus.selection) {
// same client?
if (keys.focus.surface->client() == dataDevice->client()) {
keys.focus.selection = dataDevice;
if (currentSelection) {
dataDevice->sendSelection(currentSelection);
}
}
}
}
void SeatInterface::Private::updateSelection(DataDeviceInterface *dataDevice, bool set)
{
if (keys.focus.surface && (keys.focus.surface->client() == dataDevice->client())) {
// new selection on a data device belonging to current keyboard focus
currentSelection = dataDevice;
}
if (dataDevice == currentSelection) {
// need to send out the selection
if (keys.focus.selection) {
if (set) {
keys.focus.selection->sendSelection(dataDevice);
} else {
keys.focus.selection->sendClearSelection();
}
}
}
}
void SeatInterface::setHasKeyboard(bool has)
{
Q_D();
......@@ -570,6 +636,13 @@ void SeatInterface::setFocusedKeyboardSurface(SurfaceInterface *surface)
}
);
d->keys.focus.serial = serial;
// selection?
d->keys.focus.selection = d->dataDeviceForSurface(surface);
if (d->keys.focus.selection) {
if (d->currentSelection) {
d->keys.focus.selection->sendSelection(d->currentSelection);
}
}
}
if (!k) {
return;
......
......@@ -117,6 +117,7 @@ Q_SIGNALS:
private:
friend class Display;
friend class DataDeviceManagerInterface;
explicit SeatInterface(Display *display, QObject *parent);
class Private;
......
......@@ -33,6 +33,8 @@ namespace KWayland
namespace Server
{
class DataDeviceInterface;
class SeatInterface::Private : public Global::Private
{
public:
......@@ -42,6 +44,8 @@ public:
void sendName(wl_resource *r);
PointerInterface *pointerForSurface(SurfaceInterface *surface) const;
KeyboardInterface *keyboardForSurface(SurfaceInterface *surface) const;
DataDeviceInterface *dataDeviceForSurface(SurfaceInterface *surface) const;
void registerDataDevice(DataDeviceInterface *dataDevice);
QString name;
bool pointer = false;
......@@ -51,6 +55,8 @@ public:
quint32 timestamp = 0;
QVector<PointerInterface*> pointers;
QVector<KeyboardInterface*> keyboards;
QVector<DataDeviceInterface*> dataDevices;
DataDeviceInterface *currentSelection = nullptr;
// Pointer related members
struct Pointer {
......@@ -100,6 +106,7 @@ public:
KeyboardInterface *keyboard = nullptr;
QMetaObject::Connection destroyConnection;
quint32 serial = 0;
DataDeviceInterface *selection = nullptr;
};
Focus focus;
quint32 lastStateSerial = 0;
......@@ -115,6 +122,7 @@ public:
private:
void getPointer(wl_client *client, wl_resource *resource, uint32_t id);
void getKeyboard(wl_client *client, wl_resource *resource, uint32_t id);
void updateSelection(DataDeviceInterface *dataDevice, bool set);
static Private *cast(wl_resource *r);
static void unbind(wl_resource *r);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment