[server] Ensure we have a DataSource on the DataDevice in setSelection
Summary: SeatInterface provides a way to set the current selection. This method did not verify whether the new DataDeviceInterface actually has a DataSourceInterface. If there is no DataSourceInterface on that DataDeviceInterface the selection should not be sent to the current selection owner. This results in a crash as DataOfferInterface (correctly) doesn't expect the passed in DataSourceInterface to be null. To ensure we don't hit this again the DataOfferInterface ctor gained an Q_ASSERT to validate the DataSourceInterface. Reviewers: #plasma_on_wayland Subscribers: plasma-devel Tags: #plasma_on_wayland Differential Revision: https://phabricator.kde.org/D3148
This commit is contained in:
parent
a037a0cb4f
commit
988a239637
3 changed files with 48 additions and 1 deletions
|
@ -79,6 +79,7 @@ private Q_SLOTS:
|
|||
void testCast();
|
||||
void testDestroy();
|
||||
void testSelection();
|
||||
void testSelectionNoDataSource();
|
||||
void testTouch();
|
||||
void testDisconnect();
|
||||
void testPointerEnterOnUnboundSurface();
|
||||
|
@ -1552,6 +1553,51 @@ void TestWaylandSeat::testSelection()
|
|||
QVERIFY(cancelledSpy.wait());
|
||||
}
|
||||
|
||||
void TestWaylandSeat::testSelectionNoDataSource()
|
||||
{
|
||||
// this test verifies that the server doesn't crash when using setSelection with
|
||||
// a DataDevice which doesn't have a DataSource yet
|
||||
using namespace KWayland::Client;
|
||||
using namespace KWayland::Server;
|
||||
// first create the DataDevice
|
||||
QScopedPointer<DataDeviceManagerInterface> ddmi(m_display->createDataDeviceManager());
|
||||
ddmi->create();
|
||||
QSignalSpy ddiCreatedSpy(ddmi.data(), &DataDeviceManagerInterface::dataDeviceCreated);
|
||||
QVERIFY(ddiCreatedSpy.isValid());
|
||||
Registry registry;
|
||||
QSignalSpy dataDeviceManagerSpy(®istry, &Registry::dataDeviceManagerAnnounced);
|
||||
QVERIFY(dataDeviceManagerSpy.isValid());
|
||||
registry.setEventQueue(m_queue);
|
||||
registry.create(m_connection->display());
|
||||
QVERIFY(registry.isValid());
|
||||
registry.setup();
|
||||
|
||||
QVERIFY(dataDeviceManagerSpy.wait());
|
||||
QScopedPointer<DataDeviceManager> ddm(registry.createDataDeviceManager(dataDeviceManagerSpy.first().first().value<quint32>(),
|
||||
dataDeviceManagerSpy.first().last().value<quint32>()));
|
||||
QVERIFY(ddm->isValid());
|
||||
|
||||
QScopedPointer<DataDevice> dd(ddm->getDataDevice(m_seat));
|
||||
QVERIFY(dd->isValid());
|
||||
QVERIFY(ddiCreatedSpy.wait());
|
||||
auto ddi = ddiCreatedSpy.first().first().value<DataDeviceInterface*>();
|
||||
QVERIFY(ddi);
|
||||
|
||||
// now create a surface and pass it keyboard focus
|
||||
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
||||
QVERIFY(surfaceCreatedSpy.isValid());
|
||||
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
||||
QVERIFY(surface->isValid());
|
||||
QVERIFY(surfaceCreatedSpy.wait());
|
||||
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
||||
QVERIFY(!m_seatInterface->selection());
|
||||
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
|
||||
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
|
||||
|
||||
// now let's set the selection
|
||||
m_seatInterface->setSelection(ddi);
|
||||
}
|
||||
|
||||
void TestWaylandSeat::testTouch()
|
||||
{
|
||||
using namespace KWayland::Client;
|
||||
|
|
|
@ -93,6 +93,7 @@ void DataOfferInterface::Private::receive(const QString &mimeType, qint32 fd)
|
|||
DataOfferInterface::DataOfferInterface(DataSourceInterface *source, DataDeviceInterface *parentInterface, wl_resource *parentResource)
|
||||
: Resource(new Private(source, parentInterface, this, parentResource))
|
||||
{
|
||||
Q_ASSERT(source);
|
||||
connect(source, &DataSourceInterface::mimeTypeOffered, this,
|
||||
[this](const QString &mimeType) {
|
||||
Q_D();
|
||||
|
|
|
@ -1344,7 +1344,7 @@ void SeatInterface::setSelection(DataDeviceInterface *dataDevice)
|
|||
d->cancelPreviousSelection(dataDevice);
|
||||
d->currentSelection = dataDevice;
|
||||
if (d->keys.focus.selection) {
|
||||
if (dataDevice) {
|
||||
if (dataDevice && dataDevice->selection()) {
|
||||
d->keys.focus.selection->sendSelection(dataDevice);
|
||||
} else {
|
||||
d->keys.focus.selection->sendClearSelection();
|
||||
|
|
Loading…
Reference in a new issue