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 | : QObject(parent) |
129 | { |
130 | // nothing |
131 | } |
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 | { |
143 | } |
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 | { |
237 | const QMimeData *const data = mimeData(mode); |
238 | if (!data) |
239 | return QString(); |
240 | |
241 | const QStringList formats = data->formats(); |
242 | if (subtype.isEmpty()) { |
243 | if (formats.contains(str: "text/plain"_L1 )) |
244 | subtype = "plain"_L1 ; |
245 | else { |
246 | for (const auto &format : formats) { |
247 | if (format.startsWith(s: "text/"_L1 )) { |
248 | subtype = format.sliced(pos: 5); |
249 | break; |
250 | } |
251 | } |
252 | if (subtype.isEmpty()) |
253 | return QString(); |
254 | } |
255 | } else if (!formats.contains(t: "text/"_L1 + subtype)) { |
256 | return QString(); |
257 | } |
258 | |
259 | const QByteArray rawData = data->data(mimetype: "text/"_L1 + subtype); |
260 | auto encoding = QStringConverter::encodingForData(data: rawData); |
261 | if (!encoding) |
262 | encoding = QStringConverter::Utf8; |
263 | return QStringDecoder(*encoding).decode(ba: rawData); |
264 | } |
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 | { |
281 | const QMimeData *data = mimeData(mode); |
282 | return data ? data->text() : QString(); |
283 | } |
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 | { |
299 | QMimeData *data = new QMimeData; |
300 | data->setText(text); |
301 | setMimeData(data, mode); |
302 | } |
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 | { |
319 | const QMimeData *data = mimeData(mode); |
320 | if (!data) |
321 | return QImage(); |
322 | return qvariant_cast<QImage>(v: data->imageData()); |
323 | } |
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 | { |
342 | QMimeData *data = new QMimeData; |
343 | data->setImageData(image); |
344 | setMimeData(data, mode); |
345 | } |
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 | { |
364 | const QMimeData *data = mimeData(mode); |
365 | return data ? qvariant_cast<QPixmap>(v: data->imageData()) : QPixmap(); |
366 | } |
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 | { |
383 | QMimeData *data = new QMimeData; |
384 | data->setImageData(pixmap); |
385 | setMimeData(data, mode); |
386 | } |
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 | { |
414 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
415 | if (!clipboard->supportsMode(mode)) return nullptr; |
416 | return clipboard->mimeData(mode); |
417 | } |
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 | { |
440 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
441 | if (!clipboard->supportsMode(mode)) { |
442 | if (src != nullptr) { |
443 | qDebug(msg: "Data set on unsupported clipboard mode. QMimeData object will be deleted." ); |
444 | src->deleteLater(); |
445 | } |
446 | } else { |
447 | clipboard->setMimeData(data: src,mode); |
448 | } |
449 | } |
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 | { |
466 | setMimeData(src: nullptr, mode); |
467 | } |
468 | |
469 | /*! |
470 | Returns \c true if the clipboard supports mouse selection; otherwise |
471 | returns \c false. |
472 | */ |
473 | bool QClipboard::supportsSelection() const |
474 | { |
475 | return supportsMode(mode: Selection); |
476 | } |
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 | { |
484 | return supportsMode(mode: FindBuffer); |
485 | } |
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 | { |
493 | return ownsMode(mode: Clipboard); |
494 | } |
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 | { |
502 | return ownsMode(mode: Selection); |
503 | } |
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 | { |
513 | return ownsMode(mode: FindBuffer); |
514 | } |
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 | { |
524 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
525 | return clipboard && clipboard->supportsMode(mode); |
526 | } |
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 | { |
536 | QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard(); |
537 | return clipboard && clipboard->ownsMode(mode); |
538 | } |
539 | |
540 | /*! |
541 | \internal |
542 | Emits the appropriate changed signal for \a mode. |
543 | */ |
544 | void QClipboard::emitChanged(Mode mode) |
545 | { |
546 | switch (mode) { |
547 | case Clipboard: |
548 | emit dataChanged(); |
549 | break; |
550 | case Selection: |
551 | emit selectionChanged(); |
552 | break; |
553 | case FindBuffer: |
554 | emit findBufferChanged(); |
555 | break; |
556 | } |
557 | |
558 | emit changed(mode); |
559 | } |
560 | |
561 | QT_END_NAMESPACE |
562 | |
563 | #include "moc_qclipboard.cpp" |
564 | |
565 | #endif // QT_NO_CLIPBOARD |
566 | |