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
qqnxclipboard.cpp
Go to the documentation of this file.
1// Copyright (C) 2011 - 2012 Research In Motion
2// Copyright (c) 2020 BlackBerry Limited
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
7
8#if !defined(QT_NO_CLIPBOARD)
9
10#include "qqnxclipboard.h"
11
12#include <QtGui/QColor>
13#include <QtGui/QImage>
14
15#include <QtCore/QBuffer>
16#include <QtCore/QDebug>
17#include <QtCore/QDirIterator>
18#include <QtCore/QMimeData>
19#include <QtCore/QSaveFile>
20#include <QtCore/QSet>
21#include <QtCore/QStringList>
22#include <QtCore/QUrl>
23
24
25#include <errno.h>
26
28
29Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard");
30
31using namespace Qt::StringLiterals;
32
34{
36public:
38 : QMimeData(),
40 m_userMimeData(nullptr),
41 m_formatsToCheck({u"text/html"_s,
42 u"text/plain"_s,
43 u"image/png"_s,
44 u"image/jpeg"_s,
45 u"application/x-color"_s})
46 {
48 }
49
51 {
52 }
53
58
60 {
61 const bool result = m_clipboard->hasFormat(mimetype);
62 qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "result=" << result;
63 return result;
64 }
65
67 {
69
70 for (const QString &format : m_formatsToCheck) {
72 result << format;
73 }
74
75 qCDebug(lcQpaClipboard) << "result=" << result;
76 return result;
77 }
78
80 {
82
83 // system clipboard API doesn't allow detection of changes by other applications
84 // simulate an owner change through delayed invocation
85 // basically transfer ownership of data to the system clipboard once event processing resumes
87 QMetaObject::invokeMethod(this, "releaseOwnership", Qt::QueuedConnection);
88 }
89
91 {
92 return m_userMimeData.get();
93 }
94
95protected:
97 {
98 qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "preferredType=" << preferredType;
101
103 if (mimetype == "application/x-qt-image") {
108 if (image.load(&buffer, "PNG")) {
109 return QVariant::fromValue(image);
110 }
111 }
112 return QVariant::fromValue(data);
113 }
114
115private Q_SLOTS:
116 void releaseOwnership()
117 {
118 if (m_userMimeData) {
119 qCDebug(lcQpaClipboard) << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats();
122 }
123 }
124
125private:
127
128 QSet<QString> m_formatsToCheck;
129 std::unique_ptr<QMimeData> m_userMimeData;
130};
131
133 : m_mimeData(new MimeData(this)), m_serverAvailable(false)
134{
135 // The clipboard is only implemented if the desktop option is specified
136 // and if the QQNX_CLIPBOARD environment variable points to a directory
137 // that contains a .qnxclipboard node.
138 if (qEnvironmentVariableIsSet("QQNX_CLIPBOARD")) {
139 m_clipboardDir = QDir(qEnvironmentVariable("QQNX_CLIPBOARD"));
140 if (m_clipboardDir.exists(".qnxclipboard"))
141 m_serverAvailable = true;
142 }
143}
144
146{
147 delete m_mimeData;
148}
149
150void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
151{
152 if (mode != QClipboard::Clipboard)
153 return;
154
155 if (m_mimeData == data)
156 return;
157
158 if (m_mimeData->userMimeData() && m_mimeData->userMimeData() == data)
159 return;
160
161 clear();
162
163 m_mimeData->clear();
164 m_mimeData->setUserMimeData(data);
165
166 if (!data) {
167 emitChanged(QClipboard::Clipboard);
168 return;
169 }
170
171 const QStringList formats = data->formats();
172 qCDebug(lcQpaClipboard) << "formats=" << formats;
173
174 for (const QString &format : formats) {
175 QByteArray buf;
176
177 // Handling for image data
178 if (format == "application/x-qt-image") {
179 QBuffer buffer(&buf);
180 buffer.open(QIODevice::WriteOnly);
181 QImage image = qvariant_cast<QImage>(data->imageData());
182 image.save(&buffer, "PNG");
183 } else {
184 buf = data->data(format);
185 }
186
187 if (buf.isEmpty())
188 continue;
189
190 bool ret = write(format, buf);
191 qCDebug(lcQpaClipboard) << "set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret;
192 if (ret)
193 m_mimeData->addFormatToCheck(format);
194 }
195
196 emitChanged(QClipboard::Clipboard);
197}
198
199QMimeData *QQnxClipboard::mimeData(QClipboard::Mode mode)
200{
201 if (mode != QClipboard::Clipboard)
202 return 0;
203
204 if (m_mimeData->userMimeData())
205 return m_mimeData->userMimeData();
206
207 m_mimeData->clear();
208
209 return m_mimeData;
210}
211
212QFile QQnxClipboard::fileforFormat(const QString &format) const
213{
214 // If using a standard file system directory, format names of the standard
215 // "foo/bar" style cannot be handled properly.
216 QString fileName = format;
217 fileName.replace('/', '@');
218 return QFile(m_clipboardDir.filePath(fileName));
219}
220
221bool QQnxClipboard::hasFormat(const QString &format) const
222{
223 if (!m_serverAvailable)
224 return false;
225
226 QFile file = fileforFormat(format);
227 return file.exists() && file.size() > 0;
228}
229
230QByteArray QQnxClipboard::read(const QString &format) const
231{
232 if (!m_serverAvailable)
233 return QByteArray();
234
235 QFile file = fileforFormat(format);
236 if (!file.open(QIODevice::ReadOnly))
237 return QByteArray();
238
239 return file.readAll();
240}
241
242bool QQnxClipboard::write(const QString &format, const QByteArray &data) const
243{
244 if (!m_serverAvailable)
245 return false;
246
247 QFile file = fileforFormat(format);
248 if (!file.open(QIODevice::WriteOnly))
249 return false;
250
251 return file.write(data) == data.size();
252}
253
254void QQnxClipboard::clear()
255{
256 if (!m_serverAvailable)
257 return;
258
259 // Warning!
260 // Deletes all files in the given directory. Make sure QQNX_CLIPBOARD is set
261 // to the mount point of a clipboard service or to a dedicated directory.
262 // This is double-checked in the constructor, which will not start the
263 // clipboard unless it points to a directory that contains a ".qnxclipboard"
264 // node.
265 m_clipboardDir.refresh();
266 QDirIterator itr(m_clipboardDir);
267 while (itr.hasNext()) {
268 itr.next();
269 QString format = itr.fileName();
270 if (format == ".qnxclipboard"_L1)
271 continue;
272 if (m_clipboardDir.exists(format)) {
273 qCDebug(lcQpaClipboard) << "deleting" << format;
274 bool removed = m_clipboardDir.remove(format);
275 if (!removed)
276 qCDebug(lcQpaClipboard) << "Failed to remove" << format;
277 }
278 }
279}
280
281QT_END_NAMESPACE
282
283#include "qqnxclipboard.moc"
284
285#endif //QT_NO_CLIPBOARD
QMimeData * mimeData(QClipboard::Mode mode=QClipboard::Clipboard) override
void setMimeData(QMimeData *data, QClipboard::Mode mode=QClipboard::Clipboard) override
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")