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

Refactor KeyboardInterface

The KeyboardInterface gets created per wl_resource. For this all
more global information (e.g. key states) is moved into the
SeatInterface.
parent c0a4abea
......@@ -518,30 +518,31 @@ void TestWaylandSeat::testKeyboard()
SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWayland::Server::SurfaceInterface*>();
QVERIFY(serverSurface);
KeyboardInterface *serverKeyboard = m_seatInterface->keyboard();
serverKeyboard->setFocusedSurface(serverSurface);
// no pointer yet - won't be set
QVERIFY(!serverKeyboard->focusedSurface());
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
// no keyboard yet
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
QVERIFY(!m_seatInterface->focusedKeyboard());
Keyboard *keyboard = m_seat->createKeyboard(m_seat);
QVERIFY(keyboard->isValid());
wl_display_flush(m_connection->display());
QTest::qWait(100);
QVERIFY(m_seatInterface->focusedKeyboard());
m_seatInterface->setTimestamp(1);
serverKeyboard->keyPressed(KEY_K);
m_seatInterface->keyPressed(KEY_K);
m_seatInterface->setTimestamp(2);
serverKeyboard->keyPressed(KEY_D);
m_seatInterface->keyPressed(KEY_D);
m_seatInterface->setTimestamp(3);
serverKeyboard->keyPressed(KEY_E);
m_seatInterface->keyPressed(KEY_E);
QSignalSpy modifierSpy(keyboard, SIGNAL(modifiersChanged(quint32,quint32,quint32,quint32)));
QVERIFY(modifierSpy.isValid());
// TODO: add a signalspy for enter
serverKeyboard->setFocusedSurface(serverSurface);
QCOMPARE(serverKeyboard->focusedSurface(), serverSurface);
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboard()->focusedSurface(), serverSurface);
// we get the modifiers sent after the enter
QVERIFY(modifierSpy.wait());
......@@ -555,19 +556,19 @@ void TestWaylandSeat::testKeyboard()
QVERIFY(keyChangedSpy.isValid());
m_seatInterface->setTimestamp(4);
serverKeyboard->keyReleased(KEY_E);
m_seatInterface->keyReleased(KEY_E);
QVERIFY(keyChangedSpy.wait());
m_seatInterface->setTimestamp(5);
serverKeyboard->keyReleased(KEY_D);
m_seatInterface->keyReleased(KEY_D);
QVERIFY(keyChangedSpy.wait());
m_seatInterface->setTimestamp(6);
serverKeyboard->keyReleased(KEY_K);
m_seatInterface->keyReleased(KEY_K);
QVERIFY(keyChangedSpy.wait());
m_seatInterface->setTimestamp(7);
serverKeyboard->keyPressed(KEY_F1);
m_seatInterface->keyPressed(KEY_F1);
QVERIFY(keyChangedSpy.wait());
m_seatInterface->setTimestamp(8);
serverKeyboard->keyReleased(KEY_F1);
m_seatInterface->keyReleased(KEY_F1);
QVERIFY(keyChangedSpy.wait());
QCOMPARE(keyChangedSpy.count(), 5);
......@@ -587,7 +588,7 @@ void TestWaylandSeat::testKeyboard()
QCOMPARE(keyChangedSpy.at(4).at(1).value<Keyboard::KeyState>(), Keyboard::KeyState::Released);
QCOMPARE(keyChangedSpy.at(4).at(2).value<quint32>(), quint32(8));
serverKeyboard->updateModifiers(1, 2, 3, 4);
m_seatInterface->updateKeyboardModifiers(1, 2, 3, 4);
QVERIFY(modifierSpy.wait());
QCOMPARE(modifierSpy.count(), 2);
QCOMPARE(modifierSpy.last().at(0).value<quint32>(), quint32(1));
......@@ -596,18 +597,21 @@ void TestWaylandSeat::testKeyboard()
QCOMPARE(modifierSpy.last().at(3).value<quint32>(), quint32(4));
// TODO: add a test for leave signal
serverKeyboard->setFocusedSurface(nullptr);
QVERIFY(!serverKeyboard->focusedSurface());
m_seatInterface->setFocusedKeyboardSurface(nullptr);
QVERIFY(!m_seatInterface->focusedKeyboardSurface());
QVERIFY(!m_seatInterface->focusedKeyboard());
// enter it again
serverKeyboard->setFocusedSurface(serverSurface);
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
QVERIFY(modifierSpy.wait());
QCOMPARE(serverKeyboard->focusedSurface(), serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboard()->focusedSurface(), serverSurface);
delete s;
wl_display_flush(m_connection->display());
QTest::qWait(100);
QVERIFY(!serverKeyboard->focusedSurface());
QVERIFY(!m_seatInterface->focusedKeyboardSurface());
QVERIFY(!m_seatInterface->focusedKeyboard());
}
void TestWaylandSeat::testCast()
......
......@@ -22,7 +22,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "seat_interface.h"
#include "surface_interface.h"
// Qt
#include <QHash>
#include <QVector>
// System
#include <fcntl.h>
#include <unistd.h>
......@@ -40,43 +40,15 @@ class KeyboardInterface::Private
public:
Private(SeatInterface *s);
void createInterfae(wl_client *client, wl_resource *parentResource, uint32_t id);
void surfaceDeleted();
wl_resource *keyboardForSurface(SurfaceInterface *surface) const;
void sendKeymap(wl_resource *r);
void sendKeymapToAll();
void sendModifiers(wl_resource *r);
enum class KeyState {
Released,
Pressed
};
void updateKey(quint32 key, KeyState state);
void sendKeymap();
void sendKeymap(int fd, quint32 size);
void sendModifiers();
void sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial);
SeatInterface *seat;
struct ResourceData {
wl_client *client = nullptr;
wl_resource *keyboard = nullptr;
};
QList<ResourceData> resources;
struct Keymap {
int fd = -1;
quint32 size = 0;
bool xkbcommonCompatible = false;
};
Keymap keymap;
struct Modifiers {
quint32 depressed = 0;
quint32 latched = 0;
quint32 locked = 0;
quint32 group = 0;
};
Modifiers modifiers;
struct FocusedSurface {
SurfaceInterface *surface = nullptr;
wl_resource *keyboard = nullptr;
};
FocusedSurface focusedSurface;
QHash<quint32, KeyState> keyStates;
SurfaceInterface *focusedSurface = nullptr;
QMetaObject::Connection destroyConnection;
wl_resource *resource = nullptr;
private:
static Private *cast(wl_resource *resource) {
......@@ -107,9 +79,8 @@ KeyboardInterface::KeyboardInterface(SeatInterface *parent)
KeyboardInterface::~KeyboardInterface()
{
while (!d->resources.isEmpty()) {
auto data = d->resources.takeLast();
wl_resource_destroy(data.keyboard);
if (d->resource) {
wl_resource_destroy(d->resource);
}
}
......@@ -125,37 +96,17 @@ void KeyboardInterface::Private::createInterfae(wl_client *client, wl_resource *
wl_resource_post_no_memory(parentResource);
return;
}
ResourceData data;
data.client = client;
data.keyboard = k;
resources << data;
resource = k;
wl_resource_set_implementation(k, &s_interface, this, unbind);
sendKeymap(k);
sendKeymap();
}
void KeyboardInterface::Private::unbind(wl_resource *resource)
{
auto k = cast(resource);
auto it = std::find_if(k->resources.begin(), k->resources.end(),
[resource](const ResourceData &data) {
return data.keyboard == resource;
}
);
if (it == k->resources.end()) {
return;
}
if ((*it).keyboard == k->focusedSurface.keyboard) {
QObject::disconnect(k->destroyConnection);
k->focusedSurface = FocusedSurface();
}
k->resources.erase(it);
}
void KeyboardInterface::Private::surfaceDeleted()
{
focusedSurface = FocusedSurface();
k->resource = nullptr;
}
void KeyboardInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
......@@ -166,121 +117,93 @@ void KeyboardInterface::Private::releaseCallback(wl_client *client, wl_resource
void KeyboardInterface::setKeymap(int fd, quint32 size)
{
d->keymap.xkbcommonCompatible = true;
d->keymap.fd = fd;
d->keymap.size = size;
d->sendKeymapToAll();
d->sendKeymap(fd, size);
}
void KeyboardInterface::Private::sendKeymap(wl_resource *r)
void KeyboardInterface::Private::sendKeymap()
{
if (keymap.xkbcommonCompatible) {
wl_keyboard_send_keymap(r,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
keymap.fd,
keymap.size);
Q_ASSERT(resource);
if (seat->isKeymapXkbCompatible()) {
sendKeymap(seat->keymapFileDescriptor(), seat->keymapSize());
} else {
int nullFd = open("/dev/null", O_RDONLY);
wl_keyboard_send_keymap(r, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP, nullFd, 0);
wl_keyboard_send_keymap(resource, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP, nullFd, 0);
close(nullFd);
}
}
void KeyboardInterface::Private::sendKeymapToAll()
void KeyboardInterface::Private::sendKeymap(int fd, quint32 size)
{
for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
sendKeymap((*it).keyboard);
}
Q_ASSERT(resource);
wl_keyboard_send_keymap(resource, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, size);
}
void KeyboardInterface::Private::sendModifiers(wl_resource* r)
void KeyboardInterface::Private::sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial)
{
wl_keyboard_send_modifiers(r, seat->display()->nextSerial(), modifiers.depressed, modifiers.latched, modifiers.locked, modifiers.group);
Q_ASSERT(resource);
wl_keyboard_send_modifiers(resource, serial, depressed, latched, locked, group);
}
void KeyboardInterface::setFocusedSurface(SurfaceInterface *surface)
void KeyboardInterface::Private::sendModifiers()
{
const quint32 serial = d->seat->display()->nextSerial();
if (d->focusedSurface.surface && d->focusedSurface.keyboard) {
wl_keyboard_send_leave(d->focusedSurface.keyboard, serial, d->focusedSurface.surface->resource());
sendModifiers(seat->depressedModifiers(), seat->latchedModifiers(), seat->lockedModifiers(), seat->groupModifiers(), seat->lastModifiersSerial());
}
void KeyboardInterface::setFocusedSurface(SurfaceInterface *surface, quint32 serial)
{
if (d->focusedSurface) {
wl_keyboard_send_leave(d->resource, serial, d->focusedSurface->resource());
disconnect(d->destroyConnection);
}
d->focusedSurface.keyboard = d->keyboardForSurface(surface);
if (!d->focusedSurface.keyboard) {
d->focusedSurface = Private::FocusedSurface();
d->focusedSurface = surface;
if (!d->focusedSurface) {
return;
}
d->focusedSurface.surface = surface;
d->destroyConnection = connect(d->focusedSurface.surface, &QObject::destroyed, this, [this] { d->surfaceDeleted(); });
d->destroyConnection = connect(d->focusedSurface, &QObject::destroyed, this,
[this] {
d->focusedSurface = nullptr;
}
);
wl_array keys;
wl_array_init(&keys);
for (auto it = d->keyStates.constBegin(); it != d->keyStates.constEnd(); ++it) {
if (it.value() == Private::KeyState::Pressed) {
continue;
}
const auto states = d->seat->pressedKeys();
for (auto it = states.begin(); it != states.end(); ++it) {
uint32_t *k = reinterpret_cast<uint32_t*>(wl_array_add(&keys, sizeof(uint32_t)));
*k = it.key();
*k = *it;
}
wl_keyboard_send_enter(d->focusedSurface.keyboard, serial, d->focusedSurface.surface->resource(), &keys);
wl_keyboard_send_enter(d->resource, serial, d->focusedSurface->resource(), &keys);
wl_array_release(&keys);
d->sendModifiers(d->focusedSurface.keyboard);
}
wl_resource *KeyboardInterface::Private::keyboardForSurface(SurfaceInterface *surface) const
{
if (!surface) {
return nullptr;
}
for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
if ((*it).client == *surface->client()) {
return (*it).keyboard;
}
}
return nullptr;
d->sendModifiers();
}
void KeyboardInterface::keyPressed(quint32 key)
void KeyboardInterface::keyPressed(quint32 key, quint32 serial)
{
d->updateKey(key, Private::KeyState::Pressed);
if (d->focusedSurface.surface && d->focusedSurface.keyboard) {
wl_keyboard_send_key(d->focusedSurface.keyboard, d->seat->display()->nextSerial(), d->seat->timestamp(), key, WL_KEYBOARD_KEY_STATE_PRESSED);
}
Q_ASSERT(d->focusedSurface);
wl_keyboard_send_key(d->resource, serial, d->seat->timestamp(), key, WL_KEYBOARD_KEY_STATE_PRESSED);
}
void KeyboardInterface::keyReleased(quint32 key)
void KeyboardInterface::keyReleased(quint32 key, quint32 serial)
{
d->updateKey(key, Private::KeyState::Released);
if (d->focusedSurface.surface && d->focusedSurface.keyboard) {
wl_keyboard_send_key(d->focusedSurface.keyboard, d->seat->display()->nextSerial(), d->seat->timestamp(), key, WL_KEYBOARD_KEY_STATE_RELEASED);
}
Q_ASSERT(d->focusedSurface);
wl_keyboard_send_key(d->resource, serial, d->seat->timestamp(), key, WL_KEYBOARD_KEY_STATE_RELEASED);
}
void KeyboardInterface::Private::updateKey(quint32 key, KeyState state)
void KeyboardInterface::updateModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial)
{
auto it = keyStates.find(key);
if (it == keyStates.end()) {
keyStates.insert(key, state);
return;
}
it.value() = state;
Q_ASSERT(d->focusedSurface);
d->sendModifiers(depressed, latched, locked, group, serial);
}
void KeyboardInterface::updateModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group)
SurfaceInterface *KeyboardInterface::focusedSurface() const
{
d->modifiers.depressed = depressed;
d->modifiers.latched = latched;
d->modifiers.locked = locked;
d->modifiers.group = group;
if (d->focusedSurface.surface && d->focusedSurface.keyboard) {
d->sendModifiers(d->focusedSurface.keyboard);
}
return d->focusedSurface;
}
SurfaceInterface *KeyboardInterface::focusedSurface() const
wl_resource *KeyboardInterface::resource() const
{
return d->focusedSurface.surface;
return d->resource;
}
}
......
......@@ -44,15 +44,16 @@ public:
void createInterfae(wl_client *client, wl_resource *parentResource, uint32_t id);
void setKeymap(int fd, quint32 size);
void keyPressed(quint32 key);
void keyReleased(quint32 key);
void updateModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group);
void setFocusedSurface(SurfaceInterface *surface);
SurfaceInterface *focusedSurface() const;
wl_resource *resource() const;
private:
void setFocusedSurface(SurfaceInterface *surface, quint32 serial);
void setKeymap(int fd, quint32 size);
void updateModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial);
void keyPressed(quint32 key, quint32 serial);
void keyReleased(quint32 key, quint32 serial);
friend class SeatInterface;
explicit KeyboardInterface(SeatInterface *parent);
......@@ -63,4 +64,6 @@ private:
}
}
Q_DECLARE_METATYPE(KWayland::Server::KeyboardInterface*)
#endif
......@@ -50,6 +50,7 @@ public:
void sendCapabilities(wl_resource *r);
void sendName(wl_resource *r);
PointerInterface *pointerForSurface(SurfaceInterface *surface) const;
KeyboardInterface *keyboardForSurface(SurfaceInterface *surface) const;
QString name;
bool pointer = false;
......@@ -64,9 +65,9 @@ public:
quint32 serial = 0;
};
FocusedPointer focusedPointer = FocusedPointer();
KeyboardInterface *keyboardInterface = nullptr;
quint32 timestamp = 0;
QVector<PointerInterface*> pointers;
QVector<KeyboardInterface*> keyboards;
// Pointer related members
struct Pointer {
......@@ -82,6 +83,39 @@ public:
void updatePointerButtonSerial(quint32 button, quint32 serial);
void updatePointerButtonState(quint32 button, Pointer::ButtonState state);
// Keyboard related members
struct Keyboard {
enum class State {
Released,
Pressed
};
QHash<quint32, State> states;
struct Keymap {
int fd = -1;
quint32 size = 0;
bool xkbcommonCompatible = false;
};
Keymap keymap;
struct Modifiers {
quint32 depressed = 0;
quint32 latched = 0;
quint32 locked = 0;
quint32 group = 0;
quint32 serial = 0;
};
Modifiers modifiers;
struct Focus {
SurfaceInterface *surface = nullptr;
KeyboardInterface *keyboard = nullptr;
QMetaObject::Connection destroyConnection;
quint32 serial = 0;
};
Focus focus;
quint32 lastStateSerial = 0;
};
Keyboard keys;
void updateKey(quint32 key, Keyboard::State state);
static SeatInterface *get(wl_resource *native) {
auto s = cast(native);
return s ? s->q : nullptr;
......@@ -89,6 +123,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);
static Private *cast(wl_resource *r);
static void unbind(wl_resource *r);
......@@ -117,7 +152,6 @@ SeatInterface::SeatInterface(Display *display, QObject *parent)
: Global(new Private(this, display), parent)
{
Q_D();
d->keyboardInterface = new KeyboardInterface(this);
connect(this, &SeatInterface::nameChanged, this,
[this, d] {
for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) {
......@@ -183,6 +217,16 @@ void SeatInterface::Private::updatePointerButtonState(quint32 button, Pointer::B
it.value() = state;
}
void SeatInterface::Private::updateKey(quint32 key, Keyboard::State state)
{
auto it = keys.states.find(key);
if (it == keys.states.end()) {
keys.states.insert(key, state);
return;
}
it.value() = state;
}
void SeatInterface::Private::sendName(wl_resource *r)
{
if (wl_resource_get_version(r) < WL_SEAT_NAME_SINCE_VERSION) {
......@@ -225,6 +269,20 @@ PointerInterface *SeatInterface::Private::pointerForSurface(SurfaceInterface *su
return nullptr;
}
KeyboardInterface *SeatInterface::Private::keyboardForSurface(SurfaceInterface *surface) const
{
if (!surface) {
return nullptr;
}
for (auto it = keyboards.begin(); it != keyboards.end(); ++it) {
if (wl_resource_get_client((*it)->resource()) == *surface->client()) {
return (*it);
}
}
return nullptr;
}
void SeatInterface::setHasKeyboard(bool has)
{
Q_D();
......@@ -301,7 +359,31 @@ void SeatInterface::Private::getPointer(wl_client *client, wl_resource *resource
void SeatInterface::Private::getKeyboardCallback(wl_client *client, wl_resource *resource, uint32_t id)
{
cast(resource)->keyboardInterface->createInterfae(client, resource, id);
cast(resource)->getKeyboard(client, resource, id);
}
void SeatInterface::Private::getKeyboard(wl_client *client, wl_resource *resource, uint32_t id)
{
// TODO: only create if seat has keyboard?
KeyboardInterface *keyboard = new KeyboardInterface(q);
keyboard->createInterfae(client, resource, id);
keyboards << keyboard;
if (keys.focus.surface && keys.focus.surface->client()->client() == client) {
// this is a keyboard for the currently focused keyboard surface
if (!keys.focus.keyboard) {
keys.focus.keyboard = keyboard;
keyboard->setFocusedSurface(keys.focus.surface, keys.focus.serial);
}
}
QObject::connect(keyboard, &QObject::destroyed, q,
[keyboard,this] {
keyboards.removeAt(keyboards.indexOf(keyboard));
if (keys.focus.keyboard == keyboard) {
keys.focus.keyboard = nullptr;
}
}
);
emit q->keyboardCreated(keyboard);
}
void SeatInterface::Private::getTouchCallback(wl_client *client, wl_resource *resource, uint32_t id)
......@@ -335,12 +417,6 @@ bool SeatInterface::hasTouch() const
return d->touch;
}
KeyboardInterface *SeatInterface::keyboard()
{
Q_D();
return d->keyboardInterface;
}
SeatInterface *SeatInterface::get(wl_resource *native)
{
return Private::get(native);
......@@ -541,5 +617,151 @@ quint32 SeatInterface::pointerButtonSerial(quint32 button) const
return it.value();
}
void SeatInterface::keyPressed(quint32 key)
{
Q_D();
d->keys.lastStateSerial = d->display->nextSerial();
d->updateKey(key, Private::Keyboard::State::Pressed);
if (d->keys.focus.keyboard && d->keys.focus.surface) {
d->keys.focus.keyboard->keyPressed(key, d->keys.lastStateSerial);
}
}
void SeatInterface::keyReleased(quint32 key)
{
Q_D();
d->keys.lastStateSerial = d->display->nextSerial();
d->updateKey(key, Private::Keyboard::State::Released);
if (d->keys.focus.keyboard && d->keys.focus.surface) {
d->keys.focus.keyboard->keyReleased(key, d->keys.lastStateSerial);
}
}
SurfaceInterface *SeatInterface::focusedKeyboardSurface() const
{
Q_D();
return d->keys.focus.surface;
}
void SeatInterface::setFocusedKeyboardSurface(SurfaceInterface *surface)
{
Q_D();
const quint32 serial = d->display->nextSerial();
if (d->keys.focus.keyboard) {