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