Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / DndDrag.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: DndDrag.c /main/5 1996/09/27 19:00:40 drk $ */
24  /*********************************************************************
25  *
26  *      File:           DndDrag.c
27  *
28  *      Description:    Implemenation of DND Drag Initator
29  *
30  *********************************************************************
31  *
32  *+SNOTICE
33  *
34  *      RESTRICTED CONFIDENTIAL INFORMATION:
35  *      
36  *      The information in this document is subject to special
37  *      restrictions in a confidential disclosure agreement between
38  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
39  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
40  *      Sun's specific written approval.  This documment and all copies
41  *      and derivative works thereof must be returned or destroyed at
42  *      Sun's request.
43  *
44  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
45  *
46  * (c) Copyright 1993, 1994 Hewlett-Packard Company
47  * (c) Copyright 1993, 1994 International Business Machines Corp.
48  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
49  * (c) Copyright 1993, 1994 Novell, Inc.
50  *
51  *+ENOTICE
52  */
53
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <X11/Intrinsic.h> 
58 #include <Xm/AtomMgr.h> 
59 #include <Xm/DragDrop.h>
60 #include <Xm/DragC.h> 
61 #include <Xm/DragCP.h>
62 #include <Xm/DragOverSP.h>
63 #include "Dnd.h"
64 #include "DndP.h"
65 #include "DtSvcLock.h"
66
67 /* 
68  * Drag Initiator Callbacks
69  */
70 static Boolean  dndConvertProc(Widget, Atom*, Atom*, Atom*, XtPointer *,
71                                 unsigned long*, int*);
72 static void     dndAppConvert(Widget, int, XEvent*, DtDragInfo*);
73 static void     dndDropStartCallback(Widget, XtPointer, XtPointer);
74 static void     dndDropFinishCallback(Widget, XtPointer, XtPointer);
75 static void     dndDragDropFinishCallback(Widget, XtPointer, XtPointer);
76 static void     dndTopLevelEnterCallback(Widget, XtPointer, XtPointer);
77 static void     dndTopLevelLeaveCallback(Widget, XtPointer, XtPointer);
78
79 /*
80  * Drag Initiator Resources
81  */
82 typedef struct {
83         XtCallbackList  dropOnRootCallback;
84         Widget          sourceIcon;
85         Boolean         bufferIsText;
86 } DragSettings;
87
88 #define Offset(field)   XtOffsetOf(DragSettings, field)
89
90 static XtResource dragResources[] = {
91       { DtNdropOnRootCallback, DtCDropOnRootCallback, 
92         XtRCallback, sizeof(XtCallbackList), Offset(dropOnRootCallback), 
93         XtRImmediate, (XtPointer)NULL},
94       { DtNsourceIcon, DtCSourceIcon, 
95         XtRWidget, sizeof(Widget), Offset(sourceIcon), 
96         XtRImmediate, (XtPointer)NULL },
97       { DtNbufferIsText, DtCBufferIsText, 
98         XtRBoolean, sizeof(Boolean), Offset(bufferIsText), 
99         XtRImmediate, (XtPointer)False },
100 };
101
102 #undef Offset
103
104 /*
105  * DtDndVaDragStart
106  *
107  *      Drag Start - varargs version
108  */
109
110 Widget
111 DtDndVaDragStart(
112         Widget          dragInitiator,
113         XEvent*         event,
114         DtDndProtocol   protocol,
115         Cardinal        numItems,
116         unsigned char   operations,
117         XtCallbackList  dragConvertCallback,
118         XtCallbackList  dragFinishCallback,
119         ...)
120 {
121         Widget          dragContext;
122         va_list         vaList;
123         ArgList         argList;
124         Cardinal        argCount;
125         _DtSvcWidgetToAppContext(dragInitiator);
126
127         _DtSvcAppLock(app);
128
129         va_start(vaList, dragFinishCallback);
130         argCount = _DtDndCountVarArgs(vaList);
131         va_end(vaList);
132
133         va_start(vaList, dragFinishCallback);
134         _DtDndArgListFromVarArgs(vaList, argCount, &argList, &argCount);
135         va_end(vaList);
136
137         dragContext = DtDndDragStart(dragInitiator, event, protocol, 
138                                         numItems, operations,
139                                         dragConvertCallback, dragFinishCallback,
140                                         argList, argCount);
141
142         XtFree((char *)argList);
143
144         _DtSvcAppUnlock(app);
145         return dragContext;
146 }
147
148 /*
149  * DtDndVaDragStart
150  *
151  *      Drag Start - arglist version
152  */
153
154 Widget
155 DtDndDragStart(
156         Widget          dragInitiator,
157         XEvent*         event,
158         DtDndProtocol   protocol,
159         Cardinal        numItems,
160         unsigned char   operations,
161         XtCallbackList  dragConvertCallback,
162         XtCallbackList  dragFinishCallback,
163         ArgList         argList,
164         Cardinal        argCount)
165 {
166         XtCallbackRec   dragDropFinishCbRec[] = { {dndDragDropFinishCallback,
167                                                    NULL}, {NULL, NULL} };
168         XtCallbackRec   topLevelEnterCbRec[]  = { {dndTopLevelEnterCallback,
169                                                    NULL},  {NULL, NULL} };
170         XtCallbackRec   topLevelLeaveCbRec[]  = { {dndTopLevelLeaveCallback,
171                                                    NULL},  {NULL, NULL} };
172         XtCallbackRec   dropStartCbRec[]      = { {dndDropStartCallback,
173                                                    NULL}, {NULL, NULL} };
174         XtCallbackRec   dropFinishCbRec[]     = { {dndDropFinishCallback,
175                                                    NULL}, {NULL, NULL} };
176         Display *       display         = XtDisplayOfObject(dragInitiator);
177         Screen *        screen          = XtScreenOfObject(dragInitiator);
178         Window          rootWindow      = RootWindowOfScreen(screen);
179         DtDragInfo *    dtDragInfo;
180         DragSettings    settings;
181         DtDndDragSource sourceType;
182         DtDndTransfer * transfer;
183         Arg *           args;
184         int             ii, nn, savedEventType;
185         Atom *          exportTargets;
186         Cardinal        numExportTargets;
187         _DtSvcWidgetToAppContext(dragInitiator);
188
189         _DtSvcAppLock(app);
190         /*
191          * Reject the drag if noop or multiple protocols specified
192          */
193
194         switch (protocol) {
195         case DtDND_BUFFER_TRANSFER:
196         case DtDND_FILENAME_TRANSFER:
197         case DtDND_TEXT_TRANSFER:
198                 break;
199         case DtDND_NOOP_TRANSFER:
200         default:
201                 _DtSvcAppUnlock(app);
202                 return (Widget)NULL;
203         }
204
205         /*
206          * Parse resources into dragResources
207          */
208
209         XtGetSubresources(dragInitiator, &settings, 
210                                 (String)NULL, (String)NULL, 
211                                 dragResources, XtNumber(dragResources),
212                                 argList, argCount);
213
214         /*
215          * Initialize DragInfo
216          */
217
218         dtDragInfo = (DtDragInfo *) XtMalloc(sizeof(DtDragInfo));
219
220         dtDragInfo->dragInitiator               = dragInitiator;
221         dtDragInfo->dragContext                 = NULL;
222         dtDragInfo->protocol                    = protocol;
223         dtDragInfo->numItems                    = numItems;
224         dtDragInfo->operations                  = operations;
225         dtDragInfo->sourceIcon                  = settings.sourceIcon;
226         dtDragInfo->bufferIsText                = settings.bufferIsText;
227         dtDragInfo->dragData                    = NULL;
228         dtDragInfo->inRoot                      = False;
229         dtDragInfo->status                      = DtDND_SUCCESS;
230         dtDragInfo->clientData                  = NULL;
231         dtDragInfo->backdropWindow 
232                         = DtWsmGetCurrentBackdropWindow(display, rootWindow);
233
234         dtDragInfo->dragConvertCallback
235                          = _DtDndCopyCallbackList(dragConvertCallback);
236         dtDragInfo->dragFinishCallback
237                          = _DtDndCopyCallbackList(dragFinishCallback);
238         dtDragInfo->dropOnRootCallback
239                          = _DtDndCopyCallbackList(settings.dropOnRootCallback);
240
241         dtDragInfo->dragData = (DtDndContext *)XtCalloc(1,sizeof(DtDndContext));
242         dtDragInfo->dragData->protocol          = dtDragInfo->protocol;
243         dtDragInfo->dragData->numItems          = 0;
244
245         /*
246          * Get data transfer method
247          * Use the transfer targets as export targets
248          */
249
250         dtDragInfo->transfer = _DtDndCreateExportTransfer(dtDragInfo);
251
252         exportTargets           = dtDragInfo->transfer->targets;
253         numExportTargets        = dtDragInfo->transfer->numTargets;
254
255 #ifdef DEBUG
256         printf("DtDndDragStart: drag from widget 0x%p\n", dragInitiator);
257         _DtDndPrintTransfers(display,dtDragInfo->transfer,1);
258 #endif
259
260         /*
261          * Set up drag icon
262          */
263
264         if (numItems > 1) {
265                 sourceType = DtDND_DRAG_SOURCE_MULTIPLE;
266         } else {
267                 sourceType = dtDragInfo->transfer->methods->sourceType;
268         }
269         
270         _DtDndSelectDragSource(dragInitiator, sourceType, 
271                                 dtDragInfo->sourceIcon);
272
273         /*
274          * Construct argument list
275          */
276
277 #define NUM_DRAG_ARGS   30
278         args = (Arg *) XtMalloc(sizeof(Arg) * (NUM_DRAG_ARGS + argCount));
279 #undef  NUM_DRAG_ARGS
280
281         /*
282          * Copy in passed arguments
283          */
284         nn = 0;
285
286         for (ii = 0; ii < argCount; ii++) {
287                 XtSetArg(args[nn], argList[ii].name, argList[ii].value); nn++;
288         }
289
290         /*
291          * Set basic drag start arguments
292          */
293
294         XtSetArg(args[nn], XmNexportTargets,    exportTargets);
295         nn++;
296         XtSetArg(args[nn], XmNnumExportTargets, numExportTargets);
297         nn++;
298         XtSetArg(args[nn], XmNdragOperations,   operations);
299         nn++;
300         XtSetArg(args[nn], XmNblendModel,       XmBLEND_ALL);
301         nn++;
302         XtSetArg(args[nn], XmNcursorBackground, WhitePixelOfScreen(screen));
303         nn++;
304         XtSetArg(args[nn], XmNcursorForeground, BlackPixelOfScreen(screen));
305         nn++;
306         XtSetArg(args[nn], XmNclientData,       dtDragInfo);
307                                         nn++;
308
309         if (dtDragInfo->sourceIcon != NULL) {
310                 XtSetArg(args[nn],XmNsourcePixmapIcon, dtDragInfo->sourceIcon);
311                 nn++;
312                 XtSetArg(args[nn],XmNsourceCursorIcon, dtDragInfo->sourceIcon);
313                 nn++;
314         }
315
316         /*
317          * Set up DnD callbacks for Motif
318          */
319
320         XtSetArg(args[nn], XmNconvertProc,      dndConvertProc);
321         nn++;
322    
323         dragDropFinishCbRec[0].closure  = (XtPointer) dtDragInfo;
324         dropFinishCbRec[0].closure      = (XtPointer) dtDragInfo;
325         dtDragInfo->dragDropFinishCallback 
326                          = _DtDndCopyCallbackList(dragDropFinishCbRec);
327         dtDragInfo->dropFinishCallback
328                          = _DtDndCopyCallbackList(dropFinishCbRec);
329
330         XtSetArg(args[nn], XmNdragDropFinishCallback, dtDragInfo->dragDropFinishCallback);
331         nn++;
332         XtSetArg(args[nn], XmNdropFinishCallback, dtDragInfo->dropFinishCallback);
333         nn++;
334
335         /*
336          * Only use top-level-enter/leave callbacks if also doing drop-on-root
337          */
338
339         if (dtDragInfo->dropOnRootCallback != NULL) {
340
341                 topLevelEnterCbRec[0].closure   = (XtPointer) dtDragInfo;
342                 topLevelLeaveCbRec[0].closure   = (XtPointer) dtDragInfo;
343                 dropStartCbRec[0].closure       = (XtPointer) dtDragInfo;
344                 dtDragInfo->topLevelEnterCallback
345                          = _DtDndCopyCallbackList(topLevelEnterCbRec);
346                 dtDragInfo->topLevelLeaveCallback
347                          = _DtDndCopyCallbackList(topLevelLeaveCbRec);
348                 dtDragInfo->dropStartCallback
349                          = _DtDndCopyCallbackList(dropStartCbRec);
350
351                 XtSetArg(args[nn], XmNtopLevelEnterCallback, dtDragInfo->topLevelEnterCallback);
352                 nn++;
353                 XtSetArg(args[nn], XmNtopLevelLeaveCallback, dtDragInfo->topLevelLeaveCallback);
354                 nn++;
355                 XtSetArg(args[nn], XmNdropStartCallback, dtDragInfo->dropStartCallback);
356                 nn++;
357         }
358
359         /*
360          * Fake a button press. This is necessary because Motif requires
361          * a drag to start on a button press. We need to be able to start
362          * a drag on a mouse motion event when Bselect is held down. Since
363          * the motion event has the fields necessary for Motif this works.
364          */
365
366         savedEventType = event->type;
367
368         if (event->type == MotionNotify) {
369                 event->type = ButtonPress;
370         }
371
372         /*
373          * Start the drag
374          */
375
376         dtDragInfo->dragContext = XmDragStart(dragInitiator, event, args, nn);
377
378         XtFree((char *)args);
379
380         event->type = savedEventType;
381
382         _DtSvcAppUnlock(app);
383         return (dtDragInfo->dragContext);
384 }
385
386 /*********************************************************************
387  *
388  *      Drag Initiator Callbacks
389  *
390  *********************************************************************/
391
392 /*
393  * dndDropStartCallback
394  *
395  *      
396  */
397 static void
398 dndDropStartCallback(
399         Widget          dragContext,
400         XtPointer       clientData,
401         XtPointer       callData)
402 {
403         DtDragInfo     *dtDragInfo      = (DtDragInfo *) clientData;
404         DtDndContext   *dragData;
405         XmDragContext   xmDragContext = (XmDragContext)dtDragInfo->dragContext;
406         XmDropStartCallbackStruct *xmDropInfo = (XmDropStartCallback) callData; 
407         DtDndTransferCallbackStruct     dropCallData;
408         int             posOffsetX, posOffsetY;
409
410         /*
411          * If the user has cancelled the drop, or the drop isn't on the
412          * root, or there are no dropOnRoot or convert callbacks
413          * then reject the drop.
414          */  
415
416         if (xmDragContext->drag.dragCompletionStatus == XmDROP_CANCEL ||
417             dtDragInfo->inRoot == False ||
418             dtDragInfo->dropOnRootCallback == NULL ||
419             dtDragInfo->dragConvertCallback == NULL ) {
420  
421                 xmDropInfo->dropSiteStatus      = XmINVALID_DROP_SITE;
422                 xmDropInfo->dropAction          = XmDROP_CANCEL;
423
424                 return;
425         }
426
427         /*
428          * The following is to handle the dropOnRoot situation.
429          * We handle both the convert and transfer sides of the
430          * transaction here.  First we get the application drag data
431          * and then we call the application dropOnRoot callback.
432          */
433  
434         /*
435          * Initialize protocol specific dragData
436          */
437
438         dtDragInfo->dragData->numItems  = dtDragInfo->numItems;
439
440         (*dtDragInfo->transfer->methods->convertInit)(dtDragInfo);
441
442         /*
443          * Invoke the application convert callback
444          */
445
446         dndAppConvert(dragContext, DtCR_DND_CONVERT_DATA, 
447                         xmDropInfo->event, dtDragInfo);
448
449         if (dtDragInfo->status == DtDND_FAILURE) {
450                 return;
451         }
452
453         /*
454          * Setup dropOnRootcall data and invoke the dropOnroot callback
455          */
456
457         _DtDndGetIconOffset(dtDragInfo->dragContext,
458                         dtDragInfo->transfer->methods->sourceType,
459                         &posOffsetX, &posOffsetY);
460
461         dropCallData.reason             = DtCR_DND_ROOT_TRANSFER;
462         dropCallData.event              = xmDropInfo->event;
463         dropCallData.x                  = xmDropInfo->x + posOffsetX;
464         dropCallData.y                  = xmDropInfo->y + posOffsetY;
465         dropCallData.operation          = xmDropInfo->operation;
466         dropCallData.dropData           = dtDragInfo->dragData;
467         dropCallData.completeMove       = False;
468         dropCallData.status             = DtDND_SUCCESS;
469
470         _DtDndCallCallbackList(dragContext, dtDragInfo->dropOnRootCallback,
471                 (XtPointer)&dropCallData);
472
473         /*
474          * Tell Motif that the root is a valid drop site
475          */
476
477         xmDropInfo->dropSiteStatus      = XmVALID_DROP_SITE;
478         xmDropInfo->dropAction          = XmDROP;
479 }
480
481 /*
482  * dndConvertProc
483  *
484  *
485  */
486 static Boolean
487 dndConvertProc(
488         Widget          dragContext,
489         Atom           *selection,
490         Atom           *target,
491         Atom           *returnType,
492         XtPointer      *returnValue,
493         unsigned long  *returnLength,
494         int            *returnFormat)
495 {
496         Atom            realSelectionAtom; /* Motif hides the selection atom */
497         DtDragInfo     *dtDragInfo = NULL;
498         XSelectionRequestEvent *selectionRequestEvent;
499         Boolean         status;
500
501 #ifdef DEBUG
502         {
503         Display *display = XtDisplayOfObject(dragContext);
504         char   *atomname = XGetAtomName(display,*target);
505         printf("dndConvertProc:  target = %s\n",(atomname ? atomname : "Null"));
506         if (atomname) XFree(atomname);
507         }
508 #endif
509         /*
510          * Get the DtDragInfo
511          */
512
513         XtVaGetValues(dragContext, XmNclientData, &dtDragInfo, NULL);
514
515         if (dtDragInfo == NULL || dtDragInfo->status == DtDND_FAILURE) {
516                 return False;
517         }
518
519         /*
520          * Get selection request event
521          */
522
523         XtVaGetValues(dragContext, XmNiccHandle, &realSelectionAtom, NULL);
524         selectionRequestEvent = XtGetSelectionRequest(dragContext,
525                 realSelectionAtom, NULL); /* REMIND: NULL for atomic transfer */
526
527         /*
528          * Get the application drag data if necessary
529          */
530
531         if (dtDragInfo->dragData->numItems == 0) {
532
533                 dtDragInfo->dragData->numItems  = dtDragInfo->numItems;
534                 
535                 (*dtDragInfo->transfer->methods->convertInit)(dtDragInfo);
536
537                 dndAppConvert(dragContext, DtCR_DND_CONVERT_DATA,
538                         (XEvent *)selectionRequestEvent, dtDragInfo);
539
540                 if (dtDragInfo->status == DtDND_FAILURE) {
541                         return False;
542                 }
543         }
544
545         /*
546          * Handle transfer protocol independent target conversions
547          */
548
549         if (*target == XA_TARGETS) {
550         /*
551          * TARGETS      Construct a list of targets consisting of those
552          *              the dnd library supports plus those supported by
553          *              the drag initiator.
554          */
555                 int     ii, LIBRARY_TARGETS = 6;
556                 Atom *  availTargets;
557                 Atom *  allTargets;
558                 Cardinal numAvailTargets;
559                 Cardinal numAllTargets;
560
561                 (*dtDragInfo->transfer->methods->getAvailTargets)(dtDragInfo, 
562                                 &availTargets, &numAvailTargets);
563
564                 numAllTargets = numAvailTargets + LIBRARY_TARGETS;
565                 allTargets    = (Atom *)XtMalloc(sizeof(Atom) * numAllTargets);
566
567                 for (ii = 0; ii < numAvailTargets; ii++) {
568                         allTargets[ii] = availTargets[ii];
569                 }
570
571                 XtFree((char *)availTargets);
572
573                 ii = numAvailTargets;
574
575                 allTargets[ii++] = XA_TARGETS;
576                 allTargets[ii++] = XA_TIMESTAMP;
577                 allTargets[ii++] = XA_MULTIPLE;
578                 allTargets[ii++] = XA_HOST_NAME;
579                 allTargets[ii++] = XA_SUN_FILE_HOST_NAME;
580                 allTargets[ii++] = XA_DELETE;
581
582                 *returnType     = XA_ATOM;
583                 *returnFormat   = 32;
584                 *returnValue    = (XtPointer)allTargets;
585                 *returnLength   = numAllTargets * sizeof(Atom)/4;
586
587                 status = True;
588
589         } else if (*target == XA_TIMESTAMP || *target == XA_MULTIPLE) {
590         /*
591          * TIMESTAMP and MULTIPLE are handled by the Intrinsics
592          */
593                 status = True;
594
595         } else if (*target == XA_HOST_NAME ||
596                    *target == XA_SUN_FILE_HOST_NAME) {
597         /*
598          * HOST_NAME, _SUN_FILE_HOST_NAME       The name of this host
599          */
600                 *returnType     = XA_STRING;
601                 *returnValue    = (XtPointer)XtNewString(_DtDndGetHostName());
602                 *returnLength   = strlen((char *)*returnValue) + 1;
603                 *returnFormat   = 8;
604
605                 status = True;
606
607         } else if (*target == XA_DELETE) {
608         /*
609          * DELETE       Set up convert callback data to specify
610          *              deletion and invoke the application-defined
611          *              convertCallback() to perform the delete.
612          */
613
614                 *returnType     = XA_NULL;
615                 *returnFormat   = 32;
616                 *returnValue    = (XtPointer) NULL;
617                 *returnLength   = 0;
618
619                 dndAppConvert(dragContext, DtCR_DND_CONVERT_DELETE,
620                         (XEvent *)selectionRequestEvent, dtDragInfo);
621
622                 status = True;
623
624         } else if (*target == XA_SUN_ENUM_COUNT) {
625         /*
626          * _SUN_ENUMERATION_COUNT       The number of items available
627          */
628                 int *count      = XtNew(int);
629
630                 if (dtDragInfo->dragData->numItems == 1) {
631                         count[0] = 1;
632                 } else {
633                         count[0] = 0;
634                         dtDragInfo->status = DtDND_FAILURE;
635                 }
636
637                 *returnType     = XA_INTEGER;
638                 *returnValue    = (XtPointer)count;
639                 *returnLength   = 1;
640                 *returnFormat   = 32;
641
642                 status = True;
643         } else {
644         /*
645          * Invoke protocol specific convert method
646          */
647                 status = (*dtDragInfo->transfer->methods->convert)(
648                                 dragContext, dtDragInfo,
649                                 selection, target, 
650                                 returnType, returnValue,
651                                 returnLength, returnFormat, 
652                                 selectionRequestEvent);
653         }
654
655         return status;
656 }
657
658 /*
659  * dndAppConvert
660  *
661  *      Call the application convert callback
662  */
663 static void
664 dndAppConvert(
665         Widget          dragContext,
666         int             reason,
667         XEvent *        event,
668         DtDragInfo *    dtDragInfo)
669 {
670         DtDndConvertCallbackStruct      convertCallData;
671
672         convertCallData.reason          = reason;
673         convertCallData.event           = event;
674         convertCallData.dragData        = dtDragInfo->dragData;
675         convertCallData.status          = DtDND_SUCCESS;
676
677         _DtDndCallCallbackList(dragContext, dtDragInfo->dragConvertCallback,
678                 (XtPointer)&convertCallData);
679
680         dtDragInfo->status = convertCallData.status;
681
682         if (reason == DtCR_DND_CONVERT_DATA &&
683             dtDragInfo->dragData->numItems <= 0) {
684                 dtDragInfo->status = DtDND_FAILURE;
685         }
686
687 }
688
689 /*
690  * dndDropFinishCallback
691  *
692  *      Handle drop-on-root case
693  */
694 static void
695 dndDropFinishCallback(
696         Widget          dragContext,
697         XtPointer       clientData,
698         XtPointer       callData)
699 {
700         DtDragInfo     *dtDragInfo = (DtDragInfo *) clientData;
701         XmDropFinishCallbackStruct *xmDropFinishCallData =
702                         (XmDropFinishCallbackStruct *) callData;
703
704         if (dtDragInfo->dropOnRootCallback != NULL &&
705             dtDragInfo->inRoot &&
706             xmDropFinishCallData->dropSiteStatus == XmVALID_DROP_SITE) {
707
708                 xmDropFinishCallData->completionStatus = XmDROP_SUCCESS;
709
710                 XtVaSetValues(dtDragInfo->dragContext,
711                         XmNblendModel, XmBLEND_NONE, NULL);
712         }
713 }
714
715 /*
716  * dndDragDropFinishCallback
717  *
718  *      Call the application dragFinishCallback
719  */
720 static void
721 dndDragDropFinishCallback(
722         Widget          dragContext,
723         XtPointer       clientData,
724         XtPointer       callData)
725 {
726         XmDragDropFinishCallbackStruct *xmDndFinishInfo =
727                                 (XmDragDropFinishCallbackStruct *)callData;
728         DtDragInfo                      *dtDragInfo = (DtDragInfo *)clientData;
729         DtDndDragFinishCallbackStruct   dragFinishCallData;
730
731         /*
732          * Invoke application dragFinishCallback
733          */
734
735         dragFinishCallData.reason       = DtCR_DND_DRAG_FINISH;
736         dragFinishCallData.event        = xmDndFinishInfo->event;
737         dragFinishCallData.sourceIcon   = dtDragInfo->sourceIcon;
738         dragFinishCallData.dragData     = dtDragInfo->dragData;
739
740         _DtDndCallCallbackList(dragContext, dtDragInfo->dragFinishCallback, 
741                 (XtPointer)&dragFinishCallData);
742
743         /*
744          * Restore motif default drag cursors
745          */
746
747         _DtDndSelectDragSource(dragContext, DtDND_DRAG_SOURCE_DEFAULT, NULL);
748
749         /*
750          * Invoke protocol specific convertFinish
751          */
752
753         (*dtDragInfo->transfer->methods->convertFinish)(dtDragInfo);
754
755         /*
756          * Free data structures allocated during the drag
757          */
758
759         XtFree((char *)dtDragInfo->transfer->targets);
760         XtFree((char *)dtDragInfo->transfer);
761         XtFree((char *)dtDragInfo->dragConvertCallback);
762         XtFree((char *)dtDragInfo->dragFinishCallback);
763         XtFree((char *)dtDragInfo->dragDropFinishCallback);
764         XtFree((char *)dtDragInfo->dropFinishCallback);
765         if (dtDragInfo->dropOnRootCallback != NULL) {
766           XtFree((char *)dtDragInfo->topLevelEnterCallback);
767           XtFree((char *)dtDragInfo->topLevelLeaveCallback);
768           XtFree((char *)dtDragInfo->dropStartCallback);
769         }
770         XtFree((char *)dtDragInfo->dropOnRootCallback);
771         XtFree((char *)dtDragInfo->dragData);
772         XtFree((char *)dtDragInfo);
773 }
774
775 /*
776  * dndTopLevelEnterCallback -- Support for drop-on-root callback.
777  *      When a drop-on-root callback has been set, determines if 
778  *      the drag has entered the root window (or equivalents)
779  *      and sneakily changes Motif's idea that the root is an
780  *      invalid drop site to think that it's really a valid one.
781  *      Also updates dtDragInfo.inRoot as needed.
782  */
783 static void
784 dndTopLevelEnterCallback(
785         Widget          dragContext,
786         XtPointer       clientData,
787         XtPointer       callData)
788 {
789         XmTopLevelEnterCallbackStruct  *xmEnterInfo =
790                 (XmTopLevelEnterCallbackStruct *) callData;
791         DtDragInfo             *dtDragInfo = (DtDragInfo *) clientData;
792         XmDragContext           xmDragContext = (XmDragContext) dragContext;
793         XmDragOverShellWidget   dragOverShell = xmDragContext->drag.curDragOver;
794
795         
796         if (xmEnterInfo->window == RootWindowOfScreen(xmEnterInfo->screen) ||
797             dtDragInfo->backdropWindow == xmEnterInfo->window ) {
798
799                 dragOverShell->drag.cursorState = XmVALID_DROP_SITE;
800                 _XmDragOverChange((Widget)dragOverShell,
801                         dragOverShell->drag.cursorState);
802
803                 dtDragInfo->inRoot = True;
804
805         } else {
806                 dtDragInfo->inRoot = False;
807         }
808 }
809
810 /*
811  * dndTopLevelLeaveCallback -- Support for drop-on-root callback.
812  *      When a drop-on-root callback has been set, determines if 
813  *      the drag is exiting the root window and restores Motif's
814  *      internal state back to thinking that the root window is
815  *      an invalid drop site.  We don't update dtDragInfo->inRoot
816  *      here since the top-level-leave callback is called before
817  *      the drop callback which needs to know if we're in the root
818  *      or not.
819  */
820 static void
821 dndTopLevelLeaveCallback(
822         Widget          dragContext,
823         XtPointer       clientData,
824         XtPointer       callData)
825 {
826         XmTopLevelLeaveCallbackStruct  *xmLeaveInfo =
827                 (XmTopLevelLeaveCallbackStruct *) callData;
828         DtDragInfo             *dtDragInfo = (DtDragInfo *) clientData;
829         XmDragContext           xmDragContext = (XmDragContext) dragContext;
830         XmDragOverShellWidget   dragOverShell = xmDragContext->drag.curDragOver;
831         
832
833         if (xmLeaveInfo->window == RootWindowOfScreen(xmLeaveInfo->screen) ||
834             dtDragInfo->backdropWindow == xmLeaveInfo->window ) {
835
836                 dragOverShell->drag.cursorState = XmINVALID_DROP_SITE;
837
838                 _XmDragOverChange((Widget)dragOverShell,
839                         dragOverShell->drag.cursorState);
840         }
841 }