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