Properly handle destroying a Pointer resource

Summary:
On client side the newer wl_pointer_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
PointerInterface between unbound and destroyed.

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

Reviewers: #plasma_on_wayland

Subscribers: plasma-devel

Tags: #plasma_on_wayland

Differential Revision: https://phabricator.kde.org/D2037
This commit is contained in:
Martin Gräßlin 2016-06-28 18:57:08 +02:00
parent 0b208fcd63
commit 89a4c2f0e1
3 changed files with 47 additions and 10 deletions

View file

@ -466,11 +466,56 @@ void TestWaylandSeat::testPointer()
QCOMPARE(p->enteredSurface(), s);
QCOMPARE(cp.enteredSurface(), s);
// destroy the focused pointer
QSignalSpy unboundSpy(serverPointer, &Resource::unbound);
QVERIFY(unboundSpy.isValid());
QSignalSpy destroyedSpy(serverPointer, &Resource::destroyed);
QVERIFY(destroyedSpy.isValid());
delete p;
QVERIFY(unboundSpy.wait());
QCOMPARE(unboundSpy.count(), 1);
QCOMPARE(destroyedSpy.count(), 0);
// now test that calling into the methods in Seat does not crash
QCOMPARE(m_seatInterface->focusedPointer(), serverPointer);
QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
m_seatInterface->setTimestamp(8);
m_seatInterface->setPointerPos(QPoint(10, 15));
m_seatInterface->setTimestamp(9);
m_seatInterface->pointerButtonPressed(1);
m_seatInterface->setTimestamp(10);
m_seatInterface->pointerButtonReleased(1);
m_seatInterface->setTimestamp(11);
m_seatInterface->pointerAxis(Qt::Horizontal, 10);
m_seatInterface->setTimestamp(12);
m_seatInterface->pointerAxis(Qt::Vertical, 20);
m_seatInterface->setFocusedPointerSurface(nullptr);
QCOMPARE(focusedPointerChangedSpy.count(), 7);
m_seatInterface->setFocusedPointerSurface(serverSurface);
QCOMPARE(focusedPointerChangedSpy.count(), 8);
QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
QVERIFY(!m_seatInterface->focusedPointer());
// and now destroy
QVERIFY(destroyedSpy.wait());
QCOMPARE(unboundSpy.count(), 1);
QCOMPARE(destroyedSpy.count(), 1);
QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
QVERIFY(!m_seatInterface->focusedPointer());
// create a pointer again
p = m_seat->createPointer(m_seat);
QVERIFY(focusedPointerChangedSpy.wait());
QCOMPARE(focusedPointerChangedSpy.count(), 9);
QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
serverPointer = m_seatInterface->focusedPointer();
QVERIFY(serverPointer);
delete s;
wl_display_flush(m_connection->display());
QVERIFY(focusedPointerChangedSpy.wait());
QCOMPARE(focusedPointerChangedSpy.count(), 7);
QCOMPARE(focusedPointerChangedSpy.count(), 10);
QVERIFY(!m_seatInterface->focusedPointerSurface());
QVERIFY(!m_seatInterface->focusedPointer());
}
void TestWaylandSeat::testPointerTransformation_data()

View file

@ -100,7 +100,7 @@ void PointerInterface::Private::sendEnter(SurfaceInterface *surface, const QPoin
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const struct wl_pointer_interface PointerInterface::Private::s_interface = {
setCursorCallback,
releaseCallback
resourceDestroyedCallback
};
#endif
@ -205,12 +205,6 @@ void PointerInterface::Private::setCursorCallback(wl_client *client, wl_resource
p->setCursor(serial, SurfaceInterface::get(surface), QPoint(hotspot_x, hotspot_y));
}
void PointerInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
{
Q_UNUSED(client)
unbind(resource);
}
Cursor *PointerInterface::cursor() const
{
Q_D();

View file

@ -51,8 +51,6 @@ private:
// interface
static void setCursorCallback(wl_client *client, wl_resource *resource, uint32_t serial,
wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y);
// since version 3
static void releaseCallback(wl_client *client, wl_resource *resource);
static const struct wl_pointer_interface s_interface;
};