Qt 4.8
qclipboard_x11.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 // #define QCLIPBOARD_DEBUG
43 // #define QCLIPBOARD_DEBUG_VERBOSE
44 
45 #ifdef QCLIPBOARD_DEBUG
46 # define DEBUG qDebug
47 #else
48 # define DEBUG if (false) qDebug
49 #endif
50 
51 #ifdef QCLIPBOARD_DEBUG_VERBOSE
52 # define VDEBUG qDebug
53 #else
54 # define VDEBUG if (false) qDebug
55 #endif
56 
57 #include "qplatformdefs.h"
58 
59 #include "qclipboard.h"
60 #include "qclipboard_p.h"
61 
62 #ifndef QT_NO_CLIPBOARD
63 
65 #include "qapplication.h"
66 #include "qdesktopwidget.h"
67 #include "qbitmap.h"
68 #include "qiodevice.h"
69 #include "qbuffer.h"
70 #include "qtextcodec.h"
71 #include "qlist.h"
72 #include "qmap.h"
73 #include "qapplication_p.h"
74 #include "qevent.h"
75 #include "qt_x11_p.h"
76 #include "qx11info_x11.h"
77 #include "qimagewriter.h"
78 #include "qelapsedtimer.h"
79 #include "qvariant.h"
80 #include "qdnd_p.h"
81 #include <private/qwidget_p.h>
82 
83 #ifndef QT_NO_XFIXES
84 #include <X11/extensions/Xfixes.h>
85 #endif // QT_NO_XFIXES
86 
88 
89 /*****************************************************************************
90  Internal QClipboard functions for X11.
91  *****************************************************************************/
92 
93 static int clipboard_timeout = 5000; // 5s timeout on clipboard operations
94 
95 static QWidget * owner = 0;
96 static QWidget *requestor = 0;
97 static bool timer_event_clear = false;
98 static int timer_id = 0;
99 
100 static int pending_timer_id = 0;
101 static bool pending_clipboard_changed = false;
102 static bool pending_selection_changed = false;
103 
104 
105 // event capture mechanism for qt_xclb_wait_for_event
106 static bool waiting_for_data = false;
107 static bool has_captured_event = false;
109 static int capture_event_type = -1;
111 
112 class QClipboardWatcher; // forward decl
115 
116 static void cleanup()
117 {
118  delete owner;
119  delete requestor;
120  owner = 0;
121  requestor = 0;
122 }
123 
124 static
126 {
127  if (owner)
128  return;
129  owner = new QWidget(0);
130  owner->setObjectName(QLatin1String("internal clipboard owner"));
131  owner->createWinId();
132  requestor = new QWidget(0);
133  requestor->createWinId();
134  requestor->setObjectName(QLatin1String("internal clipboard requestor"));
135  // We don't need this internal widgets to appear in QApplication::topLevelWidgets()
139  }
141 }
142 
143 
144 class QClipboardWatcher : public QInternalMimeData {
145 public:
148  bool empty() const;
149  virtual bool hasFormat_sys(const QString &mimetype) const;
150  virtual QStringList formats_sys() const;
151 
152  QVariant retrieveData_sys(const QString &mimetype, QVariant::Type type) const;
153  QByteArray getDataInFormat(Atom fmtatom) const;
154 
158 };
159 
160 class QClipboardData
161 {
162 private:
164  {
165  if(mode == QClipboard::Selection)
166  return selectionData;
167  return clipboardData;
168  }
169 
170 public:
172  ~QClipboardData();
173 
175  {
176  if ((mode == QClipboard::Selection && selectionData == s)
177  || clipboardData == s) {
178  return;
179  }
180 
181  if (selectionData != clipboardData) {
182  delete mimeDataRef();
183  }
184 
185  mimeDataRef() = s;
186  }
187 
188  QMimeData *source() const
189  {
190  return mimeDataRef();
191  }
192 
193  void clear()
194  {
195  timestamp = CurrentTime;
196  if (selectionData == clipboardData) {
197  mimeDataRef() = 0;
198  } else {
199  QMimeData *&src = mimeDataRef();
200  delete src;
201  src = 0;
202  }
203  }
204 
207  Time timestamp;
209 };
210 
213 
215 {
216  timestamp = CurrentTime;
217  mode = clipboardMode;
218 }
219 
221 { clear(); }
222 
223 
226 
227 static void cleanupClipboardData()
228 {
229  delete internalCbData;
230  internalCbData = 0;
231 }
232 
234 {
235  if (internalCbData == 0) {
236  internalCbData = new QClipboardData(QClipboard::Clipboard);
238  }
239  return internalCbData;
240 }
241 
242 static void cleanupSelectionData()
243 {
244  delete internalSelData;
245  internalSelData = 0;
246 }
247 
249 {
250  if (internalSelData == 0) {
251  internalSelData = new QClipboardData(QClipboard::Selection);
253  }
254  return internalSelData;
255 }
256 
258 {
259 public:
260  QClipboardINCRTransaction(Window w, Atom p, Atom t, int f, QByteArray d, unsigned int i);
262 
263  int x11Event(XEvent *event);
264 
267  int format;
269  unsigned int increment;
270  unsigned int offset;
271 };
272 
276 static int incr_timer_id = 0;
277 
278 static bool qt_x11_incr_event_filter(void *message, long *result)
279 {
280  XEvent *event = reinterpret_cast<XEvent *>(message);
281  TransactionMap::Iterator it = transactions->find(event->xany.window);
282  if (it != transactions->end()) {
283  if ((*it)->x11Event(event) != 0)
284  return true;
285  }
286  if (prev_event_filter)
287  return prev_event_filter(event, result);
288  return false;
289 }
290 
291 /*
292  called when no INCR activity has happened for 'clipboard_timeout'
293  milliseconds... we assume that all unfinished transactions have
294  timed out and remove everything from the transaction map
295 */
296 static void qt_xclb_incr_timeout(void)
297 {
298  qWarning("QClipboard: Timed out while sending data");
299 
300  while (transactions)
301  delete *transactions->begin();
302 }
303 
305  QByteArray d, unsigned int i)
306  : window(w), property(p), target(t), format(f), data(d), increment(i), offset(0u)
307 {
308  DEBUG("QClipboard: sending %d bytes (INCR transaction %p)", d.size(), this);
309 
310  XSelectInput(X11->display, window, PropertyChangeMask);
311 
312  if (! transactions) {
313  VDEBUG("QClipboard: created INCR transaction map");
314  transactions = new TransactionMap;
317  }
318  transactions->insert(window, this);
319 }
320 
322 {
323  VDEBUG("QClipboard: destroyed INCR transacton %p", this);
324 
325  XSelectInput(X11->display, window, NoEventMask);
326 
327  transactions->remove(window);
328  if (transactions->isEmpty()) {
329  VDEBUG("QClipboard: no more INCR transactions");
330  delete transactions;
331  transactions = 0;
332 
333  (void)qApp->setEventFilter(prev_event_filter);
334 
335  if (incr_timer_id != 0) {
337  incr_timer_id = 0;
338  }
339  }
340 }
341 
343 {
344  if (event->type != PropertyNotify
345  || (event->xproperty.state != PropertyDelete
346  || event->xproperty.atom != property))
347  return 0;
348 
349  // restart the INCR timer
352 
353  unsigned int bytes_left = data.size() - offset;
354  if (bytes_left > 0) {
355  unsigned int xfer = qMin(increment, bytes_left);
356  VDEBUG("QClipboard: sending %d bytes, %d remaining (INCR transaction %p)",
357  xfer, bytes_left - xfer, this);
358 
359  XChangeProperty(X11->display, window, property, target, format,
360  PropModeReplace, (uchar *) data.data() + offset, xfer);
361  offset += xfer;
362  } else {
363  // INCR transaction finished...
364  XChangeProperty(X11->display, window, property, target, format,
365  PropModeReplace, (uchar *) data.data(), 0);
366  delete this;
367  }
368 
369  return 1;
370 }
371 
372 
373 /*****************************************************************************
374  QClipboard member functions for X11.
375  *****************************************************************************/
376 
378 {
379  Time timestamp;
380 };
381 
382 #if defined(Q_C_CALLBACKS)
383 extern "C" {
384 #endif
385 
387 {
389  reinterpret_cast<qt_init_timestamp_data*>(arg);
390  switch(event->type)
391  {
392  case ButtonPress:
393  case ButtonRelease:
394  data->timestamp = event->xbutton.time;
395  break;
396  case MotionNotify:
397  data->timestamp = event->xmotion.time;
398  break;
399  case XKeyPress:
400  case XKeyRelease:
401  data->timestamp = event->xkey.time;
402  break;
403  case PropertyNotify:
404  data->timestamp = event->xproperty.time;
405  break;
406  case EnterNotify:
407  case LeaveNotify:
408  data->timestamp = event->xcrossing.time;
409  break;
410  case SelectionClear:
411  data->timestamp = event->xselectionclear.time;
412  break;
413  default:
414  break;
415  }
416 #ifndef QT_NO_XFIXES
417  if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) {
418  XFixesSelectionNotifyEvent *req =
419  reinterpret_cast<XFixesSelectionNotifyEvent *>(event);
420  data->timestamp = req->selection_timestamp;
421  }
422 #endif
423  return false;
424 }
425 
426 #if defined(Q_C_CALLBACKS)
427 }
428 #endif
429 
431  : QObject(*new QClipboardPrivate, parent)
432 {
433  // create desktop widget since we need it to get PropertyNotify or
434  // XFixesSelectionNotify events when someone changes the
435  // clipboard.
436  (void)QApplication::desktop();
437 
438 #ifndef QT_NO_XFIXES
439  if (X11->use_xfixes && X11->ptrXFixesSelectSelectionInput) {
440  const unsigned long eventMask =
441  XFixesSetSelectionOwnerNotifyMask | XFixesSelectionWindowDestroyNotifyMask | XFixesSelectionClientCloseNotifyMask;
442  for (int i = 0; i < X11->screenCount; ++i) {
443  X11->ptrXFixesSelectSelectionInput(X11->display, QX11Info::appRootWindow(i),
444  XA_PRIMARY, eventMask);
445  X11->ptrXFixesSelectSelectionInput(X11->display, QX11Info::appRootWindow(i),
446  ATOM(CLIPBOARD), eventMask);
447  }
448  }
449 #endif // QT_NO_XFIXES
450 
451  if (X11->time == CurrentTime) {
452  // send a dummy event to myself to get the timestamp from X11.
454  data.timestamp = CurrentTime;
455  XEvent ev;
456  XCheckIfEvent(X11->display, &ev, &qt_init_timestamp_scanner, (XPointer)&data);
457  if (data.timestamp == CurrentTime) {
458  setupOwner();
459  // We need this value just for completeness, we don't use it.
460  long dummy = 0;
461  Window ownerId = owner->internalWinId();
462  XChangeProperty(X11->display, ownerId,
463  ATOM(CLIP_TEMPORARY), XA_INTEGER, 32,
464  PropModeReplace, (uchar*)&dummy, 1);
465  XWindowEvent(X11->display, ownerId, PropertyChangeMask, &ev);
466  data.timestamp = ev.xproperty.time;
467  XDeleteProperty(X11->display, ownerId, ATOM(CLIP_TEMPORARY));
468  }
469  X11->time = data.timestamp;
470  }
471 }
472 
473 void QClipboard::clear(Mode mode)
474 {
475  setMimeData(0, mode);
476 }
477 
478 
479 bool QClipboard::supportsMode(Mode mode) const
480 {
481  return (mode == Clipboard || mode == Selection);
482 }
483 
484 bool QClipboard::ownsMode(Mode mode) const
485 {
486  if (mode == Clipboard)
487  return clipboardData()->timestamp != CurrentTime;
488  else if(mode == Selection)
489  return selectionData()->timestamp != CurrentTime;
490  else
491  return false;
492 }
493 
494 
495 // event filter function... captures interesting events while
496 // qt_xclb_wait_for_event is running the event loop
497 static bool qt_x11_clipboard_event_filter(void *message, long *)
498 {
499  XEvent *event = reinterpret_cast<XEvent *>(message);
500  if (event->xany.type == capture_event_type &&
501  event->xany.window == capture_event_win) {
502  VDEBUG("QClipboard: event_filter(): caught event type %d", event->type);
503  has_captured_event = true;
505  return true;
506  }
507  return false;
508 }
509 
511 {
512  return ((e->type == SelectionRequest && (e->xselectionrequest.selection == XA_PRIMARY
513  || e->xselectionrequest.selection == ATOM(CLIPBOARD)))
514  || (e->type == SelectionClear && (e->xselectionclear.selection == XA_PRIMARY
515  || e->xselectionclear.selection == ATOM(CLIPBOARD))));
516 }
517 
518 bool QX11Data::clipboardWaitForEvent(Window win, int type, XEvent *event, int timeout, bool checkManager)
519 {
520  QElapsedTimer started;
521  started.start();
522  QElapsedTimer now = started;
523 
525  || QApplication::clipboard()->property("useEventLoopWhenWaiting").toBool()) {
526  if (waiting_for_data) {
527  Q_ASSERT(!"QClipboard: internal error, qt_xclb_wait_for_event recursed");
528  return false;
529  }
530  waiting_for_data = true;
531 
532 
533  has_captured_event = false;
534  capture_event_win = win;
536 
537  QApplication::EventFilter old_event_filter =
538  qApp->setEventFilter(qt_x11_clipboard_event_filter);
539 
540  do {
541  if (XCheckTypedWindowEvent(display, win, type, event)) {
542  waiting_for_data = false;
543  qApp->setEventFilter(old_event_filter);
544  return true;
545  }
546 
547  if (checkManager && XGetSelectionOwner(X11->display, ATOM(CLIPBOARD_MANAGER)) == XNone)
548  return false;
549 
550  XSync(X11->display, false);
551  usleep(50000);
552 
553  now.start();
554 
555  QEventLoop::ProcessEventsFlags flags(QEventLoop::ExcludeUserInputEvents
560  eventDispatcher->processEvents(flags);
561 
562  if (has_captured_event) {
563  waiting_for_data = false;
564  *event = captured_event;
565  qApp->setEventFilter(old_event_filter);
566  return true;
567  }
568  } while (started.msecsTo(now) < timeout);
569 
570  waiting_for_data = false;
571  qApp->setEventFilter(old_event_filter);
572  } else {
573  do {
574  if (XCheckTypedWindowEvent(X11->display,win,type,event))
575  return true;
576 
577  if (checkManager && XGetSelectionOwner(X11->display, ATOM(CLIPBOARD_MANAGER)) == XNone)
578  return false;
579 
580  // process other clipboard events, since someone is probably requesting data from us
581  XEvent e;
582  // Pass the event through the event dispatcher filter so that applications
583  // which install an event filter on the dispatcher get to handle it first.
584  if (XCheckIfEvent(X11->display, &e, checkForClipboardEvents, 0) &&
586  qApp->x11ProcessEvent(&e);
587 
588  now.start();
589 
590  XFlush(X11->display);
591 
592  // sleep 50 ms, so we don't use up CPU cycles all the time.
593  struct timeval usleep_tv;
594  usleep_tv.tv_sec = 0;
595  usleep_tv.tv_usec = 50000;
596  select(0, 0, 0, 0, &usleep_tv);
597  } while (started.msecsTo(now) < timeout);
598  }
599  return false;
600 }
601 
602 
603 static inline int maxSelectionIncr(Display *dpy)
604 { return XMaxRequestSize(dpy) > 65536 ? 65536*4 : XMaxRequestSize(dpy)*4 - 100; }
605 
606 bool QX11Data::clipboardReadProperty(Window win, Atom property, bool deleteProperty,
607  QByteArray *buffer, int *size, Atom *type, int *format)
608 {
609  int maxsize = maxSelectionIncr(display);
610  ulong bytes_left; // bytes_after
611  ulong length; // nitems
612  uchar *data;
613  Atom dummy_type;
614  int dummy_format;
615  int r;
616 
617  if (!type) // allow null args
618  type = &dummy_type;
619  if (!format)
620  format = &dummy_format;
621 
622  // Don't read anything, just get the size of the property data
623  r = XGetWindowProperty(display, win, property, 0, 0, False,
624  AnyPropertyType, type, format,
625  &length, &bytes_left, &data);
626  if (r != Success || (type && *type == XNone)) {
627  buffer->resize(0);
628  return false;
629  }
630  XFree((char*)data);
631 
632  int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left;
633 
634  VDEBUG("QClipboard: read_property(): initial property length: %d", proplen);
635 
636  switch (*format) {
637  case 8:
638  default:
639  format_inc = sizeof(char) / 1;
640  break;
641 
642  case 16:
643  format_inc = sizeof(short) / 2;
644  proplen *= sizeof(short) / 2;
645  break;
646 
647  case 32:
648  format_inc = sizeof(long) / 4;
649  proplen *= sizeof(long) / 4;
650  break;
651  }
652 
653  int newSize = proplen;
654  buffer->resize(newSize);
655 
656  bool ok = (buffer->size() == newSize);
657  VDEBUG("QClipboard: read_property(): buffer resized to %d", buffer->size());
658 
659  if (ok && newSize) {
660  // could allocate buffer
661 
662  while (bytes_left) {
663  // more to read...
664 
665  r = XGetWindowProperty(display, win, property, offset, maxsize/4,
666  False, AnyPropertyType, type, format,
667  &length, &bytes_left, &data);
668  if (r != Success || (type && *type == XNone))
669  break;
670 
671  offset += length / (32 / *format);
672  length *= format_inc * (*format) / 8;
673 
674  // Here we check if we get a buffer overflow and tries to
675  // recover -- this shouldn't normally happen, but it doesn't
676  // hurt to be defensive
677  if ((int)(buffer_offset + length) > buffer->size()) {
678  length = buffer->size() - buffer_offset;
679 
680  // escape loop
681  bytes_left = 0;
682  }
683 
684  memcpy(buffer->data() + buffer_offset, data, length);
685  buffer_offset += length;
686 
687  XFree((char*)data);
688  }
689 
690  if (*format == 8 && *type == ATOM(COMPOUND_TEXT)) {
691  // convert COMPOUND_TEXT to a multibyte string
692  XTextProperty textprop;
693  textprop.encoding = *type;
694  textprop.format = *format;
695  textprop.nitems = buffer_offset;
696  textprop.value = (unsigned char *) buffer->data();
697 
698  char **list_ret = 0;
699  int count;
700  if (XmbTextPropertyToTextList(display, &textprop, &list_ret,
701  &count) == Success && count && list_ret) {
702  offset = buffer_offset = strlen(list_ret[0]);
703  buffer->resize(offset);
704  memcpy(buffer->data(), list_ret[0], offset);
705  }
706  if (list_ret) XFreeStringList(list_ret);
707  }
708  }
709 
710  // correct size, not 0-term.
711  if (size)
712  *size = buffer_offset;
713 
714  VDEBUG("QClipboard: read_property(): buffer size %d, buffer offset %d, offset %d",
715  buffer->size(), buffer_offset, offset);
716 
717  if (deleteProperty)
718  XDeleteProperty(display, win, property);
719 
720  XFlush(display);
721 
722  return ok;
723 }
724 
726 {
727  XEvent event;
728 
729  QByteArray buf;
730  QByteArray tmp_buf;
731  bool alloc_error = false;
732  int length;
733  int offset = 0;
734 
735  if (nbytes > 0) {
736  // Reserve buffer + zero-terminator (for text data)
737  // We want to complete the INCR transfer even if we cannot
738  // allocate more memory
739  buf.resize(nbytes+1);
740  alloc_error = buf.size() != nbytes+1;
741  }
742 
743  for (;;) {
744  XFlush(display);
745  if (!clipboardWaitForEvent(win,PropertyNotify,&event,clipboard_timeout))
746  break;
747  if (event.xproperty.atom != property ||
748  event.xproperty.state != PropertyNewValue)
749  continue;
750  if (X11->clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) {
751  if (length == 0) { // no more data, we're done
752  if (nullterm) {
753  buf.resize(offset+1);
754  buf[offset] = '\0';
755  } else {
756  buf.resize(offset);
757  }
758  return buf;
759  } else if (!alloc_error) {
760  if (offset+length > (int)buf.size()) {
761  buf.resize(offset+length+65535);
762  if (buf.size() != offset+length+65535) {
763  alloc_error = true;
764  length = buf.size() - offset;
765  }
766  }
767  memcpy(buf.data()+offset, tmp_buf.constData(), length);
768  tmp_buf.resize(0);
769  offset += length;
770  }
771  } else {
772  break;
773  }
774  }
775 
776  // timed out ... create a new requestor window, otherwise the requestor
777  // could consider next request to be still part of this timed out request
778  delete requestor;
779  requestor = new QWidget(0);
780  requestor->setObjectName(QLatin1String("internal clipboard requestor"));
781  // We don't need this internal widget to appear in QApplication::topLevelWidgets()
784 
785  return QByteArray();
786 }
787 
789 {
792  for (int i = 0; i < formats.size(); ++i) {
793  QList<Atom> atoms = X11->xdndMimeAtomsForFormat(formats.at(i));
794  for (int j = 0; j < atoms.size(); ++j) {
795  if (!types.contains(atoms.at(j)))
796  types.append(atoms.at(j));
797  }
798  }
799  types.append(ATOM(TARGETS));
800  types.append(ATOM(MULTIPLE));
801  types.append(ATOM(TIMESTAMP));
802  types.append(ATOM(SAVE_TARGETS));
803 
804  XChangeProperty(X11->display, window, property, XA_ATOM, 32,
805  PropModeReplace, (uchar *) types.data(), types.size());
806  return property;
807 }
808 
810 {
811  Atom atomFormat = target;
812  int dataFormat = 0;
814 
815  QByteArray fmt = X11->xdndAtomToString(target);
816  if (fmt.isEmpty()) { // Not a MIME type we have
817  DEBUG("QClipboard: send_selection(): converting to type '%s' is not supported", fmt.data());
818  return XNone;
819  }
820  DEBUG("QClipboard: send_selection(): converting to type '%s'", fmt.data());
821 
822  if (X11->xdndMimeDataForAtom(target, d->source(), &data, &atomFormat, &dataFormat)) {
823 
824  VDEBUG("QClipboard: send_selection():\n"
825  " property type %lx\n"
826  " property name '%s'\n"
827  " format %d\n"
828  " %d bytes\n",
829  target, X11->xdndMimeAtomToString(atomFormat).toLatin1().data(), dataFormat, data.size());
830 
831  // don't allow INCR transfers when using MULTIPLE or to
832  // Motif clients (since Motif doesn't support INCR)
833  static Atom motif_clip_temporary = ATOM(CLIP_TEMPORARY);
834  bool allow_incr = property != motif_clip_temporary;
835 
836  // X_ChangeProperty protocol request is 24 bytes
837  const int increment = (XMaxRequestSize(X11->display) * 4) - 24;
838  if (data.size() > increment && allow_incr) {
839  long bytes = data.size();
840  XChangeProperty(X11->display, window, property,
841  ATOM(INCR), 32, PropModeReplace, (uchar *) &bytes, 1);
842 
843  (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment);
844  return property;
845  }
846 
847  // make sure we can perform the XChangeProperty in a single request
848  if (data.size() > increment)
849  return XNone; // ### perhaps use several XChangeProperty calls w/ PropModeAppend?
850  int dataSize = data.size() / (dataFormat / 8);
851  // use a single request to transfer data
852  XChangeProperty(X11->display, window, property, atomFormat,
853  dataFormat, PropModeReplace, (uchar *) data.data(),
854  dataSize);
855  }
856  return property;
857 }
858 
866 { }
867 
868 
875 void QClipboard::connectNotify(const char *)
876 { }
877 
878 
879 bool QClipboard::event(QEvent *e)
880 {
881  if (e->type() == QEvent::Timer) {
882  QTimerEvent *te = (QTimerEvent *) e;
883 
884  if (waiting_for_data) // should never happen
885  return false;
886 
887  if (te->timerId() == timer_id) {
889  timer_id = 0;
890 
891  timer_event_clear = true;
892  if (selection_watcher) // clear selection
893  selectionData()->clear();
894  if (clipboard_watcher) // clear clipboard
895  clipboardData()->clear();
896  timer_event_clear = false;
897 
898  return true;
899  } else if (te->timerId() == pending_timer_id) {
900  // I hate klipper
902  pending_timer_id = 0;
903 
906  clipboardData()->clear();
908  }
911  selectionData()->clear();
913  }
914 
915  return true;
916  } else if (te->timerId() == incr_timer_id) {
918  incr_timer_id = 0;
919 
921 
922  return true;
923  } else {
924  return QObject::event(e);
925  }
926  } else if (e->type() != QEvent::Clipboard) {
927  return QObject::event(e);
928  }
929 
930  XEvent *xevent = (XEvent *)(((QClipboardEvent *)e)->data());
931  Display *dpy = X11->display;
932 
933  if (!xevent) {
934  // That means application exits and we need to give clipboard
935  // content to the clipboard manager.
936  // First we check if there is a clipboard manager.
937  if (XGetSelectionOwner(X11->display, ATOM(CLIPBOARD_MANAGER)) == XNone
938  || !owner)
939  return true;
940 
941  Window ownerId = owner->internalWinId();
942  Q_ASSERT(ownerId);
943  // we delete the property so the manager saves all TARGETS.
944  XDeleteProperty(X11->display, ownerId, ATOM(_QT_SELECTION));
945  XConvertSelection(X11->display, ATOM(CLIPBOARD_MANAGER), ATOM(SAVE_TARGETS),
946  ATOM(_QT_SELECTION), ownerId, X11->time);
947  XSync(dpy, false);
948 
949  XEvent event;
950  // waiting until the clipboard manager fetches the content.
951  if (!X11->clipboardWaitForEvent(ownerId, SelectionNotify, &event, 10000, true)) {
952  qWarning("QClipboard: Unable to receive an event from the "
953  "clipboard manager in a reasonable time");
954  }
955 
956  return true;
957  }
958 
959  switch (xevent->type) {
960 
961  case SelectionClear:
962  // new selection owner
963  if (xevent->xselectionclear.selection == XA_PRIMARY) {
965 
966  // ignore the event if it was generated before we gained selection ownership
967  if (d->timestamp != CurrentTime && xevent->xselectionclear.time <= d->timestamp)
968  break;
969 
970  DEBUG("QClipboard: new selection owner 0x%lx at time %lx (ours %lx)",
971  XGetSelectionOwner(dpy, XA_PRIMARY),
972  xevent->xselectionclear.time, d->timestamp);
973 
974  if (! waiting_for_data) {
975  d->clear();
977  } else {
979  if (! pending_timer_id)
981  }
982  } else if (xevent->xselectionclear.selection == ATOM(CLIPBOARD)) {
984 
985  // ignore the event if it was generated before we gained selection ownership
986  if (d->timestamp != CurrentTime && xevent->xselectionclear.time <= d->timestamp)
987  break;
988 
989  DEBUG("QClipboard: new clipboard owner 0x%lx at time %lx (%lx)",
990  XGetSelectionOwner(dpy, ATOM(CLIPBOARD)),
991  xevent->xselectionclear.time, d->timestamp);
992 
993  if (! waiting_for_data) {
994  d->clear();
996  } else {
998  if (! pending_timer_id)
1000  }
1001  } else {
1002  qWarning("QClipboard: Unknown SelectionClear event received");
1003  return false;
1004  }
1005  break;
1006 
1007  case SelectionNotify:
1008  /*
1009  Something has delivered data to us, but this was not caught
1010  by QClipboardWatcher::getDataInFormat()
1011 
1012  Just skip the event to prevent Bad Things (tm) from
1013  happening later on...
1014  */
1015  break;
1016 
1017  case SelectionRequest:
1018  {
1019  // someone wants our data
1020  XSelectionRequestEvent *req = &xevent->xselectionrequest;
1021 
1022  if (requestor && req->requestor == requestor->internalWinId())
1023  break;
1024 
1025  XEvent event;
1026  event.xselection.type = SelectionNotify;
1027  event.xselection.display = req->display;
1028  event.xselection.requestor = req->requestor;
1029  event.xselection.selection = req->selection;
1030  event.xselection.target = req->target;
1031  event.xselection.property = XNone;
1032  event.xselection.time = req->time;
1033 
1034  DEBUG("QClipboard: SelectionRequest from %lx\n"
1035  " selection 0x%lx (%s) target 0x%lx (%s)",
1036  req->requestor,
1037  req->selection,
1038  X11->xdndAtomToString(req->selection).data(),
1039  req->target,
1040  X11->xdndAtomToString(req->target).data());
1041 
1042  QClipboardData *d;
1043  if (req->selection == XA_PRIMARY) {
1044  d = selectionData();
1045  } else if (req->selection == ATOM(CLIPBOARD)) {
1046  d = clipboardData();
1047  } else {
1048  qWarning("QClipboard: Unknown selection '%lx'", req->selection);
1049  XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
1050  break;
1051  }
1052 
1053  if (! d->source()) {
1054  qWarning("QClipboard: Cannot transfer data, no data available");
1055  XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
1056  break;
1057  }
1058 
1059  DEBUG("QClipboard: SelectionRequest at time %lx (ours %lx)",
1060  req->time, d->timestamp);
1061 
1062  if (d->timestamp == CurrentTime // we don't own the selection anymore
1063  || (req->time != CurrentTime && req->time < d->timestamp)) {
1064  DEBUG("QClipboard: SelectionRequest too old");
1065  XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
1066  break;
1067  }
1068 
1069  Atom xa_targets = ATOM(TARGETS);
1070  Atom xa_multiple = ATOM(MULTIPLE);
1071  Atom xa_timestamp = ATOM(TIMESTAMP);
1072 
1073  struct AtomPair { Atom target; Atom property; } *multi = 0;
1074  Atom multi_type = XNone;
1075  int multi_format = 0;
1076  int nmulti = 0;
1077  int imulti = -1;
1078  bool multi_writeback = false;
1079 
1080  if (req->target == xa_multiple) {
1081  QByteArray multi_data;
1082  if (req->property == XNone
1083  || !X11->clipboardReadProperty(req->requestor, req->property, false, &multi_data,
1084  0, &multi_type, &multi_format)
1085  || multi_format != 32) {
1086  // MULTIPLE property not formatted correctly
1087  XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
1088  break;
1089  }
1090  nmulti = multi_data.size()/sizeof(*multi);
1091  multi = new AtomPair[nmulti];
1092  memcpy(multi,multi_data.data(),multi_data.size());
1093  imulti = 0;
1094  }
1095 
1096  for (; imulti < nmulti; ++imulti) {
1097  Atom target;
1098  Atom property;
1099 
1100  if (multi) {
1101  target = multi[imulti].target;
1102  property = multi[imulti].property;
1103  } else {
1104  target = req->target;
1105  property = req->property;
1106  if (property == XNone) // obsolete client
1107  property = target;
1108  }
1109 
1110  Atom ret = XNone;
1111  if (target == XNone || property == XNone) {
1112  ;
1113  } else if (target == xa_timestamp) {
1114  if (d->timestamp != CurrentTime) {
1115  XChangeProperty(dpy, req->requestor, property, XA_INTEGER, 32,
1116  PropModeReplace, (uchar *) &d->timestamp, 1);
1117  ret = property;
1118  } else {
1119  qWarning("QClipboard: Invalid data timestamp");
1120  }
1121  } else if (target == xa_targets) {
1122  ret = send_targets_selection(d, req->requestor, property);
1123  } else {
1124  ret = send_selection(d, target, req->requestor, property);
1125  }
1126 
1127  if (nmulti > 0) {
1128  if (ret == XNone) {
1129  multi[imulti].property = XNone;
1130  multi_writeback = true;
1131  }
1132  } else {
1133  event.xselection.property = ret;
1134  break;
1135  }
1136  }
1137 
1138  if (nmulti > 0) {
1139  if (multi_writeback) {
1140  // according to ICCCM 2.6.2 says to put None back
1141  // into the original property on the requestor window
1142  XChangeProperty(dpy, req->requestor, req->property, multi_type, 32,
1143  PropModeReplace, (uchar *) multi, nmulti * 2);
1144  }
1145 
1146  delete [] multi;
1147  event.xselection.property = req->property;
1148  }
1149 
1150  // send selection notify to requestor
1151  XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
1152 
1153  DEBUG("QClipboard: SelectionNotify to 0x%lx\n"
1154  " property 0x%lx (%s)",
1155  req->requestor, event.xselection.property,
1156  X11->xdndAtomToString(event.xselection.property).data());
1157  }
1158  break;
1159  }
1160 
1161  return true;
1162 }
1163 
1164 
1165 
1166 
1167 
1168 
1170  : QInternalMimeData()
1171 {
1172  switch (mode) {
1173  case QClipboard::Selection:
1174  atom = XA_PRIMARY;
1175  break;
1176 
1177  case QClipboard::Clipboard:
1178  atom = ATOM(CLIPBOARD);
1179  break;
1180 
1181  default:
1182  qWarning("QClipboardWatcher: Internal error: Unsupported clipboard mode");
1183  break;
1184  }
1185 
1186  setupOwner();
1187 }
1188 
1190 {
1191  if(selection_watcher == this)
1192  selection_watcher = 0;
1193  if(clipboard_watcher == this)
1194  clipboard_watcher = 0;
1195 }
1196 
1198 {
1199  Display *dpy = X11->display;
1200  Window win = XGetSelectionOwner(dpy, atom);
1201 
1202  if(win == requestor->internalWinId()) {
1203  qWarning("QClipboardWatcher::empty: Internal error: Application owns the selection");
1204  return true;
1205  }
1206 
1207  return win == XNone;
1208 }
1209 
1211 {
1212  if (empty())
1213  return QStringList();
1214 
1215  if (!formatList.count()) {
1216  // get the list of targets from the current clipboard owner - we do this
1217  // once so that multiple calls to this function don't require multiple
1218  // server round trips...
1219 
1221 
1222  if (format_atoms.size() > 0) {
1223  Atom *targets = (Atom *) format_atoms.data();
1224  int size = format_atoms.size() / sizeof(Atom);
1225 
1226  for (int i = 0; i < size; ++i) {
1227  if (targets[i] == 0)
1228  continue;
1229 
1230  QStringList formatsForAtom = X11->xdndMimeFormatsForAtom(targets[i]);
1231  for (int j = 0; j < formatsForAtom.size(); ++j) {
1232  if (!formatList.contains(formatsForAtom.at(j)))
1233  formatList.append(formatsForAtom.at(j));
1234  }
1235  VDEBUG(" format: %s", X11->xdndAtomToString(targets[i]).data());
1236  VDEBUG(" data:\n%s\n", getDataInFormat(targets[i]).data());
1237  }
1238  DEBUG("QClipboardWatcher::format: %d formats available", formatList.count());
1239  }
1240  }
1241 
1242  return formatList;
1243 }
1244 
1246 {
1247  QStringList list = formats();
1248  return list.contains(format);
1249 }
1250 
1251 QVariant QClipboardWatcher::retrieveData_sys(const QString &fmt, QVariant::Type requestedType) const
1252 {
1253  if (fmt.isEmpty() || empty())
1254  return QByteArray();
1255 
1256  (void)formats(); // trigger update of format list
1257  DEBUG("QClipboardWatcher::data: fetching format '%s'", fmt.toLatin1().data());
1258 
1259  QList<Atom> atoms;
1260  Atom *targets = (Atom *) format_atoms.data();
1261  int size = format_atoms.size() / sizeof(Atom);
1262  for (int i = 0; i < size; ++i)
1263  atoms.append(targets[i]);
1264 
1265  QByteArray encoding;
1266  Atom fmtatom = X11->xdndMimeAtomForFormat(fmt, requestedType, atoms, &encoding);
1267 
1268  if (fmtatom == 0)
1269  return QVariant();
1270 
1271  return X11->xdndMimeConvertToFormat(fmtatom, getDataInFormat(fmtatom), fmt, requestedType, encoding);
1272 }
1273 
1275 {
1276  QByteArray buf;
1277 
1278  Display *dpy = X11->display;
1279  requestor->createWinId();
1280  Window win = requestor->internalWinId();
1282 
1283  DEBUG("QClipboardWatcher::getDataInFormat: selection '%s' format '%s'",
1284  X11->xdndAtomToString(atom).data(), X11->xdndAtomToString(fmtatom).data());
1285 
1286  XSelectInput(dpy, win, NoEventMask); // don't listen for any events
1287 
1288  XDeleteProperty(dpy, win, ATOM(_QT_SELECTION));
1289  XConvertSelection(dpy, atom, fmtatom, ATOM(_QT_SELECTION), win, X11->time);
1290  XSync(dpy, false);
1291 
1292  VDEBUG("QClipboardWatcher::getDataInFormat: waiting for SelectionNotify event");
1293 
1294  XEvent xevent;
1295  if (!X11->clipboardWaitForEvent(win,SelectionNotify,&xevent,clipboard_timeout) ||
1296  xevent.xselection.property == XNone) {
1297  DEBUG("QClipboardWatcher::getDataInFormat: format not available");
1298  return buf;
1299  }
1300 
1301  VDEBUG("QClipboardWatcher::getDataInFormat: fetching data...");
1302 
1303  Atom type;
1304  XSelectInput(dpy, win, PropertyChangeMask);
1305 
1306  if (X11->clipboardReadProperty(win, ATOM(_QT_SELECTION), true, &buf, 0, &type, 0)) {
1307  if (type == ATOM(INCR)) {
1308  int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0;
1309  buf = X11->clipboardReadIncrementalProperty(win, ATOM(_QT_SELECTION), nbytes, false);
1310  }
1311  }
1312 
1313  XSelectInput(dpy, win, NoEventMask);
1314 
1315  DEBUG("QClipboardWatcher::getDataInFormat: %d bytes received", buf.size());
1316 
1317  return buf;
1318 }
1319 
1320 
1321 const QMimeData* QClipboard::mimeData(Mode mode) const
1322 {
1323  QClipboardData *d = 0;
1324  switch (mode) {
1325  case Selection:
1326  d = selectionData();
1327  break;
1328  case Clipboard:
1329  d = clipboardData();
1330  break;
1331  default:
1332  qWarning("QClipboard::mimeData: unsupported mode '%d'", mode);
1333  return 0;
1334  }
1335 
1336  if (! d->source() && ! timer_event_clear) {
1337  if (mode == Selection) {
1338  if (! selection_watcher)
1339  selection_watcher = new QClipboardWatcher(mode);
1340  d->setSource(selection_watcher);
1341  } else {
1342  if (! clipboard_watcher)
1343  clipboard_watcher = new QClipboardWatcher(mode);
1344  d->setSource(clipboard_watcher);
1345  }
1346 
1347  if (! timer_id) {
1348  // start a zero timer - we will clear cached data when the timer
1349  // times out, which will be the next time we hit the event loop...
1350  // that way, the data is cached long enough for calls within a single
1351  // loop/function, but the data doesn't linger around in case the selection
1352  // changes
1353  QClipboard *that = ((QClipboard *) this);
1354  timer_id = that->startTimer(0);
1355  }
1356  }
1357 
1358  return d->source();
1359 }
1360 
1361 
1362 void QClipboard::setMimeData(QMimeData* src, Mode mode)
1363 {
1364  Atom atom, sentinel_atom;
1365  QClipboardData *d;
1366  switch (mode) {
1367  case Selection:
1368  atom = XA_PRIMARY;
1369  sentinel_atom = ATOM(_QT_SELECTION_SENTINEL);
1370  d = selectionData();
1371  break;
1372 
1373  case Clipboard:
1374  atom = ATOM(CLIPBOARD);
1375  sentinel_atom = ATOM(_QT_CLIPBOARD_SENTINEL);
1376  d = clipboardData();
1377  break;
1378 
1379  default:
1380  qWarning("QClipboard::setMimeData: unsupported mode '%d'", mode);
1381  return;
1382  }
1383 
1384  Display *dpy = X11->display;
1385  Window newOwner;
1386 
1387  if (! src) { // no data, clear clipboard contents
1388  newOwner = XNone;
1389  d->clear();
1390  } else {
1391  setupOwner();
1392 
1393  newOwner = owner->internalWinId();
1394 
1395  d->setSource(src);
1396  d->timestamp = X11->time;
1397  }
1398 
1399  Window prevOwner = XGetSelectionOwner(dpy, atom);
1400  // use X11->time, since d->timestamp == CurrentTime when clearing
1401  XSetSelectionOwner(dpy, atom, newOwner, X11->time);
1402 
1403  if (mode == Selection)
1404  emitChanged(QClipboard::Selection);
1405  else
1406  emitChanged(QClipboard::Clipboard);
1407 
1408  if (XGetSelectionOwner(dpy, atom) != newOwner) {
1409  qWarning("QClipboard::setData: Cannot set X11 selection owner for %s",
1410  X11->xdndAtomToString(atom).data());
1411  d->clear();
1412  return;
1413  }
1414 
1415  // Signal to other Qt processes that the selection has changed
1416  Window owners[2];
1417  owners[0] = newOwner;
1418  owners[1] = prevOwner;
1419  XChangeProperty(dpy, QApplication::desktop()->screen(0)->internalWinId(),
1420  sentinel_atom, XA_WINDOW, 32, PropModeReplace,
1421  (unsigned char*)&owners, 2);
1422 }
1423 
1424 
1425 /*
1426  Called by the main event loop in qapplication_x11.cpp when either
1427  the _QT_SELECTION_SENTINEL property has been changed (i.e. when some
1428  Qt process has performed QClipboard::setData()) or when Xfixes told
1429  us that an other application changed the selection. If it returns
1430  true, the QClipBoard dataChanged() signal should be emitted.
1431 */
1432 
1434 {
1435  bool doIt = true;
1436  if (owner && !X11->use_xfixes) {
1437  /*
1438  Since the X selection mechanism cannot give any signal when
1439  the selection has changed, we emulate it (for Qt processes) here.
1440  The notification should be ignored in case of either
1441  a) This is the process that did setData (because setData()
1442  then has already emitted dataChanged())
1443  b) This is the process that owned the selection when dataChanged()
1444  was called (because we have then received a SelectionClear event,
1445  and have already emitted dataChanged() as a result of that)
1446  */
1447 
1448  unsigned char *retval;
1449  Atom actualType;
1450  int actualFormat;
1451  ulong nitems;
1452  ulong bytesLeft;
1453 
1454  if (XGetWindowProperty(X11->display,
1456  ATOM(_QT_SELECTION_SENTINEL), 0, 2, False, XA_WINDOW,
1457  &actualType, &actualFormat, &nitems,
1458  &bytesLeft, &retval) == Success) {
1459  Window *owners = (Window *)retval;
1460  if (actualType == XA_WINDOW && actualFormat == 32 && nitems == 2) {
1461  Window win = owner->internalWinId();
1462  if (owners[0] == win || owners[1] == win)
1463  doIt = false;
1464  }
1465 
1466  XFree(owners);
1467  }
1468  }
1469 
1470  if (doIt) {
1471  if (waiting_for_data) {
1473  if (! pending_timer_id)
1475  doIt = false;
1476  } else {
1477  selectionData()->clear();
1478  }
1479  }
1480 
1481  return doIt;
1482 }
1483 
1484 
1486 {
1487  bool doIt = true;
1488  if (owner && !X11->use_xfixes) {
1489  unsigned char *retval;
1490  Atom actualType;
1491  int actualFormat;
1492  unsigned long nitems, bytesLeft;
1493 
1494  if (XGetWindowProperty(X11->display,
1496  ATOM(_QT_CLIPBOARD_SENTINEL), 0, 2, False, XA_WINDOW,
1497  &actualType, &actualFormat, &nitems, &bytesLeft,
1498  &retval) == Success) {
1499  Window *owners = (Window *)retval;
1500  if (actualType == XA_WINDOW && actualFormat == 32 && nitems == 2) {
1501  Window win = owner->internalWinId();
1502  if (owners[0] == win || owners[1] == win)
1503  doIt = false;
1504  }
1505 
1506  XFree(owners);
1507  }
1508  }
1509 
1510  if (doIt) {
1511  if (waiting_for_data) {
1513  if (! pending_timer_id)
1515  doIt = false;
1516  } else {
1517  clipboardData()->clear();
1518  }
1519  }
1520 
1521  return doIt;
1522 }
1523 
1524 bool qt_xfixes_selection_changed(Window selectionOwner, Time timestamp)
1525 {
1527 #ifdef QCLIPBOARD_DEBUG
1528  DEBUG("qt_xfixes_selection_changed: owner = %u; selectionOwner = %u; internal timestamp = %u; external timestamp = %u",
1529  (unsigned int)(owner ? (int)owner->internalWinId() : 0), (unsigned int)selectionOwner,
1530  (unsigned int)(d ? d->timestamp : 0), (unsigned int)timestamp);
1531 #endif
1532  if (!owner || (selectionOwner && selectionOwner != owner->internalWinId()) ||
1533  (!selectionOwner && (d->timestamp == CurrentTime || d->timestamp < timestamp)))
1534  return qt_check_selection_sentinel();
1535  return false;
1536 }
1537 
1538 bool qt_xfixes_clipboard_changed(Window clipboardOwner, Time timestamp)
1539 {
1541 #ifdef QCLIPBOARD_DEBUG
1542  DEBUG("qt_xfixes_clipboard_changed: owner = %u; clipboardOwner = %u; internal timestamp = %u; external timestamp = %u",
1543  (unsigned int)(owner ? (int)owner->internalWinId() : 0), (unsigned int)clipboardOwner,
1544  (unsigned int)(d ? d->timestamp : 0), (unsigned int)timestamp);
1545 #endif
1546  if (!owner || (clipboardOwner && clipboardOwner != owner->internalWinId()) ||
1547  (!clipboardOwner && (d->timestamp == CurrentTime || d->timestamp < timestamp)))
1548  return qt_check_clipboard_sentinel();
1549  return false;
1550 }
1551 
1553 
1554 #endif // QT_NO_CLIPBOARD
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
Mode
This enum type is used to control which part of the system clipboard is used by QClipboard::mimeData(...
Definition: qclipboard.h:71
int startTimer(int interval)
Starts a timer and returns a timer identifier, or returns zero if it could not start a timer...
Definition: qobject.cpp:1623
static bool qt_x11_incr_event_filter(void *message, long *result)
double d
Definition: qnumeric_p.h:62
bool qt_check_clipboard_sentinel()
static Atom send_targets_selection(QClipboardData *d, Window window, Atom property)
static void setupOwner()
void clear(Mode mode=Clipboard)
Clear the clipboard contents.
QStringList formats_sys() const
void emitChanged(Mode mode)
Emits the appropriate changed signal for mode.
Definition: qclipboard.cpp:640
int type
Definition: qmetatype.cpp:239
static void cleanupSelectionData()
bool clipboardReadProperty(Window win, Atom property, bool deleteProperty, QByteArray *buffer, int *size, Atom *type, int *format)
bool filterEvent(void *message)
Sends message through the event filter that was set by setEventFilter().
static int clipboard_timeout
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
void clear()
Removes all the MIME type and data entries in the object.
Definition: qmimedata.cpp:613
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QByteArray clipboardReadIncrementalProperty(Window win, Atom property, int nbytes, bool nullterm)
EventRef event
static bool timer_event_clear
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
bool event(QEvent *)
Reimplemented Function
void ownerDestroyed()
Internal cleanup for Windows.
#define it(className, varName)
void qAddPostRoutine(QtCleanUpFunction p)
QMap< Window, QClipboardINCRTransaction * > TransactionMap
static bool pending_clipboard_changed
QClipboard(QObject *parent)
static QAbstractEventDispatcher * instance(QThread *thread=0)
Returns a pointer to the event dispatcher object for the specified thread.
qint64 msecsTo(const QElapsedTimer &other) const
Returns the number of milliseconds between this QElapsedTimer and other.
static Bool checkForClipboardEvents(Display *, XEvent *e, XPointer)
static int pending_timer_id
static void cleanupClipboardData()
bool remove(const T &value)
Definition: qset.h:89
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
static Qt::HANDLE appRootWindow(int screen=-1)
Returns a handle for the applications root window on the given screen.
static QStringList formatsHelper(const QMimeData *data)
Definition: qdnd.cpp:414
static QClipboardData * internalCbData
static QApplication::EventFilter prev_event_filter
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
static QMimeData * selectionData
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *)
static QClipboardWatcher * selection_watcher
static QClipboardData * internalSelData
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool supportsMode(Mode mode) const
Returns true if the clipboard supports the clipboard mode speacified by mode; otherwise returns false...
quint16 u
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
iterator find(const Key &key)
Returns an iterator pointing to the item with key key in the map.
Definition: qmap.h:618
QByteArray data(const QString &mimetype) const
Returns the data stored in the object in the format described by the MIME type specified by mimeType...
Definition: qmimedata.cpp:524
bool qt_xfixes_selection_changed(Window selectionOwner, Time timestamp)
static int timer_id
void setMimeData(QMimeData *data, Mode mode=Clipboard)
Sets the clipboard data to src.
The QString class provides a Unicode character string.
Definition: qstring.h:83
static QWidget * owner
static XEvent captured_event
bool ownsMode(Mode mode) const
Returns true if the clipboard supports the clipboard data speacified by mode; otherwise returns false...
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QVector class is a template class that provides a dynamic array.
Definition: qdatastream.h:64
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
virtual bool event(QEvent *)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition: qobject.cpp:1200
#define X11
Definition: qt_x11_p.h:724
The QElapsedTimer class provides a fast way to calculate elapsed times.
Definition: qelapsedtimer.h:53
void setObjectName(const QString &name)
Definition: qobject.cpp:1112
union _XEvent XEvent
Definition: qwindowdefs.h:116
static int incr_timer_id
#define ATOM(x)
Definition: qt_x11_p.h:723
static TransactionMap * transactions
static bool toBool(Register *reg, int type, bool *ok=0)
unsigned char uchar
Definition: qglobal.h:994
NSWindow * window
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
const QMimeData * mimeData(Mode mode=Clipboard) const
Returns a reference to a QMimeData representation of the current clipboard data.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Q_GUI_EXPORT EGLDisplay display()
Definition: qegl.cpp:589
static QClipboardData * clipboardData()
int x11Event(XEvent *event)
static QClipboard * clipboard()
Returns a pointer to the application global clipboard.
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition: qwidget.h:1041
static int capture_event_type
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
#define qApp
bool hasFormat_sys(const QString &mimetype) const
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
QStringList formats() const
Returns a list of formats supported by the object.
Definition: qdnd.cpp:351
void append(const T &t)
Inserts value at the end of the vector.
Definition: qvector.h:573
Q_CORE_EXPORT void qWarning(const char *,...)
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition: qcoreevent.h:346
static const char * data(const QByteArray &arr)
Type
This enum type defines the types of variable that a QVariant can contain.
Definition: qvariant.h:95
QBool contains(const QString &str, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the list contains the string str; otherwise returns false.
Definition: qstringlist.h:172
The QClipboard class provides access to the window system clipboard.
Definition: qclipboard.h:62
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
void setSource(QMimeData *s)
static void qt_xclb_incr_timeout(void)
unsigned long ulong
Definition: qglobal.h:997
The QMimeData class provides a container for data that records information about its MIME type...
Definition: qmimedata.h:57
static QWidgetSet * allWidgets
Definition: qwidget_p.h:715
QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const
bool inherits(const char *classname) const
Returns true if this object is an instance of a class that inherits className or a QObject subclass t...
Definition: qobject.h:275
static bool pending_selection_changed
QWidget * screen(int screen=-1)
Mode
Definition: qaudio.h:60
iterator begin()
Returns an STL-style iterator pointing to the first item in the map.
Definition: qmap.h:372
static QDesktopWidget * desktop()
Returns the desktop widget (also called the root window).
char * XPointer
Definition: qt_x11_p.h:180
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
int remove(const Key &key)
Removes all the items that have the key key from the map.
Definition: qmap.h:662
static QWidget * requestor
struct _XDisplay Display
Definition: qwindowdefs.h:115
static QClipboardData * selectionData()
The QMap::iterator class provides an STL-style non-const iterator for QMap and QMultiMap.
Definition: qmap.h:233
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
static const struct @32 types[]
virtual bool processEvents(QEventLoop::ProcessEventsFlags flags)=0
Processes pending events that match flags until there are no more events to process.
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the map...
Definition: qmap.h:375
static Atom send_selection(QClipboardData *d, Atom target, Window window, Atom property)
iterator insert(const Key &key, const T &value)
Inserts a new item with the key key and a value of value.
Definition: qmap.h:559
QStringList formatList
void resize(int size)
Sets the size of the byte array to size bytes.
bool(* EventFilter)(void *message, long *result)
A function with the following signature that can be used as an event filter:
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
bool isEmpty() const
Returns true if the map contains no items; otherwise returns false.
Definition: qmap.h:203
static bool waiting_for_data
static Window capture_event_win
QClipboard::Mode mode
friend class QWidget
Definition: qobject.h:329
WId internalWinId() const
Returns the window system identifier of the widget, or 0 if the widget is not created yet...
Definition: qwidget.h:244
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
bool contains(const T &t) const
Returns true if the vector contains an occurrence of value; otherwise returns false.
Definition: qvector.h:731
bool clipboardWaitForEvent(Window win, int type, XEvent *event, int timeout, bool checkManager=false)
QVariant property(const char *name) const
Returns the value of the object&#39;s name property.
Definition: qobject.cpp:3807
QMimeData * source()
#define DEBUG
void createWinId()
Definition: qwidget.cpp:2626
The QClipboardEvent class provides the parameters used in a clipboard event.
Definition: qevent.h:695
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
T * data()
Returns a pointer to the data stored in the vector.
Definition: qvector.h:152
QClipboardINCRTransaction(Window w, Atom p, Atom t, int f, QByteArray d, unsigned int i)
QByteArray getDataInFormat(Atom fmtatom) const
QMimeData * source() const
static int maxSelectionIncr(Display *dpy)
bool qt_check_selection_sentinel()
static QClipboardWatcher * clipboard_watcher
#define VDEBUG
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
static void cleanup()
void qAddPostRoutine(QtCleanUpFunction ptr)
Adds a global routine that will be called from the QApplication destructor.
static bool has_captured_event
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
QMimeData *& mimeDataRef() const
static bool qt_x11_clipboard_event_filter(void *message, long *)
void start()
Starts this timer.
The QAbstractEventDispatcher class provides an interface to manage Qt&#39;s event queue.
static QMimeData * clipboardData
The QMap class is a template class that provides a skip-list-based dictionary.
Definition: qdatastream.h:67
static Bool qt_init_timestamp_scanner(Display *, XEvent *event, XPointer arg)
bool qt_xfixes_clipboard_changed(Window clipboardOwner, Time timestamp)
void connectNotify(const char *)
Internal optimization for Windows.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition: qobject.cpp:1650