Qt 4.8
qmotifdnd_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 /* The following copyright notice pertains to the code as contributed
43 to Qt, not to Nokia's modifications. It is replicated
44 in doc/dnd.doc, where the documentation system can see it. */
45 
46 /* Copyright 1996 Daniel Dardailler.
47 
48  Permission to use, copy, modify, distribute, and sell this software
49  for any purpose is hereby granted without fee, provided that the above
50  copyright notice appear in all copies and that both that copyright
51  notice and this permission notice appear in supporting documentation,
52  and that the name of Daniel Dardailler not be used in advertising or
53  publicity pertaining to distribution of the software without specific,
54  written prior permission. Daniel Dardailler makes no representations
55  about the suitability of this software for any purpose. It is
56  provided "as is" without express or implied warranty.
57 
58  Modifications Copyright 1999 Matt Koss, under the same license as
59  above.
60 ************************************************************/
61 
62 /***********************************************************/
63 /* Motif Drag&Drop Dynamic Protocol messaging API code */
64 /* Only requires Xlib layer - not MT safe */
65 /* Author: Daniel Dardailler, daniel@x.org */
66 /* Adapted by: Matt Koss, koss@napri.sk */
67 /* Further adaptions by: Nokia Corporation and/or its subsidiary(-ies) */
68 /***********************************************************/
69 
70 #include "qplatformdefs.h"
71 
72 #include "qapplication.h"
73 
74 #ifndef QT_NO_DRAGANDDROP
75 
76 #include "qdebug.h"
77 #include "qtextcodec.h"
78 #include "qwidget.h"
79 #include "qevent.h"
80 #include "qt_x11_p.h"
81 #include "qx11info_x11.h"
82 #include "qiodevice.h"
83 #include "qdnd_p.h"
84 
85 #include <stdlib.h>
86 
88 
90 static QWidget *dropWidget = 0;
92 
93 static Atom Dnd_selection = 0;
94 static Time Dnd_selection_time;
95 
96 static Atom * src_targets ;
98 
99 // Motif definitions
100 #define DndVersion 1
101 #define DndRevision 0
102 #define DndIncludeVersion (DndVersion * 10 + DndRevision)
103 
104 /* The following values are used in the DndData structure */
105 
106 /* protocol style */
107 #define DND_DRAG_NONE 0
108 #define DND_DRAG_DROP_ONLY 1
109 #define DND_DRAG_DYNAMIC 5
110 
111 /* message type */
112 #define DND_TOP_LEVEL_ENTER 0
113 #define DND_TOP_LEVEL_LEAVE 1
114 #define DND_DRAG_MOTION 2
115 #define DND_DROP_SITE_ENTER 3
116 #define DND_DROP_SITE_LEAVE 4
117 #define DND_DROP_START 5
118 #define DND_OPERATION_CHANGED 8
119 
120 /* operation(s) */
121 #define DND_NOOP 0L
122 #define DND_MOVE (1L << 0)
123 #define DND_COPY (1L << 1)
124 #define DND_LINK (1L << 2)
125 
126 static Qt::DropActions DndOperationsToQtDropActions(uchar op)
127 {
128  Qt::DropActions actions = Qt::IgnoreAction;
129  if (op | DND_MOVE)
130  actions |= Qt::MoveAction;
131  if (op | DND_COPY)
132  actions |= Qt::CopyAction;
133  if (op | DND_LINK)
134  actions |= Qt::LinkAction;
135  return actions;
136 }
137 
139 {
140  switch (action & Qt::ActionMask) {
141  case Qt::CopyAction:
142  default:
143  return DND_COPY;
144  case Qt::MoveAction:
145  return DND_MOVE;
146  case Qt::LinkAction:
147  return DND_LINK;
148  }
149 }
150 
151 
152 /* status */
153 #define DND_NO_DROP_SITE 1
154 #define DND_INVALID_DROP_SITE 2
155 #define DND_VALID_DROP_SITE 3
156 
157 /* completion */
158 #define DND_DROP 0
159 #define DND_DROP_HELP 1
160 #define DND_DROP_CANCEL 2
161 
162 #define BYTE unsigned char
163 #define CARD32 unsigned int
164 #define CARD16 unsigned short
165 #define INT16 signed short
166 
167 /* Client side structure used in the API */
168 typedef struct {
169  unsigned char reason; /* message type: DND_TOP_LEVEL_ENTER, etc */
170  Time time ;
171  unsigned char operation;
172  unsigned char operations;
173  unsigned char status;
174  unsigned char completion;
175  short x ;
176  short y ;
179 } DndData ;
180 
181 
182 typedef struct _DndSrcProp {
187 } DndSrcProp ;
188 
189 typedef struct _DndReceiverProp {
198 } DndReceiverProp ;
199 
200 /* need to use some union hack since window and property are in
201  different order depending on the message ... */
202 typedef struct _DndTop {
205 } DndTop ;
206 
207 typedef struct _DndPot {
212 } DndPot ;
213 
214 typedef struct _DndMessage {
219  union {
222  } data ;
223 } DndMessage ;
224 
225 typedef struct {
230  /* then come series of CARD16,CARD32,CARD32,CARD32... */
231 } DndTargets;
232 
233 
234 /* protocol version */
235 #define DND_PROTOCOL_VERSION 0
236 
237 
238 #define DND_EVENT_TYPE_MASK ((BYTE)0x80)
239 #define DND_EVENT_TYPE_SHIFT 7
240 #define DND_CLEAR_EVENT_TYPE ((BYTE)0x7F)
241 
242 /* message_type is data[0] of the client_message
243  this return 1 (receiver bit up) or 0 (initiator) */
244 #define DND_GET_EVENT_TYPE(message_type) \
245 ((char) (((message_type) & DND_EVENT_TYPE_MASK) >> DND_EVENT_TYPE_SHIFT))
246 
247 /* event_type can be 0 (initiator) or 1 (receiver) */
248 #define DND_SET_EVENT_TYPE(event_type) \
249 (((BYTE)(event_type) << DND_EVENT_TYPE_SHIFT) & DND_EVENT_TYPE_MASK)
250 
251 
252 #define DND_OPERATION_MASK ((CARD16) 0x000F)
253 #define DND_OPERATION_SHIFT 0
254 #define DND_STATUS_MASK ((CARD16) 0x00F0)
255 #define DND_STATUS_SHIFT 4
256 #define DND_OPERATIONS_MASK ((CARD16) 0x0F00)
257 #define DND_OPERATIONS_SHIFT 8
258 #define DND_COMPLETION_MASK ((CARD16) 0xF000)
259 #define DND_COMPLETION_SHIFT 12
260 
261 #define DND_GET_OPERATION(flags) \
262 ((unsigned char) \
263 (((flags) & DND_OPERATION_MASK) >> DND_OPERATION_SHIFT))
264 
265 #define DND_SET_OPERATION(operation) \
266 (((CARD16)(operation) << DND_OPERATION_SHIFT)\
267 & DND_OPERATION_MASK)
268 
269 #define DND_GET_STATUS(flags) \
270 ((unsigned char) \
271 (((flags) & DND_STATUS_MASK) >> DND_STATUS_SHIFT))
272 
273 #define DND_SET_STATUS(status) \
274 (((CARD16)(status) << DND_STATUS_SHIFT)\
275 & DND_STATUS_MASK)
276 
277 #define DND_GET_OPERATIONS(flags) \
278 ((unsigned char) \
279 (((flags) & DND_OPERATIONS_MASK) >> DND_OPERATIONS_SHIFT))
280 
281 #define DND_SET_OPERATIONS(operation) \
282 (((CARD16)(operation) << DND_OPERATIONS_SHIFT)\
283 & DND_OPERATIONS_MASK)
284 
285 #define DND_GET_COMPLETION(flags) \
286 ((unsigned char) \
287 (((flags) & DND_COMPLETION_MASK) >> DND_COMPLETION_SHIFT))
288 
289 #define DND_SET_COMPLETION(completion) \
290 (((CARD16)(completion) << DND_COMPLETION_SHIFT)\
291 & DND_COMPLETION_MASK)
292 
293 
294 #define SWAP4BYTES(l) {\
295 struct { unsigned t :32;} bit32;\
296 char n, *tp = (char *) &bit32;\
297 bit32.t = l;\
298 n = tp[0]; tp[0] = tp[3]; tp[3] = n;\
299 n = tp[1]; tp[1] = tp[2]; tp[2] = n;\
300 l = bit32.t;\
301 }
302 
303 #define SWAP2BYTES(s) {\
304 struct { unsigned t :16; } bit16;\
305 char n, *tp = (char *) &bit16;\
306 bit16.t = s;\
307 n = tp[0]; tp[0] = tp[1]; tp[1] = n;\
308 s = bit16.t;\
309 }
310 
311 
314 static unsigned char DndByteOrder ();
315 
316 
317 /***** Targets/Index stuff */
318 
319 typedef struct {
323 
324 typedef struct {
326  DndTargetsTableEntry entries;
328 
329 
331  int index,
332  Atom ** targets);
333 
334 extern void qt_x11_intern_atom(const char *, Atom *);
335 
337 
338 static unsigned char DndByteOrder ()
339 {
340  static unsigned char byte_order = 0;
341 
342  if (!byte_order) {
343  unsigned int endian = 1;
344  byte_order = (*((char *)&endian))?'l':'B';
345  }
346  return byte_order ;
347 }
348 
349 
350 
351 static void DndReadSourceProperty(Display * dpy,
352  Window window, Atom dnd_selection,
353  Atom ** targets, unsigned short * num_targets)
354 {
355  unsigned char *retval = 0;
356  Atom type ;
357  int format ;
358  unsigned long bytesafter, lengthRtn;
359 
360  if ((XGetWindowProperty (dpy, window, dnd_selection, 0L, 100000L,
361  False, ATOM(_MOTIF_DRAG_INITIATOR_INFO), &type,
362  &format, &lengthRtn, &bytesafter,
363  &retval) != Success)
364  || (type == XNone)) {
365  *num_targets = 0;
366  return ;
367  }
368 
369  DndSrcProp * src_prop = (DndSrcProp *)retval;
370 
371  if (src_prop->byte_order != DndByteOrder()) {
372  SWAP2BYTES(src_prop->target_index);
373  SWAP4BYTES(src_prop->selection);
374  }
375 
376  *num_targets = _DndIndexToTargets(dpy, src_prop->target_index, targets);
377 
378  XFree((char*)src_prop);
379 }
380 
381 
382 /* Position the _MOTIF_DRAG_RECEIVER_INFO property on the dropsite window.
383  Called by the receiver of the drop to indicate the
384  supported protocol style : dynamic, drop_only or none */
386  unsigned char protocol_style)
387 {
388  DndReceiverProp receiver_prop;
389 
390  // squelch potential valgrind errors about uninitialized reads
391  memset(&receiver_prop, 0, sizeof(receiver_prop));
392 
393  receiver_prop.byte_order = DndByteOrder() ;
394  receiver_prop.protocol_version = DND_PROTOCOL_VERSION;
395  receiver_prop.protocol_style = protocol_style ;
396  receiver_prop.proxy_window = XNone ;
397  receiver_prop.num_drop_sites = 0 ;
398  receiver_prop.total_size = sizeof(DndReceiverProp);
399 
400  /* write the buffer to the property */
401  XChangeProperty (dpy, window, ATOM(_MOTIF_DRAG_RECEIVER_INFO), ATOM(_MOTIF_DRAG_RECEIVER_INFO),
402  8, PropModeReplace,
403  (unsigned char *)&receiver_prop,
404  sizeof(DndReceiverProp));
405 }
406 
407 
408 /* protocol style equiv (preregister stuff really) */
409 #define DND_DRAG_DROP_ONLY_EQUIV 3
410 #define DND_DRAG_DYNAMIC_EQUIV1 2
411 #define DND_DRAG_DYNAMIC_EQUIV2 4
412 
413 
414 /* Produce a client message to be sent by the caller */
416  XClientMessageEvent *cm,
417  DndData * dnd_data,
418  char receiver)
419 {
420  DndMessage * dnd_message = (DndMessage*)&cm->data.b[0] ;
421 
422  cm->display = dpy;
423  cm->type = ClientMessage;
424  cm->serial = LastKnownRequestProcessed(dpy);
425  cm->send_event = True;
426  cm->window = window;
427  cm->format = 8;
428  cm->message_type = ATOM(_MOTIF_DRAG_AND_DROP_MESSAGE);
429 
430  dnd_message->reason = dnd_data->reason | DND_SET_EVENT_TYPE(receiver);
431 
432  dnd_message->byte_order = DndByteOrder();
433 
434  /* we're filling in flags with more stuff that necessary,
435  depending on the reason, but it doesn't matter */
436  dnd_message->flags = 0 ;
437  dnd_message->flags |= DND_SET_STATUS(dnd_data->status) ;
438  dnd_message->flags |= DND_SET_OPERATION(dnd_data->operation) ;
439  dnd_message->flags |= DND_SET_OPERATIONS(dnd_data->operations) ;
440  dnd_message->flags |= DND_SET_COMPLETION(dnd_data->completion) ;
441 
442  dnd_message->time = dnd_data->time ;
443 
444  switch(dnd_data->reason) {
445  case DND_DROP_SITE_LEAVE: break ;
446  case DND_TOP_LEVEL_ENTER:
447  case DND_TOP_LEVEL_LEAVE:
448  dnd_message->data.top.src_window = dnd_data->src_window ;
449  dnd_message->data.top.property = dnd_data->property ;
450  break ; /* cannot fall through since the byte layout is different in
451  both set of messages, see top and pot union stuff */
452 
453  case DND_DRAG_MOTION:
455  case DND_DROP_SITE_ENTER:
456  case DND_DROP_START:
457  dnd_message->data.pot.x = dnd_data->x ; /* mouse position */
458  dnd_message->data.pot.y = dnd_data->y ;
459  dnd_message->data.pot.src_window = dnd_data->src_window ;
460  dnd_message->data.pot.property = dnd_data->property ;
461  break ;
462  default:
463  break ;
464  }
465 
466 }
467 
468 static Bool DndParseClientMessage(XClientMessageEvent *cm, DndData * dnd_data,
469  char * receiver)
470 {
471  DndMessage * dnd_message = (DndMessage*)&cm->data.b[0] ;
472 
473  if (cm->message_type != ATOM(_MOTIF_DRAG_AND_DROP_MESSAGE)) {
474  return False ;
475  }
476 
477  if (dnd_message->byte_order != DndByteOrder()) {
478  SWAP2BYTES(dnd_message->flags);
479  SWAP4BYTES(dnd_message->time);
480  } /* do the rest in the switch */
481 
482  dnd_data->reason = dnd_message->reason ;
483  if (DND_GET_EVENT_TYPE(dnd_data->reason))
484  *receiver = 1 ;
485  else
486  *receiver = 0 ;
487  dnd_data->reason &= DND_CLEAR_EVENT_TYPE ;
488 
489  dnd_data->time = dnd_message->time ;
490 
491  /* we're reading in more stuff that necessary. but who cares */
492  dnd_data->status = DND_GET_STATUS(dnd_message->flags) ;
493  dnd_data->operation = DND_GET_OPERATION(dnd_message->flags) ;
494  dnd_data->operations = DND_GET_OPERATIONS(dnd_message->flags) ;
495  dnd_data->completion = DND_GET_COMPLETION(dnd_message->flags) ;
496 
497  switch(dnd_data->reason) {
498  case DND_TOP_LEVEL_ENTER:
499  case DND_TOP_LEVEL_LEAVE:
500  if (dnd_message->byte_order != DndByteOrder()) {
501  SWAP4BYTES(dnd_message->data.top.src_window);
502  SWAP4BYTES(dnd_message->data.top.property);
503  }
504  dnd_data->src_window = dnd_message->data.top.src_window ;
505  dnd_data->property = dnd_message->data.top.property ;
506  break ; /* cannot fall through, see above comment in write msg */
507 
508  case DND_DRAG_MOTION:
510  case DND_DROP_SITE_ENTER:
511  case DND_DROP_START:
512  if (dnd_message->byte_order != DndByteOrder()) {
513  SWAP2BYTES(dnd_message->data.pot.x);
514  SWAP2BYTES(dnd_message->data.pot.y);
515  SWAP4BYTES(dnd_message->data.pot.property);
516  SWAP4BYTES(dnd_message->data.pot.src_window);
517  }
518  dnd_data->x = dnd_message->data.pot.x ;
519  dnd_data->y = dnd_message->data.pot.y ;
520  dnd_data->property = dnd_message->data.pot.property ;
521  dnd_data->src_window = dnd_message->data.pot.src_window ;
522  break ;
523 
524  case DND_DROP_SITE_LEAVE:
525  break;
526  default:
527  break ;
528  }
529 
530  return True ;
531 }
532 
533 
535 {
536  Atom type;
537  int format;
538  unsigned long size;
539  unsigned long bytes_after;
540  unsigned char *property = 0;
541  Window motif_window ;
542 
543  /* this version does no caching, so it's slow: round trip each time */
544 
545  if ((XGetWindowProperty (display, RootWindow(display, 0),
547  0L, 100000L, False, AnyPropertyType,
548  &type, &format, &size, &bytes_after,
549  &property) == Success) &&
550  (type != XNone)) {
551  motif_window = *(Window *)property;
552  } else {
553  XSetWindowAttributes sAttributes;
554 
555  /* really, this should be done on a separate connection,
556  with XSetCloseDownMode (RetainPermanent), so that
557  others don't have to recreate it; hopefully, some real
558  Motif application will be around to do it */
559 
560  sAttributes.override_redirect = True;
561  sAttributes.event_mask = PropertyChangeMask;
562  motif_window = XCreateWindow (display,
563  RootWindow (display, 0),
564  -170, -560, 1, 1, 0, 0,
565  InputOnly, CopyFromParent,
566  (CWOverrideRedirect |CWEventMask),
567  &sAttributes);
568  XMapWindow (display, motif_window);
569  }
570 
571  if (property) {
572  XFree ((char *)property);
573  }
574 
575  return (motif_window);
576 }
577 
578 
579 static DndTargetsTable TargetsTable(Display *display)
580 {
581  Atom type;
582  int format;
583  unsigned long size;
584  unsigned long bytes_after;
585  Window motif_window = MotifWindow(display) ;
586  unsigned char *retval;
587  DndTargetsTable targets_table ;
588  int i,j ;
589  char * target_data ;
590 
591  /* this version does no caching, so it's slow: round trip each time */
592  /* ideally, register for property notify on this target_list
593  atom and update when necessary only */
594 
595  if ((XGetWindowProperty (display, motif_window,
596  ATOM(_MOTIF_DRAG_TARGETS), 0L, 100000L,
597  False, ATOM(_MOTIF_DRAG_TARGETS),
598  &type, &format, &size, &bytes_after,
599  &retval) != Success) ||
600  type == XNone) {
601  qWarning("QMotifDND: Cannot get property on Motif window");
602  return 0;
603  }
604 
605  DndTargets * target_prop = (DndTargets *)retval;
606 
607  if (target_prop->protocol_version != DND_PROTOCOL_VERSION) {
608  qWarning("QMotifDND: Protocol mismatch");
609  }
610 
611  if (target_prop->byte_order != DndByteOrder()) {
612  /* need to swap num_target_lists and size */
613  SWAP2BYTES(target_prop->num_target_lists);
614  SWAP4BYTES(target_prop->data_size);
615  }
616 
617  /* now parse DndTarget prop data in a TargetsTable */
618 
619  targets_table = (DndTargetsTable)malloc(sizeof(DndTargetsTableRec));
620  targets_table->num_entries = target_prop->num_target_lists ;
621  targets_table->entries = (DndTargetsTableEntry)
622  malloc(sizeof(DndTargetsTableEntryRec) * target_prop->num_target_lists);
623 
624  target_data = (char*)target_prop + sizeof(*target_prop) ;
625 
626  for (i = 0 ; i < targets_table->num_entries; i++) {
627  CARD16 num_targets ;
628  CARD32 atom ;
629 
630  memcpy(&num_targets, target_data, 2);
631  target_data += 2;
632 
633  /* potential swap needed here */
634  if (target_prop->byte_order != DndByteOrder())
635  SWAP2BYTES(num_targets);
636 
637  targets_table->entries[i].num_targets = num_targets ;
638  targets_table->entries[i].targets = (Atom *)
639  malloc(sizeof(Atom) * targets_table->entries[i].num_targets);
640 
641 
642  for (j = 0; j < num_targets; j++) {
643  memcpy(&atom, target_data, 4);
644  target_data += 4;
645 
646  /* another potential swap needed here */
647  if (target_prop->byte_order != DndByteOrder())
648  SWAP4BYTES(atom);
649 
650  targets_table->entries[i].targets[j] = (Atom) atom ;
651  }
652  }
653 
654  if (target_prop) {
655  XFree((char *)target_prop);
656  }
657 
658  return targets_table ;
659 }
660 
661 
663  int index,
664  Atom ** targets)
665 {
666  DndTargetsTable targets_table;
667  int i ;
668 
669  /* again, slow: no caching here, alloc/free each time */
670 
671  if (!(targets_table = TargetsTable (display)) ||
672  (index >= targets_table->num_entries)) {
673  if (targets_table)
674  XFree((char*)targets_table);
675  return 0;
676  }
677 
678  /* transfer the correct target list index */
679  *targets = (Atom*)malloc(sizeof(Atom)*targets_table->
680  entries[index].num_targets);
681  memcpy((char*)*targets,
682  (char*)targets_table->entries[index].targets,
683  sizeof(Atom)*targets_table->entries[index].num_targets);
684 
685  /* free the target table and its guts */
686  for (i=0 ; i < targets_table->num_entries; i++)
687  XFree((char*)targets_table->entries[i].targets);
688 
689  int tmp = targets_table->entries[index].num_targets;
690  XFree((char*)targets_table);
691 
692  return tmp; // targets_table->entries[index].num_targets;
693 }
694 
695 
697 {
698  if (!motifdnd_active)
699  return 0; // should not happen
700 
701  if (n >= num_src_targets)
702  return 0;
703 
704  Atom target = src_targets[n];
705 
706  if (target == XA_STRING)
707  return "text/plain;charset=ISO-8859-1";
708  if (target == ATOM(UTF8_STRING))
709  return "text/plain;charset=UTF-8";
710  if (target == ATOM(COMPOUND_TEXT))
711  return QByteArray("text/plain;charset=") + QTextCodec::codecForLocale()->name();
712  if (target == ATOM(TEXT))
713  return "text/plain";
714 
715  return ("x-motif-dnd/" + X11->xdndAtomToString(target));
716 }
717 
718 
720 {
721  QByteArray result;
722 
723  if (Dnd_selection == 0 || !dropWidget)
724  return result;
725 
726  // try to convert the selection to the requested property
727  // qDebug("trying to convert to '%s'", mimeType);
728 
729  int n=0;
730  QByteArray f;
731  do {
732  f = motifdndFormat(n);
733  if (f.isEmpty())
734  return result;
735  n++;
736  } while(qstricmp(mimeType, f.data()));
737 
738  Atom conversion_type = XNone;
739  if (f == "text/plain;charset=ISO-8859-1") {
740  conversion_type = XA_STRING;
741  } else if (f == "text/plain;charset=UTF-8") {
742  conversion_type = ATOM(UTF8_STRING);
743  } else if (f == (QByteArray("text/plain;charset=") + QTextCodec::codecForLocale()->name())) {
744  conversion_type = ATOM(COMPOUND_TEXT);
745  } else if (f == "text/plain") {
746  conversion_type = ATOM(TEXT);
747  } else if (f.startsWith("x-motif-dnd/")) {
748  // strip off the "x-motif-dnd/" prefix
749  conversion_type = X11->xdndStringToAtom(f.remove(0, 12));
750  }
751 
752  if (XGetSelectionOwner(X11->display, Dnd_selection) == XNone) {
753  return result; // should never happen?
754  }
755 
756  QWidget* tw = dropWidget;
757  if ((dropWidget->windowType() == Qt::Desktop)) {
758  tw = new QWidget;
759  }
760 
761  // convert selection to the appropriate type
762  XConvertSelection (X11->display, Dnd_selection, conversion_type,
764 
765  XFlush(X11->display);
766 
767  XEvent xevent;
768  bool got=X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000);
769  if (got) {
770  Atom type;
771 
772  if (X11->clipboardReadProperty(tw->internalWinId(), Dnd_selection, true, &result, 0, &type, 0)) {
773  }
774  }
775 
776  // we have to convert selection in order to indicate success to the initiator
777  XConvertSelection (X11->display, Dnd_selection, ATOM(XmTRANSFER_SUCCESS),
779 
780  // wait again for SelectionNotify event
781  X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000);
782 
783  if ((dropWidget->windowType() == Qt::Desktop)) {
784  delete tw;
785  }
786 
787  return result;
788 }
789 
790 
792 {
794 }
795 
796 
797 void QX11Data::motifdndHandle(QWidget *widget, const XEvent * xe, bool /* passive */)
798 {
799  XEvent event = *xe;
800  XClientMessageEvent cm ;
801  DndData dnd_data ;
802  char receiver ;
803 
804  if (!(DndParseClientMessage ((XClientMessageEvent*)&event,
805  &dnd_data, &receiver))) {
806  return;
807  }
808 
809  switch (dnd_data.reason) {
810 
811  case DND_DRAG_MOTION:
812  {
813  QPoint p = widget->mapFromGlobal(QPoint(dnd_data.x, dnd_data.y));
814  QWidget *c = widget->childAt(p);
815 
816  if (!c || !c->acceptDrops()) {
817  // not over a drop site
818  if (dropWidget) {
819  QDragLeaveEvent dragLeaveEvent;
820  QApplication::sendEvent(dropWidget, &dragLeaveEvent);
821 
822  dropWidget = 0;
824 
825  dnd_data.reason = DND_DROP_SITE_LEAVE;
826  dnd_data.time = X11->time;
827  DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
828  XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm) ;
829  } else {
830  dnd_data.reason = DND_DRAG_MOTION;
831  dnd_data.status = DND_NO_DROP_SITE;
832  dnd_data.time = X11->time;
833  dnd_data.operation = DND_NOOP;
834  dnd_data.operations = DND_NOOP;
835  DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
836  XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm) ;
837  }
838  } else {
839  Q_ASSERT(c != 0);
840  p = c->mapFrom(widget, p);
841 
842  if (dropWidget != c) {
843  if (dropWidget) {
844  QDragLeaveEvent le;
845  QApplication::sendEvent(dropWidget, &le);
846  }
847 
848  dropWidget = c;
850 
851  const Qt::DropActions possibleActions =
853  QDragEnterEvent de(p, possibleActions, QDragManager::self()->dropData,
855  QApplication::sendEvent(dropWidget, &de);
856 
857  dnd_data.reason = DND_DROP_SITE_ENTER;
858  dnd_data.time = X11->time;
859  if (de.isAccepted()) {
861 
862  dnd_data.status = DND_VALID_DROP_SITE;
864  } else {
865  dnd_data.status = DND_INVALID_DROP_SITE;
866  dnd_data.operation = DND_NOOP;
867  dnd_data.operations = DND_NOOP;
868  }
869  DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
870  XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
871  } else {
872  const Qt::DropActions possibleActions =
874  QDragMoveEvent me(p, possibleActions, QDragManager::self()->dropData,
878  me.accept();
879  }
880  QApplication::sendEvent(dropWidget, &me);
881 
882  dnd_data.reason = DND_DRAG_MOTION;
883  dnd_data.time = X11->time;
884 
885  if (me.isAccepted()) {
887 
888  dnd_data.status = DND_VALID_DROP_SITE;
890  } else {
891  dnd_data.status = DND_INVALID_DROP_SITE;
892  dnd_data.operation = DND_NOOP;
893  dnd_data.operations = DND_NOOP;
894  }
895 
896  DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
897  XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
898  }
899  }
900 
901  break;
902  }
903 
904  case DND_TOP_LEVEL_ENTER:
905  {
906  /* get the size of our drop site for later use */
907 
908  motifdnd_active = true;
909  sourceWindow = dnd_data.src_window;
910 
911  /* no answer needed, just read source property */
912  DndReadSourceProperty (event.xclient.display,
913  sourceWindow,
914  dnd_data.property,
916 
917  break;
918  }
919 
920  case DND_TOP_LEVEL_LEAVE:
921  {
922  XEvent nextEvent;
923  if (XCheckTypedWindowEvent(X11->display, widget->winId(), ClientMessage, &nextEvent)) {
924  // we just want to check, not eat (should use XPeekIfEvent)
925  XPutBackEvent(X11->display, &nextEvent);
926 
927  if (DndParseClientMessage (&nextEvent.xclient, &dnd_data, &receiver)
928  && dnd_data.reason == DND_DROP_START) {
929  // expecting drop next, keeping DnD alive
930  break;
931  }
932  }
933 
934  // not expecting drop, need to send drag leave events and such here
935  if (dropWidget) {
936  QDragLeaveEvent le;
937  QApplication::sendEvent(dropWidget, &le);
938  }
939 
941  dropWidget = 0;
943 
944  motifdnd_active = false;
945 
946  break;
947  }
948 
950  // ### need to echo
951  break;
952 
953  case DND_DROP_START:
954  {
955  Q_ASSERT(motifdnd_active);
956  Q_ASSERT(sourceWindow == dnd_data.src_window);
957 
958  if (!dropWidget || lastAcceptedAction == Qt::IgnoreAction) {
959  // echo DROP_START
960  dnd_data.reason = DND_DROP_START;
961  dnd_data.status = DND_NO_DROP_SITE;
962  dnd_data.operation = DND_NOOP;
963  dnd_data.operations = DND_NOOP;
964  DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, 0);
965  XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
966 
967  // we have to convert selection in order to indicate failure to the initiator
968  XConvertSelection (X11->display, dnd_data.property, ATOM(XmTRANSFER_FAILURE),
969  dnd_data.property, dnd_data.src_window, dnd_data.time);
970 
971  if (dropWidget) {
972  QDragLeaveEvent e;
973  QApplication::sendEvent(dropWidget, &e);
974  }
975 
976  motifdnd_active = false;
978  dropWidget = 0;
980 
981  return;
982  }
983 
984  // store selection and its time
985  Dnd_selection = dnd_data.property;
986  Dnd_selection_time = dnd_data.time;
987 
988  QPoint p(dnd_data.x, dnd_data.y);
993  de.accept();
994  }
995  QApplication::sendEvent(dropWidget, &de);
996 
997  // reset
999  Dnd_selection_time = 0;
1000 
1001  // echo DROP_START depending on the result of the dropEvent
1002  if (de.isAccepted()) {
1003  dnd_data.reason = DND_DROP_START;
1004  dnd_data.status = DND_VALID_DROP_SITE;
1005  dnd_data.operation = QtDropActionToDndOperation(de.dropAction());
1006  } else {
1007  dnd_data.reason = DND_DROP_START;
1008  dnd_data.status = DND_NO_DROP_SITE;
1009  dnd_data.operation = DND_NOOP;
1010  dnd_data.operations = DND_NOOP;
1011  }
1012  DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, 0);
1013  XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
1014 
1015  sourceWindow = XNone;
1016  dropWidget = 0;
1018 
1019  motifdnd_active = false;
1020 
1021  break;
1022  }
1023 
1024  default:
1025  break;
1026  } // end of switch (dnd_data.reason)
1027 }
1028 
1030 
1031 #endif // QT_NO_DRAGANDDROP
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
static QTextCodec * codecForLocale()
Returns a pointer to the codec most suitable for this locale.
#define DND_DROP_SITE_ENTER
#define DND_SET_EVENT_TYPE(event_type)
int type
Definition: qmetatype.cpp:239
unsigned char c[8]
Definition: qnumeric_p.h:62
static Atom * src_targets
BYTE protocol_version
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
EventRef event
QPointer< QWidget > widget
#define BYTE
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
static Bool DndParseClientMessage(XClientMessageEvent *cm, DndData *dnd_data, char *receiver)
#define DND_SET_OPERATION(operation)
static Window MotifWindow(Display *display)
void motifdndEnable(QWidget *, bool)
Window src_window
#define DND_OPERATION_CHANGED
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void motifdndHandle(QWidget *, const XEvent *, bool)
static void DndReadSourceProperty(Display *dpy, Window window, Atom dnd_selection, Atom **targets, unsigned short *num_targets)
DndTargetsTableEntry entries
QVariant motifdndObtainData(const char *format)
#define SWAP2BYTES(s)
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
void setDropAction(Qt::DropAction action)
Sets the action to be performed on the data by the target.
Definition: qevent.cpp:2746
#define DND_GET_COMPLETION(flags)
Qt::DropAction dropAction() const
Returns the action to be performed on the data by the target.
Definition: qevent.h:494
void accept()
Calls QDropEvent::accept().
Definition: qevent.h:539
static DndTargetsTable TargetsTable(Display *display)
void qt_x11_intern_atom(const char *, Atom *)
#define DND_GET_OPERATION(flags)
#define DND_INVALID_DROP_SITE
static unsigned char DndByteOrder()
static uchar QtDropActionToDndOperation(Qt::DropAction action)
The QDragMoveEvent class provides an event which is sent while a drag and drop action is in progress...
Definition: qevent.h:530
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
bool startsWith(const QByteArray &a) const
Returns true if this byte array starts with byte array ba; otherwise returns false.
#define X11
Definition: qt_x11_p.h:724
struct _DndTop DndTop
static Atom Dnd_selection
QByteArray motifdndFormat(int n)
static ushort num_src_targets
union _XEvent XEvent
Definition: qwindowdefs.h:116
#define ATOM(x)
Definition: qt_x11_p.h:723
static Time Dnd_selection_time
#define DND_TOP_LEVEL_LEAVE
unsigned char uchar
Definition: qglobal.h:994
NSWindow * window
CARD32 src_window
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Q_GUI_EXPORT EGLDisplay display()
Definition: qegl.cpp:589
bool isAccepted() const
Definition: qcoreevent.h:307
#define DND_PROTOCOL_VERSION
unsigned char operation
#define DND_VALID_DROP_SITE
const char * name
QWidget * childAt(int x, int y) const
Returns the visible child widget at the position ({x}, {y}) in the widget&#39;s coordinate system...
Definition: qwidget.h:934
struct _DndSrcProp DndSrcProp
#define DND_DROP_START
#define DND_SET_STATUS(status)
static Qt::DropActions DndOperationsToQtDropActions(uchar op)
#define DND_SET_COMPLETION(completion)
#define CARD16
Q_CORE_EXPORT void qWarning(const char *,...)
#define DND_GET_STATUS(flags)
static const char * data(const QByteArray &arr)
CARD32 src_window
#define DND_NO_DROP_SITE
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
The QDragLeaveEvent class provides an event that is sent to a widget when a drag and drop action leav...
Definition: qevent.h:577
DropAction
Definition: qnamespace.h:1597
#define DND_SET_OPERATIONS(operation)
#define DND_GET_OPERATIONS(flags)
bool acceptDrops
whether drop events are enabled for this widget
Definition: qwidget.h:197
#define CARD32
static QDragManager * self()
Definition: qdnd.cpp:163
virtual QByteArray name() const =0
QTextCodec subclasses must reimplement this function.
unsigned char reason
struct _DndReceiverProp DndReceiverProp
static const MacSpecialKey entries[NumEntries]
static ushort _DndIndexToTargets(Display *display, int index, Atom **targets)
#define DND_TOP_LEVEL_ENTER
struct _XDisplay Display
Definition: qwindowdefs.h:115
The QDropEvent class provides an event which is sent when a drag and drop action is completed...
Definition: qevent.h:476
#define INT16
static Qt::KeyboardModifiers keyboardModifiers()
Returns the current state of the modifier keys on the keyboard.
static void DndFillClientMessage(Display *dpy, Window window, XClientMessageEvent *cm, DndData *dnd_data, char receiver)
unsigned short ushort
Definition: qglobal.h:995
unsigned char status
QDropData * dropData
Definition: qdnd_p.h:251
The QDragEnterEvent class provides an event which is sent to a widget when a drag and drop action ent...
Definition: qevent.h:555
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
static void DndWriteReceiverProperty(Display *dpy, Window window, unsigned char protocol_style)
const char * property
Definition: qwizard.cpp:138
if(void) toggleToolbarShown
struct _DndPot DndPot
unsigned char completion
WId internalWinId() const
Returns the window system identifier of the widget, or 0 if the widget is not created yet...
Definition: qwidget.h:244
#define DND_CLEAR_EVENT_TYPE
#define DND_COPY
quint16 index
#define DND_DROP_SITE_LEAVE
QPoint mapFromGlobal(const QPoint &) const
Translates the global screen coordinate pos to widget coordinates.
return(isPopup||isToolTip)
#define DND_GET_EVENT_TYPE(message_type)
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
Qt::WindowType windowType() const
Returns the window type of this widget.
Definition: qwidget.h:937
static Qt::MouseButtons mouseButtons()
Returns the current state of the buttons on the mouse.
WId winId() const
Returns the window system identifier of the widget.
Definition: qwidget.cpp:2557
CARD32 property
#define DND_NOOP
#define SWAP4BYTES(l)
static Window sourceWindow
Q_CORE_EXPORT int qstricmp(const char *, const char *)
QPoint mapFrom(QWidget *, const QPoint &) const
Translates the widget coordinate pos from the coordinate system of parent to this widget&#39;s coordinate...
Definition: qwidget.cpp:4433
static Qt::DropAction lastAcceptedAction
#define DND_DRAG_MOTION
struct _DndMessage DndMessage
union _DndMessage::@205 data
CARD32 property
CARD16 target_index
#define DND_MOVE
CARD32 data_size
QByteArray & remove(int index, int len)
Removes len bytes from the array, starting at index position pos, and returns a reference to the arra...
#define DND_DRAG_DYNAMIC
static QWidget * dropWidget
#define DND_LINK
unsigned char operations
CARD16 num_target_lists
struct DndTargetsTableEntryRec * DndTargetsTableEntry
struct DndTargetsTableRec * DndTargetsTable