1 /* $TOG: Transfer.c /main/17 1997/07/16 16:31:41 csn $ */
2 /*
3  * Motif
4  *
5  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
6  *
7  * These libraries and programs are free software; you can
8  * redistribute them and/or modify them under the terms of the GNU
9  * Lesser General Public License as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * These libraries and programs are distributed in the hope that
14  * they will be useful, but WITHOUT ANY WARRANTY; without even the
15  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16  * PURPOSE. See the GNU Lesser General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with these librararies and programs; if not, write
21  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
22  * Floor, Boston, MA 02110-1301 USA
23  */
24 /*
25  * HISTORY
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 
33 #include <X11/Xatom.h>
34 #include <Xm/AtomMgr.h>
35 #include <Xm/DragDrop.h>
36 #include <Xm/SpecRenderT.h>
37 #include <Xm/TraitP.h>
38 #include <Xm/VendorSP.h>
39 #include <Xm/XmosP.h>
40 #include "CutPasteI.h"
41 #include "DragBSI.h"
42 #include "HashI.h"
43 #include "MessagesI.h"
44 #include "ResEncodI.h"
45 #include "TransferI.h"
46 #include "XmI.h"
47 
48 
49 typedef enum { DoXFree, DoFree } FreeType;
50 #define FreeSafeAtomName(val,how) if (1) { if (DoXFree==how) XFree(val); else free(val); }
51 
52 static ConvertContext LookupContextBlock(Display*, Atom);
53 static void ClearContextBlock(Display*, Atom);
54 static void ClipboardCallback(Widget, long*, long*, int*);
55 static void DisownCallback(Widget, XtPointer, XtPointer);
56 static void FreeTransferID(XtPointer);
57 static void CallDoneProcs(Widget, XtPointer, XmTransferDoneCallbackStruct*);
58 static XtPointer GetTransferID(void);
59 static void SelectionCallbackWrapper(Widget, XtPointer, Atom*, Atom*,
60 				     XtPointer, unsigned long*, int*);
61 static Boolean DragConvertHandler(Widget, Atom *, Atom *, Atom *,
62 				  XtPointer *, unsigned long *, int *);
63 static void SecondaryConvertHandler(Widget, XtPointer,
64 				    XmConvertCallbackStruct *);
65 static void ReleaseSecondaryLock(Widget, XtEnum, XmTransferDoneCallbackStruct*);
66 static void DropDestinationHandler(Widget, XtPointer,
67 				   XmDropProcCallbackStruct *);
68 static TransferBlock AddTransferBlock(TransferContext tc);
69 static void SecondaryDone(Widget, XtPointer, Atom*, Atom*,
70 			  XtPointer, unsigned long*, int*);
71 static void TransferWarning(Widget w, char* name, char* type, char* message);
72 static void DeleteDropCBStruct(Widget w, XtEnum ignored_status,
73 			       XmTransferDoneCallbackStruct *cs);
74 static void FinishTransfer(Widget wid, TransferContext tc);
75 static char* GetSafeAtomName(Display *display, Atom a, FreeType *howFree);
76 static void LoseProc(Widget w, Atom *selection);
77 static void ClipboardLoseProc(Widget w, Atom *selection);
78 
79 #define BAD_ATOM_MESSAGE    _XmMMsgTransfer_0005
80 #define BAD_STATUS_MESSAGE  _XmMMsgTransfer_0004
81 #define BAD_SCB_MESSAGE     _XmMMsgTransfer_0000
82 #define BAD_MATCHED_CONVERT _XmMMsgTransfer_0002
83 #define BAD_STATUS          _XmMMsgTransfer_0003
84 #define ERROR_MULTIPLE_IN_PROGRESS _XmMMsgTransfer_0006
85 #define ERROR_MULTIPLE_NOT_IN_PROGRESS _XmMMsgTransfer_0007
86 #define MERGE "XmeConvertMerge"
87 #define ATOM  "XGetAtomName"
88 #define MATCH "Format or type mismatch"
89 #define ARG "Argument"
90 #define START_MULTIPLE "XmTransferStartRequest"
91 #define END_MULTIPLE "XmTransferSendRequest"
92 
93 #define XmS_MOTIF_SNAPSHOT "_MOTIF_SNAPSHOT"
94 #define XmSCLIPBOARD_MANAGER "CLIPBOARD_MANAGER"
95 
96 #define BYTELENGTH( length, format ) \
97   ((format == 8) ? length : \
98    ((format == 16) ? length * sizeof(short) : \
99     (length * sizeof(long))))
100 
101 static int local_convert_flag = 0;
102 
103 static XmHashTable DataIdDictionary = NULL;
104 
105 void
_XmConvertHandlerSetLocal(void)106 _XmConvertHandlerSetLocal(void)
107 {
108   _XmProcessLock();
109   local_convert_flag = 1;
110   _XmProcessUnlock();
111 }
112 
113 /************************************************************************/
114 /*									*/
115 /* Convert section.  These functions provide an API to setting up 	*/
116 /* selections,  working with the clipboard and starting Drag and Drop.  */
117 /* 									*/
118 /************************************************************************/
119 
120 /****************************************************************/
121 /* ConvertHandler is a generalized version of the convert proc  */
122 /* in Xt.  It calls the convertCallbacks and the transferTrait  */
123 /* on the particular widgetclass.				*/
124 /****************************************************************/
125 
126 Boolean
_XmConvertHandler(Widget wid,Atom * selection,Atom * target,Atom * type,XtPointer * value,unsigned long * size,int * fmt)127 _XmConvertHandler(Widget wid, Atom *selection, Atom *target,
128 		  Atom *type, XtPointer *value,
129 		  unsigned long *size, int *fmt)
130 {
131   enum { XmA_MOTIF_DESTINATION, XmAINSERT_SELECTION,
132 	 XmALINK_SELECTION, XmA_MOTIF_LOSE_SELECTION, XmA_MOTIF_DROP,
133 	 XmACLIPBOARD, XmA_MOTIF_CLIPBOARD_TARGETS,
134 	 XmA_MOTIF_DEFERRED_CLIPBOARD_TARGETS, NUM_ATOMS };
135   static char *atom_names[] = { XmS_MOTIF_DESTINATION, XmSINSERT_SELECTION,
136 	 XmSLINK_SELECTION, XmS_MOTIF_LOSE_SELECTION, XmS_MOTIF_DROP,
137 	 XmSCLIPBOARD, XmS_MOTIF_CLIPBOARD_TARGETS,
138 	 XmS_MOTIF_DEFERRED_CLIPBOARD_TARGETS };
139 
140   XmTransferTrait ttrait;
141   XmConvertCallbackStruct cbstruct;
142   ConvertContext cc;
143   Atom atoms[XtNumber(atom_names)];
144   Atom real_selection_atom = None; /* DND hides the selection atom from us */
145   int my_local_convert_flag;
146 
147   assert(XtNumber(atom_names) == NUM_ATOMS);
148   XInternAtoms(XtDisplay(wid), atom_names, XtNumber(atom_names), False, atoms);
149 
150   _XmProcessLock();
151   my_local_convert_flag = local_convert_flag;
152   _XmProcessUnlock();
153 
154   /* Find the context block */
155 
156   cc = LookupContextBlock(XtDisplay(wid), *selection);
157 
158   /* Setup the callback structure */
159 
160   cbstruct.reason = XmCR_OK;
161   cbstruct.event = NULL;
162   cbstruct.selection = *selection;
163   cbstruct.target = *target;
164   cbstruct.source_data = (XtPointer) cc -> drag_context;
165   cbstruct.flags = XmCONVERTING_NONE;
166   cbstruct.location_data = cc -> location_data;
167   cbstruct.status = XmCONVERT_DEFAULT;
168   cbstruct.value = NULL;
169   cbstruct.type = XA_INTEGER;
170   cbstruct.format = 8;
171   cbstruct.length = 0;
172 
173 
174   _XmProcessLock();
175   /* Get the request event if we can */
176   if (my_local_convert_flag == 0) {
177     Arg args[1];
178     Widget req_widget;
179 
180     if (*selection == atoms[XmA_MOTIF_DROP]) {
181       XtSetArg(args[0], XmNiccHandle, &real_selection_atom);
182       XtGetValues(cc -> drag_context, args, 1);
183       cbstruct.event = (XEvent *) XtGetSelectionRequest(cc -> drag_context,
184 							real_selection_atom,
185 							NULL);
186       req_widget = cc -> drag_context;
187     } else {
188       cbstruct.event = (XEvent *) XtGetSelectionRequest(wid, *selection,
189 							NULL);
190       req_widget = wid;
191     }
192 
193     /* Get the parameters from this request.  Use the correct
194        selection atom here as well */
195     {
196       Atom sel_atom = (real_selection_atom != None)
197 	? real_selection_atom : *selection;
198       XtGetSelectionParameters(req_widget, sel_atom, NULL,
199 			       &cbstruct.parm_type, &cbstruct.parm,
200 			       &cbstruct.parm_length, &cbstruct.parm_format);
201     }
202   } else {
203     /* We're called locally when XmeClipboardSource is invoked and there
204        is no CLIPBOARD_MANAGER.  In this case we must pickup the operation
205        from the context block and put it in the parameter */
206     if (*selection == atoms[XmACLIPBOARD]) {
207       if (*target == atoms[XmA_MOTIF_CLIPBOARD_TARGETS] ||
208 	  *target == atoms[XmA_MOTIF_DEFERRED_CLIPBOARD_TARGETS]) {
209 	cbstruct.parm = (XtPointer) cc -> op;
210 	cbstruct.parm_length = 1;
211 	cbstruct.parm_format = 32;
212 	cbstruct.parm_type = XA_INTEGER;
213       }	else {
214 	cbstruct.parm = NULL;
215 	cbstruct.parm_length = 0;
216 	cbstruct.parm_format = 8;
217 	cbstruct.parm_type = None;
218       }
219     }
220   }
221   _XmProcessUnlock();
222 
223   if (cbstruct.event != NULL &&
224       ((XSelectionRequestEvent *) cbstruct.event) -> requestor ==
225       ((XSelectionRequestEvent *) cbstruct.event) -> owner) {
226     cbstruct.flags |= XmCONVERTING_SAME;
227   }
228 
229   _XmProcessLock();
230   /* Reset bypass flag */
231   local_convert_flag = 0;
232   _XmProcessUnlock();
233 
234   if (*selection != atoms[XmA_MOTIF_DESTINATION] ||
235       *target == atoms[XmA_MOTIF_LOSE_SELECTION]) {
236     /* First we call any convert callbacks */
237 
238     if (XtHasCallbacks(wid, XmNconvertCallback) == XtCallbackHasSome)
239       XtCallCallbacks(wid, XmNconvertCallback, &cbstruct);
240 
241     if (cbstruct.status == XmCONVERT_MORE)
242       {
243 	/* Print error message,  and revert this flag to
244 	   XmCONVERT_DEFAULT */
245 	XmeWarning(wid, BAD_STATUS_MESSAGE);
246 	cbstruct.status = XmCONVERT_DEFAULT;
247       }
248 
249     /* Now lookup the trait on this widget and call the
250        internal routine */
251 
252     if (cbstruct.status == XmCONVERT_DEFAULT ||
253 	cbstruct.status == XmCONVERT_MERGE) {
254       ttrait = (XmTransferTrait)
255 	XmeTraitGet((XtPointer) XtClass(wid), XmQTtransfer);
256       if (ttrait != NULL)
257 	ttrait -> convertProc(wid, NULL, &cbstruct);
258     }
259   }
260 
261   /* If this is an INSERT_SELECTION or LINK_SELECTION then
262      we call SecondaryConvertHandler to finish the work */
263   if (cbstruct.status == XmCONVERT_DEFAULT &&
264       (*target == atoms[XmAINSERT_SELECTION] ||
265        *target == atoms[XmALINK_SELECTION]))
266     SecondaryConvertHandler(wid, NULL, &cbstruct);
267 
268   /* Copy out the flags value for CLIPBOARD to use */
269   cc -> flags = cbstruct.flags;
270 
271   if (cbstruct.status == XmCONVERT_DONE ||
272       cbstruct.status == XmCONVERT_DEFAULT)
273     {
274       /* Copy out the data */
275       *value = cbstruct.value;
276       *size = cbstruct.length;
277       *fmt = cbstruct.format;
278       *type = cbstruct.type;
279       return True;
280     }
281   else
282     {
283       *value = NULL;
284       *size = 0;
285       *fmt = 8;
286       *type = None;
287       return False;
288     }
289 }
290 
291 /****************************************************************/
292 /* DragConvertHandler acts as a wrapper to convert handler for	*/
293 /* drag and drop.  This is because drag and drop passes the     */
294 /* DragContext as the widget to the convert proc in the drag    */
295 /****************************************************************/
296 
297 static Boolean
DragConvertHandler(Widget drag_context,Atom * selection,Atom * target,Atom * type,XtPointer * value,unsigned long * size,int * fmt)298 DragConvertHandler(Widget drag_context, Atom *selection, Atom *target,
299 		      Atom *type, XtPointer *value,
300 		      unsigned long *size, int *fmt)
301 {
302   ConvertContext cc;
303   Atom MOTIF_DROP = XInternAtom(XtDisplay(drag_context), XmS_MOTIF_DROP, False);
304 
305   /* Find the context block */
306 
307   cc = LookupContextBlock(XtDisplay(drag_context), MOTIF_DROP);
308 
309   /* Originating widget was stored in client_data */
310 
311   return(_XmConvertHandler((Widget) cc -> client_data,
312 			   selection, target,
313 			   type, value, size, fmt));
314 
315 }
316 
317 static int secondary_lock = 0;
318 
319 /********************************************************************/
320 /* SecondaryConvertHandler handles the detail of                    */
321 /* Secondary selection.  This is because secondary is a synchronous */
322 /* mechanism which requires a spinlock.				    */
323 /********************************************************************/
324 
325 /*ARGSUSED*/
326 static void
SecondaryConvertHandler(Widget w,XtPointer ignored,XmConvertCallbackStruct * cs)327 SecondaryConvertHandler(Widget w,
328 			XtPointer ignored, /* unused */
329 			XmConvertCallbackStruct *cs)
330 {
331   enum { XmANULL, XmAINSERT_SELECTION, XmALINK_SELECTION, NUM_ATOMS };
332   static char *atom_names[] = {XmSNULL, XmSINSERT_SELECTION, XmSLINK_SELECTION};
333 
334   XtAppContext app = XtWidgetToApplicationContext(w);
335   _XmTextInsertPair *pair;
336   XSelectionRequestEvent *req_event;
337   static unsigned long old_serial = 0;
338   Atom atoms[XtNumber(atom_names)];
339   XtEnum operation;
340 
341   _XmProcessLock();
342   if (secondary_lock != 0) {
343     cs -> status = XmCONVERT_REFUSE;
344     _XmProcessUnlock();
345     return;
346   }
347   _XmProcessUnlock();
348 
349   req_event = XtGetSelectionRequest(w, cs -> selection, NULL);
350 
351   cs -> event = (XEvent *) req_event;
352 
353   _XmProcessLock();
354   /* Work around for intrinsics selection bug */
355   if (req_event != NULL && old_serial != req_event->serial)
356     old_serial = req_event->serial;
357   else {
358     cs -> status = XmCONVERT_REFUSE;
359     _XmProcessUnlock();
360     return;
361   }
362   _XmProcessUnlock();
363 
364   if (cs -> parm_length == 0)
365     {
366       cs -> status = XmCONVERT_REFUSE;
367       return;
368     }
369 
370   pair = (_XmTextInsertPair *) cs -> parm;
371 
372   _XmProcessLock();
373   /* Lock */
374   secondary_lock = 1;
375   _XmProcessUnlock();
376 
377   assert(XtNumber(atom_names) == NUM_ATOMS);
378   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
379 
380   if (cs -> target == atoms[XmAINSERT_SELECTION])
381     operation = XmCOPY;
382   else if (cs -> target == atoms[XmALINK_SELECTION])
383     operation = XmLINK;
384   else
385     operation = XmOTHER;
386 
387   if (_XmDestinationHandler(w, pair -> selection,
388 			    operation, ReleaseSecondaryLock,
389 			    (XtPointer) pair -> target,
390 			    req_event -> time, req_event) != True) {
391     cs -> status = XmCONVERT_REFUSE;
392     return;
393   }
394 
395   /*
396    * Make sure the above selection request is completed
397    * before returning from the convert proc.
398    */
399 
400 #ifdef XTHREADS
401   while (XtAppGetExitFlag(app) == False) {
402 #else
403   for (;;) {
404 #endif
405     XEvent event;
406     XtInputMask mask;
407 
408     if (secondary_lock == 0) break;
409 #ifndef XTHREADS
410     XtAppNextEvent(app, &event);
411     XtDispatchEvent(&event);
412 #else
413     while (!(mask = XtAppPending(app)))
414 	;  /* Busy waiting - so that we don't lose our lock */
415     if (mask & XtIMXEvent) { /* We have an XEvent */
416 	/* Get the event since we know its there.
417 	 * Note that XtAppNextEvent would also process
418 	 * timers/alternate inputs.
419 	 */
420 	XtAppNextEvent(app, &event); /* no blocking */
421 	XtDispatchEvent(&event); /* Process it */
422     }
423     else /* not an XEvent, process it */
424 	XtAppProcessEvent(app, mask); /* non blocking */
425 #endif
426   }
427 
428   cs -> value = NULL;
429   cs -> type = atoms[XmANULL];
430   cs -> format = 8;
431   cs -> length = 0;
432   cs -> status = XmCONVERT_DONE;
433 }
434 
435 /*ARGSUSED*/
436 static void
437 ReleaseSecondaryLock(Widget w,	/* unused */
438 		     XtEnum a,	/* unused */
439 		     XmTransferDoneCallbackStruct *ts) /* unused */
440 {
441   _XmProcessLock();
442   secondary_lock = 0;
443   _XmProcessUnlock();
444 }
445 
446 
447 /****************************************************************/
448 /* ClipboardLoseProc allows us to perform the delete operation  */
449 /* for the case where the user is performing a CUT to the       */
450 /* CLIPBOARD,  and the CLIPBOARD is owned by a			*/
451 /* CLIPBOARD_MANAGER.						*/
452 /****************************************************************/
453 static void
454 ClipboardLoseProc(Widget w, Atom *selection)
455 {
456   Atom DELETE = XInternAtom(XtDisplay(w), XmSDELETE, False);
457   XtPointer value;
458   Atom type;
459   unsigned long size;
460   int fmt;
461 
462   _XmConvertHandlerSetLocal();
463   _XmConvertHandler(w, selection, &DELETE,
464 		    &type, &value, &size, &fmt);
465 
466   LoseProc(w, selection);
467 }
468 
469 /****************************************************************/
470 /* LoseProc is just a thin wrapper routine so			*/
471 /* we have a place to do bookkeeping.				*/
472 /****************************************************************/
473 
474 static void
475 LoseProc(Widget w, Atom *selection)
476 {
477   XtPointer value;
478   Atom type;
479   unsigned long size;
480   int fmt;
481   Atom MOTIF_LOSE = XInternAtom(XtDisplay(w), XmS_MOTIF_LOSE_SELECTION, False);
482 
483   _XmConvertHandlerSetLocal();
484   _XmConvertHandler(w, selection, &MOTIF_LOSE,
485 		    &type, &value, &size, &fmt);
486   XtFree((char*) value);
487   XtRemoveCallback(w, XmNdestroyCallback, DisownCallback,
488 		   (XtPointer) *selection);
489 }
490 
491 /********************************************************************/
492 /* This gets run to disown the selection if the widget is destroyed */
493 /********************************************************************/
494 
495 /*ARGSUSED*/
496 static void
497 DisownCallback(Widget w,
498 	       XtPointer ignore, /* unused */
499 	       XtPointer client_data)
500 {
501   Time time = XtLastTimestampProcessed(XtDisplay(w));
502 
503   XtDisownSelection(w, (Atom) client_data, time);
504 }
505 
506 
507 /****************************************************************/
508 /* XmeConvertMerge  merges the new data into the old return     */
509 /* value in the callback structure.				*/
510 /****************************************************************/
511 void
512 XmeConvertMerge(XtPointer data, Atom type, int format,
513 		unsigned long size, XmConvertCallbackStruct *cs)
514 {
515   _XmProcessLock();
516   if (cs -> status != XmCONVERT_MERGE) {
517     TransferWarning(NULL, MERGE, ARG, BAD_STATUS);
518     _XmProcessUnlock();
519     return;
520   }
521 
522   /* Merge the results.  Format and type better agree */
523   if (format == cs -> format && type == cs -> type)
524     {
525       int total_size, offset, user_bytes;
526 
527       /* Calculate all sizes in bytes */
528       offset = BYTELENGTH(cs -> length, cs -> format);
529       user_bytes = BYTELENGTH(size, format);
530       total_size = offset + user_bytes;
531       /* Reallocate user data */
532       cs-> value = (XtPointer) XtRealloc((char*) cs -> value, total_size);
533       if (cs -> value == NULL) {
534     	_XmProcessUnlock();
535 	return;
536       }
537       /* Copy widget data to cs.value from data */
538       memcpy(&((char*) cs -> value)[offset], (char*) data, user_bytes);
539       /* Add in the new size */
540       cs -> length += size;
541     }
542   else /* If not,  print an error message */
543     TransferWarning(NULL, MERGE, MATCH, BAD_MATCHED_CONVERT);
544   _XmProcessUnlock();
545 }
546 
547 
548 /****************************************************************/
549 /* XmeTransferAddDoneProc(tid, done_proc)			*/
550 /* Adds a new done proc to the end of the current list of done  */
551 /* procs.  							*/
552 /****************************************************************/
553 
554 void
555 XmeTransferAddDoneProc(XtPointer id,
556 		       XmSelectionFinishedProc done_proc)
557 {
558   TransferContext tid = (TransferContext) id;
559 
560   _XmProcessLock();
561   tid -> numDoneProcs++;
562 
563   if (tid -> numDoneProcs == 1)
564     tid -> doneProcs = (XmSelectionFinishedProc *)
565       XtMalloc(sizeof(XmSelectionFinishedProc*));
566   else
567     tid -> doneProcs = (XmSelectionFinishedProc *)
568       XtRealloc((char*) tid -> doneProcs,
569 		sizeof(XmSelectionFinishedProc*) * tid -> numDoneProcs);
570 
571   tid -> doneProcs[tid -> numDoneProcs - 1] = done_proc;
572   _XmProcessUnlock();
573 }
574 
575 
576 /****************************************************************/
577 /* XmePrimarySource(Widget, Time) 				*/
578 /* Owns the primary selection and sets up the appropriate       */
579 /* conversion handling						*/
580 /****************************************************************/
581 
582 Boolean
583 XmePrimarySource(Widget w, Time time)
584 {
585   return(XmeNamedSource(w, XA_PRIMARY, time));
586 }
587 
588 /****************************************************************/
589 /* XmeNamedSource(Widget, Atom, Time) 				*/
590 /* Owns the named selection and sets up the appropriate         */
591 /* conversion handling						*/
592 /****************************************************************/
593 
594 Boolean
595 XmeNamedSource(Widget w, Atom sel, Time time)
596 {
597   Boolean status;
598 
599   _XmWidgetToAppContext(w);
600 
601   _XmAppLock(app);
602   ClearContextBlock(XtDisplay(w), sel);
603 
604   if (time == 0) time = XtLastTimestampProcessed(XtDisplay(w));
605 
606   status = XtOwnSelection(w, sel, time, _XmConvertHandler,
607 			  LoseProc, NULL);
608 
609   if (status) XtAddCallback(w, XmNdestroyCallback, DisownCallback,
610 			    (XtPointer) sel);
611 
612   _XmAppUnlock(app);
613   return(status);
614 }
615 
616 /****************************************************************/
617 /* XmeSecondarySource(Widget, Op, Time) 			*/
618 /* Owns the secondary selection and sets up the appropriate     */
619 /* conversion handling.  This is the function to call when 	*/
620 /* starting the secondary selection.  				*/
621 /****************************************************************/
622 
623 Boolean
624 XmeSecondarySource(Widget w, Time time)
625 {
626   return(XmeNamedSource(w, XA_SECONDARY, time));
627 }
628 
629 /****************************************************************/
630 /* XmeSecondaryTransfer(Widget, target, op, Time) 		*/
631 /* Triggers the actual secondary transfer by requesting the     */
632 /* target passed into XmeSecondarySource of the selection 	*/
633 /* _MOTIF_DESTINATION						*/
634 /****************************************************************/
635 
636 void
637 XmeSecondaryTransfer(Widget w, Atom target, XtEnum op, Time time)
638 {
639   enum { XmA_MOTIF_DESTINATION, XmAINSERT_SELECTION,
640 	 XmALINK_SELECTION, XmAATOM_PAIR, NUM_ATOMS };
641   static char *atom_names[] = { XmS_MOTIF_DESTINATION, XmSINSERT_SELECTION,
642 	 XmSLINK_SELECTION, XmIATOM_PAIR };
643 
644   ConvertContext cc;
645   _XmTextInsertPair pair;
646   Atom transfer_target;
647   Atom atoms[XtNumber(atom_names)];
648   _XmWidgetToAppContext(w);
649 
650   _XmAppLock(app);
651   assert(XtNumber(atom_names) == NUM_ATOMS);
652   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
653 
654   cc = LookupContextBlock(XtDisplay(w), XA_SECONDARY);
655   cc -> op = op;
656 
657   if (op == XmLINK)
658     transfer_target = atoms[XmALINK_SELECTION];
659   else
660     transfer_target = atoms[XmAINSERT_SELECTION];
661 
662   pair.selection = XA_SECONDARY;
663   pair.target = target;
664 
665   XtSetSelectionParameters(w, atoms[XmA_MOTIF_DESTINATION], atoms[XmAATOM_PAIR],
666 			   (XtPointer) &pair, 2, 32);
667   XtGetSelectionValue(w, atoms[XmA_MOTIF_DESTINATION], transfer_target,
668 		      SecondaryDone, NULL, time);
669   _XmAppUnlock(app);
670 }
671 
672 /*****************************************************************/
673 /* SecondaryDone deals with the completion of the                */
674 /* convert selection request started in XmeSecondaryTransfer     */
675 /* This also callback to a widget supplied routine to deal with  */
676 /* issues surrounding the success or failure of the transfer     */
677 /*****************************************************************/
678 /*ARGSUSED*/
679 static void
680 SecondaryDone(Widget wid,
681 	      XtPointer client_data, /* unused */
682 	      Atom *selection,	/* unused */
683 	      Atom *type, XtPointer value,
684 	      unsigned long *length, int *format)
685 {
686   ConvertContext cc;
687   Boolean success;
688   Atom convert_selection;
689   Atom DELETE = XInternAtom(XtDisplay(wid), XmSDELETE, False);
690 
691   cc = LookupContextBlock(XtDisplay(wid), XA_SECONDARY);
692 
693   if (*type == None && *length == 0 && value == NULL)
694     success = False;
695   else
696     success = True;
697 
698   convert_selection = XA_SECONDARY;
699   /* Call the convertCallback with target DELETE if successful */
700   if (success && cc -> op == XmMOVE) {
701     _XmConvertHandlerSetLocal();
702     _XmConvertHandler(wid, &convert_selection,
703 		      &DELETE,
704 		      type, (XtPointer*) &value, length, format);
705     XtFree((char*) value);
706   }
707 
708   XtDisownSelection(wid, convert_selection,
709 		    XtLastTimestampProcessed(XtDisplay(wid)));
710 }
711 
712 
713 
714 /****************************************************************/
715 /* XmeClipboardSource(Widget, Op, Time)				*/
716 /* Puts data onto the clipboard.  				*/
717 /****************************************************************/
718 
719 Boolean
720 XmeClipboardSource(Widget w, XtEnum op, Time time)
721 {
722   enum { XmA_MOTIF_DEFERRED_CLIPBOARD_TARGETS,
723 	 XmA_MOTIF_CLIPBOARD_TARGETS, XmACLIPBOARD,
724 	 XmACLIPBOARD_MANAGER, XmA_MOTIF_SNAPSHOT, XmADELETE, NUM_ATOMS };
725   static char *atom_names[] = { XmS_MOTIF_DEFERRED_CLIPBOARD_TARGETS,
726 	 XmS_MOTIF_CLIPBOARD_TARGETS, XmSCLIPBOARD,
727 	 XmSCLIPBOARD_MANAGER, XmS_MOTIF_SNAPSHOT, XmSDELETE };
728 
729   ConvertContext cc;
730   Atom type, type2, *targets;
731   XtPointer value;
732   unsigned long size, size2;
733   int format, format2;
734   int i, count, status, transferred = 0;
735   Display *display;
736   long itemid;
737   char *name;
738   FreeType howFree;
739   Atom atoms[XtNumber(atom_names)];
740   Window clipboard_owner;
741   _XmWidgetToAppContext(w);
742 
743   _XmAppLock(app);
744   display = XtDisplay(w);
745 
746   assert(XtNumber(atom_names) == NUM_ATOMS);
747   XInternAtoms(display, atom_names, XtNumber(atom_names), False, atoms);
748 
749   if (time == 0) time = XtLastTimestampProcessed(display);
750 
751   ClearContextBlock(display, atoms[XmACLIPBOARD]);
752 
753   cc = LookupContextBlock(display, atoms[XmACLIPBOARD]);
754   cc -> op = op;
755 
756   /* If there is a clipboard manager,  then just take
757      ownership of the clipboard selection and the manager
758      will do the rest.  Otherwise we use the motif clipboard
759      code. */
760   clipboard_owner = XGetSelectionOwner(display, atoms[XmACLIPBOARD_MANAGER]);
761   if (clipboard_owner != None) {
762     int status;
763 
764     if (op == XmMOVE) {
765       /* We call a special lose proc for move which will call
766 	 _XmConvertHandler to delete the selection */
767       status = XtOwnSelection(w, atoms[XmACLIPBOARD], time,
768 			      _XmConvertHandler, ClipboardLoseProc, NULL);
769     } else {
770       status = XtOwnSelection(w, atoms[XmACLIPBOARD], time,
771 			      _XmConvertHandler, LoseProc, NULL);
772     }
773 
774     if (status)
775     {
776       XtAddCallback(w, XmNdestroyCallback, DisownCallback,
777 			      (XtPointer) atoms[XmACLIPBOARD]);
778     } else {
779       _XmAppUnlock(app);
780       return True;
781     }
782   }
783 
784   /* Use Motif clipboard */
785   status = XmClipboardStartCopy(display, XtWindow(w), NULL,
786 				time, w, ClipboardCallback, &itemid);
787 
788   if (status == XmClipboardLocked) {
789 	_XmAppUnlock(app);
790 	return(False);
791   }
792 
793   /* OK.  We've got the clipboard, now setup the targets items */
794   cc -> itemid = itemid;
795 
796   /* Call the converter to get the targets for the clipboard
797      if _MOTIF_CLIPBOARD_TARGETS doesn't work then try
798      TARGETS target */
799   _XmConvertHandlerSetLocal();
800   if (_XmConvertHandler(w, &atoms[XmACLIPBOARD],
801 			&atoms[XmA_MOTIF_CLIPBOARD_TARGETS],
802 			&type, &value, &size, &format) == True &&
803       size != 0 &&
804       type == XA_ATOM) {
805     targets = (Atom *) value;
806     count = size;
807     /* For each item we register the format, ask to convert it
808        and if it is converted we put it on the clipboard */
809     for(i = 0; i < count; i++) {
810       name = GetSafeAtomName(display, targets[i], &howFree);
811       _XmConvertHandlerSetLocal();
812       if (_XmConvertHandler(w, &atoms[XmACLIPBOARD], &targets[i],
813 			    &type2, &value, &size2, &format2) == True &&
814 	  ! (cc -> flags & XmCONVERTING_PARTIAL)) {
815 	XmClipboardRegisterFormat(display, name, format2);
816 	/* format must be 8, 16 or 32. */
817 	size2 = BYTELENGTH(size2, format2);
818 	transferred++;
819 	/* Critical section for MT */
820 	_XmProcessLock();
821 	_XmClipboardPassType(type2);
822 	XmClipboardCopy(display, XtWindow(w), itemid, name, value, size2, 0, 0);
823 	_XmProcessUnlock();
824 	/* End Critical section for MT */
825       }
826       XtFree((char*) value);
827       FreeSafeAtomName(name,howFree);
828     }
829     XtFree((char*) targets);
830   }
831 
832   /* Call the converter to get the deferred targets for the
833      clipboard */
834   _XmConvertHandlerSetLocal();
835   if( _XmConvertHandler(w, &atoms[XmACLIPBOARD],
836 			&atoms[XmA_MOTIF_DEFERRED_CLIPBOARD_TARGETS],
837 			&type, &value, &size, &format) == True &&
838       size != 0 &&
839       type == XA_ATOM) {
840     _XmProcessLock();
841     if (DataIdDictionary == NULL) {
842       /* Create dictionary which stores data about particular
843 	 snapshots and particular dataids.  Since it
844 	 takes an integer as a key,  don't need match or hash
845 	 functions */
846       DataIdDictionary = _XmAllocHashTable(10, NULL, NULL);
847     }
848     _XmProcessUnlock();
849 
850     targets = (Atom *) value;
851     count = size;
852     /* If there are deferred targets then the snapshot target
853        must be converted successfully.  The value returned
854        by snapshot will be used as a unique id in the
855        clipboard callback to identify this deferred data
856        item */
857     _XmConvertHandlerSetLocal();
858     if (_XmConvertHandler(w, &atoms[XmACLIPBOARD], &atoms[XmA_MOTIF_SNAPSHOT],
859 			  &type2, &value, &size2, &format2) == True) {
860       long data_id;
861       SnapshotRequest req;
862 
863       if (count != 0) {
864 	req = (SnapshotRequest) XtMalloc(sizeof(SnapshotRequestRec));
865 	req -> outstanding = 0;
866 	req -> distinguisher = * (Atom *) value;
867       } else {
868 	req = NULL;
869       }
870 
871       XtFree((char*) value);
872 
873       for(i = 0; i < count; i++) {
874 	name = GetSafeAtomName(display, targets[i], &howFree);
875 	transferred++;
876 	/* Critical section for MT */
877 	_XmProcessLock();
878 	_XmClipboardPassType(type2);
879 	XmClipboardCopy(display, XtWindow(w), itemid, name,
880 			NULL, 0, targets[i], &data_id);
881 	_XmProcessUnlock();
882 	/* End Critical section for MT */
883 	/* Associate the data_id with this snapshot and increment
884 	   the number of requests outstanding */
885 	_XmProcessLock();
886 	_XmAddHashEntry(DataIdDictionary, (XmHashKey)data_id, (XtPointer)req);
887 	_XmProcessUnlock();
888 	req -> outstanding++;
889         FreeSafeAtomName(name,howFree);
890       }
891     }
892     XtFree((char*) targets);
893   }
894   XmClipboardEndCopy(display, XtWindow(w), itemid);
895 
896   if (op == XmMOVE && transferred != 0) {
897     _XmConvertHandlerSetLocal();
898     _XmConvertHandler(w, &atoms[XmACLIPBOARD], &atoms[XmADELETE],
899 		      &type, &value, &size, &format);
900     XtFree((char*) value);
901   }
902 
903   if (transferred != 0) {
904     _XmAppUnlock(app);
905     return(True);
906   }
907   else {
908     _XmAppUnlock(app);
909     return(False);
910   }
911 }
912 
913 static void
914 ClipboardCallback(Widget w, long *data_id, long *target, int *reason)
915 {
916   XtPointer value;
917   Atom type;
918   unsigned long size;
919   int format;
920   Display *display;
921   Atom CLIPBOARD = XInternAtom(XtDisplay(w), XmSCLIPBOARD, False);
922   SnapshotRequest req;
923   ConvertContext cc;
924 
925   cc = LookupContextBlock(XtDisplay(w), CLIPBOARD);
926 
927   _XmProcessLock();
928   req = (SnapshotRequest) _XmGetHashEntry(DataIdDictionary,
929 					  (XmHashKey) *data_id);
930   /* Decrement count and remove this association */
931   req -> outstanding--;
932   _XmRemoveHashEntry(DataIdDictionary, (XtPointer)data_id);
933   _XmProcessUnlock();
934 
935   display = XtDisplay(w);
936 
937   if (*reason != XmCR_CLIPBOARD_DATA_DELETE) {
938     _XmConvertHandlerSetLocal();
939     if (_XmConvertHandler(w, &req -> distinguisher, (Atom *) target,
940 			  &type, &value, &size, &format) == True &&
941 	! (cc -> flags & XmCONVERTING_PARTIAL)) {
942       char *name;
943       FreeType howFree;
944 
945       size = BYTELENGTH( size, format );
946       if (format % 8 != 0) size++;
947 
948       name = GetSafeAtomName(display, * (Atom *) target, &howFree);
949       XmClipboardRegisterFormat(display, name, format);
950       FreeSafeAtomName(name,howFree);
951       /* Critical section for MT */
952       _XmProcessLock();
953       _XmClipboardPassType(type);
954       XmClipboardCopyByName(display, XtWindow(w), *data_id,
955 			    value, size, 0L);
956       _XmProcessUnlock();
957       XtFree((char*) value);
958     }
959     else
960       XmClipboardCopyByName(display, XtWindow(w), *data_id,
961 			    NULL, 0, 0L);
962   }
963 
964   if (req -> outstanding == 0) {
965     Atom done = XInternAtom(display, XmIDONE, False);
966 
967     /* If this was the last item,  call _XmConvertHandler with
968        DELETE on the distinguisher and then free the req */
969     _XmConvertHandlerSetLocal();
970     _XmConvertHandler(w, &req -> distinguisher,
971 		      (Atom *) &done, &type, &value, &size, &format);
972     XtFree((char*) value);
973     XtFree((char*) req);
974   }
975 }
976 
977 /****************************************************************/
978 /* XmeDragSource						*/
979 /* Sets up for drag and drop and calls XmDragStart		*/
980 /****************************************************************/
981 
982 Widget
983 XmeDragSource(Widget w, XtPointer location_data, XEvent *event,
984 	      ArgList in_args, Cardinal in_arg_count)
985 {
986   enum { XmA_MOTIF_DROP, XmA_MOTIF_EXPORT_TARGETS, NUM_ATOMS };
987   static char *atom_names[] = { XmS_MOTIF_DROP, XmS_MOTIF_EXPORT_TARGETS };
988 
989   Arg *args;
990   int arg_count;
991   XtPointer targets;
992   unsigned long size;
993   Atom type;
994   int format;
995   Widget dragContext;
996   ConvertContext cc;
997   Atom atoms[XtNumber(atom_names)];
998   _XmWidgetToAppContext(w);
999 
1000   _XmAppLock(app);
1001 
1002   assert(XtNumber(atom_names) == NUM_ATOMS);
1003   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1004 
1005   /* merge and copy arg list */
1006   arg_count = in_arg_count + 10;
1007   args = (Arg *) XtMalloc(sizeof(Arg) * arg_count);
1008   for(arg_count = 0; arg_count < in_arg_count; arg_count++)
1009     args[arg_count] = in_args[arg_count];
1010 
1011   arg_count = in_arg_count;
1012 
1013   ClearContextBlock(XtDisplay(w), atoms[XmA_MOTIF_DROP]);
1014 
1015   cc = LookupContextBlock(XtDisplay(w), atoms[XmA_MOTIF_DROP]);
1016 
1017   cc -> location_data = location_data;
1018   cc -> client_data = (XtPointer) w;
1019 
1020   XtSetArg(args[arg_count], XmNconvertProc, DragConvertHandler);
1021   arg_count++;
1022 
1023   _XmConvertHandlerSetLocal();
1024   if (_XmConvertHandler(w, &atoms[XmA_MOTIF_DROP],
1025 			&atoms[XmA_MOTIF_EXPORT_TARGETS],
1026 			&type, &targets, &size, &format) == True) {
1027     XtSetArg(args[arg_count], XmNexportTargets, targets); arg_count++;
1028     XtSetArg(args[arg_count], XmNnumExportTargets, size); arg_count++;
1029   } else {
1030     /* Free copied arguments */
1031     XtFree((char*) args);
1032     XtFree((char*) targets);
1033     _XmAppUnlock(app);
1034     return(NULL);
1035   }
1036 
1037   XtSetArg(args[arg_count], XmNclientData, location_data); arg_count++;
1038 
1039   dragContext = XmDragStart(w, event, args, arg_count);
1040   cc -> drag_context = dragContext;
1041 
1042   /* Free copied arguments */
1043   XtFree((char*) args);
1044   XtFree((char*) targets);
1045 
1046   _XmAppUnlock(app);
1047   return(dragContext);
1048 }
1049 
1050 
1051 /****************************************************************/
1052 /* Destination section						*/
1053 /* 								*/
1054 /****************************************************************/
1055 
1056 /* internal flag for transfer block setup */
1057 static int TB_internal = 0;
1058 
1059 Boolean
1060 _XmDestinationHandler(Widget wid, Atom selection, XtEnum op,
1061 		      XmSelectionFinishedProc done_proc,
1062 		      XtPointer location_data, Time time,
1063 		      XSelectionRequestEvent *event)
1064 {
1065   Window selection_owner;
1066   TransferContext tc;
1067   XmDestinationCallbackStruct *cbstruct;
1068   XmTransferTrait ttrait;
1069   Atom MOTIF_DROP = XInternAtom(XtDisplay(wid), XmS_MOTIF_DROP, False);
1070 
1071   cbstruct = (XmDestinationCallbackStruct *)
1072     XtMalloc(sizeof(XmDestinationCallbackStruct));
1073 
1074   cbstruct -> reason = XmCR_OK;
1075   cbstruct -> event = (XEvent *) event;
1076   cbstruct -> selection = selection;
1077   cbstruct -> flags = 0;
1078   cbstruct -> operation = op;
1079   cbstruct -> location_data = location_data;
1080   cbstruct -> destination_data = NULL;
1081   cbstruct -> time = time;
1082 
1083   /* Setup transfer */
1084   cbstruct -> transfer_id = (XtPointer) GetTransferID();
1085   tc = (TransferContext) cbstruct -> transfer_id;
1086   tc -> widget = wid;
1087   tc -> numDoneProcs = 0;
1088   tc -> doneProcs = NULL;
1089   tc -> auto_proc = (XtCallbackProc) NULL;
1090   tc -> status = XmTRANSFER_DONE_DEFAULT;
1091   tc -> flags = TC_NONE;
1092   tc -> selection = selection;
1093   tc -> real_selection = selection;
1094   tc -> op = op;
1095   tc -> client_data = NULL;
1096   tc -> drop_context = (Widget) NULL;
1097   tc -> drag_context = (Widget) NULL;
1098   tc -> callback_struct = cbstruct;
1099 
1100   if (done_proc != NULL)
1101     XmeTransferAddDoneProc((XtPointer) tc, done_proc);
1102 
1103   ttrait = (XmTransferTrait)
1104     XmeTraitGet((XtPointer) XtClass(wid), XmQTtransfer);
1105 
1106   if (tc -> selection == MOTIF_DROP) {
1107     /* We pass the drop callback struct in through location_data */
1108     XmDropProcCallbackStruct *ds = (XmDropProcCallbackStruct *) location_data;
1109     XtPointer malloc_ds;
1110     int i;
1111     Arg args[1];
1112 
1113     malloc_ds = XtMalloc(sizeof(XmDropProcCallbackStruct));
1114     memcpy(malloc_ds, ds, sizeof(XmDropProcCallbackStruct));
1115     location_data = malloc_ds;
1116     XmeTransferAddDoneProc((XtPointer) tc, DeleteDropCBStruct);
1117     tc -> drag_context = ds -> dragContext;
1118 
1119     i = 0;
1120     XtSetArg(args[i], XmNiccHandle, &tc -> real_selection); i++;
1121     XtGetValues(ds->dragContext, args, i);
1122 
1123     /* If this is a drop,  we need to do more to figure out who
1124        really owns the selection */
1125     selection_owner = XGetSelectionOwner(XtDisplay(wid), tc -> real_selection);
1126     if (XtWindowToWidget(XtDisplay(wid), selection_owner) != (Widget) NULL) {
1127       ConvertContext cc;
1128       cc = LookupContextBlock(XtDisplay(wid), MOTIF_DROP);
1129 
1130       /* We go get the origination information if this is in the same
1131 	 client as the originator.  We know its the same client if
1132 	 XtWindowToWidget is successful */
1133       if (cc -> client_data == (XtPointer) wid)
1134 	cbstruct -> flags |= XmCONVERTING_SAME;
1135     }
1136 
1137     /* We pass this callback struct on through destination_data
1138        and get new data from the widget trait for location_data */
1139     cbstruct -> destination_data = location_data;
1140     cbstruct -> location_data = NULL;
1141   } else { /* Not D&D */
1142     /* For regular selections,  we can just use this info,  otherwise
1143        we need to get the real selection atom for D&D */
1144     selection_owner = XGetSelectionOwner(XtDisplay(wid), selection);
1145     if (selection_owner == XtWindow(wid))
1146       cbstruct -> flags |= XmCONVERTING_SAME;
1147   }
1148 
1149   /* Call the prehook to allow the widget to setup information.  This
1150      is currently only envisioned to be useful in D&D */
1151   if (ttrait != NULL && ttrait -> destinationPreHookProc != NULL)
1152     ttrait -> destinationPreHookProc(wid, NULL, cbstruct);
1153 
1154     /* First we call any destination callbacks */
1155   if (XtHasCallbacks(wid, XmNdestinationCallback) == XtCallbackHasSome)
1156     XtCallCallbacks(wid, XmNdestinationCallback, cbstruct);
1157 
1158   tc -> flags |= TC_CALLED_CALLBACKS;
1159 
1160   /* Now lookup the trait on this widget and call the
1161      internal routine if there were no transfers via the
1162      destination callbacks (or no destination callbacks) or
1163      there were transfers and the user set the status to
1164      DEFAULT and has finished (if it hasn't finished we'll
1165      handle this in SelectionCallbackWrapper) */
1166   if (ttrait != NULL &&
1167       tc -> status == XmTRANSFER_DONE_DEFAULT &&
1168       ((tc -> count == 0) ||
1169        (tc -> outstanding == 0 &&
1170 	! (TC_CALLED_WIDGET)))) {
1171     _XmProcessLock();
1172     TB_internal = 1;
1173     _XmProcessUnlock();
1174     tc -> flags |= TC_CALLED_WIDGET;
1175     if (ttrait -> destinationProc != 0)
1176       ttrait -> destinationProc(wid, NULL, cbstruct);
1177     _XmProcessLock();
1178     TB_internal = 0;
1179     _XmProcessUnlock();
1180   }
1181 
1182   if (tc -> count == 0 &&
1183       tc -> selection == MOTIF_DROP) {
1184     XmDropProcCallbackStruct *ds = (XmDropProcCallbackStruct *) location_data;
1185 
1186     if (ds -> dropAction == XmDROP_HELP) {
1187       /* If a drop help occured, then we do not want to cleanup yet,
1188 	 despite there being no transfers.  Right at this moment,
1189 	 the user is deciding whether to accept or cancel the drop
1190 	 based on the presented dialog. */
1191       tc -> flags |= TC_EXITED_DH; /* Indicate safe to free record */
1192       /* Exit immediately to avoid freeing the transfer block below */
1193       return(True);
1194     } else {
1195       /* If no transfers occurred,  and this is a drop,
1196 	 then it failed */
1197       Arg args[2];
1198       XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE);
1199       XtSetArg(args[1], XmNnumDropTransfers, 0);
1200       XmDropTransferStart(tc -> drag_context, args, 2);
1201     }
1202   }
1203 
1204   /* If we either have performed no transfers or we are finished
1205      with the transfers,  go finish the work */
1206   if (tc -> count == 0 || tc -> outstanding == 0)
1207     {
1208       FinishTransfer(wid, tc);
1209       return(True);
1210     }
1211   else {
1212     /* Otherwise set the flag so SelectionCallbackWrapper can
1213        finish the work */
1214     tc -> flags |= TC_EXITED_DH; /* Indicate safe to free record */
1215     return(True);
1216   }
1217 }
1218 
1219 static void
1220 FinishTransfer(Widget wid, TransferContext tc)
1221 {
1222   XmTransferDoneCallbackStruct ts;
1223 
1224   tc -> flags |= TC_FLUSHED;  /* Ignore any future requests */
1225   ts.reason = XmCR_OK;
1226   ts.event = (XEvent *) NULL;
1227   ts.selection = tc -> selection;
1228   ts.transfer_id = (XtPointer) tc;
1229 
1230   if (tc -> status == XmTRANSFER_DONE_FAIL)
1231     ts.status = XmTRANSFER_DONE_FAIL;
1232   else
1233     ts.status = XmTRANSFER_DONE_SUCCEED;
1234 
1235   /* Override if no transfers have occurred */
1236   if (tc -> count == 0) ts.status = XmTRANSFER_DONE_FAIL;
1237 
1238   ts.client_data = tc -> client_data;
1239 
1240   CallDoneProcs(wid, tc, &ts);
1241   XtFree((char*) tc -> callback_struct);
1242   FreeTransferID(tc);
1243 }
1244 
1245 /****************************************************************/
1246 /* DropDestinationHandler acts as a wrapper to the destination  */
1247 /* handler for drag and drop.  This is because drag and drop    */
1248 /* passes the DragContext as the widget to the destination proc */
1249 /* in the drop							*/
1250 /****************************************************************/
1251 
1252 /*ARGSUSED*/
1253 static void
1254 DeleteDropCBStruct(Widget w,	/* unused */
1255 		   XtEnum ignored_status, /* unused */
1256 		   XmTransferDoneCallbackStruct *cs)
1257 {
1258   TransferContext tc = (TransferContext) cs -> transfer_id;
1259 
1260   /* The malloc'd structure is in the destination_data member */
1261   XtFree((char*) tc -> callback_struct -> destination_data);
1262 }
1263 
1264 /*ARGSUSED*/
1265 static void
1266 DropDestinationHandler(Widget w,
1267 		       XtPointer client_data, /* unused */
1268 		       XmDropProcCallbackStruct *ds)
1269 {
1270   Atom MOTIF_DROP = XInternAtom(XtDisplay(w), XmS_MOTIF_DROP, False);
1271   XtEnum op;
1272 
1273   if (ds -> dropAction == XmDROP_HELP ||
1274       ds -> operation == XmDROP_NOOP)
1275     op = XmOTHER;
1276   else
1277     op = ds -> operation;
1278 
1279   (void) _XmDestinationHandler(w, MOTIF_DROP, op, NULL,
1280 			       (XtPointer) ds, ds -> timeStamp, NULL);
1281 }
1282 
1283 
1284 /*************************************************************/
1285 /* XmePrimarySink begins a transfer for the contents of the  */
1286 /* XA_PRIMARY selection.                                     */
1287 /*************************************************************/
1288 Boolean
1289 XmePrimarySink(Widget w, XtEnum op, XtPointer location_data, Time time)
1290 {
1291   Boolean ret_val;
1292   _XmWidgetToAppContext(w);
1293 
1294   _XmAppLock(app);
1295   ret_val = _XmDestinationHandler(w, XA_PRIMARY, op, NULL,
1296 			       location_data, time, NULL);
1297   _XmAppUnlock(app);
1298   return ret_val;
1299 }
1300 
1301 /*************************************************************/
1302 /* XmeNamedSink begins a transfer for the contents of the    */
1303 /* named selection.                                          */
1304 /*************************************************************/
1305 Boolean
1306 XmeNamedSink(Widget w, Atom sel, XtEnum op, XtPointer location_data, Time time)
1307 {
1308   Boolean ret_val;
1309   _XmWidgetToAppContext(w);
1310 
1311   _XmAppLock(app);
1312   ret_val = _XmDestinationHandler(w, sel, op, NULL,
1313 			       location_data, time, NULL);
1314   _XmAppUnlock(app);
1315   return ret_val;
1316 }
1317 
1318 /*************************************************************/
1319 /* XmeSecondarySink takes ownership of the MOTIF_DESTINATION */
1320 /* selection.                                                */
1321 /*************************************************************/
1322 Boolean
1323 XmeSecondarySink(Widget w, Time time)
1324 {
1325   Boolean status;
1326   Atom MOTIF_DESTINATION = XInternAtom(XtDisplay(w), XmS_MOTIF_DESTINATION, False);
1327   _XmWidgetToAppContext(w);
1328 
1329   _XmAppLock(app);
1330   ClearContextBlock(XtDisplay(w), MOTIF_DESTINATION);
1331 
1332   if (time == 0) time = XtLastTimestampProcessed(XtDisplay(w));
1333 
1334   /* Setup our end of the secondary selection */
1335 
1336   status = XtOwnSelection(w, MOTIF_DESTINATION, time,
1337 			  _XmConvertHandler, LoseProc, NULL);
1338 
1339   if (status) XtAddCallback(w, XmNdestroyCallback, DisownCallback,
1340 			    (XtPointer) MOTIF_DESTINATION);
1341 
1342   _XmAppUnlock(app);
1343   return(status);
1344 }
1345 
1346 /**************************************************************/
1347 /* XmeClipboardSink begins a transfer for the contents of the */
1348 /* CLIPBOARD selection.                                       */
1349 /**************************************************************/
1350 Boolean
1351 XmeClipboardSink(Widget w, XtEnum op, XtPointer location_data)
1352 {
1353   Atom CLIPBOARD = XInternAtom(XtDisplay(w), XmSCLIPBOARD, False);
1354   Boolean ret_val;
1355   _XmWidgetToAppContext(w);
1356 
1357   _XmAppLock(app);
1358   ret_val = _XmDestinationHandler(w, CLIPBOARD, op,
1359 			       NULL, location_data, 0, NULL);
1360   _XmAppUnlock(app);
1361   return ret_val;
1362 }
1363 
1364 /*************************************************************/
1365 /* XmeDropSink creates a drop site that will use the         */
1366 /* destinationCallbacks to handle drops.                     */
1367 /*************************************************************/
1368 void
1369 XmeDropSink(Widget w, ArgList in_args, Cardinal in_arg_count)
1370 {
1371   Arg *args;
1372   int arg_count;
1373   _XmWidgetToAppContext(w);
1374 
1375   _XmAppLock(app);
1376   /* merge and copy arg list */
1377   arg_count = in_arg_count + 2;
1378   args = (Arg *) XtMalloc(sizeof(Arg) * arg_count);
1379   for(arg_count = 0; arg_count < in_arg_count; arg_count++)
1380     args[arg_count] = in_args[arg_count];
1381 
1382   arg_count = in_arg_count;
1383 
1384   XtSetArg(args[arg_count], XmNdropProc, DropDestinationHandler);
1385   arg_count++;
1386 
1387   XmDropSiteRegister(w, args, arg_count);
1388 
1389   XtFree((char*) args);
1390   _XmAppUnlock(app);
1391 }
1392 
1393 
1394 /*************************************************************/
1395 /* Transfer routine section                                  */
1396 /*************************************************************/
1397 
1398 /************************************************************************/
1399 /* XmTransferDone allows the user to control the transfer queue		*/
1400 /* If the user calls XmTransferDone with a status of DEFAULT then	*/
1401 /* all remaining non-internal transfers are ignored and the widget's    */
1402 /* internal transfers are done.   SUCCEED, FAIL or CONTINUE cause the   */
1403 /* entire queue to be flushed,  and the appropriate status to be set.   */
1404 /************************************************************************/
1405 void
1406 XmTransferDone(XtPointer transfer_id, XmTransferStatus status)
1407 {
1408   TransferContext tc = (TransferContext) transfer_id;
1409   Atom MOTIF_DROP = XInternAtom(XtDisplay(tc -> widget), XmS_MOTIF_DROP, False);
1410   _XmWidgetToAppContext(tc->widget);
1411 
1412   _XmAppLock(app);
1413   tc -> status = status;
1414 
1415   /* Make sure MULTIPLE request is unblocked */
1416   if (tc -> flags & TC_IN_MULTIPLE) {
1417     tc -> flags &= ~ TC_IN_MULTIPLE;
1418     XtSendSelectionRequest(tc -> widget, tc -> selection,
1419 			   XtLastTimestampProcessed(XtDisplay(tc -> widget)));
1420   }
1421 
1422   if (status == XmTRANSFER_DONE_SUCCEED ||
1423       status == XmTRANSFER_DONE_FAIL ||
1424       status == XmTRANSFER_DONE_CONTINUE)
1425     {
1426       tc -> flags |= TC_FLUSHED;
1427 
1428       if (status == XmTRANSFER_DONE_FAIL &&
1429 	  tc -> selection == MOTIF_DROP) {
1430 	Arg args[2];
1431 	XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE);
1432 	XtSetArg(args[1], XmNnumDropTransfers, 0);
1433 	if (tc -> drop_context != (Widget) NULL)
1434 	  XtSetValues(tc -> drop_context, args, 2);
1435 	else
1436 	  XmDropTransferStart(tc -> drag_context, args, 2);
1437 
1438 	/* Also,  if there are no transfers,  and we have exited
1439 	   _XmDestinationHandler,  we must cleanup the transfer
1440 	   infomation here as SelectionCallbackWrapper,  where the
1441 	   data is normally freed, won't be called */
1442 	if (tc -> count == 0 &&
1443 	    tc -> flags & TC_EXITED_DH ) {
1444 	  FinishTransfer(tc -> widget, tc);
1445 	}
1446       }
1447     }
1448   else if (status == XmTRANSFER_DONE_DEFAULT)
1449     {
1450       TransferBlock tb;
1451 
1452       /* If we are going to default then we'll skip
1453 	 all requests placed by callbacks */
1454       for(tb = tc -> requests;
1455 	  tb != NULL;
1456 	  tb = (TransferBlock) tb -> next) {
1457 	if (!(tb -> flags & TB_INTERNAL))
1458 	  tb -> flags = tb -> flags | TB_IGNORE;
1459       }
1460     }
1461   _XmAppUnlock(app);
1462 }
1463 
1464 /************************************************************************/
1465 /* XmTransferSetParameters defines a set of parameters to be passed     */
1466 /* with the next call to XmTransferValue.				*/
1467 /************************************************************************/
1468 
1469 void
1470 XmTransferSetParameters(XtPointer transfer_id,
1471 			XtPointer parm,
1472 			int parm_fmt,
1473 			unsigned long parm_length,
1474 			Atom parm_type)
1475 {
1476   TransferContext tc = (TransferContext) transfer_id;
1477   _XmWidgetToAppContext(tc->widget);
1478 
1479   _XmAppLock(app);
1480   /******************************************************/
1481   /* Return if we already finished this transfer set    */
1482   /* The problem is that if the flags are set then we   */
1483   /* are about to delete the transferContext in         */
1484   /* SelectionCallbackWrapper()                         */
1485   /******************************************************/
1486   if (tc -> flags & TC_FLUSHED) {
1487 	_XmAppUnlock(app);
1488 	return;
1489   }
1490 
1491   if (parm_fmt == 0) parm_fmt = 8;
1492 
1493   if (parm != NULL)
1494     XtSetSelectionParameters(tc -> widget, tc -> real_selection,
1495 			     parm_type, parm, parm_length, parm_fmt);
1496   _XmAppUnlock(app);
1497 }
1498 
1499 /************************************************************************/
1500 /* XmTransferValue allows the user to get data from the owner of the    */
1501 /* selection for which we started the destination callback.		*/
1502 /* This takes care of the small details for getting the data from 	*/
1503 /* either the selection mechanism (user, PRIMARY, SECONDARY, or		*/
1504 /* CLIPBOARD) or from another mechanism (Drag and Drop).		*/
1505 /************************************************************************/
1506 
1507 void
1508 XmTransferValue(XtPointer transfer_id,
1509 		Atom target,
1510 		XtCallbackProc proc,
1511 		XtPointer client_data,
1512 		Time time)
1513 {
1514   enum { XmACLIPBOARD, XmA_MOTIF_DROP, NUM_ATOMS };
1515   static char *atom_names[] = { XmSCLIPBOARD, XmS_MOTIF_DROP };
1516 
1517   TransferContext tc = (TransferContext) transfer_id;
1518   TransferBlock tb;
1519   unsigned long length;
1520   Atom atoms[XtNumber(atom_names)];
1521   _XmWidgetToAppContext(tc->widget);
1522 
1523   _XmAppLock(app);
1524   /******************************************************/
1525   /* Return if we already finished this transfer set    */
1526   /* The problem is that if the flags are set then we   */
1527   /* are about to delete the transferContext in         */
1528   /* SelectionCallbackWrapper()                         */
1529   /******************************************************/
1530   if (tc -> flags & TC_FLUSHED) {
1531 	_XmAppUnlock(app);
1532 	return;
1533   }
1534 
1535   assert(XtNumber(atom_names) == NUM_ATOMS);
1536   XInternAtoms(XtDisplay(tc -> widget), atom_names, XtNumber(atom_names),
1537 	       False, atoms);
1538 
1539   if (time == 0)
1540     time = XtLastTimestampProcessed(XtDisplay(tc -> widget));
1541 
1542   tb = AddTransferBlock(tc);
1543 
1544   tb -> client_data = client_data;
1545   tb -> selection_proc = proc;
1546   tb -> target = target;
1547   tb -> location_data = NULL;
1548 
1549   tc -> outstanding++;
1550   tc -> count++;
1551 
1552   if (tc -> selection == atoms[XmACLIPBOARD]) {
1553     /* Assure the clipboard is owned to prevent orphan data
1554        problems in the data transfer */
1555     XmClipboardInquireLength(XtDisplay(tc -> widget),
1556 			     XtWindow(tc -> widget),
1557 			     XmSTARGETS,
1558 			     &length);
1559   }
1560 
1561   if (tc -> selection != atoms[XmA_MOTIF_DROP])
1562     {
1563       XtGetSelectionValue(tc -> widget, tc -> real_selection, target,
1564 			  SelectionCallbackWrapper, (XtPointer)tc, time);
1565     }
1566   else
1567     {
1568       XmDropTransferEntryRec transfers[1];
1569 
1570       transfers[0].client_data = (XtPointer) tc;
1571       transfers[0].target = tb -> target;
1572       if (tc -> drop_context == NULL)
1573 	{
1574 	  Arg args[5];
1575 
1576 	  XtSetArg(args[0], XmNdropTransfers, transfers);
1577 	  XtSetArg(args[1], XmNnumDropTransfers, 1);
1578 	  XtSetArg(args[2], XmNtransferProc, SelectionCallbackWrapper);
1579 	  tc -> drop_context =
1580 	    (Widget) XmDropTransferStart(tc -> drag_context, args, 3);
1581 	}
1582       else
1583 	XmDropTransferAdd(tc -> drop_context, transfers, 1);
1584     }
1585   _XmAppUnlock(app);
1586 }
1587 
1588 
1589 /************************************************************************/
1590 /* XmTransferStartRequest and XmTransferSendRequest bracket a MULTIPLE	*/
1591 /* request.  In between the user calls XmTransferSetParameters and 	*/
1592 /* XmTransferValue to arrange requests.					*/
1593 /************************************************************************/
1594 void
1595 XmTransferStartRequest(XtPointer transfer_id)
1596 {
1597   TransferContext tc = (TransferContext) transfer_id;
1598   _XmWidgetToAppContext(tc->widget);
1599 
1600   _XmAppLock(app);
1601   /******************************************************/
1602   /* Return if we already finished this transfer set    */
1603   /* The problem is that if the flags are set then we   */
1604   /* are about to delete the transferContext in         */
1605   /* SelectionCallbackWrapper()                         */
1606   /******************************************************/
1607   if (tc -> flags & TC_FLUSHED) {
1608 	_XmAppUnlock(app);
1609 	return;
1610   }
1611 
1612   if (tc -> flags & TC_IN_MULTIPLE) {
1613     char *sel;
1614     FreeType howFree;
1615 
1616     sel = GetSafeAtomName(XtDisplay(tc -> widget), tc -> selection, &howFree);
1617     /* Already doing a multiple */
1618     TransferWarning(tc->widget, START_MULTIPLE,
1619 		    sel,
1620 		    ERROR_MULTIPLE_IN_PROGRESS);
1621     FreeSafeAtomName(sel,howFree);
1622     _XmAppUnlock(app);
1623     return;
1624   }
1625 
1626   tc -> flags |= TC_IN_MULTIPLE;
1627 
1628   XtCreateSelectionRequest(tc -> widget, tc -> real_selection);
1629   _XmAppUnlock(app);
1630 }
1631 
1632 void
1633 XmTransferSendRequest(XtPointer transfer_id, Time time)
1634 {
1635   TransferContext tc = (TransferContext) transfer_id;
1636   _XmWidgetToAppContext(tc->widget);
1637 
1638   _XmAppLock(app);
1639   /******************************************************/
1640   /* Return if we already finished this transfer set    */
1641   /* The problem is that if the flags are set then we   */
1642   /* are about to delete the transferContext in         */
1643   /* SelectionCallbackWrapper()                         */
1644   /******************************************************/
1645   if (tc -> flags & TC_FLUSHED) {
1646     /* Assume that cleanup would be appropriate here */
1647     XtCancelSelectionRequest(tc -> widget, tc -> real_selection);
1648     _XmAppUnlock(app);
1649     return;
1650   }
1651 
1652   if (! (tc -> flags & TC_IN_MULTIPLE)) {
1653     char     *sel;
1654     FreeType howFree;
1655 
1656     sel = GetSafeAtomName(XtDisplay(tc -> widget), tc -> selection, &howFree);
1657     /* Not doing a multiple */
1658     TransferWarning(tc->widget, END_MULTIPLE,
1659 		    sel,
1660 		    ERROR_MULTIPLE_NOT_IN_PROGRESS);
1661     FreeSafeAtomName(sel, howFree);
1662     _XmAppUnlock(app);
1663     return;
1664   }
1665 
1666   tc -> flags &= ~ TC_IN_MULTIPLE;
1667 
1668   if (time == 0) time = XtLastTimestampProcessed(XtDisplay(tc -> widget));
1669 
1670   XtSendSelectionRequest(tc -> widget, tc -> real_selection, time);
1671   _XmAppUnlock(app);
1672 }
1673 
1674 /************************************************************************/
1675 /* SelectionCallbackWrapper does the bookeeping for the transfer 	*/
1676 /* routines and makes sure that the TransferContext is deleted when 	*/
1677 /* there are no more outstanding transfers.				*/
1678 /************************************************************************/
1679 static void
1680 SelectionCallbackWrapper(Widget wid, XtPointer client_data,
1681 			 Atom *selection, Atom *type,
1682 			 XtPointer value, unsigned long *length,
1683 			 int *format)
1684 {
1685   enum { XmA_MOTIF_DROP, XmADELETE, NUM_ATOMS };
1686   static char *atom_names[] = { XmS_MOTIF_DROP, XmSDELETE };
1687 
1688   XmSelectionCallbackStruct cbstruct;
1689   TransferContext tc = (TransferContext) client_data;
1690   TransferBlock tb = tc -> requests;
1691   Atom atoms[XtNumber(atom_names)];
1692 
1693   assert(XtNumber(atom_names) == NUM_ATOMS);
1694   XInternAtoms(XtDisplay(wid), atom_names, XtNumber(atom_names), False, atoms);
1695 
1696   /* Get the real widget if this is a drop transfer */
1697   if (tc -> selection == atoms[XmA_MOTIF_DROP])
1698     wid = tc -> widget;
1699 
1700   if (tc -> outstanding == 0) {
1701     XmeWarning(wid, BAD_SCB_MESSAGE);
1702     return;
1703   }
1704 
1705   if (tb != NULL) {
1706     /* Unchain this transfer block */
1707     tc -> requests = (TransferBlock) tb -> next;
1708     /* If this is the last block then reset last */
1709     if (tc -> last == tb) tc -> last = NULL;
1710   }
1711 
1712   if (! (tc -> flags & TC_FLUSHED)) {
1713     if (tb != NULL &&
1714 	! (tb -> flags & TB_IGNORE)) {
1715       cbstruct.reason = XmCR_OK;
1716       cbstruct.event = (XEvent *) NULL;
1717       cbstruct.selection = *selection;
1718       cbstruct.target = tb -> target;
1719       cbstruct.transfer_id = (XtPointer) tc;
1720       cbstruct.flags = XmSELECTION_DEFAULT;
1721       cbstruct.remaining = tc -> outstanding;
1722       cbstruct.type = *type;
1723       cbstruct.value = value;
1724       cbstruct.length = *length;
1725       cbstruct.format = *format;
1726 
1727       if (tb -> selection_proc != NULL)
1728 	tb -> selection_proc(wid, tb -> client_data, &cbstruct);
1729     }
1730   }
1731 
1732 
1733   /* Free this transfer block */
1734   if (tb != NULL) {
1735     XtFree((char*) tb);
1736   }
1737 
1738   /* Ignore callbacks after we're done */
1739   tc -> outstanding--;
1740 
1741   /* When outstanding is 0,  check to see if the status is
1742      XmTRANSFER_DONE_DEFAULT.  This indicates that we
1743      should attempt calling the widget's destination
1744      proc.  We'll set a flag in tc to indicate that
1745      we've done this,  so we don't repeat the action */
1746   if (tc -> outstanding == 0 &&
1747       tc -> status == XmTRANSFER_DONE_DEFAULT &&
1748       tc -> flags & TC_CALLED_CALLBACKS &&
1749       !(tc -> flags & TC_CALLED_WIDGET)) {
1750     XmTransferTrait ttrait;
1751 
1752     tc -> flags |= TC_CALLED_WIDGET;
1753     ttrait = (XmTransferTrait)
1754       XmeTraitGet((XtPointer) XtClass(wid), XmQTtransfer);
1755 
1756     /* Now lookup the trait on this widget and call the
1757        internal routine. */
1758     if (ttrait != NULL) {
1759     _XmProcessLock();
1760       TB_internal = 1;
1761     _XmProcessUnlock();
1762       if (ttrait -> destinationProc != 0)
1763 	ttrait -> destinationProc(wid, NULL, tc -> callback_struct);
1764     _XmProcessLock();
1765       TB_internal = 0;
1766     _XmProcessUnlock();
1767     }
1768   }
1769 
1770   /* Send a delete if this is a move operation and we've complete
1771      successfully for PRIMARY transfer */
1772   if (tc -> selection == XA_PRIMARY &&
1773       tc -> outstanding == 0 &&
1774       tc -> count != 0 &&
1775       (tc -> status == XmTRANSFER_DONE_SUCCEED ||
1776        tc -> status == XmTRANSFER_DONE_DEFAULT) &&
1777       tc -> op == XmMOVE &&
1778       ! (tc -> flags & TC_DID_DELETE)) {
1779     tc -> flags |= TC_DID_DELETE;
1780     XmTransferValue((XtPointer) tc, atoms[XmADELETE], NULL, NULL,
1781 		    XtLastTimestampProcessed(XtDisplay(wid)));
1782   }
1783 
1784   /* When outstanding reaches 0,  free context block.  But don't
1785      do this in the local case.  There we can free in the caller,
1786      so check the TC_EXITED_DH flag to see if we've exited
1787      _XmDestinationHandler yet. */
1788   if (tc -> outstanding == 0 &&
1789       tc -> flags & TC_EXITED_DH ) {
1790     FinishTransfer(wid, tc);
1791   }
1792 }
1793 
1794 /**********************************************************/
1795 /* Context block handlers for convert and transfer blocks */
1796 /**********************************************************/
1797 
1798 typedef struct __XmCCKey {
1799   Display *display;
1800   Atom	  selection;
1801 } _XmCCKeyRec, *_XmCCKey;
1802 
1803 static Boolean
1804 CCMatch(XtPointer x, XtPointer y)
1805 {
1806   _XmCCKey a, b;
1807 
1808   a = (_XmCCKey) x;
1809   b = (_XmCCKey) y;
1810 
1811   return(a -> display   ==  b -> display &&
1812 	 a -> selection ==  b -> selection);
1813 }
1814 
1815 static XmHashValue
1816 CCHash(XtPointer x)
1817 {
1818   _XmCCKey a;
1819 
1820   a = (_XmCCKey) x;
1821 
1822   return((XmHashValue) ((long) a -> display + (long) a -> selection));
1823 }
1824 
1825 static XmHashTable ConvertHashTable = (XmHashTable) NULL;
1826 
1827 static ConvertContext
1828 LookupContextBlock(Display *d, Atom a)
1829 {
1830   ConvertContext cc;
1831   _XmCCKeyRec x;
1832 
1833   x.display = d;
1834   x.selection = a;
1835 
1836   _XmProcessLock();
1837   if (ConvertHashTable == (XmHashTable) NULL)
1838     ConvertHashTable = _XmAllocHashTable(10, CCMatch, CCHash);
1839 
1840   cc = (ConvertContext) _XmGetHashEntry(ConvertHashTable, (XmHashKey) &x);
1841   _XmProcessUnlock();
1842 
1843   if (cc == NULL) {
1844     _XmCCKey new_k;
1845 
1846     new_k = (_XmCCKey) XtMalloc(sizeof(_XmCCKeyRec));
1847     new_k -> display = d;
1848     new_k -> selection = a;
1849 
1850     /* Allocate a context block for this selection */
1851     cc = (ConvertContext) XtMalloc(sizeof(ConvertContextRec));
1852     _XmProcessLock();
1853     _XmAddHashEntry(ConvertHashTable, (XmHashKey)new_k, (XtPointer)cc);
1854     _XmProcessUnlock();
1855   }
1856 
1857   return(cc);
1858 }
1859 
1860 static void
1861 ClearContextBlock(Display *d, Atom a)
1862 {
1863   ConvertContext cc;
1864 
1865   cc = LookupContextBlock(d, a);
1866 
1867   cc -> flags = 0;
1868   cc -> op = 0;
1869   cc -> itemid = 0;
1870   cc -> location_data = NULL;
1871   cc -> client_data = NULL;
1872   cc -> drag_context = (Widget) NULL;
1873 }
1874 
1875 /* Functions to get and free transfer ids */
1876 
1877 static TransferContext global_tc = NULL;
1878 static TransferContext free_tc = NULL;
1879 
1880 static XtPointer
1881 GetTransferID(void)
1882 {
1883   TransferContext rval;
1884 
1885   /* If there is one on the free list,  unchain it
1886      and return it */
1887 
1888   _XmProcessLock();
1889   if (free_tc != NULL)
1890     {
1891       rval = free_tc;
1892       free_tc = (TransferContext) rval -> next;
1893     }
1894   else
1895     rval = (TransferContext) XtMalloc(sizeof(TransferContextRec));
1896 
1897   /* Put it on the chain */
1898 
1899   rval -> next = (XtPointer) global_tc;
1900   rval -> prev = NULL;
1901 
1902   if (global_tc != NULL) global_tc -> prev = (XtPointer) rval;
1903   global_tc = rval;
1904   _XmProcessUnlock();
1905 
1906   /* Initialize */
1907   rval -> outstanding = 0;
1908   rval -> count = 0;
1909   rval -> flags = TC_NONE;
1910   rval -> requests = NULL;
1911   rval -> last = NULL;
1912 
1913   return((XtPointer) rval);
1914 }
1915 
1916 static void
1917 FreeTransferID(XtPointer id)
1918 {
1919   TransferContext tid = (TransferContext) id;
1920   TransferContext pid, nid;
1921 
1922   /* Free done_proc list */
1923   if (tid -> doneProcs != NULL) XtFree((char*) tid -> doneProcs);
1924 
1925   /* first unchain from global_tc */
1926 
1927   if (global_tc == tid)
1928     {
1929       _XmProcessLock();
1930       global_tc = (TransferContext) tid -> next;
1931       if (global_tc != NULL)
1932 	global_tc -> prev = NULL;
1933       _XmProcessUnlock();
1934     }
1935   else
1936     {
1937       /* Get previous and next */
1938       pid = (TransferContext) tid -> prev;
1939       nid = (TransferContext) tid -> next;
1940       /* Connect prev and next */
1941       if (pid != NULL) pid -> next = (XtPointer) nid;
1942       if (nid != NULL) nid -> prev = (XtPointer) pid;
1943     }
1944 
1945   _XmProcessLock();
1946   /* Put on free list */
1947   tid -> next = (XtPointer) free_tc;
1948   free_tc = tid;
1949   _XmProcessUnlock();
1950 }
1951 
1952 static void
1953 CallDoneProcs(Widget wid, XtPointer id, XmTransferDoneCallbackStruct *ts)
1954 {
1955   int i;
1956   TransferContext tid = (TransferContext) id;
1957 
1958   for(i = 0; i < tid -> numDoneProcs; i++) {
1959     (tid -> doneProcs[i])(wid, tid -> op, ts);
1960   }
1961 }
1962 
1963 static TransferBlock
1964 AddTransferBlock(TransferContext tc)
1965 {
1966   TransferBlock tb;
1967 
1968   tb = (TransferBlock) XtMalloc(sizeof(TransferBlockRec));
1969   tb -> next = NULL;
1970   /* we append blocks to the end of the list */
1971   if (tc -> requests == NULL)
1972     {
1973       tc -> requests = tb;
1974       tc -> last = tb;
1975     }
1976   else
1977     {
1978       (tc -> last) -> next = (XtPointer) tb;
1979       tc -> last = tb;
1980     }
1981 
1982   _XmProcessLock();
1983   if (TB_internal)
1984     tb -> flags = TB_INTERNAL;
1985   else
1986     tb -> flags = TB_NONE;
1987   _XmProcessUnlock();
1988 
1989   return(tb);
1990 }
1991 
1992 /* Warning routine */
1993 static void
1994 TransferWarning(Widget w, char* name, char* type, char* message)
1995 {
1996   XmeWarning(w, message);
1997 }
1998 
1999 /****************************************************************/
2000 /* Standard target support					*/
2001 /*								*/
2002 /* This support makes it easy for all widgets to support a set	*/
2003 /* of targets which can be automatically converted to.		*/
2004 /*								*/
2005 /****************************************************************/
2006 
2007 /*
2008  * XmeStandardTargets takes a widget, and a count of the widget's
2009  * private target list, and returns a list of standard targets.
2010  * The count of standard targets is returned in the passed in
2011  * integer
2012  */
2013 
2014 #define MAXBUILTIN 12
2015 
2016 Atom*
2017 XmeStandardTargets(Widget w, int count, int *tcount)
2018 {
2019   enum { XmATARGETS, XmATIMESTAMP, XmAFOREGROUND, XmABACKGROUND,
2020 	 XmACLASS, XmANAME, XmACLIENT_WINDOW, XmA_MOTIF_RENDER_TABLE,
2021 	 XmA_MOTIF_ENCODING_REGISTRY, NUM_ATOMS };
2022   static char *atom_names[] = {
2023     XmSTARGETS, XmSTIMESTAMP, XmIFOREGROUND, XmIBACKGROUND,
2024     XmICLASS, XmINAME, XmSCLIENT_WINDOW, XmS_MOTIF_RENDER_TABLE,
2025     XmS_MOTIF_ENCODING_REGISTRY };
2026 
2027   int i = 0;
2028   Atom atoms[XtNumber(atom_names)];
2029   Atom *targets;
2030   _XmWidgetToAppContext(w);
2031 
2032   _XmAppLock(app);
2033   targets = (Atom *) XtMalloc(sizeof(Atom) * MAXBUILTIN);
2034 
2035   assert(XtNumber(atom_names) == NUM_ATOMS);
2036   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
2037 
2038   targets[i] = atoms[XmATARGETS]; i++;
2039   targets[i] = atoms[XmATIMESTAMP]; i++;
2040   targets[i] = atoms[XmAFOREGROUND]; i++;
2041   targets[i] = atoms[XmABACKGROUND]; i++;
2042   targets[i] = XA_COLORMAP; i++;
2043   targets[i] = atoms[XmACLASS]; i++;
2044   targets[i] = atoms[XmANAME]; i++;
2045   targets[i] = atoms[XmACLIENT_WINDOW]; i++;
2046   targets[i] = atoms[XmA_MOTIF_RENDER_TABLE]; i++;
2047   targets[i] = atoms[XmA_MOTIF_ENCODING_REGISTRY]; i++;
2048 
2049   /* Realloc the full size now */
2050   targets = (Atom *) XtRealloc((char*) targets, sizeof(Atom) * (count + i));
2051 
2052   *tcount = i; /* Return the builtin target count */
2053   _XmAppUnlock(app);
2054   return(targets);
2055 }
2056 
2057 /*
2058  * XmeStandardConvert is called when receiving an unknown
2059  * target.  It should be called last in most convert procs.
2060  */
2061 
2062 /*ARGSUSED*/
2063 void
2064 XmeStandardConvert(Widget w,
2065 		   XtPointer ignore, /* unused */
2066 		   XmConvertCallbackStruct *cs)
2067 {
2068   enum { XmATARGETS, XmAFOREGROUND, XmAPIXEL, XmABACKGROUND,
2069 	 XmACLASS, XmANAME, XmACLIENT_WINDOW, XmA_MOTIF_RENDER_TABLE,
2070 	 XmA_MOTIF_ENCODING_REGISTRY, NUM_ATOMS };
2071   static char *atom_names[] = {
2072     XmSTARGETS, XmIFOREGROUND, XmIPIXEL, XmIBACKGROUND,
2073     XmICLASS, XmINAME, XmSCLIENT_WINDOW, XmS_MOTIF_RENDER_TABLE,
2074     XmS_MOTIF_ENCODING_REGISTRY };
2075 
2076   Arg arg[1];
2077   Atom atoms[XtNumber(atom_names)];
2078   _XmWidgetToAppContext(w);
2079 
2080   _XmAppLock(app);
2081   assert(XtNumber(atom_names) == NUM_ATOMS);
2082   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
2083 
2084   if (atoms[XmATARGETS] == cs -> target) {
2085     int tcount;
2086     cs -> value = (XtPointer) XmeStandardTargets(w, 0, &tcount);
2087     cs -> format = 32;
2088     cs -> length = tcount;
2089     cs -> type = XA_ATOM;
2090   } else if (atoms[XmAFOREGROUND] == cs -> target) {
2091     Pixel *fg;
2092 
2093     if (XmIsGadget(w)) w = XtParent(w);
2094 
2095     fg = (Pixel *) XtMalloc(sizeof(Pixel));
2096     XtSetArg(arg[0], XtNforeground, fg);
2097     XtGetValues(w, arg, 1);
2098 
2099     cs -> value = (XtPointer) fg;
2100     cs -> format = 32;
2101     cs -> length = 1;
2102     cs -> type = atoms[XmAPIXEL];
2103   } else if (atoms[XmABACKGROUND] == cs -> target) {
2104     Pixel *bg;
2105 
2106     if (XmIsGadget(w)) w = XtParent(w);
2107 
2108     bg = (Pixel *) XtMalloc(sizeof(Pixel));
2109     XtSetArg(arg[0], XtNbackground, bg);
2110     XtGetValues(w, arg, 1);
2111 
2112     cs -> value = (XtPointer) bg;
2113     cs -> format = 32;
2114     cs -> length = 1;
2115     cs -> type = atoms[XmAPIXEL];
2116   } else if (XA_COLORMAP == cs -> target) {
2117     Colormap *cmap;
2118 
2119     if (XmIsGadget(w)) w = XtParent(w);
2120 
2121     cmap = (Colormap *) XtMalloc(sizeof(Colormap));
2122     XtSetArg(arg[0], XtNcolormap, cmap);
2123     XtGetValues(w, arg, 1);
2124 
2125     cs -> value = (XtPointer) cmap;
2126     cs -> format = 32;
2127     cs -> length = 1;
2128     cs -> type = XA_COLORMAP;
2129   } else if (atoms[XmACLASS] == cs -> target) {
2130     Widget current;
2131     unsigned long bytesAfter;
2132 
2133     cs -> value = NULL;
2134     cs -> format = 32;
2135     cs -> length = 0;
2136     cs -> type = XA_INTEGER;
2137 
2138     for(current = w;
2139 	current != (Widget) NULL;
2140 	current = XtParent(current)) {
2141       if (XtIsShell(current)) {
2142 	XGetWindowProperty(XtDisplay(current), XtWindow(current),
2143 			   XA_WM_CLASS, 0L, 100000L, False,
2144 			   (Atom) AnyPropertyType,
2145 			   &cs -> type,
2146 			   &cs -> format,
2147 			   &cs -> length,
2148 			   &bytesAfter,
2149 			   (unsigned char**) &cs -> value);
2150 	if (cs -> value != NULL) break;
2151       }
2152     }
2153   } else if (atoms[XmANAME] == cs -> target) {
2154     Widget current;
2155     unsigned long bytesAfter;
2156     Atom type;
2157     int format;
2158     unsigned char *value = NULL;
2159     char *total_value;
2160     unsigned long length;
2161 
2162     for(current = w;
2163 	current != (Widget) NULL;
2164 	current = XtParent(current)) {
2165       if (XtIsShell(current)) {
2166 	XGetWindowProperty(XtDisplay(current), XtWindow(current),
2167 			   XA_WM_NAME, 0L, 100000L, False,
2168 			   (Atom) AnyPropertyType,
2169 			   &type,
2170 			   &format,
2171 			   &length,
2172 			   &bytesAfter,
2173 			   &value);
2174 	if (value != NULL) break;
2175       }
2176     }
2177 
2178     total_value = _XmTextToLocaleText(w, (XtPointer)value, type,
2179 				      format, length, NULL);
2180 
2181     cs -> value = (XtPointer) total_value;
2182     cs -> format = 8;
2183     cs -> length = total_value != NULL ? strlen(total_value) : 0;
2184     cs -> type = XmeGetEncodingAtom(w);
2185   } else if (atoms[XmACLIENT_WINDOW] == cs -> target) {
2186     Widget current;
2187     Window *cw;
2188 
2189     cw = (Window *) XtMalloc(sizeof(Window));
2190     for(current = w; current != (Widget) NULL; current = XtParent(current))
2191       if (XtIsShell(current)) break;
2192 
2193     *cw = XtWindow(current);
2194     cs -> value = (XtPointer) cw;
2195     cs -> format = 32;
2196     cs -> length = 1;
2197     cs -> type = XA_WINDOW;
2198   } else if (atoms[XmA_MOTIF_RENDER_TABLE] == cs -> target) {
2199     XmRenderTable table;
2200     Arg args[1];
2201     char *value;
2202     int size;
2203 
2204     table = (XmRenderTable) NULL;
2205     XtSetArg(args[0], XmNrenderTable, &table);
2206     XtGetValues(w, args, 1);
2207 
2208     if (table == NULL) {
2209       /* If we didn't find a render table on this widget, then
2210 	 go ahead and look up the chain for something which
2211 	 does have one */
2212       table = XmeGetDefaultRenderTable(w, XmTEXT_RENDER_TABLE);
2213     }
2214 
2215     if (table != NULL) {
2216       size = XmRenderTableCvtToProp(w, table, &value);
2217       cs -> value = (XtPointer) value;
2218       cs -> format = 8;
2219       cs -> length = size;
2220       cs -> type = XA_STRING;
2221     }
2222   } else if (atoms[XmA_MOTIF_ENCODING_REGISTRY] == cs -> target) {
2223     int len;
2224 
2225     cs -> format = 8;
2226     cs -> type = XA_STRING;
2227     cs -> value = _XmGetEncodingRegistryTarget(&len);
2228     cs -> length = len;
2229   }
2230   _XmAppUnlock(app);
2231 }
2232 
2233 Atom
2234 XmeGetEncodingAtom(Widget w)
2235 {
2236   int ret_status = 0;
2237   XTextProperty tmp_prop;
2238   char * tmp_string = "ABC";  /* these are characters in XPCS, so... safe */
2239   Atom encoding;
2240   _XmWidgetToAppContext(w);
2241 
2242   _XmAppLock(app);
2243   tmp_prop.value = NULL; /* just in case X doesn't do it */
2244   ret_status = XmbTextListToTextProperty(XtDisplay(w), &tmp_string, 1,
2245 					 (XICCEncodingStyle)XTextStyle,
2246 					 &tmp_prop);
2247   if (ret_status == Success)
2248     encoding = tmp_prop.encoding;
2249   else
2250     encoding = None;        /* XmbTextList... should always be able
2251 			   * to convert XPCS characters; but in
2252 			   * case its broken, this prevents a core
2253 			   * dump.
2254 			   */
2255   if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
2256   _XmAppUnlock(app);
2257   return(encoding);
2258 }
2259 
2260 
2261 char *
2262 _XmTextToLocaleText(Widget w,
2263 		    XtPointer value,
2264 		    Atom type,
2265 		    int format,
2266 		    unsigned long length,
2267 		    Boolean *success)
2268 {
2269   Atom COMPOUND_TEXT = XInternAtom(XtDisplay(w), XmSCOMPOUND_TEXT, False);
2270 #ifdef UTF8_SUPPORTED
2271   Atom UTF8_STRING = XInternAtom(XtDisplay(w), XmSUTF8_STRING, False);
2272 #endif
2273   XTextProperty text_prop;
2274   int status;
2275   char ** values;
2276   int num_values = 0;
2277   char *total_value = NULL;
2278   int malloc_size = 0;
2279   int i;
2280 
2281   if (type == XA_STRING || type == COMPOUND_TEXT
2282 #ifdef UTF8_SUPPORTED
2283       || type == UTF8_STRING
2284 #endif
2285      ) {
2286     text_prop.value = (unsigned char *) value;
2287     text_prop.encoding = type;
2288     text_prop.format = format;
2289     text_prop.nitems = length;
2290 
2291     status = XmbTextPropertyToTextList(XtDisplay(w), &text_prop, &values,
2292 				       &num_values);
2293 
2294     if (success != NULL) {
2295       if (status == Success || status > 0)
2296 	*success = True;
2297       else
2298 	*success = False;
2299     }
2300 
2301     if (num_values) {
2302       for (i = 0; i < num_values ; i++)
2303 	malloc_size += strlen(values[i]);
2304 
2305       total_value = XtMalloc ((unsigned) malloc_size + 1);
2306       total_value[0] = '\0';
2307       for (i = 0; i < num_values ; i++)
2308 	strcat(total_value, values[i]);
2309       XFreeStringList(values);
2310     }
2311   }
2312   return total_value;
2313 }
2314 
2315 void
2316 _XmConvertComplete(Widget wid, XtPointer value,
2317 		   unsigned long size, int format, Atom type,
2318 		   XmConvertCallbackStruct *cs)
2319 {
2320 
2321   if (value == NULL && cs -> value == NULL) {
2322     XmeStandardConvert(wid, NULL, cs);
2323   } else {
2324     if (cs -> status == XmCONVERT_MERGE) {
2325       XmeConvertMerge(value, type, format,  size, cs);
2326       XtFree((char*) value);
2327     } else {
2328       /* Not merging */
2329       if (cs -> value != NULL) XtFree((char*) cs -> value);
2330       cs -> type = type;
2331       cs -> value = value;
2332       cs -> length = size;
2333       cs -> format = format;
2334     }
2335   }
2336 
2337   if (cs -> value != NULL)
2338     cs -> status = XmCONVERT_DONE;
2339   else
2340     cs -> status = XmCONVERT_REFUSE;
2341 }
2342 
2343 XmDestinationCallbackStruct*
2344 _XmTransferGetDestinationCBStruct(XtPointer tid)
2345 {
2346   TransferContext tc = (TransferContext) tid;
2347 
2348   return(tc -> callback_struct);
2349 }
2350 
2351 /* Error handler for XGetAtomName */
2352 
2353 static int SIF_ErrorFlag;
2354 
2355 /*ARGSUSED*/
2356 static int
2357 SIF_ErrorHandler(
2358      Display *display,		/* unused */
2359      XErrorEvent *event)
2360 
2361 {
2362   _XmProcessLock();
2363   SIF_ErrorFlag = event -> type;
2364   _XmProcessUnlock();
2365 
2366   return 0;
2367 }
2368 
2369 /* NOTE! XGetAtomName return value MUST be freed with XFree; however, there
2370  ** isn't a good way to allocate data which can be freed with XFree. We could
2371  ** cache a static character pointer to NULL and check it to decide whether or
2372  ** not to free; for now, just pass information back on what to do with the
2373  ** returned value.
2374  */
2375 static char*
2376 GetSafeAtomName(Display *display, Atom a, FreeType *howFree)
2377 {
2378   XErrorHandler old_Handler;
2379   char *returnvalue;
2380 
2381   /* Setup error proc and reset error flag */
2382   old_Handler = XSetErrorHandler((XErrorHandler) SIF_ErrorHandler);
2383   _XmProcessLock();
2384   SIF_ErrorFlag = 0;
2385   _XmProcessUnlock();
2386 
2387   returnvalue = XGetAtomName(display, a);
2388   *howFree = DoXFree;
2389 
2390   XSetErrorHandler(old_Handler);
2391 
2392   _XmProcessLock();
2393   if (SIF_ErrorFlag != 0) {
2394     returnvalue = (char*) malloc(1);
2395     returnvalue[0] = 0; /* Create empty string to return */
2396     *howFree = DoFree;
2397     TransferWarning(NULL, ATOM, ARG, BAD_ATOM_MESSAGE);
2398   }
2399   _XmProcessUnlock();
2400   return(returnvalue);
2401 }
2402