1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the plugins of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qwaylandclipboard.h"
43 #include "qwaylanddisplay.h"
44 #include "qwaylandinputdevice.h"
45 #include <QtGui/QPlatformNativeInterface>
46 #include <QtGui/QGuiApplication>
47 #include <QtCore/QMimeData>
48 #include <QtCore/QStringList>
49 #include <QtCore/QFile>
50 #include <QtCore/QtDebug>
51 #include <QtWidgets/private/qdnd_p.h>
53 static QWaylandClipboard *clipboard;
55 class QWaylandMimeData : public QInternalMimeData
59 void setFormats(const QStringList &formatList);
60 bool hasFormat_sys(const QString &mimeType) const;
61 QStringList formats_sys() const;
62 QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const;
64 QStringList mFormatList;
67 void QWaylandMimeData::clearAll()
73 void QWaylandMimeData::setFormats(const QStringList &formatList)
75 mFormatList = formatList;
78 bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
80 return formats().contains(mimeType);
83 QStringList QWaylandMimeData::formats_sys() const
88 QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
90 return clipboard->retrieveData(mimeType, type);
93 class QWaylandSelection
96 QWaylandSelection(QWaylandDisplay *display, QMimeData *data);
100 static uint32_t getTime();
101 static void send(void *data, struct wl_selection *selection, const char *mime_type, int fd);
102 static void cancelled(void *data, struct wl_selection *selection);
103 static const struct wl_selection_listener selectionListener;
105 QMimeData *mMimeData;
106 struct wl_selection *mSelection;
109 const struct wl_selection_listener QWaylandSelection::selectionListener = {
110 QWaylandSelection::send,
111 QWaylandSelection::cancelled
114 uint32_t QWaylandSelection::getTime()
117 gettimeofday(&tv, 0);
118 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
121 QWaylandSelection::QWaylandSelection(QWaylandDisplay *display, QMimeData *data)
122 : mMimeData(data), mSelection(0)
124 struct wl_shell *shell = display->wl_shell();
125 mSelection = wl_shell_create_selection(shell);
126 wl_selection_add_listener(mSelection, &selectionListener, this);
127 foreach (const QString &format, data->formats())
128 wl_selection_offer(mSelection, format.toLatin1().constData());
129 wl_selection_activate(mSelection,
130 display->inputDevices().at(0)->wl_input_device(),
134 QWaylandSelection::~QWaylandSelection()
137 clipboard->unregisterSelection(this);
138 wl_selection_destroy(mSelection);
143 void QWaylandSelection::send(void *data,
144 struct wl_selection *selection,
145 const char *mime_type,
149 QWaylandSelection *self = static_cast<QWaylandSelection *>(data);
150 QString mimeType = QString::fromLatin1(mime_type);
151 QByteArray content = self->mMimeData->data(mimeType);
152 if (!content.isEmpty()) {
154 if (f.open(fd, QIODevice::WriteOnly))
160 void QWaylandSelection::cancelled(void *data, struct wl_selection *selection)
163 delete static_cast<QWaylandSelection *>(data);
166 QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
167 : mDisplay(display), mSelection(0), mMimeDataIn(0), mOffer(0)
172 QWaylandClipboard::~QWaylandClipboard()
175 wl_selection_offer_destroy(mOffer);
177 qDeleteAll(mSelections);
180 void QWaylandClipboard::unregisterSelection(QWaylandSelection *selection)
182 mSelections.removeOne(selection);
185 void QWaylandClipboard::syncCallback(void *data)
187 *static_cast<bool *>(data) = true;
190 void QWaylandClipboard::forceRoundtrip(struct wl_display *display)
193 wl_display_sync_callback(display, syncCallback, &done);
194 wl_display_iterate(display, WL_DISPLAY_WRITABLE);
196 wl_display_iterate(display, WL_DISPLAY_READABLE);
199 QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type type) const
202 if (mOfferedMimeTypes.isEmpty() || !mOffer)
205 if (pipe(pipefd) == -1) {
206 qWarning("QWaylandClipboard: pipe() failed");
209 QByteArray mimeTypeBa = mimeType.toLatin1();
210 wl_selection_offer_receive(mOffer, mimeTypeBa.constData(), pipefd[1]);
212 forceRoundtrip(mDisplay->wl_display());
216 while ((n = read(pipefd[0], &buf, sizeof buf)) > 0)
217 content.append(buf, n);
222 QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
224 Q_ASSERT(mode == QClipboard::Clipboard);
226 mMimeDataIn = new QWaylandMimeData;
227 mMimeDataIn->clearAll();
228 if (!mOfferedMimeTypes.isEmpty() && mOffer)
229 mMimeDataIn->setFormats(mOfferedMimeTypes);
233 void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
235 Q_ASSERT(mode == QClipboard::Clipboard);
236 if (!mDisplay->inputDevices().isEmpty()) {
238 data = new QMimeData;
239 mSelection = new QWaylandSelection(mDisplay, data);
241 qWarning("QWaylandClipboard::setMimeData: No input devices");
245 bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const
247 return mode == QClipboard::Clipboard;
250 const struct wl_selection_offer_listener QWaylandClipboard::selectionOfferListener = {
251 QWaylandClipboard::offer,
252 QWaylandClipboard::keyboardFocus
255 void QWaylandClipboard::createSelectionOffer(uint32_t id)
257 mOfferedMimeTypes.clear();
259 wl_selection_offer_destroy(mOffer);
261 struct wl_selection_offer *offer = wl_selection_offer_create(mDisplay->wl_display(), id, 1);
262 wl_selection_offer_add_listener(offer, &selectionOfferListener, this);
265 void QWaylandClipboard::offer(void *data,
266 struct wl_selection_offer *selection_offer,
269 Q_UNUSED(selection_offer);
270 QWaylandClipboard *self = static_cast<QWaylandClipboard *>(data);
271 self->mOfferedMimeTypes.append(QString::fromLatin1(type));
274 void QWaylandClipboard::keyboardFocus(void *data,
275 struct wl_selection_offer *selection_offer,
276 wl_input_device *input_device)
278 QWaylandClipboard *self = static_cast<QWaylandClipboard *>(data);
280 wl_selection_offer_destroy(selection_offer);
284 self->mOffer = selection_offer;
285 self->emitChanged(QClipboard::Clipboard);