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

Properly handle destroying a Keyboard resource

Summary:
On client side the newer wl_keyboard_release is used which is a
destructor call. On server side the shared destroy callback is used
and it's ensured that KWayland doesn't crash if called into the
KeyboardInterface between unbound and destroyed.

Test Plan:
Test case extended to cover the condition of an unbound
KeyboardInterface.

Reviewers: #plasma_on_wayland

Subscribers: plasma-devel

Tags: #plasma_on_wayland

Differential Revision: https://phabricator.kde.org/D2036
parent 5c9a63b1
......@@ -48,6 +48,9 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include <wayland-client-protocol.h>
#include <linux/input.h>
// System
#include <fcntl.h>
#include <unistd.h>
class TestWaylandSeat : public QObject
{
......@@ -1066,7 +1069,8 @@ void TestWaylandSeat::testKeyboard()
QCOMPARE(keyboard->keyRepeatRate(), 0);
wl_display_flush(m_connection->display());
QTest::qWait(100);
QVERIFY(m_seatInterface->focusedKeyboard());
auto serverKeyboard = m_seatInterface->focusedKeyboard();
QVERIFY(serverKeyboard);
// we should get the repeat info announced
QCOMPARE(repeatInfoSpy.count(), 1);
......@@ -1177,11 +1181,49 @@ void TestWaylandSeat::testKeyboard()
QCOMPARE(keyboard->enteredSurface(), s);
QCOMPARE(ckeyboard.enteredSurface(), s);
QSignalSpy serverSurfaceDestroyedSpy(serverSurface, &QObject::destroyed);
QVERIFY(serverSurfaceDestroyedSpy.isValid());
delete s;
wl_display_flush(m_connection->display());
QTest::qWait(100);
QVERIFY(serverSurfaceDestroyedSpy.wait());
QVERIFY(!m_seatInterface->focusedKeyboardSurface());
QVERIFY(!m_seatInterface->focusedKeyboard());
QVERIFY(!serverKeyboard->focusedSurface());
// let's create a Surface again
QScopedPointer<Surface> s2(m_compositor->createSurface());
QVERIFY(surfaceCreatedSpy.wait());
QCOMPARE(surfaceCreatedSpy.count(), 2);
serverSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface*>();
QVERIFY(serverSurface);
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboard(), serverKeyboard);
// delete the Keyboard
QSignalSpy unboundSpy(serverKeyboard, &Resource::unbound);
QVERIFY(unboundSpy.isValid());
QSignalSpy destroyedSpy(serverKeyboard, &Resource::destroyed);
QVERIFY(destroyedSpy.isValid());
delete keyboard;
QVERIFY(unboundSpy.wait());
QCOMPARE(unboundSpy.count(), 1);
QCOMPARE(destroyedSpy.count(), 0);
// verify that calling into the Keyboard related functionality doesn't crash
m_seatInterface->setTimestamp(9);
m_seatInterface->keyPressed(KEY_F2);
m_seatInterface->setTimestamp(10);
m_seatInterface->keyReleased(KEY_F2);
m_seatInterface->setKeyRepeatInfo(30, 560);
m_seatInterface->setKeyRepeatInfo(25, 660);
m_seatInterface->updateKeyboardModifiers(5, 6, 7, 8);
m_seatInterface->setKeymap(open("/dev/null", O_RDONLY), 0);
m_seatInterface->setFocusedKeyboardSurface(nullptr);
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
QVERIFY(!m_seatInterface->focusedKeyboard());
QVERIFY(destroyedSpy.wait());
QCOMPARE(destroyedSpy.count(), 1);
// create a second Keyboard to verify that repeat info is announced properly
Keyboard *keyboard2 = m_seat->createKeyboard(m_seat);
......@@ -1196,6 +1238,17 @@ void TestWaylandSeat::testKeyboard()
QCOMPARE(keyboard2->isKeyRepeatEnabled(), true);
QCOMPARE(keyboard2->keyRepeatRate(), 25);
QCOMPARE(keyboard2->keyRepeatDelay(), 660);
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
serverKeyboard = m_seatInterface->focusedKeyboard();
QVERIFY(serverKeyboard);
QSignalSpy keyboard2DestroyedSpy(serverKeyboard, &QObject::destroyed);
QVERIFY(keyboard2DestroyedSpy.isValid());
delete keyboard2;
QVERIFY(keyboard2DestroyedSpy.wait());
// this should have unset it on the server
QVERIFY(!m_seatInterface->focusedKeyboard());
// but not the surface
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
}
void TestWaylandSeat::testCast()
......
......@@ -34,7 +34,7 @@ public:
Private(Keyboard *q);
void setup(wl_keyboard *k);
WaylandPointer<wl_keyboard, wl_keyboard_destroy> keyboard;
WaylandPointer<wl_keyboard, wl_keyboard_release> keyboard;
Surface *enteredSurface = nullptr;
struct {
......
......@@ -76,7 +76,7 @@ void KeyboardInterface::Private::sendEnter(SurfaceInterface *surface, quint32 se
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const struct wl_keyboard_interface KeyboardInterface::Private::s_interface {
releaseCallback
resourceDestroyedCallback
};
#endif
......@@ -87,12 +87,6 @@ KeyboardInterface::KeyboardInterface(SeatInterface *parent, wl_resource *parentR
KeyboardInterface::~KeyboardInterface() = default;
void KeyboardInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
{
Q_UNUSED(client)
unbind(resource);
}
void KeyboardInterface::setKeymap(int fd, quint32 size)
{
Q_D();
......@@ -113,13 +107,17 @@ void KeyboardInterface::Private::sendKeymap()
void KeyboardInterface::Private::sendKeymap(int fd, quint32 size)
{
Q_ASSERT(resource);
if (!resource) {
return;
}
wl_keyboard_send_keymap(resource, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, size);
}
void KeyboardInterface::Private::sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial)
{
Q_ASSERT(resource);
if (!resource) {
return;
}
wl_keyboard_send_modifiers(resource, serial, depressed, latched, locked, group);
}
......@@ -154,6 +152,9 @@ void KeyboardInterface::setFocusedSurface(SurfaceInterface *surface, quint32 ser
void KeyboardInterface::keyPressed(quint32 key, quint32 serial)
{
Q_D();
if (!d->resource) {
return;
}
Q_ASSERT(d->focusedSurface);
wl_keyboard_send_key(d->resource, serial, d->seat->timestamp(), key, WL_KEYBOARD_KEY_STATE_PRESSED);
}
......@@ -161,6 +162,9 @@ void KeyboardInterface::keyPressed(quint32 key, quint32 serial)
void KeyboardInterface::keyReleased(quint32 key, quint32 serial)
{
Q_D();
if (!d->resource) {
return;
}
Q_ASSERT(d->focusedSurface);
wl_keyboard_send_key(d->resource, serial, d->seat->timestamp(), key, WL_KEYBOARD_KEY_STATE_RELEASED);
}
......@@ -175,6 +179,9 @@ void KeyboardInterface::updateModifiers(quint32 depressed, quint32 latched, quin
void KeyboardInterface::repeatInfo(qint32 charactersPerSecond, qint32 delay)
{
Q_D();
if (!d->resource) {
return;
}
if (wl_resource_get_version(d->resource) < WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
// only supported since version 4
return;
......
......@@ -48,9 +48,6 @@ public:
QMetaObject::Connection destroyConnection;
private:
// since version 3
static void releaseCallback(wl_client *client, wl_resource *resource);
static const struct wl_keyboard_interface s_interface;
};
......
Markdown is supported
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