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