TGDNDManager.cxx

Go to the documentation of this file.
00001 // @(#)root/gui:$Id: TGDNDManager.cxx 32804 2010-03-29 08:47:47Z bellenot $
00002 // Author: Bertrand Bellenot   19/04/07
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TGFrame.h"
00013 #include "TTimer.h"
00014 #include "TGDNDManager.h"
00015 #include "TRootCanvas.h"
00016 
00017 #define ROOTDND_PROTOCOL_VERSION      4
00018 #define XA_ATOM ((Atom_t) 4)
00019 #define XA_WINDOW ((Atom_t) 33)
00020 
00021 Atom_t TGDNDManager::fgDNDAware         = kNone;
00022 Atom_t TGDNDManager::fgDNDSelection     = kNone;
00023 Atom_t TGDNDManager::fgDNDProxy         = kNone;
00024 
00025 Atom_t TGDNDManager::fgDNDEnter         = kNone;
00026 Atom_t TGDNDManager::fgDNDLeave         = kNone;
00027 Atom_t TGDNDManager::fgDNDPosition      = kNone;
00028 Atom_t TGDNDManager::fgDNDStatus        = kNone;
00029 Atom_t TGDNDManager::fgDNDDrop          = kNone;
00030 Atom_t TGDNDManager::fgDNDFinished      = kNone;
00031 Atom_t TGDNDManager::fgDNDVersion       = kNone;
00032 
00033 Atom_t TGDNDManager::fgDNDActionCopy    = kNone;
00034 Atom_t TGDNDManager::fgDNDActionMove    = kNone;
00035 Atom_t TGDNDManager::fgDNDActionLink    = kNone;
00036 Atom_t TGDNDManager::fgDNDActionAsk     = kNone;
00037 Atom_t TGDNDManager::fgDNDActionPrivate = kNone;
00038 
00039 Atom_t TGDNDManager::fgDNDTypeList      = kNone;
00040 Atom_t TGDNDManager::fgDNDActionList    = kNone;
00041 Atom_t TGDNDManager::fgDNDActionDescrip = kNone;
00042 
00043 Atom_t TGDNDManager::fgXAWMState     = kNone;
00044 Atom_t TGDNDManager::fgXCDNDData     = kNone;
00045 
00046 Bool_t TGDNDManager::fgInit = kFALSE;
00047 
00048 // TODO:
00049 // - add an TGFrame::HandleDNDStatus event handler?
00050 // - implement INCR protocol
00051 // - cache several requests?
00052 
00053 TGDNDManager *gDNDManager = 0;
00054 
00055 Cursor_t TGDragWindow::fgDefaultCursor = kNone;
00056 
00057 //_____________________________________________________________________________
00058 //
00059 // TGDragWindow
00060 //
00061 // Window used as drag icon during drag and drop operations.
00062 //_____________________________________________________________________________
00063 
00064 ClassImp(TGDragWindow)
00065 
00066 //______________________________________________________________________________
00067 TGDragWindow::TGDragWindow(const TGWindow *p, Pixmap_t pic, Pixmap_t mask,
00068                            UInt_t options, Pixel_t back) :
00069    TGFrame(p, 32, 32, options, back)
00070 {
00071    // TGDragWindow constructor.
00072 
00073    if (fgDefaultCursor == kNone) {
00074       fgDefaultCursor = gVirtualX->CreateCursor(kTopLeft);
00075    }
00076 
00077    fPic = pic;
00078    fMask = mask;
00079 
00080    SetWindowAttributes_t wattr;
00081 
00082    wattr.fMask = kWAOverrideRedirect | kWASaveUnder;
00083    wattr.fSaveUnder = kTRUE;
00084    wattr.fOverrideRedirect = kTRUE;
00085 
00086    gVirtualX->ChangeWindowAttributes(fId, &wattr);
00087 
00088    int x, y;
00089 
00090    gVirtualX->GetWindowSize(fPic, x, y, fPw, fPh);
00091 
00092    wattr.fMask = kWAOverrideRedirect;
00093    wattr.fOverrideRedirect = kTRUE;
00094 
00095    // This input window is used to make the dragging smoother when using
00096    // highly complicated shapped windows (like labels and semitransparent
00097    // icons), for some obscure reason most of the motion events get lost
00098    // while the pointer is over the shaped window.
00099 
00100    //fInput = gVirtualX->CreateWindow(fParent->GetId(), 0, 0, fWidth,
00101    //                                 fHeight, 0, 0, 0, 0, &wattr, 0);
00102    fInput = fId;
00103 
00104    Resize(GetDefaultSize());
00105 
00106    gVirtualX->ShapeCombineMask(fId, 0, 0, fMask);
00107 
00108    gVirtualX->SetCursor(fId, fgDefaultCursor);
00109 }
00110 
00111 //______________________________________________________________________________
00112 TGDragWindow::~TGDragWindow()
00113 {
00114    // TGDragWindow destructor.
00115 
00116    //gVirtualX->DestroyWindow(fInput);
00117 }
00118 
00119 //______________________________________________________________________________
00120 void TGDragWindow::MapWindow()
00121 {
00122    // Map TGDragWindow.
00123 
00124    TGFrame::MapWindow();
00125    //gVirtualX->MapWindow(fInput);
00126 }
00127 
00128 //______________________________________________________________________________
00129 void TGDragWindow::UnmapWindow()
00130 {
00131    // Unmap TGDragWindow.
00132 
00133    TGFrame::UnmapWindow();
00134    //gVirtualX->UnmapWindow(fInput);
00135 }
00136 
00137 //______________________________________________________________________________
00138 void TGDragWindow::RaiseWindow()
00139 {
00140    // Raise TGDragWindow.
00141 
00142    TGFrame::RaiseWindow();
00143    //gVirtualX->RaiseWindow(fInput);
00144 }
00145 
00146 //______________________________________________________________________________
00147 void TGDragWindow::LowerWindow()
00148 {
00149    // Lower TGDragWindow.
00150 
00151    //gVirtualX->LowerWindow(fInput);
00152    TGFrame::LowerWindow();
00153 }
00154 
00155 //______________________________________________________________________________
00156 void TGDragWindow::MapRaised()
00157 {
00158    // Map and Raise TGDragWindow.
00159 
00160    TGFrame::MapRaised();
00161    //gVirtualX->MapRaised(fInput);
00162 }
00163 
00164 //______________________________________________________________________________
00165 void TGDragWindow::Layout()
00166 {
00167    // Layout TGDragWindow.
00168 
00169    gVirtualX->ShapeCombineMask(fId, 0, 0, fMask);
00170 }
00171 
00172 //______________________________________________________________________________
00173 void TGDragWindow::DoRedraw()
00174 {
00175    // Redraw TGDragWindow.
00176 
00177    gVirtualX->CopyArea(fPic, fId, GetBckgndGC()(), 0, 0, fWidth, fHeight, 0, 0);
00178 }
00179 
00180 //_____________________________________________________________________________
00181 //
00182 // TGDNDManager
00183 //
00184 // Central Drag and Drop manager for ROOT.
00185 //_____________________________________________________________________________
00186 
00187 ClassImp(TGDNDManager)
00188 
00189 //______________________________________________________________________________
00190 TGDNDManager::TGDNDManager(TGFrame *toplevel, Atom_t * /*typelist*/)
00191 {
00192    // TGDNDManager constructor.
00193 
00194    if (gDNDManager)
00195       return;
00196 
00197    fMain = toplevel;
00198    fVersion = ROOTDND_PROTOCOL_VERSION;
00199    fUseVersion = kTRUE;
00200    //fTypelist = typelist;
00201    fTypelist = new Atom_t[3];
00202    fTypelist[0] = gVirtualX->InternAtom("application/root", kFALSE);
00203    fTypelist[1] = gVirtualX->InternAtom("text/uri-list", kFALSE);
00204    fTypelist[2] = 0;
00205 
00206    if (!fgInit) {
00207       InitAtoms();
00208       fgInit = kTRUE;
00209    }
00210 
00211    //Reset();
00212    fDropTimeout = 0;
00213 
00214    fSource = kNone;
00215    fTarget = kNone;
00216    fTargetIsDNDAware = kFALSE;
00217    fStatusPending = kFALSE;
00218    fDropAccepted = kFALSE;  // this would become obsoleted by _acceptedAction
00219    fAcceptedAction = kNone; // target's accepted action
00220    fLocalAction = kNone;    // our last specified action when we act as source
00221    fDragging = kFALSE;
00222    fDragWin = 0;
00223    fLocalSource = 0;
00224    fLocalTarget = 0;
00225    fPic = fMask = kNone;
00226    fDraggerTypes = 0;
00227    fDropType = kNone;
00228    fHotx = fHoty = 0;
00229 
00230    fGrabEventMask = kButtonPressMask | kButtonReleaseMask | kButtonMotionMask;
00231 
00232    fDNDNoDropCursor = gVirtualX->CreateCursor(kNoDrop); // kNoDrop
00233 
00234    // set the aware prop
00235 
00236    fProxyOurs = kFALSE;
00237    gDNDManager = this;
00238 }
00239 
00240 //______________________________________________________________________________
00241 TGDNDManager::~TGDNDManager()
00242 {
00243    // TGDNDManager destructor.
00244 
00245    // remove the proxy prop if we own it
00246    if (fProxyOurs)
00247       RemoveRootProxy();
00248 
00249    // remove the aware prop ant the types list, if any
00250    if (fMain) {
00251       gVirtualX->DeleteProperty(fMain->GetId(), fgDNDAware);
00252       gVirtualX->DeleteProperty(fMain->GetId(), fgDNDTypeList);
00253    }
00254    if (fDropTimeout) delete fDropTimeout;
00255 
00256    // delete the drag pixmap, if any
00257    if (fDragWin) {
00258       fDragWin->DeleteWindow();
00259       fDragWin = 0;
00260    }
00261    if (fPic != kNone) gVirtualX->DeletePixmap(fPic);
00262    if (fMask != kNone) gVirtualX->DeletePixmap(fMask);
00263 
00264    if (fDraggerTypes) delete[] fDraggerTypes;
00265 }
00266 
00267 Atom_t TGDNDManager::GetDNDAware() { return fgDNDAware; }
00268 Atom_t TGDNDManager::GetDNDSelection() { return fgDNDSelection; }
00269 Atom_t TGDNDManager::GetDNDProxy() { return fgDNDProxy; }
00270 Atom_t TGDNDManager::GetDNDEnter() { return fgDNDEnter; }
00271 Atom_t TGDNDManager::GetDNDLeave() { return fgDNDLeave; }
00272 Atom_t TGDNDManager::GetDNDPosition() { return fgDNDPosition; }
00273 Atom_t TGDNDManager::GetDNDStatus() { return fgDNDStatus; }
00274 Atom_t TGDNDManager::GetDNDDrop() { return fgDNDDrop; }
00275 Atom_t TGDNDManager::GetDNDFinished() { return fgDNDFinished; }
00276 Atom_t TGDNDManager::GetDNDVersion() { return fgDNDVersion; }
00277 Atom_t TGDNDManager::GetDNDActionCopy() { return fgDNDActionCopy; }
00278 Atom_t TGDNDManager::GetDNDActionMove() { return fgDNDActionMove; }
00279 Atom_t TGDNDManager::GetDNDActionLink() { return fgDNDActionLink; }
00280 Atom_t TGDNDManager::GetDNDActionAsk() { return fgDNDActionAsk; }
00281 Atom_t TGDNDManager::GetDNDActionPrivate() { return fgDNDActionPrivate; }
00282 Atom_t TGDNDManager::GetDNDTypeList() { return fgDNDTypeList; }
00283 Atom_t TGDNDManager::GetDNDActionList() { return fgDNDActionList; }
00284 Atom_t TGDNDManager::GetDNDActionDescrip() { return fgDNDActionDescrip; }
00285 Atom_t TGDNDManager::GetXCDNDData() { return fgXCDNDData; }
00286 
00287 //______________________________________________________________________________
00288 void TGDNDManager::InitAtoms()
00289 {
00290    // Initialize drag and drop atoms.
00291 
00292    // awareness
00293    fgDNDAware = gVirtualX->InternAtom("XdndAware", kFALSE);
00294 
00295    // selection
00296    fgDNDSelection = gVirtualX->InternAtom("XdndSelection", kFALSE);
00297 
00298    // proxy window
00299    fgDNDProxy = gVirtualX->InternAtom("XdndProxy", kFALSE);
00300 
00301    // messages
00302    fgDNDEnter    = gVirtualX->InternAtom("XdndEnter", kFALSE);
00303    fgDNDLeave    = gVirtualX->InternAtom("XdndLeave", kFALSE);
00304    fgDNDPosition = gVirtualX->InternAtom("XdndPosition", kFALSE);
00305    fgDNDStatus   = gVirtualX->InternAtom("XdndStatus", kFALSE);
00306    fgDNDDrop     = gVirtualX->InternAtom("XdndDrop", kFALSE);
00307    fgDNDFinished = gVirtualX->InternAtom("XdndFinished", kFALSE);
00308 
00309    // actions
00310    fgDNDActionCopy    = gVirtualX->InternAtom("XdndActionCopy", kFALSE);
00311    fgDNDActionMove    = gVirtualX->InternAtom("XdndActionMove", kFALSE);
00312    fgDNDActionLink    = gVirtualX->InternAtom("XdndActionLink", kFALSE);
00313    fgDNDActionAsk     = gVirtualX->InternAtom("XdndActionAsk", kFALSE);
00314    fgDNDActionPrivate = gVirtualX->InternAtom("XdndActionPrivate", kFALSE);
00315 
00316    // types list
00317    fgDNDTypeList      = gVirtualX->InternAtom("XdndTypeList", kFALSE);
00318    fgDNDActionList    = gVirtualX->InternAtom("XdndActionList", kFALSE);
00319    fgDNDActionDescrip = gVirtualX->InternAtom("XdndActionDescription", kFALSE);
00320 
00321    // misc
00322    fgXAWMState = gVirtualX->InternAtom("WM_STATE", kFALSE);
00323    fgXCDNDData = gVirtualX->InternAtom("_XC_DND_DATA", kFALSE);
00324 }
00325 
00326 static int ArrayLength(Atom_t *a)
00327 {
00328    // Returns length of array a.
00329 
00330    int n;
00331 
00332    for (n = 0; a[n]; n++) { }
00333    return n;
00334 }
00335 
00336 //______________________________________________________________________________
00337 Bool_t TGDNDManager::IsDNDAware(Window_t win, Atom_t *typelist)
00338 {
00339    // Check if window win is DND aware.
00340 
00341    return gVirtualX->IsDNDAware(win, typelist);
00342 }
00343 
00344 //______________________________________________________________________________
00345 Window_t TGDNDManager::FindWindow(Window_t root, int x, int y, int maxd)
00346 {
00347    // Search for DND aware window at position x,y.
00348 
00349    if (maxd <= 0) return kNone;
00350 
00351    if (fDragWin && fDragWin->HasWindow(root)) return kNone;
00352 
00353    return gVirtualX->FindRWindow(root, fDragWin ? fDragWin->GetId() : 0,
00354                                  fDragWin ? fDragWin->GetInputId() : 0,
00355                                  x, y, maxd);
00356 }
00357 
00358 
00359 //______________________________________________________________________________
00360 Window_t TGDNDManager::GetRootProxy()
00361 {
00362    // Get root window proxy.
00363 
00364    Atom_t actual;
00365    Int_t format = 32;
00366    ULong_t count, remaining;
00367    unsigned char *data = 0;
00368    Window_t win, proxy = kNone;
00369 
00370    // search for XdndProxy property on the root window...
00371 
00372    // XSync(_dpy, kFALSE);      // get to known state...
00373    gVirtualX->UpdateWindow(0);
00374 
00375    //oldhandler = XSetErrorHandler(TGDNDManager::CatchXError);
00376    //target_error = kFALSE;
00377 
00378    gVirtualX->GetProperty(gVirtualX->GetDefaultRootWindow(),
00379                           fgDNDProxy, 0, 1, kFALSE, XA_WINDOW,
00380                           &actual, &format, &count, &remaining, &data);
00381 
00382    if ((actual == XA_WINDOW) && (format == 32) && (count > 0) && data) {
00383 
00384       // found the XdndProxy property, now check for the proxy window...
00385       win = *((Window_t *) data);
00386       delete[] data;
00387       data = 0;
00388 
00389       gVirtualX->GetProperty(win, fgDNDProxy, 0, 1, kFALSE, XA_WINDOW,
00390                              &actual, &format, &count, &remaining, &data);
00391 
00392       // XSync(_dpy, kFALSE);      // force the error...
00393       gVirtualX->UpdateWindow(0);
00394 
00395       if ((actual == XA_WINDOW) && (format == 32) && (count > 0) && data) {
00396          if (*((Window_t *) data) == win) {
00397 
00398             // proxy window exists and is correct
00399             proxy = win;
00400          }
00401       }
00402    }
00403    if (data) delete[] data;
00404    //oldhandler = XSetErrorHandler(oldhandler);
00405    return proxy;
00406 }
00407 
00408 //______________________________________________________________________________
00409 Bool_t TGDNDManager::HandleClientMessage(Event_t *event)
00410 {
00411    // Handle DND related client messages.
00412 
00413    if (event->fHandle == fgDNDEnter) {
00414       HandleDNDEnter((Window_t) event->fUser[0], event->fUser[1],
00415                      (Atom_t *) &event->fUser[2]);
00416 
00417    } else if (event->fHandle == fgDNDLeave) {
00418       HandleDNDLeave((Window_t) event->fUser[0]);
00419 
00420    } else if (event->fHandle == fgDNDPosition) {
00421       HandleDNDPosition((Window_t) event->fUser[0],
00422                        (Int_t) (event->fUser[2] >> 16) & 0xFFFF,  // x_root
00423                        (Int_t) (event->fUser[2] & 0xFFFF),        // y_root
00424                        (Atom_t) event->fUser[4],                  // action
00425                        (Time_t) event->fUser[3]);                 // timestamp
00426 
00427    } else if (event->fHandle == fgDNDStatus) {
00428       Rectangle_t skip;
00429       skip.fX      = (event->fUser[2] >> 16) & 0xFFFF;
00430       skip.fY      = (event->fUser[2] & 0xFFFF);
00431       skip.fWidth  = (event->fUser[3] >> 16) & 0xFFFF;
00432       skip.fHeight = (event->fUser[3] & 0xFFFF);
00433 
00434       HandleDNDStatus((Window_t) event->fUser[0],
00435                       (int) (event->fUser[1] & 0x1),
00436                        skip, (Atom_t) event->fUser[4]);
00437 
00438    } else if (event->fHandle == fgDNDDrop) {
00439       HandleDNDDrop((Window_t) event->fUser[0], (Time_t) event->fUser[2]);
00440 
00441    } else if (event->fHandle == fgDNDFinished) {
00442       HandleDNDFinished((Window_t) event->fUser[0]);
00443 
00444    } else {
00445       return kFALSE;  // not for us...
00446    }
00447    return kTRUE;
00448 }
00449 
00450 //______________________________________________________________________________
00451 Bool_t TGDNDManager::HandleTimer(TTimer *t)
00452 {
00453    // Handle Drop timeout.
00454 
00455    if (t == fDropTimeout) {
00456       // The drop operation timed out without receiving
00457       // status confirmation from the target. Send a
00458       // leave message instead (and notify the user or widget).
00459       delete fDropTimeout;
00460       fDropTimeout = 0;
00461 
00462       SendDNDLeave(fTarget);
00463       fStatusPending = kFALSE;
00464 
00465       if (fLocalSource) fLocalSource->HandleDNDFinished();
00466       return kTRUE;
00467    }
00468    return kFALSE;
00469 }
00470 
00471 //______________________________________________________________________________
00472 void TGDNDManager::SendDNDEnter(Window_t target)
00473 {
00474    // Send DND enter message to target window.
00475 
00476    Int_t i, n;
00477    Event_t event;
00478 
00479    event.fType   = kClientMessage;
00480    event.fWindow = target;
00481    event.fHandle = fgDNDEnter;
00482    event.fFormat = 32;
00483 
00484    event.fUser[0] = fMain->GetId();  // from;
00485 
00486    n = ArrayLength(fTypelist);
00487 
00488    event.fUser[1] = ((n > 3) ? 1L : 0L) | (fUseVersion << 24);
00489 
00490    // set the first 1-3 data types
00491 
00492    for (i = 0; i < 3; ++i)
00493       event.fUser[2+i] = (i < n) ? fTypelist[i] : kNone;
00494 
00495    if (fLocalSource) {
00496       TDNDData *dnddata = 0;
00497       Atom_t dataType;
00498 
00499       // get the data type from the drag source widget
00500       if (fLocalSource)
00501          dnddata = fLocalSource->GetDNDData(0);
00502       dataType = dnddata ? (Atom_t) dnddata->fDataType : (Atom_t) kNone;
00503       event.fUser[2] = dataType;
00504       event.fUser[3] = kNone;
00505       event.fUser[4] = kNone;
00506    }
00507    
00508    gVirtualX->SendEvent(target, &event);
00509 }
00510 
00511 //______________________________________________________________________________
00512 void TGDNDManager::SendDNDLeave(Window_t target)
00513 {
00514    // Send DND leave message to target window.
00515 
00516    Event_t event;
00517 
00518    event.fType    = kClientMessage;
00519    event.fWindow  = target;
00520    event.fHandle  = fgDNDLeave;
00521    event.fFormat  = 32;
00522 
00523    event.fUser[0] = fMain->GetId();  // from;
00524    event.fUser[1] = 0L;
00525 
00526    event.fUser[2] = 0L;
00527    event.fUser[3] = 0L;
00528    event.fUser[4] = 0L;
00529 
00530    gVirtualX->SendEvent(target, &event);
00531 }
00532 
00533 //______________________________________________________________________________
00534 void TGDNDManager::SendDNDPosition(Window_t target, int x, int y,
00535                                   Atom_t action, Time_t timestamp)
00536 {
00537    // Send DND position message to target window.
00538 
00539    Event_t event;
00540 
00541    event.fType    = kClientMessage;
00542    event.fWindow  = target;
00543    event.fHandle  = fgDNDPosition;
00544    event.fFormat  = 32;
00545 
00546    event.fUser[0] = fMain->GetId();  // from;
00547    event.fUser[1] = 0L;
00548 
00549    event.fUser[2] = (x << 16) | y;   // root coodinates
00550    event.fUser[3] = timestamp;       // timestamp for retrieving data
00551    event.fUser[4] = action;          // requested action
00552 
00553    gVirtualX->SendEvent(target, &event);
00554 }
00555 
00556 //______________________________________________________________________________
00557 void TGDNDManager::SendDNDStatus(Window_t source, Atom_t action)
00558 {
00559    // Send DND status message to source window.
00560 
00561    Event_t event;
00562 
00563    event.fType    = kClientMessage;
00564    event.fWindow  = source;
00565    event.fHandle  = fgDNDStatus;
00566    event.fFormat  = 32;
00567 
00568    event.fUser[0] = fMain->GetId();    // from;
00569    event.fUser[1] = (action == kNone) ? 0L : 1L;
00570 
00571    event.fUser[2] = 0L;                // empty rectangle
00572    event.fUser[3] = 0L;
00573    event.fUser[4] = action;            // accepted action
00574 
00575    gVirtualX->SendEvent(source, &event);
00576 }
00577 
00578 //______________________________________________________________________________
00579 void TGDNDManager::SendDNDDrop(Window_t target)
00580 {
00581    // Send DND drop message to target window.
00582 
00583    Event_t event;
00584 
00585    event.fType    = kClientMessage;
00586    event.fWindow  = target;
00587    event.fHandle  = fgDNDDrop;
00588    event.fFormat  = 32;
00589 
00590    event.fUser[0] = fMain->GetId();    // from;
00591    event.fUser[1] = 0L;                // reserved
00592    event.fUser[2] = 0L; //CurrentTime;       // timestamp
00593    event.fUser[3] = 0L;
00594    event.fUser[4] = 0L;
00595 
00596    gVirtualX->SendEvent(target, &event);
00597 }
00598 
00599 //______________________________________________________________________________
00600 void TGDNDManager::SendDNDFinished(Window_t source)
00601 {
00602    // Send DND finished message to source window.
00603 
00604    Event_t event;
00605 
00606    event.fType    = kClientMessage;
00607    event.fWindow  = source;
00608    event.fHandle  = fgDNDFinished;
00609    event.fFormat  = 32;
00610 
00611    event.fUser[0] = fMain->GetId();    // from;
00612    event.fUser[1] = 0L;                // reserved
00613    event.fUser[2] = 0L;
00614    event.fUser[3] = 0L;
00615    event.fUser[4] = 0L;
00616 
00617    gVirtualX->SendEvent(source, &event);
00618 }
00619 
00620 //______________________________________________________________________________
00621 Bool_t TGDNDManager::HandleDNDEnter(Window_t src, Long_t vers, Atom_t dataTypes[3])
00622 {
00623    // Handle DND enter event.
00624 
00625    fSource = src;
00626 
00627    if (fDraggerTypes) delete[] fDraggerTypes;
00628 
00629    if (vers & 1) {  // more than 3 data types?
00630       Atom_t type, *a;
00631       Int_t format = 32;
00632       ULong_t i, count, remaining;
00633       unsigned char *data = 0;
00634 
00635       gVirtualX->GetProperty(src, fgDNDTypeList,
00636                              0, 0x8000000L, kFALSE, XA_ATOM,
00637                              &type, &format, &count, &remaining, &data);
00638 
00639       if (type != XA_ATOM || format != 32 || !data) {
00640          count = 0;
00641       }
00642 
00643       fDraggerTypes = new Atom_t[count+4];
00644 
00645       a = (Atom_t *) data;
00646       for (i = 0; i < count; i++)
00647          fDraggerTypes[i] = a[i];
00648 
00649       fDraggerTypes[i] = kNone;
00650 
00651       if (data) delete[] data;
00652 
00653    } else {
00654       fDraggerTypes = new Atom_t[4];
00655 
00656       fDraggerTypes[0] = dataTypes[0];
00657       fDraggerTypes[1] = dataTypes[1];
00658       fDraggerTypes[2] = dataTypes[2];
00659 
00660       fDraggerTypes[3] = kNone;
00661    }
00662 
00663    // the following is not strictly neccessary, unless the previous
00664    // dragging application crashed without sending XdndLeave
00665    if (fLocalTarget) fLocalTarget->HandleDNDLeave();
00666    fLocalTarget = 0;
00667 
00668    return kTRUE;
00669 }
00670 
00671 //______________________________________________________________________________
00672 Bool_t TGDNDManager::HandleDNDLeave(Window_t /*src*/)
00673 {
00674    // Handle DND leave event.
00675 
00676    fSource = kNone;
00677    if (fLocalTarget) fLocalTarget->HandleDNDLeave();
00678    fLocalTarget = 0;
00679 
00680    if (fDraggerTypes) delete[] fDraggerTypes;
00681    fDraggerTypes = 0;
00682 
00683    return kTRUE;
00684 }
00685 
00686 //______________________________________________________________________________
00687 Bool_t TGDNDManager::HandleDNDPosition(Window_t source, Int_t x_root, Int_t y_root,
00688                                       Atom_t action, Time_t /*timestamp*/)
00689 {
00690    // Handle DND position event.
00691 
00692    Int_t x, y;
00693    Window_t child;
00694    TGFrame *f = 0, *main = 0;
00695    TGWindow *w = 0;
00696    Window_t wtarget = 0;
00697 
00698    wtarget = FindWindow(gVirtualX->GetDefaultRootWindow(), x_root, y_root, 15);
00699 
00700    if (wtarget) {
00701       gVirtualX->TranslateCoordinates(gVirtualX->GetDefaultRootWindow(),
00702                                       wtarget, x_root, y_root, x, y, child);
00703       w = gClient->GetWindowById(wtarget);
00704       if (w)
00705          f = dynamic_cast<TGFrame *>(w);
00706    }
00707 
00708    if (f != fLocalTarget) {
00709       if (fLocalTarget) fLocalTarget->HandleDNDLeave();
00710       fLocalTarget = f;
00711       if (fLocalTarget) {
00712          main = (TGFrame *)fLocalTarget->GetMainFrame();
00713          main->RaiseWindow();
00714          if (fMain == 0)
00715             fMain = main;
00716          fDropType = fLocalTarget->HandleDNDEnter(fDraggerTypes);
00717       }
00718    }
00719    // query the target widget to determine whether it accepts the
00720    // required action
00721    if (fLocalTarget) {
00722       action = (fDropType == kNone) ? kNone :
00723               fLocalTarget->HandleDNDPosition(x, y, action, x_root, y_root);
00724    } else if (fProxyOurs) {
00725       action = fMain->HandleDNDPosition(x, y, action, x_root, y_root);
00726    } else {
00727       action = kNone;
00728    }
00729    SendDNDStatus(source, fLocalAction = action);
00730    return kTRUE;
00731 }
00732 
00733 //______________________________________________________________________________
00734 Bool_t TGDNDManager::HandleDNDStatus(Window_t target, Int_t accepted,
00735                                     Rectangle_t /*area*/, Atom_t action)
00736 {
00737    // Handle DND status event.
00738 
00739    if (target) {
00740       fStatusPending = kFALSE;
00741       if (accepted) {
00742          fDropAccepted = kTRUE;
00743          fAcceptedAction = action;
00744          if (fDragWin)
00745             gVirtualX->ChangeActivePointerGrab(fDragWin->GetId(),
00746                                                fGrabEventMask, kNone);
00747       } else {
00748          fDropAccepted = kFALSE;
00749          fAcceptedAction = kNone;
00750          if (fDragWin)
00751             gVirtualX->ChangeActivePointerGrab(fDragWin->GetId(),
00752                                                fGrabEventMask,
00753                                                fDNDNoDropCursor);
00754       }
00755       if (fDropTimeout) {   // were we waiting for this to do the drop?
00756          delete fDropTimeout;
00757          fDropTimeout = 0;
00758          SendDNDDrop(fTarget);
00759       }
00760    }
00761    return kTRUE;
00762 }
00763 
00764 //______________________________________________________________________________
00765 Bool_t TGDNDManager::HandleDNDDrop(Window_t source, Time_t timestamp)
00766 {
00767    // Handle DND drop event.
00768 
00769    // to get the data, we must call XConvertSelection with
00770    // the timestamp in XdndDrop, wait for SelectionNotify
00771    // to arrive to retrieve the data, and when we are finished,
00772    // send a XdndFinished message to the source.
00773 
00774    if (fMain && fDropType != kNone) {
00775       gVirtualX->ChangeProperties(fMain->GetId(), fgXCDNDData, fDropType,
00776                                   8, (unsigned char *) 0, 0);
00777 
00778       gVirtualX->ConvertSelection(fMain->GetId(), fgDNDSelection, fDropType,
00779                                   fgXCDNDData, timestamp);
00780    }
00781 
00782    fSource = source;
00783    if (fMain) SendDNDFinished(source);
00784 
00785    return kTRUE;
00786 }
00787 
00788 //______________________________________________________________________________
00789 Bool_t TGDNDManager::HandleDNDFinished(Window_t /*target*/)
00790 {
00791    // Handle DND finished event.
00792 
00793    if (fLocalSource) fLocalSource->HandleDNDFinished();
00794    return kTRUE;
00795 }
00796 
00797 //______________________________________________________________________________
00798 Bool_t TGDNDManager::HandleSelectionRequest(Event_t *event)
00799 {
00800    // Handle selection request event.
00801 
00802    if ((Atom_t)event->fUser[1] == fgDNDSelection) {
00803       Event_t xevent;
00804       TDNDData *dnddata = 0;
00805       char *data;
00806       int len;
00807 
00808       // get the data from the drag source widget
00809       if (fLocalSource)
00810          dnddata = fLocalSource->GetDNDData(event->fUser[2]);
00811 
00812       data = dnddata ? (char *) dnddata->fData : (char *) "";
00813       len  = dnddata ? dnddata->fDataLength : 0;
00814 
00815       if ((Atom_t)event->fUser[3] == kNone) {
00816          //printf("warning: kNone property specified in SelectionRequest\n");
00817          event->fUser[3] = fgXCDNDData;
00818       }
00819 
00820       gVirtualX->ChangeProperties(event->fUser[0], event->fUser[3],
00821                                   event->fUser[2], 8,
00822                                   (unsigned char *) data, len);
00823 
00824       xevent.fType    = kSelectionNotify;
00825       xevent.fTime    = event->fTime;
00826       xevent.fUser[0] = event->fUser[0]; // requestor
00827       xevent.fUser[1] = event->fUser[1]; // selection
00828       xevent.fUser[2] = event->fUser[2]; // target;
00829       xevent.fUser[3] = event->fUser[3]; // property;
00830       gVirtualX->SendEvent(event->fUser[0], &xevent);
00831 
00832       return kTRUE;
00833 
00834    } else {
00835       return kFALSE;  // not for us...
00836    }
00837 }
00838 
00839 //______________________________________________________________________________
00840 Bool_t TGDNDManager::HandleSelection(Event_t *event)
00841 {
00842    // Handle selection event.
00843 
00844    if ((Atom_t)event->fUser[1] == fgDNDSelection) {
00845       Atom_t actual = fDropType;
00846       Int_t format = 8;
00847       ULong_t count, remaining;
00848       unsigned char *data = 0;
00849 
00850       gVirtualX->GetProperty(event->fUser[0], event->fUser[3],
00851                              0, 0x8000000L, kTRUE, event->fUser[2],
00852                              &actual, &format, &count, &remaining, &data);
00853 
00854       if ((actual != fDropType) || (format != 8) || (count == 0) || !data) {
00855          if (data) delete[] data;
00856          return kFALSE;
00857       }
00858 
00859       if (fSource != kNone) SendDNDFinished(fSource);
00860 
00861       // send the data to the target widget
00862 
00863       if (fLocalTarget) {
00864          TDNDData dndData(actual, data, count, fLocalAction);
00865          fLocalTarget->HandleDNDDrop(&dndData);
00866          if (fDraggerTypes) delete[] fDraggerTypes;
00867          fDraggerTypes = 0;
00868       }
00869 
00870       fSource = kNone;
00871       fLocalAction = kNone;
00872 
00873 //      delete[] data;
00874 
00875       return kTRUE;
00876 
00877    } else {
00878       return kFALSE;  // not for us...
00879    }
00880 }
00881 
00882 //______________________________________________________________________________
00883 void TGDNDManager::SetDragPixmap(Pixmap_t pic, Pixmap_t mask,
00884                                 int hot_x, int hot_y)
00885 {
00886    // Set drag window pixmaps and hotpoint.
00887 
00888    fPic  = pic;
00889    fMask = mask;
00890    fHotx = hot_x;
00891    fHoty = hot_y;
00892 }
00893 
00894 //______________________________________________________________________________
00895 Bool_t TGDNDManager::StartDrag(TGFrame *src, int x_root, int y_root,
00896                               Window_t grabWin)
00897 {
00898    // Start dragging.
00899 
00900    if (fDragging) return kTRUE;
00901 
00902    fLocalSource = src;
00903 
00904    if ((TGWindow *)fMain != src->GetMainFrame()) {
00905       fMain = (TGFrame *)src->GetMainFrame();
00906    }
00907 
00908    if (!gVirtualX->SetSelectionOwner(fMain->GetId(), fgDNDSelection)) {
00909       // hmmm... failed to acquire ownership of XdndSelection!
00910       return kFALSE;
00911    }
00912 
00913    if (grabWin == kNone) grabWin = fMain->GetId();
00914 
00915    gVirtualX->GrabPointer(grabWin, fGrabEventMask, kNone, fDNDNoDropCursor, kTRUE, kFALSE);
00916 
00917    fLocalTarget = 0;
00918    fDragging = kTRUE;
00919    fTarget = kNone;
00920    fTargetIsDNDAware = kFALSE;
00921    fStatusPending = kFALSE;
00922    if (fDropTimeout) delete fDropTimeout;
00923    fDropTimeout = 0;
00924    fDropAccepted = kFALSE;
00925    fAcceptedAction = kNone;
00926    fLocalAction = kNone;
00927 
00928    if (!fDragWin && fPic != kNone && fMask != kNone) {
00929       fDragWin = new TGDragWindow(gClient->GetDefaultRoot(), fPic, fMask);
00930       fDragWin->Move((x_root-fHotx)|1, (y_root-fHoty)|1);
00931       fDragWin->MapSubwindows();
00932       fDragWin->MapRaised();
00933    }
00934    return kTRUE;
00935 }
00936 
00937 //______________________________________________________________________________
00938 Bool_t TGDNDManager::Drop()
00939 {
00940    // Drop.
00941 
00942    if (!fDragging) return kFALSE;
00943 
00944    if (fTargetIsDNDAware) {
00945       if (fDropAccepted) {
00946          if (fStatusPending) {
00947             if (fDropTimeout) delete fDropTimeout;
00948             fDropTimeout = new TTimer(this, 5000);
00949          } else {
00950             SendDNDDrop(fTarget);
00951          }
00952       } else {
00953          SendDNDLeave(fTarget);
00954          fStatusPending = kFALSE;
00955       }
00956    }
00957    EndDrag();
00958    return kTRUE;
00959 }
00960 
00961 //______________________________________________________________________________
00962 Bool_t TGDNDManager::EndDrag()
00963 {
00964    // End dragging.
00965 
00966    if (!fDragging) return kFALSE;
00967 
00968    gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
00969 
00970    if (fSource)
00971       SendDNDFinished(fSource);
00972    if (fLocalSource)
00973       fLocalSource->HandleDNDFinished();
00974 
00975    fDragging = kFALSE;
00976    if (fDragWin) {
00977       fDragWin->DeleteWindow();
00978       fDragWin = 0;
00979    }
00980    return kTRUE;
00981 }
00982 
00983 //______________________________________________________________________________
00984 Bool_t TGDNDManager::Drag(int x_root, int y_root, Atom_t action, Time_t timestamp)
00985 {
00986    // Process drag event.
00987 
00988    if (!fDragging) return kFALSE;
00989 
00990    Window_t newTarget = FindWindow(gVirtualX->GetDefaultRootWindow(),
00991                                    x_root, y_root, 15);
00992 
00993    if (newTarget == kNone) {
00994       Window_t t = GetRootProxy();
00995       if (t != kNone) newTarget = t;
00996    }
00997 
00998    if (fTarget != newTarget) {
00999 
01000       if (fTargetIsDNDAware) SendDNDLeave(fTarget);
01001 
01002       fTarget = newTarget;
01003       fTargetIsDNDAware = IsDNDAware(fTarget);
01004       fStatusPending = kFALSE;
01005       fDropAccepted = kFALSE;
01006       fAcceptedAction = kNone;
01007 
01008       if (fTargetIsDNDAware) SendDNDEnter(fTarget);
01009 
01010       if (fDragWin)
01011          gVirtualX->ChangeActivePointerGrab(fDragWin->GetId(), fGrabEventMask,
01012                                             fDNDNoDropCursor);
01013    }
01014 
01015    if (fTargetIsDNDAware && !fStatusPending) {
01016       SendDNDPosition(fTarget, x_root, y_root, action, timestamp);
01017 
01018       // this is to avoid sending XdndPosition messages over and over
01019       // if the target is not responding
01020       fStatusPending = kTRUE;
01021    }
01022 
01023    if (fDragWin) {
01024       fDragWin->RaiseWindow();
01025       fDragWin->Move((x_root-fHotx)|1, (y_root-fHoty)|1);
01026    }
01027    return kTRUE;
01028 }
01029 
01030 //______________________________________________________________________________
01031 Bool_t TGDNDManager::SetRootProxy()
01032 {
01033    // Set root window proxy.
01034 
01035    Window_t mainw = fMain->GetId();
01036    int result = kFALSE;
01037 
01038    if (GetRootProxy() == kNone) {
01039       gVirtualX->ChangeProperties(gVirtualX->GetDefaultRootWindow(),
01040                                   fgDNDProxy, XA_WINDOW, 32,
01041                                   (unsigned char *) &mainw, 1);
01042       gVirtualX->ChangeProperties(mainw, fgDNDProxy, XA_WINDOW, 32,
01043                                   (unsigned char *) &mainw, 1);
01044 
01045       fProxyOurs = kTRUE;
01046       result = kTRUE;
01047    }
01048    // XSync(_dpy, kFALSE);
01049    gVirtualX->UpdateWindow(0);
01050    return result;
01051 }
01052 
01053 //______________________________________________________________________________
01054 Bool_t TGDNDManager::RemoveRootProxy()
01055 {
01056    // Remove root window proxy.
01057 
01058    if (!fProxyOurs) return kFALSE;
01059 
01060    gVirtualX->DeleteProperty(fMain->GetId(), fgDNDProxy);
01061    gVirtualX->DeleteProperty(gVirtualX->GetDefaultRootWindow(), fgDNDProxy);
01062    // the following is to ensure that the properties
01063    // (specially the one on the root window) are deleted
01064    // in case the application is exiting...
01065 
01066    // XSync(_dpy, kFALSE);
01067    gVirtualX->UpdateWindow(0);
01068 
01069    fProxyOurs = kFALSE;
01070 
01071    return kTRUE;
01072 }

Generated on Tue Jul 5 14:21:58 2011 for ROOT_528-00b_version by  doxygen 1.5.1