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

Create one PointerInterface for each pointer wl_resource

Makes PointerInterface more like other Interface classes wrapping
wl_resource. The most important change is the handling of the
focused surface. This is now kept in the SeatInterface and can also
be set if there is no PointerInterface for the client yet.

The unit tests had to be adjusted and some are also disabled as the
button events are not yet moved into SeatInterface.
parent 961aaae8
......@@ -282,15 +282,23 @@ void TestWaylandSeat::testPointer()
SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWayland::Server::SurfaceInterface*>();
QVERIFY(serverSurface);
PointerInterface *serverPointer = m_seatInterface->focusedPointer();
serverPointer->setGlobalPos(QPoint(20, 18));
m_seatInterface->setPointerPos(QPoint(20, 18));
m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15));
// no pointer yet - won't be set
QVERIFY(!m_seatInterface->focusedPointerSurface());
// no pointer yet
QVERIFY(m_seatInterface->focusedPointerSurface());
QVERIFY(!m_seatInterface->focusedPointer());
Pointer *p = m_seat->createPointer(m_seat);
QVERIFY(p->isValid());
wl_display_flush(m_connection->display());
QSignalSpy pointerCreatedSpy(m_seatInterface, SIGNAL(pointerCreated(KWayland::Server::PointerInterface*)));
QVERIFY(pointerCreatedSpy.isValid());
// once the pointer is created it should be set as the focused pointer
QVERIFY(pointerCreatedSpy.wait());
QVERIFY(m_seatInterface->focusedPointer());
QCOMPARE(pointerCreatedSpy.first().first().value<PointerInterface*>(), m_seatInterface->focusedPointer());
m_seatInterface->setFocusedPointerSurface(nullptr);
serverSurface->client()->flush();
QTest::qWait(100);
QSignalSpy enteredSpy(p, SIGNAL(entered(quint32,QPointF)));
......@@ -313,6 +321,8 @@ void TestWaylandSeat::testPointer()
QVERIFY(enteredSpy.wait());
QCOMPARE(enteredSpy.first().first().value<quint32>(), m_display->serial());
QCOMPARE(enteredSpy.first().last().toPoint(), QPoint(10, 3));
PointerInterface *serverPointer = m_seatInterface->focusedPointer();
QVERIFY(serverPointer);
// test motion
m_seatInterface->setTimestamp(1);
......@@ -450,12 +460,16 @@ void TestWaylandSeat::testPointerButton()
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
PointerInterface *serverPointer = m_seatInterface->focusedPointer();
serverPointer->setGlobalPos(QPoint(20, 18));
m_seatInterface->setPointerPos(QPoint(20, 18));
m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15));
// no pointer yet - won't be set
QVERIFY(m_seatInterface->focusedPointerSurface());
QVERIFY(m_seatInterface->focusedPointer());
QCoreApplication::processEvents();
m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15));
PointerInterface *serverPointer = m_seatInterface->focusedPointer();
QVERIFY(serverPointer);
QFETCH(Qt::MouseButton, qtButton);
QFETCH(quint32, waylandButton);
quint32 msec = QDateTime::currentMSecsSinceEpoch();
......
......@@ -116,7 +116,9 @@ void TestWaylandServerSeat::testPointerButton()
display.start();
SeatInterface *seat = display.createSeat();
PointerInterface *pointer = seat->focusedPointer();
QVERIFY(!pointer);
#if 0
// no button pressed yet, should be released and no serial
QVERIFY(!pointer->isButtonPressed(0));
QVERIFY(!pointer->isButtonPressed(1));
......@@ -136,6 +138,7 @@ void TestWaylandServerSeat::testPointerButton()
pointer->buttonReleased(0);
QVERIFY(!pointer->isButtonPressed(0));
QCOMPARE(pointer->buttonSerial(0), display.serial());
#endif
}
void TestWaylandServerSeat::testPointerPos()
......@@ -147,6 +150,8 @@ void TestWaylandServerSeat::testPointerPos()
QSignalSpy seatPosSpy(seat, SIGNAL(pointerPosChanged(QPointF)));
QVERIFY(seatPosSpy.isValid());
PointerInterface *pointer = seat->focusedPointer();
QVERIFY(!pointer);
#if 0
QSignalSpy posSpy(pointer, SIGNAL(globalPosChanged(QPointF)));
QVERIFY(posSpy.isValid());
......@@ -174,6 +179,7 @@ void TestWaylandServerSeat::testPointerPos()
QCOMPARE(seatPosSpy.count(), 2);
QCOMPARE(seatPosSpy.first().first().toPointF(), QPointF(10, 15));
QCOMPARE(seatPosSpy.last().first().toPointF(), QPointF(5, 7));
#endif
}
void TestWaylandServerSeat::testDestroyThroughTerminate()
......
......@@ -39,8 +39,6 @@ class PointerInterface::Private
public:
Private(SeatInterface *parent);
void createInterface(wl_client *client, wl_resource *parentResource, uint32_t id);
wl_resource *pointerForSurface(SurfaceInterface *surface) const;
void surfaceDeleted();
void updateButtonSerial(quint32 button, quint32 serial);
enum class ButtonState {
Released,
......@@ -49,21 +47,11 @@ public:
void updateButtonState(quint32 button, ButtonState state);
SeatInterface *seat;
struct ResourceData {
wl_client *client = nullptr;
wl_resource *pointer = nullptr;
};
QList<ResourceData> resources;
struct FocusedSurface {
SurfaceInterface *surface = nullptr;
QPoint offset = QPoint();
wl_resource *pointer = nullptr;
quint32 serial = 0;
};
FocusedSurface focusedSurface;
SurfaceInterface *focusedSurface = nullptr;
QHash<quint32, quint32> buttonSerials;
QHash<quint32, ButtonState> buttonStates;
QMetaObject::Connection destroyConnection;
wl_resource *resource = nullptr;
private:
static PointerInterface::Private *cast(wl_resource *resource) {
......@@ -95,10 +83,10 @@ PointerInterface::PointerInterface(SeatInterface *parent)
: QObject(parent)
, d(new Private(parent))
{
connect(parent, &SeatInterface::pointerPosChanged, [this](const QPointF &pos) {
if (d->focusedSurface.surface && d->focusedSurface.pointer) {
const QPointF pos = d->seat->pointerPos() - d->focusedSurface.offset;
wl_pointer_send_motion(d->focusedSurface.pointer, d->seat->timestamp(),
connect(parent, &SeatInterface::pointerPosChanged, [this] {
if (d->focusedSurface) {
const QPointF pos = d->seat->pointerPos() - d->seat->focusedPointerSurfacePosition();
wl_pointer_send_motion(d->resource, d->seat->timestamp(),
wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
}
});
......@@ -107,9 +95,8 @@ PointerInterface::PointerInterface(SeatInterface *parent)
PointerInterface::~PointerInterface()
{
while (!d->resources.isEmpty()) {
auto data = d->resources.takeLast();
wl_resource_destroy(data.pointer);
if (d->resource) {
wl_resource_destroy(d->resource);
}
}
......@@ -125,61 +112,29 @@ void PointerInterface::Private::createInterface(wl_client* client, wl_resource*
wl_resource_post_no_memory(parentResource);
return;
}
ResourceData data;
data.client = client;
data.pointer = p;
resources << data;
wl_resource_set_implementation(p, &s_interface, this, unbind);
resource = p;
}
wl_resource *PointerInterface::Private::pointerForSurface(SurfaceInterface *surface) const
{
if (!surface) {
return nullptr;
}
for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
if ((*it).client == *surface->client()) {
return (*it).pointer;
}
}
return nullptr;
}
void PointerInterface::setFocusedSurface(SurfaceInterface *surface, const QPoint &surfacePosition)
void PointerInterface::setFocusedSurface(SurfaceInterface *surface, quint32 serial)
{
const quint32 serial = d->seat->display()->nextSerial();
if (d->focusedSurface.surface && d->focusedSurface.pointer) {
wl_pointer_send_leave(d->focusedSurface.pointer, serial, d->focusedSurface.surface->resource());
Q_ASSERT(d->resource);
if (d->focusedSurface) {
wl_pointer_send_leave(d->resource, serial, d->focusedSurface->resource());
disconnect(d->destroyConnection);
}
d->focusedSurface.pointer = d->pointerForSurface(surface);
if (!d->focusedSurface.pointer) {
d->focusedSurface = Private::FocusedSurface();
if (!surface) {
d->focusedSurface = nullptr;
return;
}
d->focusedSurface.surface = surface;
d->focusedSurface.offset = surfacePosition;
d->focusedSurface.serial = serial;
d->destroyConnection = connect(d->focusedSurface.surface, &QObject::destroyed, this, [this] { d->surfaceDeleted(); });
const QPointF pos = d->seat->pointerPos() - surfacePosition;
wl_pointer_send_enter(d->focusedSurface.pointer, d->focusedSurface.serial,
d->focusedSurface.surface->resource(),
wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
}
d->focusedSurface = surface;
d->destroyConnection = connect(d->focusedSurface, &QObject::destroyed, this, [this] { d->focusedSurface = nullptr; });
void PointerInterface::Private::surfaceDeleted()
{
focusedSurface = FocusedSurface();
}
void PointerInterface::setFocusedSurfacePosition(const QPoint &surfacePosition)
{
if (!d->focusedSurface.surface) {
return;
}
d->focusedSurface.offset = surfacePosition;
const QPointF pos = d->seat->pointerPos() - d->seat->focusedPointerSurfacePosition();
wl_pointer_send_enter(d->resource, serial,
d->focusedSurface->resource(),
wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
}
void PointerInterface::setGlobalPos(const QPointF &pos)
......@@ -216,10 +171,10 @@ void PointerInterface::buttonPressed(quint32 button)
const quint32 serial = d->seat->display()->nextSerial();
d->updateButtonSerial(button, serial);
d->updateButtonState(button, Private::ButtonState::Pressed);
if (!d->focusedSurface.surface || !d->focusedSurface.pointer) {
if (!d->focusedSurface) {
return;
}
wl_pointer_send_button(d->focusedSurface.pointer, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_PRESSED);
wl_pointer_send_button(d->resource, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_PRESSED);
}
void PointerInterface::buttonPressed(Qt::MouseButton button)
......@@ -236,10 +191,10 @@ void PointerInterface::buttonReleased(quint32 button)
const quint32 serial = d->seat->display()->nextSerial();
d->updateButtonSerial(button, serial);
d->updateButtonState(button, Private::ButtonState::Released);
if (!d->focusedSurface.surface || !d->focusedSurface.pointer) {
if (!d->focusedSurface) {
return;
}
wl_pointer_send_button(d->focusedSurface.pointer, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_RELEASED);
wl_pointer_send_button(d->resource, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_RELEASED);
}
void PointerInterface::buttonReleased(Qt::MouseButton button)
......@@ -305,10 +260,10 @@ bool PointerInterface::isButtonPressed(Qt::MouseButton button) const
void PointerInterface::axis(Qt::Orientation orientation, quint32 delta)
{
if (!d->focusedSurface.surface || !d->focusedSurface.pointer) {
if (!d->focusedSurface) {
return;
}
wl_pointer_send_axis(d->focusedSurface.pointer, d->seat->timestamp(),
wl_pointer_send_axis(d->resource, d->seat->timestamp(),
(orientation == Qt::Vertical) ? WL_POINTER_AXIS_VERTICAL_SCROLL : WL_POINTER_AXIS_HORIZONTAL_SCROLL,
wl_fixed_from_int(delta));
}
......@@ -316,19 +271,7 @@ void PointerInterface::axis(Qt::Orientation orientation, quint32 delta)
void PointerInterface::Private::unbind(wl_resource *resource)
{
auto p = cast(resource);
auto it = std::find_if(p->resources.begin(), p->resources.end(),
[resource](const ResourceData &data) {
return data.pointer == resource;
}
);
if (it == p->resources.end()) {
return;
}
if ((*it).pointer == p->focusedSurface.pointer) {
QObject::disconnect(p->destroyConnection);
p->focusedSurface = FocusedSurface();
}
p->resources.erase(it);
p->resource = nullptr;
}
void PointerInterface::Private::setCursorCallback(wl_client *client, wl_resource *resource, uint32_t serial,
......@@ -354,14 +297,9 @@ QPointF PointerInterface::globalPos() const
return d->seat->pointerPos();
}
SurfaceInterface *PointerInterface::focusedSurface() const
{
return d->focusedSurface.surface;
}
QPoint PointerInterface::focusedSurfacePosition() const
wl_resource *PointerInterface::resource() const
{
return d->focusedSurface.offset;
return d->resource;
}
}
......
......@@ -65,8 +65,7 @@ public:
quint32 buttonSerial(Qt::MouseButton button) const;
void axis(Qt::Orientation orientation, quint32 delta);
void setFocusedSurfacePosition(const QPoint &surfacePosition);
QPoint focusedSurfacePosition() const;
wl_resource *resource() const;
Q_SIGNALS:
/**
......@@ -76,7 +75,7 @@ Q_SIGNALS:
void globalPosChanged(const QPointF &pos);
private:
void setFocusedSurface(SurfaceInterface *surface, const QPoint &surfacePosition = QPoint());
void setFocusedSurface(SurfaceInterface *surface, quint32 serial);
SurfaceInterface *focusedSurface() const;
friend class SeatInterface;
explicit PointerInterface(SeatInterface *parent);
......@@ -87,4 +86,6 @@ private:
}
}
Q_DECLARE_METATYPE(KWayland::Server::PointerInterface*)
#endif
......@@ -25,6 +25,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "surface_interface.h"
// Qt
#include <QHash>
#include <QVector>
// Wayland
#include <wayland-server.h>
#ifndef WL_SEAT_NAME_SINCE_VERSION
......@@ -46,15 +47,24 @@ public:
void bind(wl_client *client, uint32_t version, uint32_t id) override;
void sendCapabilities(wl_resource *r);
void sendName(wl_resource *r);
PointerInterface *pointerForSurface(SurfaceInterface *surface) const;
QString name;
bool pointer = false;
bool keyboard = false;
bool touch = false;
QList<wl_resource*> resources;
PointerInterface *pointerInterface = nullptr;
struct FocusedPointer {
SurfaceInterface *surface = nullptr;
PointerInterface *pointer = nullptr;
QMetaObject::Connection destroyConnection;
QPointF offset = QPointF();
quint32 serial = 0;
};
FocusedPointer focusedPointer = FocusedPointer();
KeyboardInterface *keyboardInterface = nullptr;
quint32 timestamp = 0;
QVector<PointerInterface*> pointers;
// Pointer related members
QPointF pointerPos;
......@@ -65,6 +75,7 @@ public:
}
private:
void getPointer(wl_client *client, wl_resource *resource, uint32_t id);
static Private *cast(wl_resource *r);
static void unbind(wl_resource *r);
......@@ -93,7 +104,6 @@ SeatInterface::SeatInterface(Display *display, QObject *parent)
: Global(new Private(this, display), parent)
{
Q_D();
d->pointerInterface = new PointerInterface(this);
d->keyboardInterface = new KeyboardInterface(this);
connect(this, &SeatInterface::nameChanged, this,
[this, d] {
......@@ -168,6 +178,20 @@ SeatInterface::Private *SeatInterface::Private::cast(wl_resource *r)
return r ? reinterpret_cast<SeatInterface::Private*>(wl_resource_get_user_data(r)) : nullptr;
}
PointerInterface *SeatInterface::Private::pointerForSurface(SurfaceInterface *surface) const
{
if (!surface) {
return nullptr;
}
for (auto it = pointers.begin(); it != pointers.end(); ++it) {
if (wl_resource_get_client((*it)->resource()) == *surface->client()) {
return (*it);
}
}
return nullptr;
}
void SeatInterface::setHasKeyboard(bool has)
{
Q_D();
......@@ -210,7 +234,31 @@ void SeatInterface::setName(const QString &name)
void SeatInterface::Private::getPointerCallback(wl_client *client, wl_resource *resource, uint32_t id)
{
cast(resource)->pointerInterface->createInterface(client, resource, id);
cast(resource)->getPointer(client, resource, id);
}
void SeatInterface::Private::getPointer(wl_client *client, wl_resource *resource, uint32_t id)
{
// TODO: only create if seat has pointer?
PointerInterface *pointer = new PointerInterface(q);
pointer->createInterface(client, resource, id);
pointers << pointer;
if (focusedPointer.surface && focusedPointer.surface->client()->client() == client) {
// this is a pointer for the currently focused pointer surface
if (!focusedPointer.pointer) {
focusedPointer.pointer = pointer;
pointer->setFocusedSurface(focusedPointer.surface, focusedPointer.serial);
}
}
QObject::connect(pointer, &QObject::destroyed, q,
[pointer,this] {
pointers.removeAt(pointers.indexOf(pointer));
if (focusedPointer.pointer == pointer) {
focusedPointer.pointer = nullptr;
}
}
);
emit q->pointerCreated(pointer);
}
void SeatInterface::Private::getKeyboardCallback(wl_client *client, wl_resource *resource, uint32_t id)
......@@ -300,19 +348,57 @@ void SeatInterface::setTimestamp(quint32 time)
SurfaceInterface *SeatInterface::focusedPointerSurface() const
{
Q_D();
return d->pointerInterface->focusedSurface();
return d->focusedPointer.surface;
}
void SeatInterface::setFocusedPointerSurface(SurfaceInterface *surface, const QPoint &surfacePosition)
void SeatInterface::setFocusedPointerSurface(SurfaceInterface *surface, const QPointF &surfacePosition)
{
Q_D();
d->pointerInterface->setFocusedSurface(surface, surfacePosition);
const quint32 serial = d->display->nextSerial();
if (d->focusedPointer.pointer) {
d->focusedPointer.pointer->setFocusedSurface(nullptr, serial);
}
if (d->focusedPointer.surface) {
disconnect(d->focusedPointer.destroyConnection);
}
d->focusedPointer = Private::FocusedPointer();
d->focusedPointer.surface = surface;
PointerInterface *p = d->pointerForSurface(surface);
d->focusedPointer.pointer = p;
if (d->focusedPointer.surface) {
d->focusedPointer.destroyConnection = connect(surface, &QObject::destroyed, this,
[this] {
Q_D();
d->focusedPointer = Private::FocusedPointer();
}
);
d->focusedPointer.offset = surfacePosition;
d->focusedPointer.serial = serial;
}
if (!p) {
return;
}
p->setFocusedSurface(surface, serial);
}
PointerInterface *SeatInterface::focusedPointer() const
{
Q_D();
return d->pointerInterface;
return d->focusedPointer.pointer;
}
void SeatInterface::setFocusedPointerSurfacePosition(const QPointF &surfacePosition)
{
Q_D();
if (d->focusedPointer.surface) {
d->focusedPointer.offset = surfacePosition;
}
}
QPointF SeatInterface::focusedPointerSurfacePosition() const
{
Q_D();
return d->focusedPointer.offset;
}
}
......
......@@ -25,6 +25,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/kwaylandserver_export.h>
#include "global.h"
#include "pointer_interface.h"
struct wl_client;
struct wl_resource;
......@@ -36,7 +37,6 @@ namespace Server
class Display;
class KeyboardInterface;
class PointerInterface;
class SurfaceInterface;
class KWAYLANDSERVER_EXPORT SeatInterface : public Global
......@@ -68,9 +68,11 @@ public:
// pointer related methods
void setPointerPos(const QPointF &pos);
QPointF pointerPos() const;
void setFocusedPointerSurface(SurfaceInterface *surface, const QPoint &surfacePosition = QPoint());
void setFocusedPointerSurface(SurfaceInterface *surface, const QPointF &surfacePosition = QPoint());
SurfaceInterface *focusedPointerSurface() const;
PointerInterface *focusedPointer() const;
void setFocusedPointerSurfacePosition(const QPointF &surfacePosition);
QPointF focusedPointerSurfacePosition() const;
static SeatInterface *get(wl_resource *native);
......@@ -82,6 +84,8 @@ Q_SIGNALS:
void pointerPosChanged(const QPointF &pos);
void timestampChanged(quint32);
void pointerCreated(KWayland::Server::PointerInterface*);
private:
friend class Display;
explicit SeatInterface(Display *display, QObject *parent);
......
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