Logo ROOT   6.14/05
Reference Guide
TGDNDManager.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Bertrand Bellenot 19/04/07
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TGFrame.h"
13 #include "TTimer.h"
14 #include "TGDNDManager.h"
15 #include "TRootCanvas.h"
16 
17 #define ROOTDND_PROTOCOL_VERSION 4
18 #define XA_ATOM ((Atom_t) 4)
19 #define XA_WINDOW ((Atom_t) 33)
20 
24 
32 
38 
42 
45 
47 
48 // TODO:
49 // - add an TGFrame::HandleDNDStatus event handler?
50 // - implement INCR protocol
51 // - cache several requests?
52 
54 
56 
57 //_____________________________________________________________________________
58 //
59 // TGDragWindow
60 //
61 // Window used as drag icon during drag and drop operations.
62 //_____________________________________________________________________________
63 
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 /// TGDragWindow constructor.
68 
70  UInt_t options, Pixel_t back) :
71  TGFrame(p, 32, 32, options, back)
72 {
73  if (fgDefaultCursor == kNone) {
74  fgDefaultCursor = gVirtualX->CreateCursor(kTopLeft);
75  }
76 
77  fPic = pic;
78  fMask = mask;
79 
81 
83  wattr.fSaveUnder = kTRUE;
84  wattr.fOverrideRedirect = kTRUE;
85 
86  gVirtualX->ChangeWindowAttributes(fId, &wattr);
87 
88  int x, y;
89 
90  gVirtualX->GetWindowSize(fPic, x, y, fPw, fPh);
91 
92  wattr.fMask = kWAOverrideRedirect;
93  wattr.fOverrideRedirect = kTRUE;
94 
95  // This input window is used to make the dragging smoother when using
96  // highly complicated shapped windows (like labels and semitransparent
97  // icons), for some obscure reason most of the motion events get lost
98  // while the pointer is over the shaped window.
99 
100  //fInput = gVirtualX->CreateWindow(fParent->GetId(), 0, 0, fWidth,
101  // fHeight, 0, 0, 0, 0, &wattr, 0);
102  fInput = fId;
103 
105 
106  gVirtualX->ShapeCombineMask(fId, 0, 0, fMask);
107 
108  gVirtualX->SetCursor(fId, fgDefaultCursor);
109 }
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 /// TGDragWindow destructor.
113 
115 {
116  //gVirtualX->DestroyWindow(fInput);
117 }
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 /// Map TGDragWindow.
121 
123 {
125  //gVirtualX->MapWindow(fInput);
126 }
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Unmap TGDragWindow.
130 
132 {
134  //gVirtualX->UnmapWindow(fInput);
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// Raise TGDragWindow.
139 
141 {
143  //gVirtualX->RaiseWindow(fInput);
144 }
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// Lower TGDragWindow.
148 
150 {
151  //gVirtualX->LowerWindow(fInput);
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Map and Raise TGDragWindow.
157 
159 {
161  //gVirtualX->MapRaised(fInput);
162 }
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Layout TGDragWindow.
166 
168 {
169  gVirtualX->ShapeCombineMask(fId, 0, 0, fMask);
170 }
171 
172 ////////////////////////////////////////////////////////////////////////////////
173 /// Redraw TGDragWindow.
174 
176 {
177  gVirtualX->CopyArea(fPic, fId, GetBckgndGC()(), 0, 0, fWidth, fHeight, 0, 0);
178 }
179 
180 //_____________________________________________________________________________
181 //
182 // TGDNDManager
183 //
184 // Central Drag and Drop manager for ROOT.
185 //_____________________________________________________________________________
186 
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 /// TGDNDManager constructor.
191 
192 TGDNDManager::TGDNDManager(TGFrame *toplevel, Atom_t * /*typelist*/)
193 {
194  if (gDNDManager)
195  // coverity[uninit_member]: already done
196  return;
197 
198  fMain = toplevel;
199  fVersion = ROOTDND_PROTOCOL_VERSION;
200  fUseVersion = kTRUE;
201  //fTypelist = typelist;
202  fTypelist = new Atom_t[3];
203  fTypelist[0] = gVirtualX->InternAtom("application/root", kFALSE);
204  fTypelist[1] = gVirtualX->InternAtom("text/uri-list", kFALSE);
205  fTypelist[2] = 0;
206 
207  if (!fgInit) {
208  InitAtoms();
209  fgInit = kTRUE;
210  }
211 
212  //Reset();
213  fDropTimeout = 0;
214 
215  fSource = kNone;
216  fTarget = kNone;
217  fTargetIsDNDAware = kFALSE;
218  fStatusPending = kFALSE;
219  fDropAccepted = kFALSE; // this would become obsoleted by _acceptedAction
220  fAcceptedAction = kNone; // target's accepted action
221  fLocalAction = kNone; // our last specified action when we act as source
222  fDragging = kFALSE;
223  fDragWin = 0;
224  fLocalSource = 0;
225  fLocalTarget = 0;
226  fPic = fMask = kNone;
227  fDraggerTypes = 0;
228  fDropType = kNone;
229  fHotx = fHoty = 0;
230 
232 
233  fDNDNoDropCursor = gVirtualX->CreateCursor(kNoDrop); // kNoDrop
234 
235  // set the aware prop
236 
237  fProxyOurs = kFALSE;
238  gDNDManager = this;
239 }
240 
241 ////////////////////////////////////////////////////////////////////////////////
242 /// TGDNDManager destructor.
243 
245 {
246  // remove the proxy prop if we own it
247  if (fProxyOurs)
248  RemoveRootProxy();
249 
250  // remove the aware prop ant the types list, if any
251  if (fMain) {
252  gVirtualX->DeleteProperty(fMain->GetId(), fgDNDAware);
253  gVirtualX->DeleteProperty(fMain->GetId(), fgDNDTypeList);
254  }
255  if (fDropTimeout) delete fDropTimeout;
256 
257  // delete the drag pixmap, if any
258  if (fDragWin) {
259  fDragWin->DeleteWindow();
260  fDragWin = 0;
261  }
262  if (fPic != kNone) gVirtualX->DeletePixmap(fPic);
263  if (fMask != kNone) gVirtualX->DeletePixmap(fMask);
264 
265  if (fDraggerTypes) delete[] fDraggerTypes;
266  if (fTypelist) delete[] fTypelist;
267 }
268 
269 Atom_t TGDNDManager::GetDNDAware() { return fgDNDAware; }
270 Atom_t TGDNDManager::GetDNDSelection() { return fgDNDSelection; }
271 Atom_t TGDNDManager::GetDNDProxy() { return fgDNDProxy; }
272 Atom_t TGDNDManager::GetDNDEnter() { return fgDNDEnter; }
273 Atom_t TGDNDManager::GetDNDLeave() { return fgDNDLeave; }
274 Atom_t TGDNDManager::GetDNDPosition() { return fgDNDPosition; }
275 Atom_t TGDNDManager::GetDNDStatus() { return fgDNDStatus; }
276 Atom_t TGDNDManager::GetDNDDrop() { return fgDNDDrop; }
277 Atom_t TGDNDManager::GetDNDFinished() { return fgDNDFinished; }
278 Atom_t TGDNDManager::GetDNDVersion() { return fgDNDVersion; }
279 Atom_t TGDNDManager::GetDNDActionCopy() { return fgDNDActionCopy; }
280 Atom_t TGDNDManager::GetDNDActionMove() { return fgDNDActionMove; }
281 Atom_t TGDNDManager::GetDNDActionLink() { return fgDNDActionLink; }
282 Atom_t TGDNDManager::GetDNDActionAsk() { return fgDNDActionAsk; }
283 Atom_t TGDNDManager::GetDNDActionPrivate() { return fgDNDActionPrivate; }
284 Atom_t TGDNDManager::GetDNDTypeList() { return fgDNDTypeList; }
285 Atom_t TGDNDManager::GetDNDActionList() { return fgDNDActionList; }
286 Atom_t TGDNDManager::GetDNDActionDescrip() { return fgDNDActionDescrip; }
287 Atom_t TGDNDManager::GetXCDNDData() { return fgXCDNDData; }
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 /// Initialize drag and drop atoms.
291 
293 {
294  // awareness
295  fgDNDAware = gVirtualX->InternAtom("XdndAware", kFALSE);
296 
297  // selection
298  fgDNDSelection = gVirtualX->InternAtom("XdndSelection", kFALSE);
299 
300  // proxy window
301  fgDNDProxy = gVirtualX->InternAtom("XdndProxy", kFALSE);
302 
303  // messages
304  fgDNDEnter = gVirtualX->InternAtom("XdndEnter", kFALSE);
305  fgDNDLeave = gVirtualX->InternAtom("XdndLeave", kFALSE);
306  fgDNDPosition = gVirtualX->InternAtom("XdndPosition", kFALSE);
307  fgDNDStatus = gVirtualX->InternAtom("XdndStatus", kFALSE);
308  fgDNDDrop = gVirtualX->InternAtom("XdndDrop", kFALSE);
309  fgDNDFinished = gVirtualX->InternAtom("XdndFinished", kFALSE);
310 
311  // actions
312  fgDNDActionCopy = gVirtualX->InternAtom("XdndActionCopy", kFALSE);
313  fgDNDActionMove = gVirtualX->InternAtom("XdndActionMove", kFALSE);
314  fgDNDActionLink = gVirtualX->InternAtom("XdndActionLink", kFALSE);
315  fgDNDActionAsk = gVirtualX->InternAtom("XdndActionAsk", kFALSE);
316  fgDNDActionPrivate = gVirtualX->InternAtom("XdndActionPrivate", kFALSE);
317 
318  // types list
319  fgDNDTypeList = gVirtualX->InternAtom("XdndTypeList", kFALSE);
320  fgDNDActionList = gVirtualX->InternAtom("XdndActionList", kFALSE);
321  fgDNDActionDescrip = gVirtualX->InternAtom("XdndActionDescription", kFALSE);
322 
323  // misc
324  fgXAWMState = gVirtualX->InternAtom("WM_STATE", kFALSE);
325  fgXCDNDData = gVirtualX->InternAtom("_XC_DND_DATA", kFALSE);
326 }
327 
328 static int ArrayLength(Atom_t *a)
329 {
330  // Returns length of array a.
331 
332  int n;
333 
334  for (n = 0; a[n]; n++) { }
335  return n;
336 }
337 
338 ////////////////////////////////////////////////////////////////////////////////
339 /// Check if window win is DND aware.
340 
342 {
343  return gVirtualX->IsDNDAware(win, typelist);
344 }
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// Search for DND aware window at position x,y.
348 
349 Window_t TGDNDManager::FindWindow(Window_t root, int x, int y, int maxd)
350 {
351  if (maxd <= 0) return kNone;
352 
353  if (fDragWin && fDragWin->HasWindow(root)) return kNone;
354 
355  return gVirtualX->FindRWindow(root, fDragWin ? fDragWin->GetId() : 0,
356  fDragWin ? fDragWin->GetInputId() : 0,
357  x, y, maxd);
358 }
359 
360 
361 ////////////////////////////////////////////////////////////////////////////////
362 /// Get root window proxy.
363 
365 {
366  Atom_t actual;
367  Int_t format = 32;
368  ULong_t count, remaining;
369  unsigned char *data = 0;
370  Window_t win, proxy = kNone;
371 
372  // search for XdndProxy property on the root window...
373 
374  // XSync(_dpy, kFALSE); // get to known state...
375  gVirtualX->UpdateWindow(0);
376 
377  //oldhandler = XSetErrorHandler(TGDNDManager::CatchXError);
378  //target_error = kFALSE;
379 
380  gVirtualX->GetProperty(gVirtualX->GetDefaultRootWindow(),
381  fgDNDProxy, 0, 1, kFALSE, XA_WINDOW,
382  &actual, &format, &count, &remaining, &data);
383 
384  if ((actual == XA_WINDOW) && (format == 32) && (count > 0) && data) {
385 
386  // found the XdndProxy property, now check for the proxy window...
387  win = *((Window_t *) data);
388  delete[] data;
389  data = 0;
390 
391  gVirtualX->GetProperty(win, fgDNDProxy, 0, 1, kFALSE, XA_WINDOW,
392  &actual, &format, &count, &remaining, &data);
393 
394  // XSync(_dpy, kFALSE); // force the error...
395  gVirtualX->UpdateWindow(0);
396 
397  if ((actual == XA_WINDOW) && (format == 32) && (count > 0) && data) {
398  if (*((Window_t *) data) == win) {
399 
400  // proxy window exists and is correct
401  proxy = win;
402  }
403  }
404  }
405  if (data) delete[] data;
406  //oldhandler = XSetErrorHandler(oldhandler);
407  return proxy;
408 }
409 
410 ////////////////////////////////////////////////////////////////////////////////
411 /// Handle DND related client messages.
412 
414 {
415  if (event->fHandle == fgDNDEnter) {
416  HandleDNDEnter((Window_t) event->fUser[0], event->fUser[1],
417  (Atom_t *) &event->fUser[2]);
418 
419  } else if (event->fHandle == fgDNDLeave) {
420  HandleDNDLeave((Window_t) event->fUser[0]);
421 
422  } else if (event->fHandle == fgDNDPosition) {
423  HandleDNDPosition((Window_t) event->fUser[0],
424  (Int_t) (event->fUser[2] >> 16) & 0xFFFF, // x_root
425  (Int_t) (event->fUser[2] & 0xFFFF), // y_root
426  (Atom_t) event->fUser[4], // action
427  (Time_t) event->fUser[3]); // timestamp
428 
429  } else if (event->fHandle == fgDNDStatus) {
430  Rectangle_t skip;
431  skip.fX = (event->fUser[2] >> 16) & 0xFFFF;
432  skip.fY = (event->fUser[2] & 0xFFFF);
433  skip.fWidth = (event->fUser[3] >> 16) & 0xFFFF;
434  skip.fHeight = (event->fUser[3] & 0xFFFF);
435 
436  HandleDNDStatus((Window_t) event->fUser[0],
437  (int) (event->fUser[1] & 0x1),
438  skip, (Atom_t) event->fUser[4]);
439 
440  } else if (event->fHandle == fgDNDDrop) {
441  HandleDNDDrop((Window_t) event->fUser[0], (Time_t) event->fUser[2]);
442 
443  } else if (event->fHandle == fgDNDFinished) {
444  HandleDNDFinished((Window_t) event->fUser[0]);
445 
446  } else {
447  return kFALSE; // not for us...
448  }
449  return kTRUE;
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Handle Drop timeout.
454 
456 {
457  if (t == fDropTimeout) {
458  // The drop operation timed out without receiving
459  // status confirmation from the target. Send a
460  // leave message instead (and notify the user or widget).
461  delete fDropTimeout;
462  fDropTimeout = 0;
463 
464  SendDNDLeave(fTarget);
465  fStatusPending = kFALSE;
466 
467  if (fLocalSource) fLocalSource->HandleDNDFinished();
468  return kTRUE;
469  }
470  return kFALSE;
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /// Send DND enter message to target window.
475 
477 {
478  Int_t i, n;
479  Event_t event;
480 
481  event.fType = kClientMessage;
482  event.fWindow = target;
483  event.fHandle = fgDNDEnter;
484  event.fFormat = 32;
485 
486  event.fUser[0] = fMain->GetId(); // from;
487 
488  n = ArrayLength(fTypelist);
489 
490  event.fUser[1] = ((n > 3) ? 1L : 0L) | (fUseVersion << 24);
491 
492  // set the first 1-3 data types
493 
494  for (i = 0; i < 3; ++i)
495  event.fUser[2+i] = (i < n) ? fTypelist[i] : kNone;
496 
497  if (fLocalSource) {
498  TDNDData *dnddata = 0;
499  Atom_t dataType;
500 
501  // get the data type from the drag source widget
502  if (fLocalSource)
503  dnddata = fLocalSource->GetDNDData(0);
504  dataType = dnddata ? (Atom_t) dnddata->fDataType : (Atom_t) kNone;
505  event.fUser[2] = dataType;
506  event.fUser[3] = kNone;
507  event.fUser[4] = kNone;
508  }
509 
510  gVirtualX->SendEvent(target, &event);
511 }
512 
513 ////////////////////////////////////////////////////////////////////////////////
514 /// Send DND leave message to target window.
515 
517 {
518  Event_t event;
519 
520  event.fType = kClientMessage;
521  event.fWindow = target;
522  event.fHandle = fgDNDLeave;
523  event.fFormat = 32;
524 
525  event.fUser[0] = fMain->GetId(); // from;
526  event.fUser[1] = 0L;
527 
528  event.fUser[2] = 0L;
529  event.fUser[3] = 0L;
530  event.fUser[4] = 0L;
531 
532  gVirtualX->SendEvent(target, &event);
533 }
534 
535 ////////////////////////////////////////////////////////////////////////////////
536 /// Send DND position message to target window.
537 
539  Atom_t action, Time_t timestamp)
540 {
541  Event_t event;
542 
543  event.fType = kClientMessage;
544  event.fWindow = target;
545  event.fHandle = fgDNDPosition;
546  event.fFormat = 32;
547 
548  event.fUser[0] = fMain->GetId(); // from;
549  event.fUser[1] = 0L;
550 
551  event.fUser[2] = (x << 16) | y; // root coodinates
552  event.fUser[3] = timestamp; // timestamp for retrieving data
553  event.fUser[4] = action; // requested action
554 
555  gVirtualX->SendEvent(target, &event);
556 }
557 
558 ////////////////////////////////////////////////////////////////////////////////
559 /// Send DND status message to source window.
560 
562 {
563  Event_t event;
564 
565  event.fType = kClientMessage;
566  event.fWindow = source;
567  event.fHandle = fgDNDStatus;
568  event.fFormat = 32;
569 
570  event.fUser[0] = fMain->GetId(); // from;
571  event.fUser[1] = (action == kNone) ? 0L : 1L;
572 
573  event.fUser[2] = 0L; // empty rectangle
574  event.fUser[3] = 0L;
575  event.fUser[4] = action; // accepted action
576 
577  gVirtualX->SendEvent(source, &event);
578 }
579 
580 ////////////////////////////////////////////////////////////////////////////////
581 /// Send DND drop message to target window.
582 
584 {
585  Event_t event;
586 
587  event.fType = kClientMessage;
588  event.fWindow = target;
589  event.fHandle = fgDNDDrop;
590  event.fFormat = 32;
591 
592  event.fUser[0] = fMain->GetId(); // from;
593  event.fUser[1] = 0L; // reserved
594  event.fUser[2] = 0L; //CurrentTime; // timestamp
595  event.fUser[3] = 0L;
596  event.fUser[4] = 0L;
597 
598  gVirtualX->SendEvent(target, &event);
599 }
600 
601 ////////////////////////////////////////////////////////////////////////////////
602 /// Send DND finished message to source window.
603 
605 {
606  Event_t event;
607 
608  event.fType = kClientMessage;
609  event.fWindow = source;
610  event.fHandle = fgDNDFinished;
611  event.fFormat = 32;
612 
613  event.fUser[0] = fMain->GetId(); // from;
614  event.fUser[1] = 0L; // reserved
615  event.fUser[2] = 0L;
616  event.fUser[3] = 0L;
617  event.fUser[4] = 0L;
618 
619  gVirtualX->SendEvent(source, &event);
620 }
621 
622 ////////////////////////////////////////////////////////////////////////////////
623 /// Handle DND enter event.
624 
626 {
627  fSource = src;
628 
629  if (fDraggerTypes) delete[] fDraggerTypes;
630 
631  if (vers & 1) { // more than 3 data types?
632  Atom_t type, *a;
633  Int_t format = 32;
634  ULong_t i, count, remaining;
635  unsigned char *data = 0;
636 
637  gVirtualX->GetProperty(src, fgDNDTypeList,
638  0, 0x8000000L, kFALSE, XA_ATOM,
639  &type, &format, &count, &remaining, &data);
640 
641  if (type != XA_ATOM || format != 32 || !data) {
642  count = 0;
643  }
644 
645  fDraggerTypes = new Atom_t[count+4];
646 
647  a = (Atom_t *) data;
648  for (i = 0; i < count; i++)
649  fDraggerTypes[i] = a[i];
650 
651  fDraggerTypes[i] = kNone;
652 
653  if (data) delete[] data;
654 
655  } else {
656  fDraggerTypes = new Atom_t[4];
657 
658  fDraggerTypes[0] = dataTypes[0];
659  fDraggerTypes[1] = dataTypes[1];
660  fDraggerTypes[2] = dataTypes[2];
661 
662  fDraggerTypes[3] = kNone;
663  }
664 
665  // the following is not strictly neccessary, unless the previous
666  // dragging application crashed without sending XdndLeave
667  if (fLocalTarget) fLocalTarget->HandleDNDLeave();
668  fLocalTarget = 0;
669 
670  return kTRUE;
671 }
672 
673 ////////////////////////////////////////////////////////////////////////////////
674 /// Handle DND leave event.
675 
677 {
678  fSource = kNone;
679  if (fLocalTarget) fLocalTarget->HandleDNDLeave();
680  fLocalTarget = 0;
681 
682  if (fDraggerTypes) delete[] fDraggerTypes;
683  fDraggerTypes = 0;
684 
685  return kTRUE;
686 }
687 
688 ////////////////////////////////////////////////////////////////////////////////
689 /// Handle DND position event.
690 
692  Atom_t action, Time_t /*timestamp*/)
693 {
694  Int_t x = 0, y = 0;
695  Window_t child;
696  TGFrame *f = 0, *main = 0;
697  TGWindow *w = 0;
698  Window_t wtarget = 0;
699 
700  wtarget = FindWindow(gVirtualX->GetDefaultRootWindow(), x_root, y_root, 15);
701 
702  if (wtarget) {
703  gVirtualX->TranslateCoordinates(gVirtualX->GetDefaultRootWindow(),
704  wtarget, x_root, y_root, x, y, child);
705  w = gClient->GetWindowById(wtarget);
706  if (w)
707  f = dynamic_cast<TGFrame *>(w);
708  }
709 
710  if (f != fLocalTarget) {
711  if (fLocalTarget) fLocalTarget->HandleDNDLeave();
712  fLocalTarget = f;
713  if (fLocalTarget) {
714  main = (TGFrame *)fLocalTarget->GetMainFrame();
715  main->RaiseWindow();
716  if (fMain == 0)
717  fMain = main;
718  fDropType = fLocalTarget->HandleDNDEnter(fDraggerTypes);
719  }
720  }
721  // query the target widget to determine whether it accepts the
722  // required action
723  if (fLocalTarget) {
724  action = (fDropType == kNone) ? kNone :
725  fLocalTarget->HandleDNDPosition(x, y, action, x_root, y_root);
726  } else if (fProxyOurs) {
727  action = fMain->HandleDNDPosition(x, y, action, x_root, y_root);
728  } else {
729  action = kNone;
730  }
731  SendDNDStatus(source, fLocalAction = action);
732  return kTRUE;
733 }
734 
735 ////////////////////////////////////////////////////////////////////////////////
736 /// Handle DND status event.
737 
739  Rectangle_t /*area*/, Atom_t action)
740 {
741  if (target) {
742  fStatusPending = kFALSE;
743  if (accepted) {
744  fDropAccepted = kTRUE;
745  fAcceptedAction = action;
746  if (fDragWin)
747  gVirtualX->ChangeActivePointerGrab(fDragWin->GetId(),
748  fGrabEventMask, kNone);
749  } else {
750  fDropAccepted = kFALSE;
751  fAcceptedAction = kNone;
752  if (fDragWin)
753  gVirtualX->ChangeActivePointerGrab(fDragWin->GetId(),
754  fGrabEventMask,
755  fDNDNoDropCursor);
756  }
757  if (fDropTimeout) { // were we waiting for this to do the drop?
758  delete fDropTimeout;
759  fDropTimeout = 0;
760  SendDNDDrop(fTarget);
761  }
762  }
763  return kTRUE;
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 /// Handle DND drop event.
768 
770 {
771  // to get the data, we must call XConvertSelection with
772  // the timestamp in XdndDrop, wait for SelectionNotify
773  // to arrive to retrieve the data, and when we are finished,
774  // send a XdndFinished message to the source.
775 
776  if (fMain && fDropType != kNone) {
777  gVirtualX->ChangeProperties(fMain->GetId(), fgXCDNDData, fDropType,
778  8, (unsigned char *) 0, 0);
779 
780  gVirtualX->ConvertSelection(fMain->GetId(), fgDNDSelection, fDropType,
781  fgXCDNDData, timestamp);
782  }
783 
784  fSource = source;
785  if (fMain) SendDNDFinished(source);
786 
787  return kTRUE;
788 }
789 
790 ////////////////////////////////////////////////////////////////////////////////
791 /// Handle DND finished event.
792 
794 {
795  if (fLocalSource) fLocalSource->HandleDNDFinished();
796  return kTRUE;
797 }
798 
799 ////////////////////////////////////////////////////////////////////////////////
800 /// Handle selection request event.
801 
803 {
804  if ((Atom_t)event->fUser[1] == fgDNDSelection) {
805  Event_t xevent;
806  TDNDData *dnddata = 0;
807  char *data;
808  int len;
809 
810  // get the data from the drag source widget
811  if (fLocalSource)
812  dnddata = fLocalSource->GetDNDData(event->fUser[2]);
813 
814  data = dnddata ? (char *) dnddata->fData : (char *) "";
815  len = dnddata ? dnddata->fDataLength : 0;
816 
817  if ((Atom_t)event->fUser[3] == kNone) {
818  //printf("warning: kNone property specified in SelectionRequest\n");
819  event->fUser[3] = fgXCDNDData;
820  }
821 
822  gVirtualX->ChangeProperties(event->fUser[0], event->fUser[3],
823  event->fUser[2], 8,
824  (unsigned char *) data, len);
825 
826  xevent.fType = kSelectionNotify;
827  xevent.fTime = event->fTime;
828  xevent.fUser[0] = event->fUser[0]; // requestor
829  xevent.fUser[1] = event->fUser[1]; // selection
830  xevent.fUser[2] = event->fUser[2]; // target;
831  xevent.fUser[3] = event->fUser[3]; // property;
832  gVirtualX->SendEvent(event->fUser[0], &xevent);
833 
834  return kTRUE;
835  } else {
836  return kFALSE; // not for us...
837  }
838 }
839 
840 ////////////////////////////////////////////////////////////////////////////////
841 /// Handle selection event.
842 
844 {
845  if ((Atom_t)event->fUser[1] == fgDNDSelection) {
846  Atom_t actual = fDropType;
847  Int_t format = 8;
848  ULong_t count, remaining;
849  unsigned char *data = 0;
850 
851 
852  gVirtualX->GetProperty(event->fUser[0], event->fUser[3],
853  0, 0x8000000L, kTRUE, event->fUser[2],
854  &actual, &format, &count, &remaining, &data);
855 
856  if ((actual != fDropType) || (format != 8) || (count == 0) || !data) {
857  if (data) delete[] data;
858 
859  return kFALSE;
860  }
861 
862  if (fSource != kNone) SendDNDFinished(fSource);
863 
864  // send the data to the target widget
865 
866  if (fLocalTarget) {
867  TDNDData dndData(actual, data, count, fLocalAction);
868  fLocalTarget->HandleDNDDrop(&dndData);
869  if (fDraggerTypes) delete[] fDraggerTypes;
870  fDraggerTypes = 0;
871  }
872 
873  fSource = kNone;
874  fLocalAction = kNone;
875 
876 // delete[] data;
877 
878  return kTRUE;
879 
880  } else {
881  return kFALSE; // not for us...
882  }
883 }
884 
885 ////////////////////////////////////////////////////////////////////////////////
886 /// Set drag window pixmaps and hotpoint.
887 
889  int hot_x, int hot_y)
890 {
891  fPic = pic;
892  fMask = mask;
893  fHotx = hot_x;
894  fHoty = hot_y;
895 }
896 
897 ////////////////////////////////////////////////////////////////////////////////
898 /// Start dragging.
899 
900 Bool_t TGDNDManager::StartDrag(TGFrame *src, int x_root, int y_root,
901  Window_t grabWin)
902 {
903  if (fDragging) return kTRUE;
904 
905  fLocalSource = src;
906 
907  if ((TGWindow *)fMain != src->GetMainFrame()) {
908  fMain = (TGFrame *)src->GetMainFrame();
909  }
910 
911  if (!gVirtualX->SetSelectionOwner(fMain->GetId(), fgDNDSelection)) {
912  // hmmm... failed to acquire ownership of XdndSelection!
913  return kFALSE;
914  }
915 
916  if (grabWin == kNone) grabWin = fMain->GetId();
917 
918  gVirtualX->GrabPointer(grabWin, fGrabEventMask, kNone, fDNDNoDropCursor, kTRUE, kFALSE);
919 
920  fLocalTarget = 0;
921  fDragging = kTRUE;
922  fTarget = kNone;
923  fTargetIsDNDAware = kFALSE;
924  fStatusPending = kFALSE;
925  if (fDropTimeout) delete fDropTimeout;
926  fDropTimeout = 0;
927  fDropAccepted = kFALSE;
928  fAcceptedAction = kNone;
929  fLocalAction = kNone;
930 
931  if (!fDragWin && fPic != kNone && fMask != kNone) {
932  fDragWin = new TGDragWindow(gClient->GetDefaultRoot(), fPic, fMask);
933  fDragWin->Move((x_root-fHotx)|1, (y_root-fHoty)|1);
934  fDragWin->MapSubwindows();
935  fDragWin->MapRaised();
936  }
937  return kTRUE;
938 }
939 
940 ////////////////////////////////////////////////////////////////////////////////
941 /// Drop.
942 
944 {
945  if (!fDragging) return kFALSE;
946 
947  if (fTargetIsDNDAware) {
948  if (fDropAccepted) {
949  if (fStatusPending) {
950  if (fDropTimeout) delete fDropTimeout;
951  fDropTimeout = new TTimer(this, 5000);
952  } else {
953  SendDNDDrop(fTarget);
954  }
955  } else {
956  SendDNDLeave(fTarget);
957  fStatusPending = kFALSE;
958  }
959  }
960  EndDrag();
961  return kTRUE;
962 }
963 
964 ////////////////////////////////////////////////////////////////////////////////
965 /// End dragging.
966 
968 {
969  if (!fDragging) return kFALSE;
970 
971  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
972 
973  if (fSource)
974  SendDNDFinished(fSource);
975  if (fLocalSource)
976  fLocalSource->HandleDNDFinished();
977 
978  fDragging = kFALSE;
979  if (fDragWin) {
980  fDragWin->DeleteWindow();
981  fDragWin = 0;
982  }
983  return kTRUE;
984 }
985 
986 ////////////////////////////////////////////////////////////////////////////////
987 /// Process drag event.
988 
989 Bool_t TGDNDManager::Drag(int x_root, int y_root, Atom_t action, Time_t timestamp)
990 {
991  if (!fDragging) return kFALSE;
992 
993  Window_t newTarget = FindWindow(gVirtualX->GetDefaultRootWindow(),
994  x_root, y_root, 15);
995 
996  if (newTarget == kNone) {
997  Window_t t = GetRootProxy();
998  if (t != kNone) newTarget = t;
999  }
1000 
1001  if (fTarget != newTarget) {
1002 
1003  if (fTargetIsDNDAware) SendDNDLeave(fTarget);
1004 
1005  fTarget = newTarget;
1006  fTargetIsDNDAware = IsDNDAware(fTarget);
1007  fStatusPending = kFALSE;
1008  fDropAccepted = kFALSE;
1009  fAcceptedAction = kNone;
1010 
1011  if (fTargetIsDNDAware) SendDNDEnter(fTarget);
1012 
1013  if (fDragWin)
1014  gVirtualX->ChangeActivePointerGrab(fDragWin->GetId(), fGrabEventMask,
1015  fDNDNoDropCursor);
1016  }
1017 
1018  if (fTargetIsDNDAware && !fStatusPending) {
1019  SendDNDPosition(fTarget, x_root, y_root, action, timestamp);
1020 
1021  // this is to avoid sending XdndPosition messages over and over
1022  // if the target is not responding
1023  fStatusPending = kTRUE;
1024  }
1025 
1026  if (fDragWin) {
1027  fDragWin->RaiseWindow();
1028  fDragWin->Move((x_root-fHotx)|1, (y_root-fHoty)|1);
1029  }
1030  return kTRUE;
1031 }
1032 
1033 ////////////////////////////////////////////////////////////////////////////////
1034 /// Set root window proxy.
1035 
1037 {
1038  Window_t mainw = fMain->GetId();
1039  int result = kFALSE;
1040 
1041  if (GetRootProxy() == kNone) {
1042  gVirtualX->ChangeProperties(gVirtualX->GetDefaultRootWindow(),
1043  fgDNDProxy, XA_WINDOW, 32,
1044  (unsigned char *) &mainw, 1);
1045  gVirtualX->ChangeProperties(mainw, fgDNDProxy, XA_WINDOW, 32,
1046  (unsigned char *) &mainw, 1);
1047 
1048  fProxyOurs = kTRUE;
1049  result = kTRUE;
1050  }
1051  // XSync(_dpy, kFALSE);
1052  gVirtualX->UpdateWindow(0);
1053  return result;
1054 }
1055 
1056 ////////////////////////////////////////////////////////////////////////////////
1057 /// Remove root window proxy.
1058 
1060 {
1061  if (!fProxyOurs) return kFALSE;
1062 
1063  gVirtualX->DeleteProperty(fMain->GetId(), fgDNDProxy);
1064  gVirtualX->DeleteProperty(gVirtualX->GetDefaultRootWindow(), fgDNDProxy);
1065  // the following is to ensure that the properties
1066  // (specially the one on the root window) are deleted
1067  // in case the application is exiting...
1068 
1069  // XSync(_dpy, kFALSE);
1070  gVirtualX->UpdateWindow(0);
1071 
1072  fProxyOurs = kFALSE;
1073 
1074  return kTRUE;
1075 }
static Atom_t GetDNDFinished()
virtual void RaiseWindow()
Raise TGDragWindow.
UShort_t fWidth
Definition: GuiTypes.h:362
virtual void Resize(UInt_t w=0, UInt_t h=0)
Resize the frame.
Definition: TGFrame.cxx:587
Bool_t SetRootProxy()
Set root window proxy.
Short_t fY
Definition: GuiTypes.h:361
static Atom_t fgDNDActionDescrip
Definition: TGDNDManager.h:122
static Atom_t fgDNDActionMove
Definition: TGDNDManager.h:120
static Atom_t fgXCDNDData
Definition: TGDNDManager.h:123
Int_t fDataLength
Definition: TGDNDManager.h:78
static Atom_t GetDNDActionDescrip()
#define XA_WINDOW
UShort_t fHeight
Definition: GuiTypes.h:362
Bool_t HandleDNDDrop(Window_t src, Time_t timestamp)
Handle DND drop event.
Bool_t HandleSelection(Event_t *event)
Handle selection event.
static Atom_t fgDNDVersion
Definition: TGDNDManager.h:119
static Atom_t fgDNDActionCopy
Definition: TGDNDManager.h:120
virtual Bool_t HandleDNDDrop(TDNDData *)
Definition: TGFrame.h:323
Bool_t Drop()
Drop.
static Atom_t fgDNDDrop
Definition: TGDNDManager.h:118
static Atom_t fgDNDEnter
Definition: TGDNDManager.h:117
Bool_t HandleTimer(TTimer *t)
Handle Drop timeout.
TGDNDManager(const TGDNDManager &)
const Mask_t kButtonMotionMask
Definition: GuiTypes.h:163
ULong_t Time_t
Definition: GuiTypes.h:41
static Atom_t GetDNDProxy()
Handle_t Cursor_t
Definition: GuiTypes.h:33
static Atom_t GetDNDVersion()
virtual void MapRaised()
Map and Raise TGDragWindow.
#define gClient
Definition: TGClient.h:166
static Atom_t GetDNDSelection()
#define f(i)
Definition: RSha256.hxx:104
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
static Atom_t fgDNDActionPrivate
Definition: TGDNDManager.h:121
static Atom_t GetDNDActionList()
static Atom_t fgDNDStatus
Definition: TGDNDManager.h:117
static int ArrayLength(Atom_t *a)
static Atom_t GetDNDTypeList()
static Cursor_t fgDefaultCursor
Definition: TGDNDManager.h:26
static Atom_t GetXCDNDData()
void SendDNDLeave(Window_t target)
Send DND leave message to target window.
virtual void MapRaised()
Definition: TGFrame.h:252
void InitAtoms()
Initialize drag and drop atoms.
virtual void MapWindow()
Map TGDragWindow.
#define XA_ATOM
virtual Bool_t HandleDNDFinished()
Definition: TGFrame.h:328
static Atom_t GetDNDActionCopy()
TGDNDManager * gDNDManager
virtual TGDimension GetDefaultSize() const
std::cout << fWidth << "x" << fHeight << std::endl;
Definition: TGDNDManager.h:40
static Atom_t GetDNDAware()
static Bool_t fgInit
Definition: TGFrame.h:147
virtual void LowerWindow()
Definition: TGWindow.h:95
static Atom_t fgDNDPosition
Definition: TGDNDManager.h:117
Double_t x[n]
Definition: legend1.C:17
ULong_t Pixel_t
Definition: GuiTypes.h:39
virtual Atom_t HandleDNDPosition(Int_t, Int_t, Atom_t, Int_t, Int_t)
Definition: TGFrame.h:324
Bool_t EndDrag()
End dragging.
void SendDNDPosition(Window_t target, int x, int y, Atom_t action, Time_t timestamp)
Send DND position message to target window.
Handle_t fHandle
Definition: GuiTypes.h:184
virtual void UnmapWindow()
Unmap TGDragWindow.
Handle_t Atom_t
Definition: GuiTypes.h:36
void SendDNDFinished(Window_t src)
Send DND finished message to source window.
static Atom_t GetDNDPosition()
void * fData
Definition: TGDNDManager.h:77
Bool_t HandleClientMessage(Event_t *event)
Handle DND related client messages.
Bool_t HandleDNDPosition(Window_t src, int x_root, int y_root, Atom_t action, Time_t timestamp)
Handle DND position event.
static constexpr double L
int main(int argc, char **argv)
virtual const TGWindow * GetMainFrame() const
Returns top level main frame.
Definition: TGWindow.cxx:133
virtual void DoRedraw()
Redraw TGDragWindow.
static Atom_t fgDNDProxy
Definition: TGDNDManager.h:116
Short_t fX
Definition: GuiTypes.h:361
const Mask_t kButtonPressMask
Definition: GuiTypes.h:160
Bool_t fOverrideRedirect
Definition: GuiTypes.h:106
virtual ~TGDragWindow()
TGDragWindow destructor.
void SendDNDStatus(Window_t target, Atom_t action)
Send DND status message to source window.
virtual Atom_t HandleDNDEnter(Atom_t *)
Definition: TGFrame.h:326
static Atom_t fgDNDSelection
Definition: TGDNDManager.h:116
static Atom_t fgDNDAware
Definition: TGDNDManager.h:116
static Atom_t GetDNDDrop()
const Mask_t kWASaveUnder
Definition: GuiTypes.h:149
Time_t fTime
Definition: GuiTypes.h:176
EGEventType fType
Definition: GuiTypes.h:174
Bool_t HandleDNDStatus(Window_t from, int accepted, Rectangle_t skip, Atom_t action)
Handle DND status event.
auto * a
Definition: textangle.C:12
Bool_t HandleDNDFinished(Window_t target)
Handle DND finished event.
static Atom_t fgDNDTypeList
Definition: TGDNDManager.h:122
Bool_t RemoveRootProxy()
Remove root window proxy.
static Atom_t fgXAWMState
Definition: TGDNDManager.h:126
unsigned int UInt_t
Definition: RtypesCore.h:42
const Handle_t kNone
Definition: GuiTypes.h:87
Handles synchronous and a-synchronous timer events.
Definition: TTimer.h:51
void SetDragPixmap(Pixmap_t pic, Pixmap_t mask, Int_t hot_x, Int_t hot_y)
Set drag window pixmaps and hotpoint.
Atom_t fDataType
Definition: TGDNDManager.h:75
static Atom_t GetDNDLeave()
#define gVirtualX
Definition: TVirtualX.h:350
#define ROOTDND_PROTOCOL_VERSION
UInt_t fWidth
Definition: TGFrame.h:134
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
virtual ~TGDNDManager()
TGDNDManager destructor.
static Atom_t fgDNDFinished
Definition: TGDNDManager.h:118
static const double x1[5]
#define ClassImp(name)
Definition: Rtypes.h:359
static Atom_t fgDNDActionLink
Definition: TGDNDManager.h:120
void SendDNDDrop(Window_t target)
Send DND drop message to target window.
static Atom_t GetDNDStatus()
const Mask_t kButtonReleaseMask
Definition: GuiTypes.h:161
Pixmap_t fPic
Definition: TGDNDManager.h:32
Bool_t HandleDNDEnter(Window_t src, long vers, Atom_t dataTypes[3])
Handle DND enter event.
virtual void RaiseWindow()
Definition: TGWindow.h:94
static Atom_t fgDNDLeave
Definition: TGDNDManager.h:117
int type
Definition: TGX11.cxx:120
const Mask_t kWAOverrideRedirect
Definition: GuiTypes.h:148
unsigned long ULong_t
Definition: RtypesCore.h:51
Double_t y[n]
Definition: legend1.C:17
void SendDNDEnter(Window_t target)
Send DND enter message to target window.
static Atom_t GetDNDActionPrivate()
UInt_t fHeight
Definition: TGFrame.h:135
Long_t fUser[5]
Definition: GuiTypes.h:186
Handle_t fId
Definition: TGObject.h:36
Bool_t Drag(Int_t x_root, Int_t y_root, Atom_t action, Time_t timestamp)
Process drag event.
virtual void LowerWindow()
Lower TGDragWindow.
Handle_t Window_t
Definition: GuiTypes.h:28
virtual void UnmapWindow()
Definition: TGFrame.h:253
static Bool_t fgInit
Definition: TGDNDManager.h:125
Window_t FindWindow(Window_t root, Int_t x, Int_t y, Int_t maxd)
Search for DND aware window at position x,y.
static Atom_t GetDNDActionLink()
static Atom_t fgDNDActionAsk
Definition: TGDNDManager.h:121
virtual void MapWindow()
Definition: TGFrame.h:251
static Atom_t GetDNDActionMove()
Handle_t Pixmap_t
Definition: GuiTypes.h:29
static Atom_t GetDNDActionAsk()
Bool_t IsDNDAware(Window_t win, Atom_t *typelist=0)
Check if window win is DND aware.
Pixmap_t fMask
Definition: TGDNDManager.h:32
Bool_t HandleSelectionRequest(Event_t *event)
Handle selection request event.
virtual void Layout()
Layout TGDragWindow.
Window_t GetRootProxy()
Get root window proxy.
Bool_t StartDrag(TGFrame *src, Int_t x_root, Int_t y_root, Window_t grabWin=kNone)
Start dragging.
Window_t fInput
Definition: TGDNDManager.h:31
Bool_t HandleDNDLeave(Window_t src)
Handle DND leave event.
const Bool_t kTRUE
Definition: RtypesCore.h:87
static Atom_t GetDNDEnter()
TGDragWindow(const TGWindow *p, Pixmap_t pic, Pixmap_t mask, UInt_t options=kChildFrame, Pixel_t back=GetWhitePixel())
TGDragWindow constructor.
const Int_t n
Definition: legend1.C:16
static const TGGC & GetBckgndGC()
Get background color graphics context.
Definition: TGFrame.cxx:757
virtual Bool_t HandleDNDLeave()
Definition: TGFrame.h:327
static Atom_t fgDNDActionList
Definition: TGDNDManager.h:122