Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylanddataoffer.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
7
8#include <QtCore/private/qcore_unix_p.h>
9#include <QtGui/private/qguiapplication_p.h>
10#include <qpa/qplatformclipboard.h>
11
12#include <QtCore/QDebug>
13
14using namespace std::chrono;
15
16QT_BEGIN_NAMESPACE
17
18namespace QtWaylandClient {
19
21{
22 return QStringLiteral("text/plain");
23}
24
26{
27 return QStringLiteral("text/plain;charset=utf-8");
28}
29
31{
32 return QStringLiteral("text/uri-list");
33}
34
36{
37 return QStringLiteral("text/x-moz-url");
38}
39
41{
42 return QStringLiteral("application/vnd.portal.filetransfer");
43}
44
45static QByteArray convertData(const QString &originalMime, const QString &newMime, const QByteArray &data)
46{
47 if (originalMime == newMime)
48 return data;
49
50 // Convert text/x-moz-url, which is an UTF-16 string of
51 // URL and page title pairs, all separated by line breaks, to text/uri-list.
52 // see also qtbase/src/plugins/platforms/xcb/qxcbmime.cpp
53 if (originalMime == uriList() && newMime == mozUrl()) {
54 if (data.size() > 1) {
55 const quint8 byte0 = data.at(0);
56 const quint8 byte1 = data.at(1);
57
58 if ((byte0 == 0xff && byte1 == 0xfe) || (byte0 == 0xfe && byte1 == 0xff)
59 || (byte0 != 0 && byte1 == 0) || (byte0 == 0 && byte1 != 0)) {
60 QByteArray converted;
61 const QString str = QString::fromUtf16(
62 reinterpret_cast<const char16_t *>(data.constData()), data.size() / 2);
63 if (!str.isNull()) {
64 const auto urls = QStringView{str}.split(u'\n');
65 // Only the URL is interesting, skip the page title.
66 for (int i = 0; i < urls.size(); i += 2) {
67 const QUrl url(urls.at(i).trimmed().toString());
68 if (url.isValid()) {
69 converted += url.toEncoded();
70 converted += "\r\n";
71 }
72 }
73 }
74 return converted;
75 // 8 byte encoding, remove a possible 0 at the end.
76 } else {
77 QByteArray converted = data;
78 if (converted.endsWith('\0'))
79 converted.chop(1);
80 converted += "\r\n";
81 return converted;
82 }
83 }
84 }
85
86 return data;
87}
88
95
100
101
103{
104 if (m_mimeData->formats().isEmpty())
105 return QString();
106
107 return m_mimeData->formats().first();
108}
109
114
116{
117 if (version() < 3) {
118 return Qt::MoveAction | Qt::CopyAction;
119 }
120
121 return m_supportedActions;
122}
123
129
134
136{
138 // This is the compositor telling the drag target what action it should perform
139 // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action?
140}
141
150
152 : m_dataOffer(dataOffer)
153{
154}
155
159
160void QWaylandMimeData::appendFormat(const QString &mimeType)
161{
162 // "DELETE" is a potential leftover from XdndActionMode sent by e.g. Firefox, ignore it.
163 if (mimeType != QLatin1String("DELETE")) {
164 m_types << mimeType;
165 m_data.remove(mimeType); // Clear previous contents
166 }
167}
168
169bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
170{
171 return formats().contains(mimeType);
172}
173
175{
176 QStringList types;
177 types.reserve(m_types.size());
178
179 for (const QString &type : m_types) {
180 QString mime = type;
181
182 if (mime == utf8Text()) {
183 mime = plainText();
184 } else if (mime == mozUrl()) {
185 mime = uriList();
186 }
187
188 if (!types.contains(mime)) {
189 types << mime;
190 }
191 }
192
193 return types;
194}
195
196QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QMetaType type) const
197{
198 Q_UNUSED(type);
199
200 auto it = m_data.constFind(mimeType);
201 if (it != m_data.constEnd())
202 return *it;
203
204 QString mime = mimeType;
205
206 if (!m_types.contains(mimeType)) {
207 if (mimeType == plainText() && m_types.contains(utf8Text()))
208 mime = utf8Text();
209 else if (mimeType == uriList() && m_types.contains(mozUrl()))
210 mime = mozUrl();
211 else
212 return QVariant();
213 }
214
215 int pipefd[2];
216 if (qt_safe_pipe(pipefd) == -1) {
217 qWarning("QWaylandMimeData: pipe2() failed");
218 return QVariant();
219 }
220
221 m_dataOffer->startReceiving(mime, pipefd[1]);
222
223 close(pipefd[1]);
224
225 QByteArray content;
226 if (readData(pipefd[0], content) != 0) {
227 qWarning("QWaylandDataOffer: error reading data for mimeType %s", qPrintable(mimeType));
228 content = QByteArray();
229 }
230
231 close(pipefd[0]);
232
233 content = convertData(mimeType, mime, content);
234
235 if (mimeType != portalFileTransfer())
236 m_data.insert(mimeType, content);
237
238 return content;
239}
240
241int QWaylandMimeData::readData(int fd, QByteArray &data) const
242{
243 struct pollfd readset;
244 readset.fd = fd;
245 readset.events = POLLIN;
246
247 Q_FOREVER {
248 int ready = qt_safe_poll(&readset, 1, QDeadlineTimer(1s));
249 if (ready < 0) {
250 qWarning() << "QWaylandDataOffer: qt_safe_poll() failed";
251 return -1;
252 } else if (ready == 0) {
253 qWarning("QWaylandDataOffer: timeout reading from pipe");
254 return -1;
255 } else {
256 char buf[4096];
257 int n = QT_READ(fd, buf, sizeof buf);
258
259 if (n < 0) {
260 qWarning("QWaylandDataOffer: read() failed");
261 return -1;
262 } else if (n == 0) {
263 return 0;
264 } else if (n > 0) {
265 data.append(buf, n);
266 }
267 }
268 }
269}
270
271}
272
273QT_END_NAMESPACE
QVariant retrieveData_sys(const QString &mimeType, QMetaType type) const override
void appendFormat(const QString &mimeType)
QStringList formats_sys() const override
QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer)
bool hasFormat_sys(const QString &mimeType) const override
static QString portalFileTransfer()
static QByteArray convertData(const QString &originalMime, const QString &newMime, const QByteArray &data)
static QString utf8Text()
static QString mozUrl()
static QString uriList()
static QString plainText()