diff --git a/autotests/client/test_wayland_seat.cpp b/autotests/client/test_wayland_seat.cpp --- a/autotests/client/test_wayland_seat.cpp +++ b/autotests/client/test_wayland_seat.cpp @@ -48,6 +48,9 @@ #include #include +// System +#include +#include class TestWaylandSeat : public QObject { @@ -1066,7 +1069,8 @@ 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 @@ 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 s2(m_compositor->createSurface()); + QVERIFY(surfaceCreatedSpy.wait()); + QCOMPARE(surfaceCreatedSpy.count(), 2); + serverSurface = surfaceCreatedSpy.last().first().value(); + 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 @@ 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() diff --git a/src/client/keyboard.cpp b/src/client/keyboard.cpp --- a/src/client/keyboard.cpp +++ b/src/client/keyboard.cpp @@ -34,7 +34,7 @@ Private(Keyboard *q); void setup(wl_keyboard *k); - WaylandPointer keyboard; + WaylandPointer keyboard; Surface *enteredSurface = nullptr; struct { diff --git a/src/server/keyboard_interface.cpp b/src/server/keyboard_interface.cpp --- a/src/server/keyboard_interface.cpp +++ b/src/server/keyboard_interface.cpp @@ -76,7 +76,7 @@ #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_keyboard_interface KeyboardInterface::Private::s_interface { - releaseCallback + resourceDestroyedCallback }; #endif @@ -87,12 +87,6 @@ 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(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,13 +152,19 @@ 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); } 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::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; diff --git a/src/server/keyboard_interface_p.h b/src/server/keyboard_interface_p.h --- a/src/server/keyboard_interface_p.h +++ b/src/server/keyboard_interface_p.h @@ -48,9 +48,6 @@ QMetaObject::Connection destroyConnection; private: - // since version 3 - static void releaseCallback(wl_client *client, wl_resource *resource); - static const struct wl_keyboard_interface s_interface; };