/src/qtbase/src/gui/kernel/qclipboard.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
4 | | #include "qclipboard.h" |
5 | | |
6 | | #ifndef QT_NO_CLIPBOARD |
7 | | |
8 | | #include "qmimedata.h" |
9 | | #include "qpixmap.h" |
10 | | #include "qvariant.h" |
11 | | #include "qbuffer.h" |
12 | | #include "qimage.h" |
13 | | #include "private/qstringconverter_p.h" |
14 | | |
15 | | #include "private/qguiapplication_p.h" |
16 | | #include <qpa/qplatformintegration.h> |
17 | | #include <qpa/qplatformclipboard.h> |
18 | | |
19 | | QT_BEGIN_NAMESPACE |
20 | | |
21 | | using namespace Qt::StringLiterals; |
22 | | |
23 | | /*! |
24 | | \class QClipboard |
25 | | \brief The QClipboard class provides access to the window system clipboard. |
26 | | \inmodule QtGui |
27 | | |
28 | | The clipboard offers a simple mechanism to copy and paste data |
29 | | between applications. |
30 | | |
31 | | QClipboard supports the same data types that QDrag does, and uses |
32 | | similar mechanisms. For advanced clipboard usage read \l{Drag and |
33 | | Drop}. |
34 | | |
35 | | There is a single QClipboard object in an application, accessible |
36 | | as QGuiApplication::clipboard(). |
37 | | |
38 | | Example: |
39 | | \snippet code/src_gui_kernel_qclipboard.cpp 0 |
40 | | |
41 | | QClipboard features some convenience functions to access common |
42 | | data types: setText() allows the exchange of Unicode text and |
43 | | setPixmap() and setImage() allows the exchange of QPixmaps and |
44 | | QImages between applications. The setMimeData() function is the |
45 | | ultimate in flexibility: it allows you to add any QMimeData into |
46 | | the clipboard. There are corresponding getters for each of these, |
47 | | e.g. text(), image() and pixmap(). You can clear the clipboard by |
48 | | calling clear(). |
49 | | |
50 | | A typical example of the use of these functions follows: |
51 | | |
52 | | \snippet droparea/droparea.cpp 0 |
53 | | |
54 | | \section1 Notes for X11 Users |
55 | | |
56 | | \list |
57 | | |
58 | | \li The X11 Window System has the concept of a separate selection |
59 | | and clipboard. When text is selected, it is immediately available |
60 | | as the global mouse selection. The global mouse selection may |
61 | | later be copied to the clipboard. By convention, the middle mouse |
62 | | button is used to paste the global mouse selection. |
63 | | |
64 | | \li X11 also has the concept of ownership; if you change the |
65 | | selection within a window, X11 will only notify the owner and the |
66 | | previous owner of the change, i.e. it will not notify all |
67 | | applications that the selection or clipboard data changed. |
68 | | |
69 | | \li Lastly, the X11 clipboard is event driven, i.e. the clipboard |
70 | | will not function properly if the event loop is not running. |
71 | | Similarly, it is recommended that the contents of the clipboard |
72 | | are stored or retrieved in direct response to user-input events, |
73 | | e.g. mouse button or key presses and releases. You should not |
74 | | store or retrieve the clipboard contents in response to timer or |
75 | | non-user-input events. |
76 | | |
77 | | \li Since there is no standard way to copy and paste files between |
78 | | applications on X11, various MIME types and conventions are currently |
79 | | in use. For instance, Nautilus expects files to be supplied with a |
80 | | \c{x-special/gnome-copied-files} MIME type with data beginning with |
81 | | the cut/copy action, a newline character, and the URL of the file. |
82 | | |
83 | | \endlist |
84 | | |
85 | | \section1 Notes for \macos Users |
86 | | |
87 | | \macos supports a separate find buffer that holds the current |
88 | | search string in Find operations. This find clipboard can be accessed |
89 | | by specifying the FindBuffer mode. |
90 | | |
91 | | \section1 Notes for Windows and \macos Users |
92 | | |
93 | | \list |
94 | | |
95 | | \li Windows and \macos do not support the global mouse |
96 | | selection; they only supports the global clipboard, i.e. they |
97 | | only add text to the clipboard when an explicit copy or cut is |
98 | | made. |
99 | | |
100 | | \li Windows and \macos does not have the concept of ownership; |
101 | | the clipboard is a fully global resource so all applications are |
102 | | notified of changes. |
103 | | |
104 | | \endlist |
105 | | |
106 | | \section1 Notes for Android Users |
107 | | |
108 | | On Android only these mime types are supported: text/plain, text/html, and text/uri-list. |
109 | | |
110 | | \sa QGuiApplication |
111 | | */ |
112 | | |
113 | | /*! |
114 | | \internal |
115 | | |
116 | | Constructs a clipboard object. |
117 | | |
118 | | Do not call this function. |
119 | | |
120 | | Call QGuiApplication::clipboard() instead to get a pointer to the |
121 | | application's global clipboard object. |
122 | | |
123 | | There is only one clipboard in the window system, and creating |
124 | | more than one object to represent it is almost certainly an error. |
125 | | */ |
126 | | |
127 | | QClipboard::QClipboard(QObject *parent) |
128 | 0 | : QObject(parent) |
129 | 0 | { |
130 | | // nothing |
131 | 0 | } |
132 | | |
133 | | /*! |
134 | | \internal |
135 | | |
136 | | Destroys the clipboard. |
137 | | |
138 | | You should never delete the clipboard. QGuiApplication will do this |
139 | | when the application terminates. |
140 | | */ |
141 | | QClipboard::~QClipboard() |
142 | 0 | { |
143 | 0 | } |
144 | | |
145 | | /*! |
146 | | \fn void QClipboard::changed(QClipboard::Mode mode) |
147 | | \since 4.2 |
148 | | |
149 | | This signal is emitted when the data for the given clipboard \a |
150 | | mode is changed. |
151 | | |
152 | | \sa dataChanged(), selectionChanged(), findBufferChanged() |
153 | | */ |
154 | | |
155 | | /*! |
156 | | \fn void QClipboard::dataChanged() |
157 | | |
158 | | This signal is emitted when the clipboard data is changed. |
159 | | |
160 | | On \macos and with Qt version 4.3 or higher, clipboard |
161 | | changes made by other applications will only be detected |
162 | | when the application is activated. |
163 | | |
164 | | \sa findBufferChanged(), selectionChanged(), changed() |
165 | | */ |
166 | | |
167 | | /*! |
168 | | \fn void QClipboard::selectionChanged() |
169 | | |
170 | | This signal is emitted when the selection is changed. This only |
171 | | applies to windowing systems that support selections, e.g. X11. |
172 | | Windows and \macos don't support selections. |
173 | | |
174 | | \sa dataChanged(), findBufferChanged(), changed() |
175 | | */ |
176 | | |
177 | | /*! |
178 | | \fn void QClipboard::findBufferChanged() |
179 | | \since 4.2 |
180 | | |
181 | | This signal is emitted when the find buffer is changed. This only |
182 | | applies to \macos. |
183 | | |
184 | | With Qt version 4.3 or higher, clipboard changes made by other |
185 | | applications will only be detected when the application is activated. |
186 | | |
187 | | \sa dataChanged(), selectionChanged(), changed() |
188 | | */ |
189 | | |
190 | | |
191 | | /*! \enum QClipboard::Mode |
192 | | \keyword clipboard mode |
193 | | |
194 | | This enum type is used to control which part of the system clipboard is |
195 | | used by QClipboard::mimeData(), QClipboard::setMimeData() and related functions. |
196 | | |
197 | | \value Clipboard indicates that data should be stored and retrieved from |
198 | | the global clipboard. |
199 | | |
200 | | \value Selection indicates that data should be stored and retrieved from |
201 | | the global mouse selection. Support for \c Selection is provided only on |
202 | | systems with a global mouse selection (e.g. X11). |
203 | | |
204 | | \value FindBuffer indicates that data should be stored and retrieved from |
205 | | the Find buffer. This mode is used for holding search strings on \macos. |
206 | | |
207 | | \omitvalue LastMode |
208 | | |
209 | | \sa QClipboard::supportsSelection() |
210 | | */ |
211 | | |
212 | | |
213 | | /*! |
214 | | \overload |
215 | | |
216 | | Returns the clipboard text in subtype \a subtype, or an empty string |
217 | | if the clipboard does not contain any text. If \a subtype is null, |
218 | | any subtype is acceptable, and \a subtype is set to the chosen |
219 | | subtype. |
220 | | |
221 | | The \a mode argument is used to control which part of the system |
222 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
223 | | text is retrieved from the global clipboard. If \a mode is |
224 | | QClipboard::Selection, the text is retrieved from the global |
225 | | mouse selection. |
226 | | |
227 | | Common values for \a subtype are "plain" and "html". |
228 | | |
229 | | Note that calling this function repeatedly, for instance from a |
230 | | key event handler, may be slow. In such cases, you should use the |
231 | | \c dataChanged() signal instead. |
232 | | |
233 | | \sa setText(), mimeData() |
234 | | */ |
235 | | QString QClipboard::text(QString &subtype, Mode mode) const |
236 | 0 | { |
237 | 0 | const QMimeData *const data = mimeData(mode); |
238 | 0 | if (!data) |
239 | 0 | return QString(); |
240 | | |
241 | 0 | const QStringList formats = data->formats(); |
242 | 0 | if (subtype.isEmpty()) { |
243 | 0 | if (formats.contains("text/plain"_L1)) |
244 | 0 | subtype = "plain"_L1; |
245 | 0 | else { |
246 | 0 | for (const auto &format : formats) { |
247 | 0 | if (format.startsWith("text/"_L1)) { |
248 | 0 | subtype = format.sliced(5); |
249 | 0 | break; |
250 | 0 | } |
251 | 0 | } |
252 | 0 | if (subtype.isEmpty()) |
253 | 0 | return QString(); |
254 | 0 | } |
255 | 0 | } else if (!formats.contains("text/"_L1 + subtype)) { |
256 | 0 | return QString(); |
257 | 0 | } |
258 | | |
259 | 0 | const QByteArray rawData = data->data("text/"_L1 + subtype); |
260 | 0 | auto encoding = QStringConverter::encodingForData(rawData); |
261 | 0 | if (!encoding) |
262 | 0 | encoding = QStringConverter::Utf8; |
263 | 0 | return QStringDecoder(*encoding).decode(rawData); |
264 | 0 | } |
265 | | |
266 | | /*! |
267 | | Returns the clipboard text as plain text, or an empty string if the |
268 | | clipboard does not contain any text. |
269 | | |
270 | | The \a mode argument is used to control which part of the system |
271 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
272 | | text is retrieved from the global clipboard. If \a mode is |
273 | | QClipboard::Selection, the text is retrieved from the global |
274 | | mouse selection. If \a mode is QClipboard::FindBuffer, the |
275 | | text is retrieved from the search string buffer. |
276 | | |
277 | | \sa setText(), mimeData() |
278 | | */ |
279 | | QString QClipboard::text(Mode mode) const |
280 | 0 | { |
281 | 0 | const QMimeData *data = mimeData(mode); |
282 | 0 | return data ? data->text() : QString(); |
283 | 0 | } |
284 | | |
285 | | /*! |
286 | | Copies \a text into the clipboard as plain text. |
287 | | |
288 | | The \a mode argument is used to control which part of the system |
289 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
290 | | text is stored in the global clipboard. If \a mode is |
291 | | QClipboard::Selection, the text is stored in the global |
292 | | mouse selection. If \a mode is QClipboard::FindBuffer, the |
293 | | text is stored in the search string buffer. |
294 | | |
295 | | \sa text(), setMimeData() |
296 | | */ |
297 | | void QClipboard::setText(const QString &text, Mode mode) |
298 | 0 | { |
299 | 0 | QMimeData *data = new QMimeData; |
300 | 0 | data->setText(text); |
301 | 0 | setMimeData(data, mode); |
302 | 0 | } |
303 | | |
304 | | /*! |
305 | | Returns the clipboard image, or returns a null image if the |
306 | | clipboard does not contain an image or if it contains an image in |
307 | | an unsupported image format. |
308 | | |
309 | | The \a mode argument is used to control which part of the system |
310 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
311 | | image is retrieved from the global clipboard. If \a mode is |
312 | | QClipboard::Selection, the image is retrieved from the global |
313 | | mouse selection. |
314 | | |
315 | | \sa setImage(), pixmap(), mimeData(), QImage::isNull() |
316 | | */ |
317 | | QImage QClipboard::image(Mode mode) const |
318 | 0 | { |
319 | 0 | const QMimeData *data = mimeData(mode); |
320 | 0 | if (!data) |
321 | 0 | return QImage(); |
322 | 0 | return qvariant_cast<QImage>(data->imageData()); |
323 | 0 | } |
324 | | |
325 | | /*! |
326 | | Copies the \a image into the clipboard. |
327 | | |
328 | | The \a mode argument is used to control which part of the system |
329 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
330 | | image is stored in the global clipboard. If \a mode is |
331 | | QClipboard::Selection, the data is stored in the global |
332 | | mouse selection. |
333 | | |
334 | | This is shorthand for: |
335 | | |
336 | | \snippet code/src_gui_kernel_qclipboard.cpp 1 |
337 | | |
338 | | \sa image(), setPixmap(), setMimeData() |
339 | | */ |
340 | | void QClipboard::setImage(const QImage &image, Mode mode) |
341 | 0 | { |
342 | 0 | QMimeData *data = new QMimeData; |
343 | 0 | data->setImageData(image); |
344 | 0 | setMimeData(data, mode); |
345 | 0 | } |
346 | | |
347 | | /*! |
348 | | Returns the clipboard pixmap, or null if the clipboard does not |
349 | | contain a pixmap. Note that this can lose information. For |
350 | | example, if the image is 24-bit and the display is 8-bit, the |
351 | | result is converted to 8 bits, and if the image has an alpha |
352 | | channel, the result just has a mask. |
353 | | |
354 | | The \a mode argument is used to control which part of the system |
355 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
356 | | pixmap is retrieved from the global clipboard. If \a mode is |
357 | | QClipboard::Selection, the pixmap is retrieved from the global |
358 | | mouse selection. |
359 | | |
360 | | \sa setPixmap(), image(), mimeData(), QPixmap::convertFromImage() |
361 | | */ |
362 | | QPixmap QClipboard::pixmap(Mode mode) const |
363 | 0 | { |
364 | 0 | const QMimeData *data = mimeData(mode); |
365 | 0 | return data ? qvariant_cast<QPixmap>(data->imageData()) : QPixmap(); |
366 | 0 | } |
367 | | |
368 | | /*! |
369 | | Copies \a pixmap into the clipboard. Note that this is slower |
370 | | than setImage() because it needs to convert the QPixmap to a |
371 | | QImage first. |
372 | | |
373 | | The \a mode argument is used to control which part of the system |
374 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
375 | | pixmap is stored in the global clipboard. If \a mode is |
376 | | QClipboard::Selection, the pixmap is stored in the global |
377 | | mouse selection. |
378 | | |
379 | | \sa pixmap(), setImage(), setMimeData() |
380 | | */ |
381 | | void QClipboard::setPixmap(const QPixmap &pixmap, Mode mode) |
382 | 0 | { |
383 | 0 | QMimeData *data = new QMimeData; |
384 | 0 | data->setImageData(pixmap); |
385 | 0 | setMimeData(data, mode); |
386 | 0 | } |
387 | | |
388 | | |
389 | | /*! |
390 | | \fn QMimeData *QClipboard::mimeData(Mode mode) const |
391 | | |
392 | | Returns a pointer to a QMimeData representation of the current |
393 | | clipboard data (can be \nullptr if the given \a mode is not |
394 | | supported by the platform). |
395 | | |
396 | | The \a mode argument is used to control which part of the system |
397 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
398 | | data is retrieved from the global clipboard. If \a mode is |
399 | | QClipboard::Selection, the data is retrieved from the global |
400 | | mouse selection. If \a mode is QClipboard::FindBuffer, the |
401 | | data is retrieved from the search string buffer. |
402 | | |
403 | | The text(), image(), and pixmap() functions are simpler |
404 | | wrappers for retrieving text, image, and pixmap data. |
405 | | |
406 | | \note The pointer returned might become invalidated when the contents |
407 | | of the clipboard changes; either by calling one of the setter functions |
408 | | or externally by the system clipboard changing. |
409 | | |
410 | | \sa setMimeData() |
411 | | */ |
412 | | const QMimeData* QClipboard::mimeData(Mode mode) const |
413 | 0 | { |
414 | 0 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
415 | 0 | if (!clipboard->supportsMode(mode)) return nullptr; |
416 | 0 | return clipboard->mimeData(mode); |
417 | 0 | } |
418 | | |
419 | | /*! |
420 | | \fn void QClipboard::setMimeData(QMimeData *src, Mode mode) |
421 | | |
422 | | Sets the clipboard data to \a src. Ownership of the data is |
423 | | transferred to the clipboard. If you want to remove the data |
424 | | either call clear() or call setMimeData() again with new data. |
425 | | |
426 | | The \a mode argument is used to control which part of the system |
427 | | clipboard is used. If \a mode is QClipboard::Clipboard, the |
428 | | data is stored in the global clipboard. If \a mode is |
429 | | QClipboard::Selection, the data is stored in the global |
430 | | mouse selection. If \a mode is QClipboard::FindBuffer, the |
431 | | data is stored in the search string buffer. |
432 | | |
433 | | The setText(), setImage() and setPixmap() functions are simpler |
434 | | wrappers for setting text, image and pixmap data respectively. |
435 | | |
436 | | \sa mimeData() |
437 | | */ |
438 | | void QClipboard::setMimeData(QMimeData* src, Mode mode) |
439 | 0 | { |
440 | 0 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
441 | 0 | if (!clipboard->supportsMode(mode)) { |
442 | 0 | if (src != nullptr) { |
443 | 0 | qDebug("Data set on unsupported clipboard mode. QMimeData object will be deleted."); |
444 | 0 | src->deleteLater(); |
445 | 0 | } |
446 | 0 | } else { |
447 | 0 | clipboard->setMimeData(src,mode); |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | /*! |
452 | | \fn void QClipboard::clear(Mode mode) |
453 | | Clear the clipboard contents. |
454 | | |
455 | | The \a mode argument is used to control which part of the system |
456 | | clipboard is used. If \a mode is QClipboard::Clipboard, this |
457 | | function clears the global clipboard contents. If \a mode is |
458 | | QClipboard::Selection, this function clears the global mouse |
459 | | selection contents. If \a mode is QClipboard::FindBuffer, this |
460 | | function clears the search string buffer. |
461 | | |
462 | | \sa QClipboard::Mode, supportsSelection() |
463 | | */ |
464 | | void QClipboard::clear(Mode mode) |
465 | 0 | { |
466 | 0 | setMimeData(nullptr, mode); |
467 | 0 | } |
468 | | |
469 | | /*! |
470 | | Returns \c true if the clipboard supports mouse selection; otherwise |
471 | | returns \c false. |
472 | | */ |
473 | | bool QClipboard::supportsSelection() const |
474 | 0 | { |
475 | 0 | return supportsMode(Selection); |
476 | 0 | } |
477 | | |
478 | | /*! |
479 | | Returns \c true if the clipboard supports a separate search buffer; otherwise |
480 | | returns \c false. |
481 | | */ |
482 | | bool QClipboard::supportsFindBuffer() const |
483 | 0 | { |
484 | 0 | return supportsMode(FindBuffer); |
485 | 0 | } |
486 | | |
487 | | /*! |
488 | | Returns \c true if this clipboard object owns the clipboard data; |
489 | | otherwise returns \c false. |
490 | | */ |
491 | | bool QClipboard::ownsClipboard() const |
492 | 0 | { |
493 | 0 | return ownsMode(Clipboard); |
494 | 0 | } |
495 | | |
496 | | /*! |
497 | | Returns \c true if this clipboard object owns the mouse selection |
498 | | data; otherwise returns \c false. |
499 | | */ |
500 | | bool QClipboard::ownsSelection() const |
501 | 0 | { |
502 | 0 | return ownsMode(Selection); |
503 | 0 | } |
504 | | |
505 | | /*! |
506 | | \since 4.2 |
507 | | |
508 | | Returns \c true if this clipboard object owns the find buffer data; |
509 | | otherwise returns \c false. |
510 | | */ |
511 | | bool QClipboard::ownsFindBuffer() const |
512 | 0 | { |
513 | 0 | return ownsMode(FindBuffer); |
514 | 0 | } |
515 | | |
516 | | /*! |
517 | | \internal |
518 | | \fn bool QClipboard::supportsMode(Mode mode) const; |
519 | | Returns \c true if the clipboard supports the clipboard mode speacified by \a mode; |
520 | | otherwise returns \c false. |
521 | | */ |
522 | | bool QClipboard::supportsMode(Mode mode) const |
523 | 0 | { |
524 | 0 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
525 | 0 | return clipboard && clipboard->supportsMode(mode); |
526 | 0 | } |
527 | | |
528 | | /*! |
529 | | \internal |
530 | | \fn bool QClipboard::ownsMode(Mode mode) const; |
531 | | Returns \c true if the clipboard supports the clipboard data speacified by \a mode; |
532 | | otherwise returns \c false. |
533 | | */ |
534 | | bool QClipboard::ownsMode(Mode mode) const |
535 | 0 | { |
536 | 0 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
537 | 0 | return clipboard && clipboard->ownsMode(mode); |
538 | 0 | } |
539 | | |
540 | | /*! |
541 | | \internal |
542 | | Emits the appropriate changed signal for \a mode. |
543 | | */ |
544 | | void QClipboard::emitChanged(Mode mode) |
545 | 0 | { |
546 | 0 | switch (mode) { |
547 | 0 | case Clipboard: |
548 | 0 | emit dataChanged(); |
549 | 0 | break; |
550 | 0 | case Selection: |
551 | 0 | emit selectionChanged(); |
552 | 0 | break; |
553 | 0 | case FindBuffer: |
554 | 0 | emit findBufferChanged(); |
555 | 0 | break; |
556 | 0 | } |
557 | | |
558 | 0 | emit changed(mode); |
559 | 0 | } |
560 | | |
561 | | QT_END_NAMESPACE |
562 | | |
563 | | #include "moc_qclipboard.cpp" |
564 | | |
565 | | #endif // QT_NO_CLIPBOARD |