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