From 4e39ec1cd7aed754c9d6052c99438b77ab3678c8 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 12 May 2011 16:20:03 +0200 Subject: [PATCH] Fix deadlocks in wayland clipboard that can occur in special scenarios. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit setMimeData() emits the changed signal always so to prevent duplicated signals keyboardFocus() must only emit when the change came from another wayland client. However direct connection may cause issues when invoking the slot from a wayland callback, so use a metacall to make sure we return from the callback. Unnecessary data transfer and potential deadlock is now also avoided when a client is requesting the mime data from itself. Reviewed-by: Jørgen Lind --- .../platforms/wayland/qwaylandclipboard.cpp | 25 ++++++++++++++-------- src/plugins/platforms/wayland/qwaylandclipboard.h | 9 +++++++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp index 47ca228..cf9c5a7 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -96,7 +96,6 @@ public: QWaylandSelection(QWaylandDisplay *display, QMimeData *data); ~QWaylandSelection(); -private: static uint32_t getTime(); static void send(void *data, struct wl_selection *selection, const char *mime_type, int fd); static void cancelled(void *data, struct wl_selection *selection); @@ -164,7 +163,7 @@ void QWaylandSelection::cancelled(void *data, struct wl_selection *selection) } QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display) - : mDisplay(display), mSelection(0), mMimeDataIn(0), mOffer(0) + : mDisplay(display), mMimeDataIn(0), mOffer(0) { clipboard = this; } @@ -222,6 +221,8 @@ QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) { Q_ASSERT(mode == QClipboard::Clipboard); + if (!mSelections.isEmpty()) + return mSelections.last()->mMimeData; if (!mMimeDataIn) mMimeDataIn = new QWaylandMimeData; mMimeDataIn->clearAll(); @@ -236,7 +237,7 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) if (!mDisplay->inputDevices().isEmpty()) { if (!data) data = new QMimeData; - mSelection = new QWaylandSelection(mDisplay, data); + mSelections.append(new QWaylandSelection(mDisplay, data)); } else { qWarning("QWaylandClipboard::setMimeData: No input devices"); } @@ -266,21 +267,27 @@ void QWaylandClipboard::offer(void *data, struct wl_selection_offer *selection_offer, const char *type) { + Q_UNUSED(data); Q_UNUSED(selection_offer); - QWaylandClipboard *self = static_cast(data); - self->mOfferedMimeTypes.append(QString::fromLatin1(type)); + clipboard->mOfferedMimeTypes.append(QString::fromLatin1(type)); } void QWaylandClipboard::keyboardFocus(void *data, struct wl_selection_offer *selection_offer, wl_input_device *input_device) { - QWaylandClipboard *self = static_cast(data); + Q_UNUSED(data); if (!input_device) { wl_selection_offer_destroy(selection_offer); - self->mOffer = 0; + clipboard->mOffer = 0; return; } - self->mOffer = selection_offer; - self->emitChanged(QClipboard::Clipboard); + clipboard->mOffer = selection_offer; + if (clipboard->mSelections.isEmpty()) + QMetaObject::invokeMethod(&clipboard->mEmitter, "emitChanged", Qt::QueuedConnection); +} + +void QWaylandClipboardSignalEmitter::emitChanged() +{ + clipboard->emitChanged(QClipboard::Clipboard); } diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.h b/src/plugins/platforms/wayland/qwaylandclipboard.h index 6a02254..db436b8 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.h +++ b/src/plugins/platforms/wayland/qwaylandclipboard.h @@ -51,6 +51,13 @@ class QWaylandSelection; class QWaylandMimeData; struct wl_selection_offer; +class QWaylandClipboardSignalEmitter : public QObject +{ + Q_OBJECT +public slots: + void emitChanged(); +}; + class QWaylandClipboard : public QPlatformClipboard { public: @@ -80,11 +87,11 @@ private: static void forceRoundtrip(struct wl_display *display); QWaylandDisplay *mDisplay; - QWaylandSelection *mSelection; QWaylandMimeData *mMimeDataIn; QList mSelections; QStringList mOfferedMimeTypes; struct wl_selection_offer *mOffer; + QWaylandClipboardSignalEmitter mEmitter; }; #endif // QWAYLANDCLIPBOARD_H -- 2.7.4