1 /**
2  *
3  * $Id: DropTrans.c,v 1.1 2004/08/28 19:22:44 dannybackx Exp $
4  *
5  * Copyright (C) 1995 Free Software Foundation, Inc.
6  * Copyright (C) 1995-2002 LessTif Development Team
7  *
8  * This file is part of the GNU LessTif Library.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the Free
22  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  **/
25 
26 static const char rcsid[] = "$Id: DropTrans.c,v 1.1 2004/08/28 19:22:44 dannybackx Exp $";
27 
28 #include <LTconfig.h>
29 
30 #include <string.h>
31 
32 #include <XmI/XmI.h>
33 #include <Xm/XmP.h>
34 #include <Xm/AtomMgr.h>
35 #include <Xm/DropTransP.h>
36 #include <Xm/DragCP.h>
37 #include <XmI/DragDropI.h>
38 #include <XmI/AtomMgrI.h>
39 #include <Xm/DisplayP.h>
40 
41 #include <XmI/DebugUtil.h>
42 
43 #if 0
44 static void class_initialize();
45 #endif
46 
47 static void class_part_initialize(WidgetClass w_class);
48 
49 static void initialize(Widget request, Widget new_w,
50 		       ArgList args, Cardinal *num_args);
51 
52 static void destroy(Widget w);
53 
54 static Boolean set_values(Widget current, Widget request, Widget new_w,
55 			  ArgList args, Cardinal *num_args);
56 
57 static void select_callback(Widget w, XtPointer cd, Atom *select,
58 			    Atom *type, XtPointer value,
59 			    unsigned long *len, int *fmt);
60 
61 static Widget start_drop_transfer(Widget refWidget,
62 				  ArgList args, Cardinal argCount);
63 
64 static void add_drop_transfer(Widget widget,
65 			      XmDropTransferEntry transfers,
66 			      Cardinal num_transfers);
67 
68 #define Offset(field) XtOffsetOf(XmDropTransferRec, dropTransfer.field)
69 static XtResource resources[] =
70 {
71     {
72 	XmNdropTransfers, XmCDropTransfers, XmRDropTransfers,
73 	sizeof(XmDropTransferEntry), Offset(drop_transfers),
74 	XmRImmediate, (XtPointer)NULL
75     },
76     {
77 	XmNnumDropTransfers, XmCNumDropTransfers, XmRCardinal,
78 	sizeof(Cardinal), Offset(num_drop_transfers),
79 	XmRImmediate, (XtPointer)0
80     },
81     {
82 	XmNincremental, XmCIncremental, XmRBoolean,
83 	sizeof(Boolean), Offset(incremental),
84 	XmRImmediate, (XtPointer)False
85     },
86     {
87 	XmNtransferProc, XmCTransferProc, XmRCallbackProc,
88 	sizeof(XtSelectionCallbackProc), Offset(transfer_callback),
89 	XmRImmediate, (XtPointer)NULL
90     },
91     {
92 	XmNtransferStatus, XmCTransferStatus, XmRTransferStatus,
93 	sizeof(unsigned char), Offset(transfer_status),
94 	XmRImmediate, (XtPointer)XmTRANSFER_SUCCESS
95     }
96 };
97 
98 #if 0
99 static XmBaseClassExtRec _XmDropTransferObjectClassExtRec = {
100     /* next_extension            */ NULL,
101     /* record_type               */ NULLQUARK,
102     /* version                   */ XmBaseClassExtVersion,
103     /* size                      */ sizeof(XmBaseClassExtRec),
104     /* initialize_prehook        */ NULL,
105     /* set_values_prehook        */ NULL,
106     /* initialize_posthook       */ NULL,
107     /* set_values_posthook       */ NULL,
108     /* secondary_object_class    */ NULL,
109     /* secondary_object_create   */ NULL,
110     /* get_secondary_resources   */ NULL,
111     /* fast_subclass             */ { 0 },
112     /* get_values_prehook        */ NULL,
113     /* get_values_posthook       */ NULL,
114     /* class_part_init_prehook   */ NULL,
115     /* class_part_init_posthook  */ NULL,
116     /* ext_resources             */ NULL,
117     /* compiled_ext_resources    */ NULL,
118     /* num_ext_resources         */ 0,
119     /* use_sub_resources         */ False,
120     /* widget_navigable          */ NULL,
121     /* focus_change              */ NULL,
122     /* wrapper_data              */ NULL
123 };
124 #endif
125 
126 XmDropTransferClassRec xmDropTransferClassRec = {
127     /* Object class part */
128     {
129 	/* superclass            */ (WidgetClass) &objectClassRec,
130         /* class_name            */ "XmDropTransferObject",
131 	/* widget_size           */ sizeof(XmDropTransferRec),
132 	/* class_initialize      */ NULL /*class_initialize*/,
133 	/* class_part_initialize */ class_part_initialize,
134 	/* class_inited          */ False,
135 	/* initialize            */ initialize,
136 	/* initialize_hook       */ NULL,
137 	/* obj1                  */ NULL,
138 	/* obj2                  */ NULL,
139 	/* obj3                  */ 0,
140 	/* resources             */ resources,
141 	/* num_resources         */ XtNumber(resources),
142 	/* xrm_class             */ NULLQUARK,
143 	/* obj4                  */ True,
144 	/* obj5                  */ XtExposeCompressSeries,
145 	/* obj6                  */ True,
146 	/* obj7                  */ 0,
147 	/* destroy               */ destroy,
148 	/* obj8                  */ NULL,
149 	/* obj9                  */ NULL,
150 	/* set_values            */ set_values,
151 	/* set_values_hook       */ NULL,
152 	/* obj10                 */ NULL,
153 	/* get_values_hook       */ NULL,
154 	/* obj11                 */ NULL,
155 	/* version               */ XtVersion,
156 	/* callback offsets      */ NULL,
157 	/* obj12                 */ NULL,
158 	/* obj13                 */ NULL,
159         /* obj14                 */ NULL,
160 	/* extension             */ NULL
161     },
162     /* XmDropTranferObject part */
163     {
164         /* start_drop_transfer*/ start_drop_transfer,
165         /* add_drop_transfer  */ add_drop_transfer,
166         /* extension          */ NULL
167     }
168 };
169 
170 
171 WidgetClass xmDropTransferObjectClass = (WidgetClass)&xmDropTransferClassRec;
172 
173 #if 0
174 static void
175 class_initialize()
176 {
177     DEBUGOUT(_LtDebug(__FILE__, NULL, "DropTransfer class initialize\n"));
178 
179     _XmDropTransferObjectClassExtRec.record_type = XmQmotif;
180 }
181 #endif
182 
183 static void
class_part_initialize(WidgetClass widget_class)184 class_part_initialize(WidgetClass widget_class)
185 {
186     WidgetClass sc;
187 
188     DEBUGOUT(_LtDebug(__FILE__, NULL, "DropTransfer class part initialize\n"));
189 
190     _XmFastSubclassInit(widget_class, XmDROP_TRANSFER_BIT);
191 
192     sc = widget_class->core_class.superclass;
193 
194     if (DTC_StartTransferProc(widget_class) == XmInheritStartTransferProc)
195     {
196 	DTC_StartTransferProc(widget_class) = DTC_StartTransferProc(sc);
197     }
198 
199     if (DTC_AddTransferProc(widget_class) == XmInheritAddTransferProc)
200     {
201 	DTC_AddTransferProc(widget_class) = DTC_AddTransferProc(sc);
202     }
203 }
204 
205 static void
initialize(Widget request,Widget new_w,ArgList args,Cardinal * num_args)206 initialize(Widget request, Widget new_w,
207 	   ArgList args, Cardinal *num_args)
208 {
209     XmDropTransferEntry entries;
210 
211     DEBUGOUT(_LtDebug(__FILE__, new_w,
212 		      "%s:initialize(%d) - %i args\n"
213 		      "\trequest X %5i Y %5i W %5i H %5i\n"
214 		      "\t  new_w X %5i Y %5i W %5i H %5i\n",
215 		      __FILE__, __LINE__,
216 		      *num_args,
217 		      XtX(request), XtY(request),
218 		      XtWidth(request), XtHeight(request),
219 		      XtX(new_w), XtY(new_w),
220 		      XtWidth(new_w), XtHeight(new_w)));
221     DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));
222 
223     if (DT_NumDropTransfers(new_w) != 0)
224     {
225 
226 	/* Copy the user specified list */
227 	DT_NumDropTransferLists(new_w) = 1;
228 
229 	DT_DropTransferLists(new_w) =
230 	    (XmDropTransferList)XtMalloc(sizeof(XmDropTransferListRec));
231 
232 	entries = (XmDropTransferEntry)XtMalloc(DT_NumDropTransfers(new_w) *
233 						sizeof(XmDropTransferEntryRec));
234 
235 	memcpy(entries, DT_DropTransfers(new_w),
236 	      DT_NumDropTransfers(new_w) * sizeof(XmDropTransferEntryRec));
237 
238 	DT_DropTransferLists(new_w)[0].transfer_list = entries;
239 	DT_DropTransferLists(new_w)[0].num_transfers =
240 	    DT_NumDropTransfers(new_w);
241 
242 	DT_DropTransfers(new_w) = entries;
243     }
244     else
245     {
246 	DT_DropTransferLists(new_w) = NULL;
247 	DT_NumDropTransferLists(new_w) = 0;
248     }
249 
250     DT_MotifDropAtom(new_w) = XmInternAtom(XtDisplay(new_w),
251 					   _XA_MOTIF_DROP,
252 					   False);
253 
254     DT_CurDropTransferList(new_w) = XmUNSPECIFIED;
255     DT_CurXfer(new_w) = XmUNSPECIFIED;
256 
257     DT_CurTargets(new_w) = NULL;
258     DT_CurClientData(new_w) = NULL;
259 }
260 
261 static void
destroy(Widget w)262 destroy(Widget w)
263 {
264     Widget dc;
265     Cardinal i;
266 
267     DEBUGOUT(_LtDebug(__FILE__, w, "DropTransfer destroy\n"));
268 
269     dc = XmGetDragContext(w, DT_Timestamp(w));
270 
271     if (dc && DC_SourceIsExternal(dc))
272     {
273 	XtDestroyWidget(dc);
274     }
275 
276     for (i = 0; i < DT_NumDropTransferLists(w); i++)
277     {
278 	XtFree((char *)DT_DropTransferLists(w)[i].transfer_list);
279     }
280 
281     XtFree((char *)DT_DropTransferLists(w));
282 }
283 
284 static Boolean
set_values(Widget current,Widget request,Widget new_w,ArgList args,Cardinal * num_args)285 set_values(Widget current, Widget request, Widget new_w,
286 	   ArgList args, Cardinal *num_args)
287 {
288     DEBUGOUT(_LtDebug(__FILE__, new_w,
289 		      "%s:set_values(%d) - %i args\n"
290 		      "\t    old X %5i Y %5i W %5i H %5i\n"
291 		      "\trequest X %5i Y %5i W %5i H %5i\n"
292 		      "\t  new_w X %5i Y %5i W %5i H %5i\n",
293 		      __FILE__, __LINE__,
294 		      *num_args,
295 		      XtX(current), XtY(current),
296 		      XtWidth(current), XtHeight(current),
297 		      XtX(request), XtY(request),
298 		      XtWidth(request), XtHeight(request),
299 		      XtX(new_w), XtY(new_w),
300 		      XtWidth(new_w), XtHeight(new_w)));
301     DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));
302 
303     return True;
304 }
305 
306 static void
entry_transfer(Widget dt,int which)307 entry_transfer(Widget dt, int which)
308 {
309     XmDropTransferList lst = &DT_DropTransferLists(dt)[which];
310     Widget dc = DT_DragContext(dt);
311     Cardinal i;
312 
313     DEBUGOUT(_LtDebug(__FILE__, dt, "%s:entry_transfer(%d)",
314     	__FILE__, __LINE__));
315 
316     DT_CurDropTransferList(dt) = which;
317     DT_CurTargets(dt) = (Atom *)XtMalloc(lst->num_transfers * sizeof(Atom));
318     DT_CurClientData(dt) = (XtPointer *)XtMalloc(lst->num_transfers *
319 						 sizeof(XtPointer));
320 
321     for (i = 0; i < lst->num_transfers; i++)
322     {
323 	DT_CurTargets(dt)[i] = lst->transfer_list[i].target;
324 	DT_CurClientData(dt)[i] = (XtPointer)dt;
325     }
326 
327     DT_CurXfer(dt) = 0;
328 
329     if (DT_Incremental(dt))
330     {
331 	XtGetSelectionValuesIncremental(DC_CurrReceiverInfo(dc)->shell,
332 					DC_ICCHandle(dc),
333 					DT_CurTargets(dt),
334 					lst->num_transfers, select_callback,
335 					(XtPointer)DT_CurClientData(dt),
336 					DT_Timestamp(dt));
337     }
338     else
339     {
340 	XtGetSelectionValues(DC_CurrReceiverInfo(dc)->shell,
341 			     DC_ICCHandle(dc),
342 			     DT_CurTargets(dt),
343 			     lst->num_transfers, select_callback,
344 			     (XtPointer)DT_CurClientData(dt),
345 			     DT_Timestamp(dt));
346     }
347 }
348 
349 static void
notified_callback(Widget w,XtPointer cd,Atom * select,Atom * type,XtPointer value,unsigned long * len,int * fmt)350 notified_callback(Widget w, XtPointer cd, Atom *select, Atom *type,
351 		  XtPointer value, unsigned long *len, int *fmt)
352 {
353     DEBUGOUT(_LtDebug(__FILE__, w, "%s:notified_callback(%d)\n",
354     	__FILE__, __LINE__));
355 
356     if (value != NULL)
357     {
358 	XtFree((char *)value);
359     }
360 
361     XtDestroyWidget((Widget)cd);
362 }
363 
364 static void
terminate_transfer(Widget dt,Atom * select)365 terminate_transfer(Widget dt, Atom *select)
366 {
367     Atom how;
368 
369     DEBUGOUT(_LtDebug(__FILE__, dt, "%s:terminate_transfer(%d) - drag context %s receiver info %s %s\n",
370     	__FILE__, __LINE__,
371     	DT_DragContext(dt) ? "Yes" : "No",
372     	DC_CurrReceiverInfo(DT_DragContext(dt)) ?  "Yes" : "No",
373     	XGetAtomName(XtDisplay(dt), *select)
374     	));
375 
376     if (DT_TransferStatus(dt) == XmTRANSFER_SUCCESS)
377     {
378 	how = XmInternAtom(XtDisplay(dt), _XA_XmTRANSFER_SUCCESS, False);
379     }
380     else
381     {
382 	how = XmInternAtom(XtDisplay(dt), _XA_XmTRANSFER_FAILURE, False);
383     }
384 
385     if (DT_DragContext(dt) && DC_CurrReceiverInfo(DT_DragContext(dt)) && DC_CurrReceiverInfo(DT_DragContext(dt))->shell)
386     {
387 	XtGetSelectionValue(DC_CurrReceiverInfo(DT_DragContext(dt))->shell,
388 			*select, how, notified_callback, (XtPointer)dt,
389 			DT_Timestamp(dt));
390     }
391 }
392 
393 static void
select_callback(Widget w,XtPointer cd,Atom * select,Atom * type,XtPointer value,unsigned long * len,int * fmt)394 select_callback(Widget w, XtPointer cd, Atom *select, Atom *type,
395 		XtPointer value, unsigned long *len, int *fmt)
396 {
397     Widget dt = (Widget)cd;
398     XmDropTransferList lst;
399 
400     DEBUGOUT(_LtDebug(__FILE__, dt, "%s:select_callback(%d)",
401     	__FILE__, __LINE__));
402 
403     lst = &DT_DropTransferLists(dt)[DT_CurDropTransferList(dt)];
404 
405     if (DT_TransferCallback(dt))
406     {
407 	(*DT_TransferCallback(dt)) (dt,
408 				lst->transfer_list[DT_CurXfer(dt)].client_data,
409 				    select, type, value, len, fmt);
410     }
411 
412     lst = &DT_DropTransferLists(dt)[DT_CurDropTransferList(dt)];
413 
414     if (!DT_Incremental(dt) ||
415 	(DT_Incremental(dt) && value != NULL && *len == 0))
416     {
417 
418 	DT_CurXfer(dt)++;
419 
420 	if (DT_CurXfer(dt) == lst->num_transfers)
421 	{
422 
423 	    XtFree((char *)DT_CurTargets(dt));
424 	    XtFree((char *)DT_CurClientData(dt));
425 
426 	    DT_CurDropTransferList(dt)++;
427 
428 	    if (DT_CurDropTransferList(dt) < DT_NumDropTransferLists(dt))
429 	    {
430 		entry_transfer(dt, DT_CurDropTransferList(dt));
431 	    }
432 	    else
433 	    {
434 		terminate_transfer(dt, select);
435 	    }
436 	}
437     }
438 }
439 
440 static void
drop_timer(XtPointer cd,XtIntervalId * id)441 drop_timer(XtPointer cd, XtIntervalId *id)
442 {
443     Widget dt = (Widget)cd;
444     Atom select;
445 
446     DEBUGOUT(_LtDebug(__FILE__, dt, "%s:drop_timer(%d)\n",
447     	__FILE__, __LINE__));
448 
449     if (DT_NumDropTransferLists(dt))
450     {
451 	entry_transfer(dt, 0);
452     }
453     else
454     {
455 	select = DC_ICCHandle(DT_DragContext(dt));
456 
457 	terminate_transfer(dt, &select);
458     }
459 }
460 
461 static Widget
start_drop_transfer(Widget refWidget,ArgList args,Cardinal argCount)462 start_drop_transfer(Widget refWidget,
463 		    ArgList args, Cardinal argCount)
464 {
465     Widget disp = XmGetXmDisplay(XtDisplay(refWidget)), dt;
466 
467     DEBUGOUT(_LtDebug(__FILE__, refWidget, "%s:start_drop_transfer(%d)\n",
468     	__FILE__, __LINE__));
469 
470     dt = XtCreateWidget("drop_transfer",
471 			Display_DropTransferClass(disp),
472 			disp, args, argCount);
473 
474     /* refWidget had BETTER be a DC */
475     DT_DragContext(dt) = refWidget;
476     DT_Timestamp(dt) = DC_DragFinishTime(refWidget);
477 
478     XtAppAddTimeOut(XtWidgetToApplicationContext(dt), 0,
479 		    drop_timer, (XtPointer)dt);
480     return dt;
481 }
482 
483 static void
add_drop_transfer(Widget widget,XmDropTransferEntry transfers,Cardinal num_transfers)484 add_drop_transfer(Widget widget,
485 		  XmDropTransferEntry transfers,
486 		  Cardinal num_transfers)
487 {
488     XmDropTransferEntry entries;
489     int idx;
490 
491     DEBUGOUT(_LtDebug(__FILE__, widget, "%s:add_drop_transfer(%d)",
492     	__FILE__, __LINE__));
493 
494     idx = DT_NumDropTransferLists(widget);
495     DT_NumDropTransferLists(widget)++;
496 
497     DT_DropTransferLists(widget) =
498 	(XmDropTransferList)XtRealloc((char *)DT_DropTransferLists(widget),
499 				      DT_NumDropTransferLists(widget) *
500 				      sizeof(XmDropTransferListRec));
501 
502     entries = (XmDropTransferEntry)XtMalloc(num_transfers *
503 					    sizeof(XmDropTransferEntryRec));
504     memcpy(entries, transfers, num_transfers * sizeof(XmDropTransferEntryRec));
505 
506     DT_DropTransferLists(widget)[idx].transfer_list = entries;
507     DT_DropTransferLists(widget)[idx].num_transfers = num_transfers;
508 }
509 
510 void
XmDropTransferAdd(Widget drop_transfer,XmDropTransferEntryRec * transfers,Cardinal num_transfers)511 XmDropTransferAdd(Widget drop_transfer,
512 		  XmDropTransferEntryRec *transfers,
513 		  Cardinal num_transfers)
514 {
515     DEBUGOUT(_LtDebug(__FILE__, drop_transfer, "%s:XmDropTransferAdd(%d)",
516     	__FILE__, __LINE__));
517 
518     DTC_AddTransferProc(XtClass(drop_transfer)) (drop_transfer,
519 						 transfers,
520 						 num_transfers);
521 }
522 
523 Widget
XmDropTransferStart(Widget widget,ArgList arglist,Cardinal argcount)524 XmDropTransferStart(Widget widget,
525 		    ArgList arglist,
526 		    Cardinal argcount)
527 {
528     Widget disp = XmGetXmDisplay(XtDisplay(widget));
529 
530     DEBUGOUT(_LtDebug(__FILE__, widget, "%s:XmDropTransferStart(%d)\n",
531     	__FILE__, __LINE__));
532     DEBUGOUT(_LtDebugPrintArgList(__FILE__, widget, arglist, argcount, False));
533 
534 
535     return DTC_StartTransferProc(Display_DropTransferClass(disp)) (widget,
536 								   arglist,
537 								   argcount);
538 }
539