47ca22865b12e80849b458799c81cbc8ab25e723
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylandclipboard.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
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
14 ** this package.
15 **
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.
23 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwaylandclipboard.h"
43 #include "qwaylanddisplay.h"
44 #include "qwaylandinputdevice.h"
45 #include <QtGui/QPlatformNativeInterface>
46 #include <QtGui/QApplication>
47 #include <QtCore/QMimeData>
48 #include <QtCore/QStringList>
49 #include <QtCore/QFile>
50 #include <QtCore/QtDebug>
51 #include <QtGui/private/qdnd_p.h>
52
53 static QWaylandClipboard *clipboard;
54
55 class QWaylandMimeData : public QInternalMimeData
56 {
57 public:
58     void clearAll();
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;
63 private:
64     QStringList mFormatList;
65 };
66
67 void QWaylandMimeData::clearAll()
68 {
69     clear();
70     mFormatList.clear();
71 }
72
73 void QWaylandMimeData::setFormats(const QStringList &formatList)
74 {
75     mFormatList = formatList;
76 }
77
78 bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
79 {
80     return formats().contains(mimeType);
81 }
82
83 QStringList QWaylandMimeData::formats_sys() const
84 {
85     return mFormatList;
86 }
87
88 QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
89 {
90     return clipboard->retrieveData(mimeType, type);
91 }
92
93 class QWaylandSelection
94 {
95 public:
96     QWaylandSelection(QWaylandDisplay *display, QMimeData *data);
97     ~QWaylandSelection();
98
99 private:
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;
104
105     QMimeData *mMimeData;
106     struct wl_selection *mSelection;
107 };
108
109 const struct wl_selection_listener QWaylandSelection::selectionListener = {
110     QWaylandSelection::send,
111     QWaylandSelection::cancelled
112 };
113
114 uint32_t QWaylandSelection::getTime()
115 {
116     struct timeval tv;
117     gettimeofday(&tv, 0);
118     return tv.tv_sec * 1000 + tv.tv_usec / 1000;
119 }
120
121 QWaylandSelection::QWaylandSelection(QWaylandDisplay *display, QMimeData *data)
122     : mMimeData(data), mSelection(0)
123 {
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(),
131                           getTime());
132 }
133
134 QWaylandSelection::~QWaylandSelection()
135 {
136     if (mSelection) {
137         clipboard->unregisterSelection(this);
138         wl_selection_destroy(mSelection);
139     }
140     delete mMimeData;
141 }
142
143 void QWaylandSelection::send(void *data,
144                              struct wl_selection *selection,
145                              const char *mime_type,
146                              int fd)
147 {
148     Q_UNUSED(selection);
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()) {
153         QFile f;
154         if (f.open(fd, QIODevice::WriteOnly))
155             f.write(content);
156     }
157     close(fd);
158 }
159
160 void QWaylandSelection::cancelled(void *data, struct wl_selection *selection)
161 {
162     Q_UNUSED(selection);
163     delete static_cast<QWaylandSelection *>(data);
164 }
165
166 QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
167     : mDisplay(display), mSelection(0), mMimeDataIn(0), mOffer(0)
168 {
169     clipboard = this;
170 }
171
172 QWaylandClipboard::~QWaylandClipboard()
173 {
174     if (mOffer)
175         wl_selection_offer_destroy(mOffer);
176     delete mMimeDataIn;
177     qDeleteAll(mSelections);
178 }
179
180 void QWaylandClipboard::unregisterSelection(QWaylandSelection *selection)
181 {
182     mSelections.removeOne(selection);
183 }
184
185 void QWaylandClipboard::syncCallback(void *data)
186 {
187     *static_cast<bool *>(data) = true;
188 }
189
190 void QWaylandClipboard::forceRoundtrip(struct wl_display *display)
191 {
192     bool done = false;
193     wl_display_sync_callback(display, syncCallback, &done);
194     wl_display_iterate(display, WL_DISPLAY_WRITABLE);
195     while (!done)
196         wl_display_iterate(display, WL_DISPLAY_READABLE);
197 }
198
199 QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type type) const
200 {
201     Q_UNUSED(type);
202     if (mOfferedMimeTypes.isEmpty() || !mOffer)
203         return QVariant();
204     int pipefd[2];
205     if (pipe(pipefd) == -1) {
206         qWarning("QWaylandClipboard: pipe() failed");
207         return QVariant();
208     }
209     QByteArray mimeTypeBa = mimeType.toLatin1();
210     wl_selection_offer_receive(mOffer, mimeTypeBa.constData(), pipefd[1]);
211     QByteArray content;
212     forceRoundtrip(mDisplay->wl_display());
213     char buf[256];
214     int n;
215     close(pipefd[1]);
216     while ((n = read(pipefd[0], &buf, sizeof buf)) > 0)
217         content.append(buf, n);
218     close(pipefd[0]);
219     return content;
220 }
221
222 QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
223 {
224     Q_ASSERT(mode == QClipboard::Clipboard);
225     if (!mMimeDataIn)
226         mMimeDataIn = new QWaylandMimeData;
227     mMimeDataIn->clearAll();
228     if (!mOfferedMimeTypes.isEmpty() && mOffer)
229         mMimeDataIn->setFormats(mOfferedMimeTypes);
230     return mMimeDataIn;
231 }
232
233 void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
234 {
235     Q_ASSERT(mode == QClipboard::Clipboard);
236     if (!mDisplay->inputDevices().isEmpty()) {
237         if (!data)
238             data = new QMimeData;
239         mSelection = new QWaylandSelection(mDisplay, data);
240     } else {
241         qWarning("QWaylandClipboard::setMimeData: No input devices");
242     }
243 }
244
245 bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const
246 {
247     return mode == QClipboard::Clipboard;
248 }
249
250 const struct wl_selection_offer_listener QWaylandClipboard::selectionOfferListener = {
251     QWaylandClipboard::offer,
252     QWaylandClipboard::keyboardFocus
253 };
254
255 void QWaylandClipboard::createSelectionOffer(uint32_t id)
256 {
257     mOfferedMimeTypes.clear();
258     if (mOffer)
259         wl_selection_offer_destroy(mOffer);
260     mOffer = 0;
261     struct wl_selection_offer *offer = wl_selection_offer_create(mDisplay->wl_display(), id, 1);
262     wl_selection_offer_add_listener(offer, &selectionOfferListener, this);
263 }
264
265 void QWaylandClipboard::offer(void *data,
266                               struct wl_selection_offer *selection_offer,
267                               const char *type)
268 {
269     Q_UNUSED(selection_offer);
270     QWaylandClipboard *self = static_cast<QWaylandClipboard *>(data);
271     self->mOfferedMimeTypes.append(QString::fromLatin1(type));
272 }
273
274 void QWaylandClipboard::keyboardFocus(void *data,
275                                       struct wl_selection_offer *selection_offer,
276                                       wl_input_device *input_device)
277 {
278     QWaylandClipboard *self = static_cast<QWaylandClipboard *>(data);
279     if (!input_device) {
280         wl_selection_offer_destroy(selection_offer);
281         self->mOffer = 0;
282         return;
283     }
284     self->mOffer = selection_offer;
285     self->emitChanged(QClipboard::Clipboard);
286 }