Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / DndDrop.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: DndDrop.c /main/6 1996/09/27 19:00:45 drk $ */
24  /*********************************************************************
25  *
26  *      File:           DndDrop.c
27  *
28  *      Description:    Implementation of DND Drop Registration
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 <stdlib.h>
55 #include <stdarg.h>
56 #include <stdint.h>
57 #include <X11/Intrinsic.h> 
58 #include <Xm/AtomMgr.h> 
59 #include <Xm/DragDrop.h>
60 #include <Xm/DropSMgr.h> 
61 #include <Xm/DropTrans.h> 
62 #include "Dnd.h"
63 #include "DndP.h"
64 #include "DtSvcLock.h"
65
66 /* 
67  * Drop Receiver Callbacks
68  */
69
70 static void             dndDropProc(Widget, XtPointer, XtPointer);
71 static void             dndTransferStart(Widget, XmDropProcCallbackStruct*, 
72                                 DtDropInfo*, DtDndTransfer*, Atom*, Cardinal);
73 static void             dndTransferProc(Widget, XtPointer, Atom*, Atom*, 
74                                 XtPointer, unsigned long*, int*);
75 static void             dndAppTransfer(Widget, DtDropInfo*);
76 static void             dndDropAnimateCallback(Widget, XtPointer, XtPointer);
77
78 /*
79  * Drop Support Functions
80  */
81
82 static  void            dndDropSiteDestroy(Widget, XtPointer, XtPointer);
83 static  XID             dndGetContextXID(Display*);
84 static  Boolean         dndSaveDropInfo(Display*, Widget, DtDropInfo*);
85 static  DtDropInfo *    dndFindDropInfo(Display*, Widget);
86 static  void            dndTransferStartFailed(Widget);
87 static  void            dndTransferFail(DtDropInfo*, Widget);
88  
89 /*
90  * Drop Register Resources
91  */
92
93 typedef struct {
94         XtCallbackList  dropAnimateCallback;
95         Boolean         preserveRegistration;
96         Boolean         registerChildren;
97         Boolean         textIsBuffer;
98 } DropSettings;
99
100 #define Offset(field)   XtOffsetOf(DropSettings, field)
101
102 static XtResource dropResources[] = {
103       { DtNdropAnimateCallback, DtCDropAnimateCallback, 
104         XtRCallback, sizeof(XtCallbackList), Offset(dropAnimateCallback), 
105         XtRImmediate, (XtPointer)NULL },
106       { DtNpreserveRegistration, DtCPreserveRegistration, 
107         XtRBoolean, sizeof(Boolean), Offset(preserveRegistration), 
108         XtRImmediate, (XtPointer)True },
109       { DtNregisterChildren, DtCRegisterChildren, 
110         XtRBoolean, sizeof(Boolean), Offset(registerChildren), 
111         XtRImmediate, (XtPointer)False },
112       { DtNtextIsBuffer, DtCTextIsBuffer, 
113         XtRBoolean, sizeof(Boolean), Offset(textIsBuffer), 
114         XtRImmediate, (XtPointer)False },
115 };
116
117 extern int _DtDndCountVarArgs(va_list vaList);
118 extern void _DtDndArgListFromVarArgs(va_list vaList,
119                                      Cardinal maxArgs,
120                                      ArgList *argListReturn,
121                                      Cardinal *argCountReturn);
122
123
124
125 #undef Offset
126
127 /*
128  * DtDndVaDropRegister
129  *
130  *      Drop Site Registration - varargs version
131  */
132
133 void
134 DtDndVaDropRegister(
135         Widget          dropReceiver,
136         DtDndProtocol   protocols,
137         unsigned char   operations,
138         XtCallbackList  transferCallback,
139         ...)
140 {
141         va_list         vaList;
142         ArgList         argList;
143         Cardinal        argCount;
144         _DtSvcWidgetToAppContext(dropReceiver);
145
146         _DtSvcAppLock(app);
147         va_start(vaList, transferCallback);
148         argCount = _DtDndCountVarArgs(vaList);
149         va_end(vaList);
150
151         va_start(vaList, transferCallback);
152         _DtDndArgListFromVarArgs(vaList, argCount, &argList, &argCount);
153         va_end(vaList);
154
155         DtDndDropRegister(dropReceiver, protocols, operations, 
156                                 transferCallback, argList, argCount);
157
158         XtFree((char *)argList);
159         _DtSvcAppUnlock(app);
160 }
161
162 /*
163  * DtDndDropRegister
164  *
165  *      Drop Site Registration - arglist version
166  */
167
168 void
169 DtDndDropRegister(
170         Widget          dropReceiver,
171         DtDndProtocol   protocols,
172         unsigned char   operations,
173         XtCallbackList  dropTransferCallback,
174         ArgList         argList,
175         Cardinal        argCount)
176 {
177         Display *       display         = XtDisplayOfObject(dropReceiver);
178         DropSettings    settings;
179         DtDropInfo *    dtDropInfo;
180         DtDropSiteInfo* dsInfo = NULL;
181         DtDndTransfer * transfers;
182         Cardinal        numTransfers;
183         Atom            *importTargets;
184         Cardinal        numImportTargets;
185         unsigned char   mergedOperations;
186         Arg *           args;
187         int             ii, jj, kk, nn;
188         _DtSvcWidgetToAppContext(dropReceiver);
189
190         _DtSvcAppLock(app);
191
192         /*
193          * Reject a noop registration
194          */
195         if (protocols == DtDND_NOOP_TRANSFER) {
196                 _DtSvcAppUnlock(app);
197                 return;
198         }
199
200         /*
201          * Parse resources into dropResources
202          */
203         XtGetSubresources(dropReceiver, &settings,
204                                 (String)NULL, (String)NULL,
205                                 dropResources, XtNumber(dropResources),
206                                 argList, argCount);
207         /*
208          * Initialize DropInfo
209          */
210
211         dtDropInfo = (DtDropInfo *) XtMalloc(sizeof(DtDropInfo));
212
213         dtDropInfo->dropReceiver                = dropReceiver;
214         dtDropInfo->protocols                   = protocols;
215         dtDropInfo->operations                  = operations;
216         dtDropInfo->textIsBuffer                = settings.textIsBuffer;
217         dtDropInfo->dropSiteInfo                = NULL;
218         dtDropInfo->transferInfo                = NULL;
219         dtDropInfo->status                      = DtDND_SUCCESS;
220
221         dtDropInfo->dropTransferCallback 
222                         = _DtDndCopyCallbackList(dropTransferCallback);
223         dtDropInfo->dropAnimateCallback
224                         = _DtDndCopyCallbackList(settings.dropAnimateCallback);
225
226         /*
227          * Initialize Transfer Methods
228          */
229
230         transfers = _DtDndCreateImportTransfers(dtDropInfo, &numTransfers);
231
232         dtDropInfo->transfers           = transfers;
233         dtDropInfo->numTransfers        = numTransfers;
234
235 #ifdef DEBUG
236         printf("DtDndDropRegister: registering widget 0x%p\n", dropReceiver);
237         _DtDndPrintTransfers(display,transfers,numTransfers);
238 #endif
239
240         /*
241          * Preserve existing drop registration info if requested
242          */
243
244         if (settings.preserveRegistration) {
245                 Arg             pArgs[4];
246
247                 dsInfo = (DtDropSiteInfo *)XtMalloc(sizeof(DtDropSiteInfo));
248
249                 dsInfo->dropProc                = (XtCallbackProc)NULL;
250                 dsInfo->operations              = XmDROP_NOOP;
251                 dsInfo->importTargets           = NULL;
252                 dsInfo->numImportTargets        = 0;
253
254                 nn = 0;
255
256                 XtSetArg(pArgs[nn], XmNimportTargets,
257                                 &(dsInfo->importTargets));              nn++;
258                 XtSetArg(pArgs[nn], XmNdropSiteOperations,
259                                 &(dsInfo->operations));                 nn++;
260                 XtSetArg(pArgs[nn], XmNnumImportTargets,
261                                 &(dsInfo->numImportTargets));           nn++;
262                 XtSetArg(pArgs[nn], XmNdropProc,
263                                 &(dsInfo->dropProc));                   nn++;
264
265                 XmDropSiteRetrieve(dropReceiver, pArgs, nn);
266
267                 if ( (dsInfo->dropProc != NULL) && 
268                      (dsInfo->numImportTargets > 0)  &&
269                      (dsInfo->operations != XmDROP_NOOP) ){
270
271                         dtDropInfo->dropSiteInfo = dsInfo;
272                 } else {
273                         XtFree((char *)dsInfo);
274                         dsInfo = NULL;
275                 }
276         }
277         
278         /*
279          * Create list of import targets based on the requested transfer
280          * protocols and any preserved drop site registration.
281          */
282
283         numImportTargets = 0;
284
285         for (ii = 0; ii < numTransfers; ii++) {
286                 numImportTargets += transfers[ii].numTargets;
287         }
288
289         if (dsInfo != NULL) { 
290                 numImportTargets += dsInfo->numImportTargets;
291         }
292
293         importTargets = (Atom *) XtMalloc(numImportTargets * sizeof(Atom));
294
295         kk = 0;
296         for (ii = 0; ii < numTransfers; ii++) {
297                 for (jj = 0; jj < transfers[ii].numTargets; jj++) {
298                         importTargets[kk++] = transfers[ii].targets[jj];
299                 }
300         }
301
302         if (dsInfo != NULL) {
303                 for (jj = 0; jj < dsInfo->numImportTargets; jj++) {
304                         importTargets[kk++] = dsInfo->importTargets[jj];
305                 }
306         }
307
308         /*
309          * Merge operations
310          */
311  
312         if (dsInfo != NULL) {
313                 mergedOperations = dsInfo->operations | operations;
314         } else {
315                 mergedOperations = operations;
316         }
317
318         /*
319          * Create an argument list
320          */
321
322 #define NUM_DROP_ARGS   5
323         args = (Arg *) XtMalloc(sizeof(Arg) * (NUM_DROP_ARGS + argCount));
324 #undef  NUM_DROP_ARGS
325
326         /*
327          * Copy in passed arguments
328          */
329
330         nn = 0;
331
332         for (ii = 0; ii < argCount; ii++) {
333                 XtSetArg(args[nn], argList[ii].name, argList[ii].value); nn++;
334         }
335
336         /*
337          * Set argument list for drop site registration
338          */
339
340         XtSetArg(args[nn], XmNimportTargets,      importTargets);    nn++;
341         XtSetArg(args[nn], XmNnumImportTargets,   numImportTargets); nn++;
342         XtSetArg(args[nn], XmNdropSiteOperations, mergedOperations);       nn++;
343         XtSetArg(args[nn], XmNdropProc,           dndDropProc);            nn++;
344
345         if (settings.registerChildren) {
346                XtSetArg(args[nn], XmNdropSiteType, XmDROP_SITE_COMPOSITE); nn++;
347         }
348
349         /*
350          * Register the drop site
351          */
352
353         if (dsInfo != NULL) {
354                 XmDropSiteUnregister(dropReceiver);
355                 XmDropSiteRegister(dropReceiver, args, nn);
356         } else {
357                 XmDropSiteRegister(dropReceiver, args, nn);
358         }
359
360         /*
361          * Add a destroy callback to unregister the drop site
362          * Store the dropInfo using the dropReceiver as the context
363          * Free locally allocated memory
364          */
365
366         XtAddCallback(dropReceiver, XtNdestroyCallback, 
367                         dndDropSiteDestroy, NULL);
368
369         (void)dndSaveDropInfo(display, dropReceiver, dtDropInfo);
370
371         XtFree((char *)importTargets);
372         XtFree((char *)args);
373         _DtSvcAppUnlock(app);
374 }
375
376 /*
377  * DtDndDropUnregister
378  *
379  *      Unregister the drop site
380  */
381 void
382 DtDndDropUnregister(
383         Widget          dropReceiver)
384 {
385         Display        *display         = XtDisplayOfObject(dropReceiver);
386         DtDropInfo     *dtDropInfo;
387         DtDropSiteInfo *dsInfo;
388         _DtSvcWidgetToAppContext(dropReceiver);
389
390         _DtSvcAppLock(app);
391
392         /*
393          * Retrieve dropInfo.  If there isn't one then the drop site
394          * was not registered by DtDndDropRegister() so return.
395          */
396
397         if ((dtDropInfo = dndFindDropInfo(display, dropReceiver)) == NULL) {
398                 _DtSvcAppUnlock(app);
399                 return;
400         }
401         dsInfo = dtDropInfo->dropSiteInfo;
402
403         /*
404          * Unregister the drop site
405          */
406
407         XmDropSiteUnregister(dropReceiver);
408
409         /*
410          * If we have preserved drop site registration
411          * then restore the drop site to it's original state.
412          */
413
414         if (dsInfo != NULL) {
415                 Arg             args[4];
416                 Cardinal        nn = 0;
417  
418                 XtSetArg(args[nn], XmNimportTargets, 
419                         dsInfo->importTargets);                 nn++;
420                 XtSetArg(args[nn], XmNnumImportTargets,
421                         dsInfo->numImportTargets);              nn++;
422                 XtSetArg(args[nn], XmNdropProc,
423                         dsInfo->dropProc);                      nn++;
424                 XtSetArg(args[nn], XmNdropSiteOperations,
425                         dsInfo->operations);                    nn++;
426
427                 XmDropSiteRegister(dropReceiver, args, nn);
428
429                 XtFree((char *)dsInfo);
430         }
431  
432         /*
433          * Free callback, context and memory associated with DtDndDropRegister
434          */
435
436         XtRemoveCallback(dropReceiver, XtNdestroyCallback, 
437                         dndDropSiteDestroy, NULL);
438
439         XDeleteContext(display, dndGetContextXID(display), 
440                 (XContext)(intptr_t)dropReceiver);
441
442         _DtDndDestroyTransfers(dtDropInfo->transfers, dtDropInfo->numTransfers);
443
444         XtFree((char *)dtDropInfo->dropTransferCallback);
445         XtFree((char *)dtDropInfo->dropAnimateCallback);
446         XtFree((char *)dtDropInfo);
447         _DtSvcAppUnlock(app);
448 }
449
450
451 /*********************************************************************
452  *
453  * Drop Receiver Callbacks
454  *
455  *********************************************************************/
456
457
458 /*
459  * dndDropProc
460  *
461  *      Determine transfer target and operation and initiate transfer.
462  */
463 static void
464 dndDropProc(
465         Widget          dropReceiver,
466         XtPointer       clientData,
467         XtPointer       callData)
468 {
469         XmDropProcCallbackStruct *xmDropInfo =
470                         (XmDropProcCallbackStruct *) callData;
471         Display *       display         = XtDisplayOfObject(dropReceiver);
472         Boolean         compatible;
473         Atom *          exportTargets    = NULL;
474         Cardinal        numExportTargets = 0;
475         DtDropInfo *    dtDropInfo;
476         DtDropSiteInfo* dsInfo;
477         DtDndTransfer * transfer;
478  
479         /*
480          * Reject invalid drops
481          */
482
483         if ( (xmDropInfo->dropSiteStatus != XmDROP_SITE_VALID) || 
484              (xmDropInfo->operation == XmDROP_NOOP) || 
485              (xmDropInfo->dropAction != XmDROP) ) {
486
487 #ifdef DEBUG
488                 printf("dndDropProc: failed drop status or operation\n");
489 #endif
490                 dndTransferStartFailed(xmDropInfo->dragContext);
491                 return;
492         }
493
494         /*
495          * Get the cached DropInfo
496          */
497
498         if ((dtDropInfo = dndFindDropInfo(display, dropReceiver)) == NULL) {
499                 dndTransferStartFailed(xmDropInfo->dragContext);
500                 return;
501         }
502
503         /*
504          * Get the export targets from the dragContext
505          */
506
507         XtVaGetValues(xmDropInfo->dragContext,
508                 XmNexportTargets, &exportTargets,
509                 XmNnumExportTargets, &numExportTargets,
510                 NULL);
511
512         if (exportTargets == NULL) {
513                 dndTransferStartFailed(xmDropInfo->dragContext);
514                 dtDropInfo->status = DtDND_FAILURE;
515                 return;
516         }
517
518 #ifdef DEBUG
519         printf("dndDropProc: Export Targets: ");
520         _DtDndPrintTargets(display,exportTargets,numExportTargets);
521 #endif
522
523         /*
524          * Search the DnD protocol import targets list to see
525          * if it's a target we handle.  If it is then start our transfer.
526          */
527
528         transfer = _DtDndTransferFromTargets(
529                         dtDropInfo->transfers, dtDropInfo->numTransfers,
530                         exportTargets, numExportTargets);
531
532         if (transfer != NULL) {
533
534                 dndTransferStart(dropReceiver, xmDropInfo, dtDropInfo,
535                         transfer, exportTargets, numExportTargets);
536                 return;
537         }
538
539         /*
540          * If there isn't any alternate drop registration
541          * then fail the transfer
542          */
543
544         dsInfo = dtDropInfo->dropSiteInfo;
545
546         if (dsInfo == NULL) {
547                 dndTransferStartFailed(xmDropInfo->dragContext);
548                 dtDropInfo->status = DtDND_FAILURE;
549                 return;
550         }
551
552         /*
553          * Determine if the exportTargets are compatible with
554          * the alternate drop registration targets
555          * If they are not compatible then fail the transfer
556          * Otherwise call the original dropProc.
557          */
558
559         compatible = XmTargetsAreCompatible(display,
560                         dsInfo->importTargets, dsInfo->numImportTargets,
561                         exportTargets, numExportTargets);
562
563         if (!compatible) {
564                 dndTransferStartFailed(xmDropInfo->dragContext);
565                 dtDropInfo->status = DtDND_FAILURE;
566                 return;
567         }
568
569         if (dsInfo->dropProc != NULL) {
570                 (*(dsInfo->dropProc))(dropReceiver, clientData, callData);
571         }
572 }
573
574 /*
575  * dndTransferStart
576  *
577  *      Start the transfer using protocol specific transfer entries
578  *
579  */
580 static void
581 dndTransferStart(
582         Widget          dropReceiver,
583         XmDropProcCallbackStruct *xmDropInfo,
584         DtDropInfo *    dtDropInfo,
585         DtDndTransfer * transfer,
586         Atom *          exportTargets,
587         Cardinal        numExportTargets)
588 {
589         XtCallbackRec   dropAnimateCbRec[] = { {dndDropAnimateCallback,
590                                                         NULL}, {NULL, NULL} };
591         Display *       display            = XtDisplayOfObject(dropReceiver);
592         DtDndContext *  dropData;
593         DtTransferInfo *transferInfo;
594         Atom *          transferTargets;
595         Cardinal        numTransferTargets;
596         Boolean         owCompat;
597         XmDropTransferEntryRec * transferEntries;
598         Cardinal        numTransferEntries;
599         int             posOffsetX, posOffsetY;
600         Boolean         status;
601         Arg             args[10];
602         Cardinal        ii, nn;
603
604 #ifdef DEBUG
605         printf("dndTransferStart: transfer method = %s\n",
606                                         transfer->methods->name);
607 #endif
608         /*
609          * If the operation is a move but not registered for a move
610          * then force it to a copy drop.
611          */
612
613         if ((xmDropInfo->operation == XmDROP_MOVE) && 
614            !(dtDropInfo->operations & XmDROP_MOVE)) {
615                 xmDropInfo->operation = XmDROP_COPY;
616         }
617
618         /*
619          * Determine icon adjustment to drop position
620          */
621
622         _DtDndGetIconOffset(xmDropInfo->dragContext,
623                         transfer->methods->sourceType,
624                         &posOffsetX, &posOffsetY);
625
626         /*
627          * Initialize drop transfer info
628          */
629
630         transferInfo = (DtTransferInfo *)XtMalloc(sizeof(DtTransferInfo));
631
632         transferInfo->dragContext               = xmDropInfo->dragContext;
633         transferInfo->protocol                  = transfer->methods->protocol;
634         transferInfo->operation                 = xmDropInfo->operation;
635         transferInfo->methods                   = transfer->methods;
636         transferInfo->transferTargets           = NULL;
637         transferInfo->numTransferTargets        = 0;
638         transferInfo->currentTransfer           = 0;
639         transferInfo->appTransferCalled         = False;
640         transferInfo->event                     = xmDropInfo->event;
641         transferInfo->x                         = xmDropInfo->x + posOffsetX;
642         transferInfo->y                         = xmDropInfo->y + posOffsetY;
643         transferInfo->clientData                = NULL;
644
645         /*
646          * Initialize drop data
647          */
648
649         dropData = (DtDndContext *)XtCalloc(1,sizeof(DtDndContext));
650
651         dropData->protocol              = transferInfo->protocol;
652
653         /*
654          * Initialize drop transfer fields of DtDropInfo
655          */
656
657         dtDropInfo->transferInfo        = transferInfo;
658         dtDropInfo->dropData            = dropData;
659         dtDropInfo->status              = DtDND_SUCCESS;
660
661         /* 
662          * Get protocol specific transfer targets 
663          */
664
665         (*transferInfo->methods->transferTargets)(dtDropInfo,
666                         exportTargets, numExportTargets,
667                         &transferTargets, &numTransferTargets);
668
669         if (transferTargets == NULL) {
670
671                 XtFree((char *)dtDropInfo->transferInfo);
672                 XtFree((char *)dtDropInfo->dropData);
673
674                 dtDropInfo->transferInfo        = NULL;
675                 dtDropInfo->dropData            = NULL;
676                 dtDropInfo->status              = DtDND_FAILURE;
677
678                 dndTransferStartFailed(xmDropInfo->dragContext);
679                 return;
680         }
681
682         /*
683          * Convert _SUN_ENUMERATION_COUNT if available
684          * Insert into transfer targets list
685          */
686         owCompat = XmTargetsAreCompatible(display, 
687                         exportTargets, numExportTargets,
688                         &XA_SUN_ENUM_COUNT, 1);
689
690         if (owCompat) {
691                 Cardinal        jj, numTargets;
692                 Atom            *targets;
693
694                 numTargets      = numTransferTargets + 1;
695                 targets         = (Atom *)XtMalloc(numTargets * sizeof(Atom));
696
697                 jj = 0;
698                 targets[jj++] = XA_SUN_ENUM_COUNT;
699
700                 for (ii = 0; ii < numTransferTargets; ii++, jj++) {
701                         targets[jj] = transferTargets[ii];
702                 }
703
704                 XtFree((char *)transferTargets);
705
706                 transferTargets         = targets;
707                 numTransferTargets      = numTargets;
708         }
709
710         /*
711          * Create a transfer entries list from the transfer targets
712          */
713
714         numTransferEntries = numTransferTargets;
715         transferEntries = (XmDropTransferEntryRec *)
716                 XtMalloc(numTransferEntries * sizeof(XmDropTransferEntryRec));
717
718         for (ii = 0; ii < numTransferEntries; ii++) {
719                 transferEntries[ii].target      = transferTargets[ii];
720                 transferEntries[ii].client_data = (XtPointer)dtDropInfo;
721         }
722
723         transferInfo->transferTargets           = transferTargets;
724         transferInfo->numTransferTargets        = numTransferTargets;
725
726 #ifdef DEBUG
727         printf("Requesting transfers: ");
728         _DtDndPrintTargets(display,transferTargets,numTransferTargets);
729 #endif
730
731         /*
732          * Start the drop transfer
733          */
734
735         dropAnimateCbRec[0].closure = (XtPointer) dtDropInfo;
736         transferInfo->dropAnimateCallback
737                         = _DtDndCopyCallbackList(dropAnimateCbRec);
738         nn = 0;
739         XtSetArg(args[nn], XmNdropTransfers,    transferEntries); nn++;
740         XtSetArg(args[nn], XmNnumDropTransfers, numTransferEntries);nn++;
741         XtSetArg(args[nn], XmNtransferProc,     dndTransferProc); nn++;
742         XtSetArg(args[nn], XmNdestroyCallback,  transferInfo->dropAnimateCallback); nn++;
743
744         (void)XmDropTransferStart(xmDropInfo->dragContext, args, nn);
745
746         XtFree((char *)transferEntries);
747 }
748
749 /*
750  * dndTransferProc
751  *
752  *      Process the transfers
753  */
754 static void
755 dndTransferProc(
756         Widget          dropTransfer,
757         XtPointer       clientData,
758         Atom *          selection,
759         Atom *          type,
760         XtPointer       value,
761         unsigned long * length,
762         int *           format)
763 {
764         DtDropInfo *    dtDropInfo      = (DtDropInfo *)clientData;
765         DtTransferInfo *transferInfo    = dtDropInfo->transferInfo;
766         int             index;
767         Atom            target;
768
769         /*
770          * Ignore if no dtDropInfo or failed transfer
771          * Ignore null transfer (which are responses to DELETE)
772          */
773
774         if (value == NULL || dtDropInfo == NULL || 
775             dtDropInfo->status == DtDND_FAILURE) {
776                 dndTransferFail(dtDropInfo, dropTransfer);
777                 XtFree(value);
778                 return;
779         } else if (*type == XA_NULL) {
780                 XtFree(value);
781                 return;
782         }
783
784         /*
785          * Determine current transfer target
786          */
787
788         index = transferInfo->currentTransfer;
789         
790         if (index < transferInfo->numTransferTargets) {
791                 target = transferInfo->transferTargets[index];
792         } else {
793                 target = None;
794         }
795         transferInfo->currentTransfer++;
796
797 #ifdef DEBUG
798         {
799         Display *display = XtDisplayOfObject(dropTransfer);
800         char *targetname = XGetAtomName(display,target);
801         char *typename   = XGetAtomName(display,*type);
802         printf("dndTransferProc: target = %s type = %s fmt = %d len = %ld\n",
803                         (targetname ? targetname : "Null"), 
804                         (typename ? typename : "Null"),
805                          *format, *length);
806         if (targetname) XFree(targetname);
807         if (typename) XFree(typename);
808         }
809 #endif
810
811         /*
812          * Handle _SUN_ENUMERATION_COUNT request; reject multiple items
813          */
814         if (target == XA_SUN_ENUM_COUNT) {
815                 int *   enumCount = (int *)value;
816                 if (enumCount[0] > 1) {
817                         dndTransferFail(dtDropInfo, dropTransfer);
818                 }
819                 XtFree(value);
820                 return;
821         }
822
823         /*
824          * Invoke protocol specific transfer proc
825          */
826
827         (*transferInfo->methods->transfer)( dropTransfer, dtDropInfo, 
828                 selection, &target, type, value, length, format);
829
830         /*
831          * If the transfer failed, set up to terminate unsuccessfully
832          */
833
834         if (dtDropInfo->status == DtDND_FAILURE) {
835                 dndTransferFail(dtDropInfo, dropTransfer);
836                 return;
837         }
838
839         /*
840          * If the transfers are complete;
841          * If the dropData isn't ready then fail the transfer
842          * Otherwise call the application transfer callback
843          */
844
845         if (transferInfo->currentTransfer == transferInfo->numTransferTargets) {
846
847                 if (dtDropInfo->dropData->numItems == 0) {
848                         dndTransferFail(dtDropInfo, dropTransfer);
849                         return;
850                 } else if (!transferInfo->appTransferCalled) {
851                         dndAppTransfer(dropTransfer, dtDropInfo);
852                         transferInfo->appTransferCalled = True;
853                 }
854         }
855 }
856
857 /*
858  * dndAppTransfer
859  *
860  *       Call the application transfer callback
861  */
862 static void
863 dndAppTransfer(
864         Widget          dropTransfer,
865         DtDropInfo *    dtDropInfo)
866 {
867         DtTransferInfo *transferInfo    = dtDropInfo->transferInfo;
868         DtDndTransferCallbackStruct     transferCallData;
869
870         /*
871          * If the transfer failed or there isn't a callback simply return
872          */
873
874         if (dtDropInfo->status == DtDND_FAILURE ||
875             dtDropInfo->dropTransferCallback == NULL) {
876                 return;
877         }
878
879         /*
880          * Fill in the callback structure and call the
881          * application-defined dropTransferCallback.
882          */
883
884         transferCallData.reason         = DtCR_DND_TRANSFER_DATA;
885         transferCallData.event          = transferInfo->event;
886         transferCallData.x              = transferInfo->x;
887         transferCallData.y              = transferInfo->y;
888         transferCallData.operation      = transferInfo->operation;
889         transferCallData.dropData       = dtDropInfo->dropData;
890         transferCallData.dragContext    = transferInfo->dragContext;
891         transferCallData.status         = DtDND_SUCCESS;
892
893         if (transferInfo->operation == XmDROP_MOVE) {
894                 transferCallData.completeMove = True;
895         } else {
896                 transferCallData.completeMove = False;
897         }
898
899         _DtDndCallCallbackList(dtDropInfo->dropReceiver, 
900                 dtDropInfo->dropTransferCallback, 
901                 (XtPointer)&transferCallData);
902
903         dtDropInfo->status = transferCallData.status;
904
905         /*
906          * If the app requests it then fail the transfer
907          */
908         if (transferCallData.status == DtDND_FAILURE) {
909                 dndTransferFail(dtDropInfo, dropTransfer);
910                 return;
911         }
912
913         /*
914          * If the transfer succeeded and this is a move operation
915          * then transfer DELETE to delete the original.
916          */
917
918         if (transferCallData.status == DtDND_SUCCESS &&
919             transferCallData.completeMove &&
920             transferInfo->operation == XmDROP_MOVE) {
921
922                 XmDropTransferEntryRec  transferEntries[1];
923
924                 transferEntries[0].target       = XA_DELETE;
925                 transferEntries[0].client_data  = (XtPointer)dtDropInfo;
926
927                 XmDropTransferAdd(dropTransfer, transferEntries, 1);
928         }
929 }
930
931 /*
932  * dndDropAnimateCallback
933  *
934  *      Call the application dropAnimateCallback
935  */
936 static void
937 dndDropAnimateCallback(
938         Widget          dropTransfer,
939         XtPointer       clientData,
940         XtPointer       callData)
941 {
942         DtDropInfo *    dtDropInfo      = (DtDropInfo *)clientData;
943         DtTransferInfo *transferInfo    = dtDropInfo->transferInfo;
944         DtDndDropAnimateCallbackStruct  dropAnimateCallData;
945
946         /*
947          * Fill in the callback structure and call the
948          * application-defined dropAnimateCallback.
949          */
950
951         if (dtDropInfo->status == DtDND_SUCCESS &&
952             dtDropInfo->dropAnimateCallback != NULL) {
953
954                 dropAnimateCallData.reason      = DtCR_DND_DROP_ANIMATE;
955                 dropAnimateCallData.event       = transferInfo->event;
956                 dropAnimateCallData.x           = transferInfo->x;
957                 dropAnimateCallData.y           = transferInfo->y;
958                 dropAnimateCallData.operation   = transferInfo->operation;
959                 dropAnimateCallData.dropData    = dtDropInfo->dropData;
960
961                 _DtDndCallCallbackList(dtDropInfo->dropReceiver, 
962                         dtDropInfo->dropAnimateCallback, 
963                         (XtPointer)&dropAnimateCallData);
964         }
965
966         /*
967          * Invoke the protocol specific transfer finish proc
968          */
969
970         (*transferInfo->methods->transferFinish)(dtDropInfo);
971
972         /*
973          * Free transfer created memory 
974          */
975         XtFree((char *)dtDropInfo->transferInfo->transferTargets);
976         XtFree((char *)dtDropInfo->transferInfo->dropAnimateCallback); 
977         XtFree((char *)dtDropInfo->transferInfo);
978         XtFree((char *)dtDropInfo->dropData);
979         
980         dtDropInfo->transferInfo        = NULL;
981         dtDropInfo->dropData            = NULL;
982 }
983
984 /*
985  * dndDropSiteDestroy
986  *
987  * Destroy callback unregisters the widget being destroyed as a drop site
988  */
989 static void
990 dndDropSiteDestroy(
991         Widget          widget,
992         XtPointer       clientData,
993         XtPointer       callData)
994 {
995         DtDndDropUnregister(widget);
996 }
997         
998 /*
999  * dndGetContextXID
1000  *
1001  *      Returns a pixmap to use as the XID for Save/Find Context
1002  */
1003 static XID
1004 dndGetContextXID(
1005         Display *       display)
1006 {
1007         static XID contextXID;
1008
1009         _DtSvcProcessLock();
1010         if (contextXID == 0) {
1011                 contextXID = XCreatePixmap(display, 
1012                                         DefaultRootWindow(display), 1, 1, 1);
1013         }
1014         _DtSvcProcessUnlock();
1015         return contextXID;
1016 }
1017
1018 /*
1019  * dndSaveDropInfo
1020  *
1021  *      Saves the DtDropInfo relative to the dropReceiver
1022  */
1023 static Boolean          
1024 dndSaveDropInfo(
1025         Display *       display,
1026         Widget          dropReceiver,
1027         DtDropInfo *    dtDropInfo)
1028 {
1029         int             status;
1030
1031         status = XSaveContext(display, dndGetContextXID(display),
1032                 (XContext)(intptr_t)dropReceiver, (XPointer)dtDropInfo);
1033
1034         return (status == 0);
1035 }
1036
1037 /*
1038  * dndFindDropInfo
1039  *
1040  *      Finds the DtDropInfo saved relative to the dropReceiver
1041  */
1042 static DtDropInfo *
1043 dndFindDropInfo(
1044         Display *       display,
1045         Widget          dropReceiver)
1046 {
1047         int             status;
1048         DtDropInfo *    dtDropInfo;
1049
1050         status = XFindContext(display, dndGetContextXID(display), 
1051                 (XContext)(intptr_t)dropReceiver, (XPointer *)&dtDropInfo);
1052
1053         if (status != 0)
1054                 dtDropInfo = (DtDropInfo *)NULL;
1055         
1056         return dtDropInfo;
1057 }
1058
1059 /*
1060  * dndTransferStartFailed
1061  *
1062  *      Fail the transfer by starting a 'failure' transfer
1063  *      Calls XmDropTransferStart()
1064  */
1065 static void
1066 dndTransferStartFailed(
1067         Widget  dragContext)
1068 {
1069         Arg     args[2];
1070         int     nn = 0;
1071
1072         XtSetArg(args[nn], XmNtransferStatus, XmTRANSFER_FAILURE); nn++;
1073         XtSetArg(args[nn], XmNnumDropTransfers, 0); nn++;
1074
1075         XmDropTransferStart(dragContext, args, nn);
1076 }
1077
1078 /*
1079  * dndTransferFail
1080  *
1081  *      Fail the transfer by setting the dropTransfer widget to failure
1082  *      Assumes XmDropTransferStart() already called.
1083  */
1084 static void
1085 dndTransferFail(
1086         DtDropInfo *    dtDropInfo,
1087         Widget          dropTransfer)
1088 {
1089         if (dtDropInfo)
1090                 dtDropInfo->status = DtDND_FAILURE;
1091
1092         XtVaSetValues(dropTransfer,
1093                 XmNtransferStatus,      XmTRANSFER_FAILURE,
1094                 XmNnumDropTransfers,    0,
1095                 NULL);
1096 }
1097