1 /*
2  * Motif
3  *
4  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22 */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 
28 #ifdef REV_INFO
29 #ifndef lint
30 static char rcsid[] = "$TOG: TextFSel.c /main/22 1997/10/14 15:38:30 cshi $"
31 #endif
32 #endif
33 
34 #include <X11/Xatom.h>
35 #include <Xm/AtomMgr.h>
36 #include <Xm/DragC.h>
37 #include <Xm/TraitP.h>		/* for XmeTraitSet() */
38 #include <Xm/TransferP.h>
39 #include <Xm/TransferT.h>
40 #include <Xm/XmosP.h>
41 #include "TextFI.h"
42 #include "TextFSelI.h"
43 #include "TransferI.h"		/* for _XmConvertComplete() */
44 #include "TraversalI.h"		/* for _XmGetFocusPolicy() */
45 #include "XmI.h"
46 
47 /********    Static Function Declarations    ********/
48 
49 static void InsertSelection(
50                         Widget w,
51                         XtPointer closure,
52                         Atom *seltype,
53                         Atom *type,
54                         XtPointer value,
55                         unsigned long *length,
56                         int *format,
57 			XtPointer tid) ;
58 static void HandleInsertTargets(
59                         Widget w,
60                         XtPointer closure,
61                         Atom *seltype,
62                         Atom *type,
63                         XtPointer value,
64                         unsigned long *length,
65                         int *format,
66 			XtPointer tid);
67 static void HandleDrop(Widget w,
68 		       XmDropProcCallbackStruct *cb,
69 		       XmDestinationCallbackStruct *ds);
70 static void TextFieldConvertCallback(Widget,
71 				     XtPointer,
72 				     XmConvertCallbackStruct*);
73 
74 static void TextFieldDestinationCallback(Widget,
75 					 XtPointer,
76 					 XmDestinationCallbackStruct*);
77 static void SetDropContext(Widget w);
78 
79 static void DeleteDropContext(Widget w);
80 
81 static void HandleTargets(Widget w,
82 			  XtPointer ignore,
83 			  XmSelectionCallbackStruct *ds);
84 
85 static void HandleDrop(Widget w,
86 		       XmDropProcCallbackStruct *cb,
87 		       XmDestinationCallbackStruct *ds);
88 
89 static void DropDestroyCB(Widget w,
90 			  XtPointer clientData,
91 			  XtPointer callData);
92 
93 static void DropTransferProc(Widget w,
94 			     XtPointer ignore,
95 			     XmSelectionCallbackStruct *ds);
96 static void DoStuff(Widget w,
97 		    XtPointer ignore,
98 		    XmSelectionCallbackStruct *ds);
99 
100 /********    End Static Function Declarations    ********/
101 
102 
103 /* Transfer Trait record for TextField */
104 
105 static XmConst XmTransferTraitRec textFieldTT = {
106   0,  				/* version */
107   (XmConvertCallbackProc) 	TextFieldConvertCallback,
108   (XmDestinationCallbackProc)	TextFieldDestinationCallback,
109   (XmDestinationCallbackProc)	NULL,
110 };
111 
112 static XContext _XmTextFDNDContext = 0;
113 static _XmInsertSelect insert_select;
114 static _XmTextPrimSelect *prim_select;
115 
116 /*ARGSUSED*/
117 static void
SetPrimarySelection(Widget w,XtEnum op,XmTransferDoneCallbackStruct * ts)118 SetPrimarySelection(Widget w,
119 		    XtEnum op,	/* unused */
120 		    XmTransferDoneCallbackStruct *ts) /* unused */
121 {
122   XmTextFieldWidget tf = (XmTextFieldWidget) w;
123   XmTextPosition cursorPos = tf->text.cursor_position;
124 
125   _XmProcessLock();
126   if (!prim_select) {
127     _XmProcessUnlock();
128     return;
129   }
130 
131   if (prim_select->num_chars > 0) {
132     tf->text.prim_anchor = prim_select->position;
133     cursorPos = prim_select->position + prim_select->num_chars;
134     _XmTextFieldStartSelection(tf, tf->text.prim_anchor, cursorPos,
135 			       prim_select->time);
136     tf->text.pending_off = False;
137     _XmTextFieldSetCursorPosition(tf, NULL, cursorPos, True, True);
138   }
139   if (--prim_select->ref_count == 0) {
140     XtFree((char *)prim_select);
141     prim_select = NULL;
142   }
143   _XmProcessUnlock();
144 }
145 
146 
147 /*ARGSUSED*/
148 static void
CleanPrimarySelection(Widget w,XtEnum op,XmTransferDoneCallbackStruct * ts)149 CleanPrimarySelection(Widget w,
150 		    XtEnum op,	/* unused */
151 		    XmTransferDoneCallbackStruct *ts) /* unused */
152 {
153   _XmProcessLock();
154   if (!prim_select)
155   {
156     _XmProcessUnlock();
157     return;
158   }
159 
160   if (--prim_select->ref_count == 0) {
161     XtFree((char *)prim_select);
162     prim_select = NULL;
163   }
164   _XmProcessUnlock();
165 }
166 
167 
168 static void
TextFieldSecondaryWrapper(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)169 TextFieldSecondaryWrapper(Widget w, XtPointer closure,
170 			     XmSelectionCallbackStruct *ds)
171 {
172   Atom XA_TARGETS = XInternAtom(XtDisplay(w), XmSTARGETS, False);
173 
174   if (ds -> target == XA_TARGETS)
175     HandleInsertTargets(w, closure, &(ds -> selection), &(ds -> type),
176 			ds -> value, &(ds -> length), &(ds -> format),
177 			ds -> transfer_id);
178   else
179     InsertSelection(w, closure, &(ds -> selection), &(ds -> type),
180 		    ds -> value, &(ds -> length), &(ds -> format),
181 		    ds -> transfer_id);
182 }
183 
184 /* ARGSUSED */
185 static void
InsertSelection(Widget w,XtPointer closure,Atom * seltype,Atom * type,XtPointer value,unsigned long * length,int * format,XtPointer tid)186 InsertSelection(
187         Widget w,
188         XtPointer closure,
189         Atom *seltype,
190         Atom *type,
191         XtPointer value,
192         unsigned long *length,
193         int *format,
194 	XtPointer tid)
195 {
196   _XmInsertSelect *insert_select = (_XmInsertSelect *) closure;
197   XmTextFieldWidget tf = (XmTextFieldWidget) w;
198   XmTextPosition left = 0;
199   XmTextPosition right = 0;
200   Boolean replace_res = False;
201   Boolean dest_disjoint = False;
202   wchar_t * wc_value;
203   char * temp;
204   int num_chars = 0;
205   Atom COMPOUND_TEXT = XInternAtom(XtDisplay(w), XmSCOMPOUND_TEXT, False);
206   Atom UTF8_STRING = XInternAtom(XtDisplay(w), XmSUTF8_STRING, False);
207   char * total_value = NULL;
208   XmAnyCallbackStruct cb;
209 
210   if (!value) {
211     insert_select->done_status = True;
212     return;
213   }
214 
215   /* Don't do replace if there is not text to add */
216   if (*(char *) value == (char)'\0' || *length == 0){
217     XtFree((char *)value);
218     insert_select->done_status = True;
219     return;
220   }
221 
222   if (insert_select->select_type == XmPRIM_SELECT) {
223     if (!tf->text.has_primary ||
224 	tf->text.prim_pos_left == tf->text.prim_pos_right) {
225       XBell(XtDisplay(w), 0);
226       XtFree((char *)value);
227       insert_select->done_status = True;
228       insert_select->success_status = False;
229       return;
230     }
231   } else if (insert_select->select_type == XmDEST_SELECT) {
232     if (tf->text.has_primary &&
233 	(left = tf->text.prim_pos_left) != (right = tf->text.prim_pos_right)) {
234       if ( TextF_CursorPosition(tf) < left ||
235 	  TextF_CursorPosition(tf) > right ||
236 	  !tf->text.pending_delete) {
237 	left = right = TextF_CursorPosition(tf);
238 	dest_disjoint = True;
239       }
240     } else
241       left = right = TextF_CursorPosition(tf);
242   }
243 
244 
245   if (*type == COMPOUND_TEXT || *type == XA_STRING || *type == UTF8_STRING) {
246     total_value =  _XmTextToLocaleText(w, value, *type, *format,
247 				       *length, NULL);
248     if (total_value) {
249       if (tf->text.max_char_size == 1) {
250 	num_chars = strlen(total_value);
251 	replace_res = _XmTextFieldReplaceText(tf,
252 					      (XEvent *)insert_select->event,
253 					      left, right, total_value,
254 					      num_chars, True);
255       } else { /* must convert to wchar_t before passing to Replace */
256 	int len = strlen(total_value) + 1;
257 	wc_value = (wchar_t *)XtMalloc((unsigned) len * sizeof(wchar_t));
258 	num_chars = mbstowcs(wc_value, total_value, len);
259 	if (num_chars < 0)
260 	  num_chars = 0;
261 	else
262 	  replace_res = _XmTextFieldReplaceText(tf,
263                                                 (XEvent *)insert_select->event,
264                                                 left, right, (char*) wc_value,
265                                                 num_chars, True);
266 	XtFree((char *)wc_value);
267       }
268       XtFree(total_value);
269     }
270   } else { /* it must be either TEXT or codeset of the locale */
271     if (tf->text.max_char_size == 1) {
272       /* NOTE: casting *length could result in a truncated long. */
273       num_chars = *length;
274       replace_res = _XmTextFieldReplaceText(tf,
275 					    (XEvent *)insert_select->event,
276 					    left, right, (char *)value,
277 					    (unsigned)*length, True);
278     } else {
279       temp = XtMalloc((unsigned) *length + 1);
280       /* NOTE: casting *length could result in a truncated long. */
281       (void)memcpy((void*)temp, (void*)value, (size_t)*length);
282       temp[*length] = '\0';
283       wc_value = (wchar_t*)XtMalloc((unsigned)
284 				    (*length + 1) * sizeof(wchar_t));
285 
286       /* NOTE: casting *length could result in a truncated long. */
287       num_chars = mbstowcs(wc_value, temp, (unsigned)*length + 1);
288       if (num_chars < 0)
289 	num_chars = 0;
290       else
291 	replace_res = _XmTextFieldReplaceText(tf,
292 					      (XEvent *)insert_select->event,
293 					      left, right, (char*) wc_value,
294 					      num_chars, True);
295       XtFree(temp);
296       XtFree((char *)wc_value);
297     }
298   }
299 
300   if (!replace_res) {
301     insert_select->success_status = False;
302   } else {
303     insert_select->success_status = True;
304 
305     if (!tf->text.add_mode) tf->text.prim_anchor = left;
306 
307     tf->text.pending_off = True;
308     _XmTextFieldSetCursorPosition(tf, NULL, left + num_chars, False, True);
309     (void) _XmTextFieldSetDestination(w, TextF_CursorPosition(tf),
310 				      insert_select->event->time);
311     if (insert_select->select_type == XmDEST_SELECT) {
312       if (left != right) {
313 	if (!dest_disjoint || !tf->text.add_mode) {
314 	  _XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
315 				     TextF_CursorPosition(tf),
316 				     insert_select->event->time);
317 	}
318       }
319     }
320     cb.reason = XmCR_VALUE_CHANGED;
321     cb.event = (XEvent *)insert_select->event;
322     XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
323 		       (XtPointer) &cb);
324   }
325 
326   XtFree((char *)value);
327   value = NULL;
328   insert_select->done_status = True;
329 }
330 
331 /* ARGSUSED */
332 static void
HandleInsertTargets(Widget w,XtPointer closure,Atom * seltype,Atom * type,XtPointer value,unsigned long * length,int * format,XtPointer tid)333 HandleInsertTargets(
334         Widget w,
335         XtPointer closure,
336         Atom *seltype,
337         Atom *type,
338         XtPointer value,
339         unsigned long *length,
340         int *format,
341 	XtPointer tid )
342 {
343   enum { XmATEXT, XmACOMPOUND_TEXT, XmAUTF8_STRING, NUM_ATOMS };
344   static char *atom_names[] = { XmSTEXT, XmSCOMPOUND_TEXT, XmSUTF8_STRING };
345 
346   _XmInsertSelect *insert_select = (_XmInsertSelect *) closure;
347   Atom atoms[XtNumber(atom_names)];
348   Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
349   Atom target;
350   Atom *atom_ptr;
351   Boolean supports_encoding_data = False;
352   Boolean supports_CT = False;
353   Boolean supports_text = False;
354   Boolean supports_utf8_string = False;
355   int i;
356 
357   if (0 == *length) {
358     XtFree((char *)value);
359     insert_select->done_status = True;
360     return; /* Supports no targets, so don't bother sending anything */
361   }
362 
363   assert(XtNumber(atom_names) == NUM_ATOMS);
364   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
365 
366   atom_ptr = (Atom *)value;
367 
368   for (i = 0; i < *length; i++, atom_ptr++) {
369     if (*atom_ptr == atoms[XmATEXT])
370       supports_text = True;
371 
372     if (*atom_ptr == CS_OF_ENCODING)
373       supports_encoding_data = True;
374 
375     if (*atom_ptr == atoms[XmACOMPOUND_TEXT])
376       supports_CT = True;
377 
378 #ifdef UTF8_SUPPORTED
379     if (*atom_ptr == atoms[XmAUTF8_STRING])
380       supports_utf8_string = True;
381 #endif
382   }
383 
384   if (supports_text && supports_encoding_data)
385     target = atoms[XmATEXT];
386   else if (supports_CT)
387     target = atoms[XmACOMPOUND_TEXT];
388 #ifdef UTF8_SUPPORTED
389   else if (supports_utf8_string)
390     target = atoms[XmAUTF8_STRING];
391 #endif
392   else if (supports_encoding_data)
393     target = CS_OF_ENCODING;
394   else
395     target = XA_STRING;
396 
397   XmTransferValue(tid, target,
398 		  (XtCallbackProc) TextFieldSecondaryWrapper,
399 		  closure, insert_select -> event -> time);
400 }
401 
402 
403 /* ARGSUSED */
404 Boolean
_XmTextFieldConvert(Widget w,Atom * selection,Atom * target,Atom * type,XtPointer * value,unsigned long * length,int * format,Widget drag_context,XEvent * event)405 _XmTextFieldConvert(
406         Widget w,
407         Atom *selection,
408         Atom *target,
409         Atom *type,
410         XtPointer *value,
411         unsigned long *length,
412         int *format,
413 	Widget drag_context,
414         XEvent *event)
415 {
416   enum { XmA_MOTIF_DESTINATION, XmAINSERT_SELECTION, XmADELETE,
417 	 XmATARGETS, XmATEXT, XmACOMPOUND_TEXT, XmATIMESTAMP,
418 	 XmA_MOTIF_DROP, XmACLIPBOARD, XmANULL, XmAUTF8_STRING,
419 	 NUM_ATOMS };
420   static char *atom_names[] = {
421     XmS_MOTIF_DESTINATION, XmSINSERT_SELECTION, XmSDELETE,
422     XmSTARGETS, XmSTEXT, XmSCOMPOUND_TEXT, XmSTIMESTAMP,
423     XmS_MOTIF_DROP, XmSCLIPBOARD, XmSNULL, XmSUTF8_STRING };
424 
425   XmTextFieldWidget tf;
426   Atom atoms[XtNumber(atom_names)];
427   Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
428   XSelectionRequestEvent * req_event = (XSelectionRequestEvent *) event;
429   Boolean has_selection = False;
430   XmTextPosition left = 0;
431   XmTextPosition right = 0;
432   Boolean is_primary;
433   Boolean is_secondary;
434   Boolean is_destination;
435   Boolean is_drop;
436   int target_count = 0;
437   XTextProperty tmp_prop;
438   char *tmp_value;
439   int ret_status = 0;
440   Time _time;
441   XmAnyCallbackStruct cb;
442 
443   assert(XtNumber(atom_names) == NUM_ATOMS);
444   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
445 
446   if (req_event == NULL)
447     _time = XtLastTimestampProcessed(XtDisplay(w));
448   else
449     _time = req_event -> time;
450 
451   tf = (XmTextFieldWidget) w;
452 
453   if (tf == NULL) return False;
454 
455   if (*selection == XA_PRIMARY || *selection == atoms[XmACLIPBOARD]) {
456     has_selection = tf->text.has_primary;
457     left = tf->text.prim_pos_left;
458     right = tf->text.prim_pos_right;
459     is_primary = True;
460     is_secondary = is_destination = is_drop = False;
461   } else if (*selection == atoms[XmA_MOTIF_DESTINATION]) {
462     has_selection = tf->text.has_destination;
463     is_destination = True;
464     is_secondary = is_primary = is_drop = False;
465   } else if (*selection == XA_SECONDARY) {
466     has_selection = tf->text.has_secondary;
467     left = tf->text.sec_pos_left;
468     right = tf->text.sec_pos_right;
469     is_secondary = True;
470     is_destination = is_primary = is_drop = False;
471   } else if (*selection == atoms[XmA_MOTIF_DROP]) {
472     has_selection = tf->text.has_primary;
473     left = tf->text.prim_pos_left;
474     right = tf->text.prim_pos_right;
475     is_drop = True;
476     is_destination = is_primary = is_secondary = False;
477   } else {
478     return False;
479   }
480 
481   /*
482    * TARGETS identifies what targets the textfield widget can
483    * provide data for.
484    */
485   if (*target == atoms[XmATARGETS]) {
486     Atom *targs = XmeStandardTargets(w, 10, &target_count);
487 
488     *value = (XtPointer) targs;
489     if (XA_STRING != CS_OF_ENCODING) {
490       targs[target_count] = CS_OF_ENCODING;  target_count++;
491     }
492     if (is_primary || is_destination) {
493       targs[target_count] = atoms[XmAINSERT_SELECTION]; target_count++;
494     }
495     if (is_primary || is_secondary || is_drop) {
496       targs[target_count] = atoms[XmACOMPOUND_TEXT]; target_count++;
497       targs[target_count] = atoms[XmATEXT]; target_count++;
498       targs[target_count] = XA_STRING; target_count++;
499       targs[target_count] = atoms[XmAUTF8_STRING]; target_count++;
500     }
501     if (is_primary || is_drop) {
502       targs[target_count] = atoms[XmADELETE]; target_count++;
503     }
504     *type = XA_ATOM;
505     *length = target_count;
506     *format = 32;
507   } else if (*target == atoms[XmATIMESTAMP]) {
508     Time *timestamp;
509     timestamp = (Time *) XtMalloc(sizeof(Time));
510     if (is_primary)
511       *timestamp = tf->text.prim_time;
512     else if (is_destination)
513       *timestamp = tf->text.dest_time;
514     else if (is_secondary)
515       *timestamp = tf->text.sec_time;
516     else if (is_drop)
517       *timestamp = tf->text.prim_time;
518     *value = (XtPointer) timestamp;
519     *type = XA_INTEGER;
520     *length = sizeof(Time) / 4;
521     *format = 32;
522   } else if (*target == XA_STRING) {
523     *type = (Atom) XA_STRING;
524     *format = 8;
525     if (is_destination || !has_selection) return False;
526 
527     /* put a char* value into tmp_value, then convert to 8859.1 */
528     if (tf->text.max_char_size != 1) {
529       int stat ;
530 
531       /* NOTE: casting (right - left) could result in a truncated long. */
532       *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
533 				       (int)(right - left));
534       tmp_value = XtMalloc((unsigned) *length + 1);
535       stat = wcstombs(tmp_value, TextF_WcValue(tf) + left,
536 		      (unsigned)*length); /* NOTE: casting *length could
537 					     result in a truncated long. */
538       if (stat < 0) /* wcstombs will return neg value on conv failure */
539 	*length = 0;
540       else *length = (unsigned long) stat ;
541     } else {
542       *length = right - left;
543       tmp_value = XtMalloc((unsigned) *length + 1);
544       /* get the selection value */
545       (void)memcpy((void*)tmp_value, (void*)(TextF_Value(tf) + left),
546 		   (size_t)*length); /* NOTE: casting *length could result
547 					  in a truncated long. */
548     }
549     tmp_value[*length] = '\0';
550     tmp_prop.value = NULL;
551     /* convert tmp_value to 8859.1 */
552     ret_status = XmbTextListToTextProperty(XtDisplay(w), &tmp_value, 1,
553 					   (XICCEncodingStyle)XStringStyle,
554 					   &tmp_prop);
555     XtFree(tmp_value);
556     if (ret_status == Success || ret_status > 0){
557       *value = (XtPointer) tmp_prop.value;
558       *length = tmp_prop.nitems;
559     } else {
560       *value = NULL;
561       *length = 0;
562       return False;
563     }
564   } else if (*target == atoms[XmATEXT] || *target == CS_OF_ENCODING) {
565     *type = CS_OF_ENCODING;
566     *format = 8;
567     if (is_destination || !has_selection) return False;
568     if (tf->text.max_char_size != 1) {
569       int stat ;
570 
571       /* NOTE: casting (right - left) could result in a truncated long. */
572       *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
573 				       (int)(right - left));
574       *value = XtMalloc((unsigned) *length + 1);
575       stat = wcstombs((char *)*value, TextF_WcValue(tf) + left,
576 		      (unsigned)*length); /* NOTE: casting *length could
577 					     result in a truncated long */
578       if (stat < 0) /* wcstombs return neg value on conv failure */
579 	*length = 0;
580       else *length = (unsigned long) stat ;
581     } else {
582       *length = right - left;
583       *value = XtMalloc((unsigned) *length + 1);
584       /* get the selection value */
585       (void)memcpy((void*)*value, (void*)(TextF_Value(tf) + left),
586 		   (size_t)*length); /* NOTE: casting *length could result
587 					  in a truncated long. */
588     }
589     (*(char **)value)[*length]='\0';
590   } else if (*target == atoms[XmACOMPOUND_TEXT]) {
591     *type = atoms[XmACOMPOUND_TEXT];
592     *format = 8;
593     if (is_destination || !has_selection) return False;
594     if (tf->text.max_char_size != 1) {
595       int stat ;
596 
597       /* convert to char* before converting to CT.  NOTE: casting
598        * (right - left) could result in a truncated long.
599        */
600       *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
601 				       (int)(right - left));
602       tmp_value = XtMalloc((unsigned) *length + 1);
603       stat = wcstombs(tmp_value, TextF_WcValue(tf) + left,
604 		      (unsigned)*length); /* NOTE: casting *length could
605 					     result in a truncated long. */
606       if (stat < 0) /* wcstombs will return neg value on conv failure */
607 	*length = 0;
608       else *length = (unsigned long) stat ;
609     } else { /* malloc the space and copy the data to be converted */
610       *length = right - left;
611       tmp_value = XtMalloc((unsigned) *length + 1);
612       /* get the selection value */
613       (void)memcpy((void*)tmp_value, (void*)(TextF_Value(tf) + left),
614 		   (size_t)*length); /* NOTE: casting *length could result
615 					  in a truncated long. */
616     }
617     tmp_value[*length] = '\0';
618     tmp_prop.value = NULL;
619     /* Convert to compound text */
620     ret_status =
621       XmbTextListToTextProperty(XtDisplay(w), &tmp_value, 1,
622 				(XICCEncodingStyle)XCompoundTextStyle,
623 				&tmp_prop);
624     XtFree(tmp_value);
625     if (ret_status == Success || ret_status > 0){
626       *length = tmp_prop.nitems;
627       *value = (XtPointer)tmp_prop.value;
628     } else {
629       *value = NULL;
630       *length = 0;
631       return False;
632     }
633 #ifdef UTF8_SUPPORTED
634   } else if (*target == atoms[XmAUTF8_STRING]) {
635     *type = atoms[XmAUTF8_STRING];
636     *format = 8;
637     if (is_destination || !has_selection) return False;
638     if (tf->text.max_char_size != 1) {
639       int stat ;
640 
641       /* convert to char* before converting to CT.  NOTE: casting
642        * (right - left) could result in a truncated long.
643        */
644       *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
645 				       (int)(right - left));
646       tmp_value = XtMalloc((unsigned) *length + 1);
647       stat = wcstombs(tmp_value, TextF_WcValue(tf) + left,
648 		      (unsigned)*length); /* NOTE: casting *length could
649 					     result in a truncated long. */
650       if (stat < 0) /* wcstombs will return neg value on conv failure */
651 	*length = 0;
652       else *length = (unsigned long) stat ;
653     } else { /* malloc the space and copy the data to be converted */
654       *length = right - left;
655       tmp_value = XtMalloc((unsigned) *length + 1);
656       /* get the selection value */
657       (void)memcpy((void*)tmp_value, (void*)(TextF_Value(tf) + left),
658 		   (size_t)*length); /* NOTE: casting *length could result
659 					  in a truncated long. */
660     }
661     tmp_value[*length] = '\0';
662     tmp_prop.value = NULL;
663     /* Convert to compound text */
664     ret_status =
665       XmbTextListToTextProperty(XtDisplay(w), &tmp_value, 1,
666 				(XICCEncodingStyle)XUTF8StringStyle,
667 				&tmp_prop);
668     XtFree(tmp_value);
669     if (ret_status == Success || ret_status > 0){
670       *length = tmp_prop.nitems;
671       *value = (XtPointer)tmp_prop.value;
672     } else {
673       *value = NULL;
674       *length = 0;
675       return False;
676     }
677 #endif
678   } else if (*target == atoms[XmAINSERT_SELECTION]) {
679     if (is_secondary)
680       return False;
681     else
682       return True;
683     /* Delete the selection */
684   } else if (*target == atoms[XmADELETE]) {
685     XmTextPosition left, right;
686     Boolean move_cursor = True;
687 
688     if (!(is_primary || is_drop)) return False;
689 
690     left = tf->text.prim_pos_left;
691     right = tf->text.prim_pos_right;
692 
693       if (is_drop) {
694 	if (_XmTextFieldGetDropReciever((Widget)tf) == (Widget) tf)
695 	  move_cursor = False;
696       } else {
697 	if (req_event != NULL &&
698 	    req_event->requestor == XtWindow((Widget)tf))
699 	  move_cursor = False;
700       }
701 
702     if (!_XmTextFieldReplaceText(tf, (XEvent *) req_event,
703 				 left, right, NULL, 0, move_cursor)) {
704       tf->text.has_primary = True;
705       return False;
706     }
707 
708     _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
709 			       tf->text.prim_anchor, _time);
710 
711     cb.reason = XmCR_VALUE_CHANGED;
712     cb.event = (XEvent *) req_event;
713     XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
714 		       (XtPointer) &cb);
715 
716     tf->text.has_primary = True;
717 
718     if (tf->text.has_destination)
719       tf->text.prim_anchor = TextF_CursorPosition(tf);
720 
721     *type = atoms[XmANULL];
722     *value = NULL;
723     *length = 0;
724     *format = 8;
725   } else
726     /* unknown selection type */
727     return FALSE;
728   return TRUE;
729 }
730 
731 /* ARGSUSED */
732 void
_XmTextFieldLoseSelection(Widget w,Atom * selection)733 _XmTextFieldLoseSelection(
734         Widget w,
735         Atom *selection )
736 {
737     XmTextFieldWidget tf = (XmTextFieldWidget) w;
738     Atom MOTIF_DESTINATION = XInternAtom(XtDisplay(w),
739                                         XmS_MOTIF_DESTINATION, False);
740 /* Losing Primary Selection */
741     if (*selection == XA_PRIMARY && tf->text.has_primary) {
742         XmAnyCallbackStruct cb;
743         _XmTextFieldDeselectSelection(w, False, 0);
744 
745         cb.reason = XmCR_LOSE_PRIMARY;
746         cb.event = NULL;
747         XtCallCallbackList(w, tf->text.lose_primary_callback, (XtPointer) &cb);
748 /* Losing Destination Selection */
749     } else if (*selection == MOTIF_DESTINATION) {
750         Boolean orig_ibeam_off = tf->text.refresh_ibeam_off;
751         tf->text.has_destination = False;
752        /* if we have focus, we have a valid putback area.  If we don't have
753 	* focus, don't want to update the putback with the destination cursor
754 	* image.
755 	*/
756 	tf->text.refresh_ibeam_off = False;
757 	_XmTextFieldDrawInsertionPoint(tf, False);
758 	tf->text.blink_on = True;
759 	_XmTextFieldDrawInsertionPoint(tf, True);
760 	/* Restore the state of the refresh_ibeam_off flag. */
761         tf->text.refresh_ibeam_off = orig_ibeam_off;
762 /* Losing Secondary Selection */
763     } else if (*selection == XA_SECONDARY && tf->text.has_secondary){
764         _XmTextFieldSetSel2(w, 0, 0, True,
765 			    XtLastTimestampProcessed(XtDisplay(w)));
766     }
767 }
768 
769 
770 static void
SetDropContext(Widget w)771 SetDropContext(Widget w)
772 {
773   Display *display = XtDisplay(w);
774   Screen *screen = XtScreen(w);
775   XContext loc_context;
776 
777 
778   _XmProcessLock();
779   if (_XmTextFDNDContext == 0)
780     _XmTextFDNDContext = XUniqueContext();
781   loc_context = _XmTextFDNDContext;
782   _XmProcessUnlock();
783 
784   XSaveContext(display, (Window)screen,
785 	       loc_context, (XPointer)w);
786 }
787 
788 static void
DeleteDropContext(Widget w)789 DeleteDropContext(Widget w)
790 {
791   Display *display = XtDisplay(w);
792   Screen *screen = XtScreen(w);
793   XContext loc_context;
794 
795   _XmProcessLock();
796   loc_context = _XmTextFDNDContext;
797   _XmProcessUnlock();
798 
799   XDeleteContext(display, (Window)screen, loc_context);
800 }
801 
802 Widget
_XmTextFieldGetDropReciever(Widget w)803 _XmTextFieldGetDropReciever(Widget w)
804 {
805   Widget widget;
806   XContext loc_context;
807 
808   _XmProcessLock();
809   loc_context = _XmTextFDNDContext;
810   _XmProcessUnlock();
811 
812   if (loc_context == 0) return NULL;
813 
814   if (!XFindContext(XtDisplay(w), (Window) XtScreen(w),
815 		    loc_context, (char **) &widget)) {
816     return widget;
817   }
818 
819   return NULL;
820 }
821 
822 
823 /* ARGSUSED */
824 static void
DropDestroyCB(Widget w,XtPointer clientData,XtPointer callData)825 DropDestroyCB(Widget      w,
826 	      XtPointer   clientData,
827 	      XtPointer   callData)
828 {
829   XmTransferDoneCallbackStruct *ts =
830     (XmTransferDoneCallbackStruct *) callData;
831 
832   DeleteDropContext(w);
833   if (ts->client_data != NULL) XtFree((char*) ts->client_data);
834 }
835 
836 static void
DropTransferProc(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)837 DropTransferProc(Widget w, XtPointer closure,
838 		 XmSelectionCallbackStruct *ds)
839 {
840   enum { XmACOMPOUND_TEXT, XmANULL, XmADELETE,
841 #ifdef UTF8_SUPPORTED
842       XmAUTF8_STRING,
843 #endif
844       NUM_ATOMS };
845   static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSNULL, XmSDELETE,
846 #ifdef UTF8_SUPPORTED
847       XmSUTF8_STRING
848 #endif
849       };
850 
851   _XmTextDropTransferRec *transfer_rec = (_XmTextDropTransferRec *) closure;
852   XmTextFieldWidget tf = (XmTextFieldWidget) w;
853   Atom atoms[XtNumber(atom_names)];
854   Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
855   XmTextPosition insertPosLeft, insertPosRight, left, right, cursorPos;
856   int max_length = 0;
857   Boolean local = tf->text.has_primary;
858   char * total_value = NULL;
859   wchar_t * wc_total_value;
860   unsigned long total_length = 0;
861   int wc_total_length;
862   Boolean replace = False;
863   XmAnyCallbackStruct cb;
864 
865   assert(XtNumber(atom_names) == NUM_ATOMS);
866   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
867 
868   /* When type = NULL, we are assuming a DELETE request has been requested */
869   if (ds->type == atoms[XmANULL]) {
870     if (transfer_rec->num_chars > 0 && transfer_rec->move) {
871       tf->text.prim_anchor = transfer_rec->insert_pos;
872       cursorPos = transfer_rec->insert_pos + transfer_rec->num_chars;
873       _XmTextFieldSetCursorPosition(tf, NULL, cursorPos,
874 				    False, True);
875       _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
876 				 TextF_CursorPosition(tf),
877 				 XtLastTimestampProcessed(XtDisplay(w)));
878       tf->text.pending_off = False;
879       _XmTextFieldSetCursorPosition(tf, NULL, TextF_CursorPosition(tf),
880 				    True, True);
881     }
882     if (ds->value) {
883       XtFree((char*) ds->value);
884       ds->value = NULL;
885     }
886     return;
887   }
888 
889   if (!(ds->value) ||
890       (ds->type != CS_OF_ENCODING &&
891        ds->type != atoms[XmACOMPOUND_TEXT] &&
892 #ifdef UTF8_SUPPORTED
893        ds->type != atoms[XmAUTF8_STRING] &&
894 #endif
895        ds->type != XA_STRING)) {
896     XmTransferDone(ds->transfer_id, XmTRANSFER_DONE_FAIL);
897     if (ds->value) {
898       XtFree((char*) ds->value);
899       ds->value = NULL;
900     }
901     return;
902   }
903 
904   insertPosLeft = insertPosRight = transfer_rec->insert_pos;
905 
906   if (ds->type == XA_STRING
907 #ifdef UTF8_SUPPORTED
908       || ds->type == atoms[XmAUTF8_STRING]
909 #endif
910       || ds->type == atoms[XmACOMPOUND_TEXT]) {
911     if ((total_value = _XmTextToLocaleText(w, ds->value, ds->type,
912 					   8, ds->length, NULL)) != NULL)
913       total_length = strlen(total_value);
914     else
915       if (ds->value) {
916 	XtFree((char*) ds->value);
917 	ds->value = NULL;
918       }
919   } else {
920     total_value = (char*) ds->value;
921     total_length = ds->length;
922   }
923 
924   if (total_value == NULL) return;
925 
926   if (TextF_PendingDelete(tf) && tf->text.has_primary &&
927       tf->text.prim_pos_left != tf->text.prim_pos_right) {
928       if(insertPosLeft > tf->text.prim_pos_left
929 		&& insertPosLeft <  tf->text.prim_pos_right)
930         insertPosLeft = tf->text.prim_pos_left;
931       if(insertPosRight < tf->text.prim_pos_right
932 		&& insertPosRight >  tf->text.prim_pos_left)
933         insertPosRight = tf->text.prim_pos_right;
934   }
935 
936   transfer_rec->num_chars = _XmTextFieldCountCharacters(tf, total_value,
937 							total_length);
938 
939   _XmTextFieldDrawInsertionPoint(tf, False);
940 
941   if (transfer_rec->move && local) {
942     max_length = TextF_MaxLength(tf);
943     TextF_MaxLength(tf) = INT_MAX;
944   }
945 
946   if (tf->text.max_char_size == 1) {
947     replace = _XmTextFieldReplaceText(tf, ds->event, insertPosLeft,
948 				      insertPosRight, (char *) total_value,
949 				      (int)total_length, False);
950   } else {
951     wc_total_length = _XmTextFieldCountCharacters(tf, total_value,
952                                                   total_length);
953     wc_total_value = (wchar_t*)XtMalloc((unsigned)
954 					(wc_total_length+1) * sizeof(wchar_t));
955     wc_total_length = mbstowcs(wc_total_value, total_value, wc_total_length+1);
956     if (wc_total_length > 0)
957       replace = _XmTextFieldReplaceText(tf, ds->event, insertPosLeft,
958 					insertPosRight, (char *)wc_total_value,
959 					wc_total_length, False);
960     XtFree((char*)wc_total_value);
961   }
962 
963   if (replace) {
964     tf->text.pending_off = FALSE;
965     if (transfer_rec->num_chars > 0 && !transfer_rec->move) {
966       cursorPos = transfer_rec->insert_pos + transfer_rec->num_chars;
967       _XmTextFieldSetCursorPosition(tf, NULL, cursorPos,
968 				    True, True);
969       _XmTextFieldSetDestination((Widget)tf, TextF_CursorPosition(tf),
970 				 transfer_rec->timestamp);
971     }
972     left = tf->text.prim_pos_left;
973     right = tf->text.prim_pos_right;
974     if (tf->text.has_primary) {
975       if (transfer_rec->move && left < transfer_rec->insert_pos)
976 	transfer_rec->insert_pos -= transfer_rec->num_chars;
977       if (TextF_CursorPosition(tf) < left ||
978 	  TextF_CursorPosition(tf) > right)
979 	tf->text.pending_off = TRUE;
980     } else {
981       if (!transfer_rec->move && !tf->text.add_mode &&
982 	  transfer_rec->num_chars != 0)
983 	tf->text.prim_anchor = insertPosLeft;
984     }
985     if (transfer_rec->move) {
986       XmTransferValue(ds->transfer_id,
987 		      atoms[XmADELETE],
988 		      (XtCallbackProc) DropTransferProc,
989 		      (XtPointer) transfer_rec, 0);
990     }
991     cb.reason = XmCR_VALUE_CHANGED;
992     cb.event = ds->event;
993     XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
994 		       (XtPointer) &cb);
995   }
996 
997   if (transfer_rec->move && local) {
998     TextF_MaxLength(tf) = max_length;
999   }
1000 
1001   if (total_value && (total_value != (char*)ds->value))
1002     XtFree(total_value);
1003   if (ds->value) {
1004     XtFree((char*) ds->value);
1005     ds->value = NULL;
1006   }
1007 
1008   _XmTextFieldDrawInsertionPoint(tf, True);
1009 }
1010 
1011 #define CR1228
1012 /*ARGSUSED*/
1013 static void
DoStuff(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)1014 DoStuff(Widget w,
1015 #ifdef CR1228
1016 	XtPointer closure,
1017 #else
1018 	XtPointer closure,	/* unused */
1019 #endif
1020 	XmSelectionCallbackStruct *ds)
1021 {
1022   enum { XmANULL, XmACLIPBOARD, XmATEXT, XmACOMPOUND_TEXT,
1023 #ifdef UTF8_SUPPORTED
1024     XmAUTF8_STRING,
1025 #endif
1026     NUM_ATOMS };
1027   static char *atom_names[] = {
1028     XmSNULL, XmSCLIPBOARD, XmSTEXT, XmSCOMPOUND_TEXT,
1029 #ifdef UTF8_SUPPORTED
1030     XmSUTF8_STRING
1031 #endif
1032     };
1033 
1034   XmTextFieldWidget tf = (XmTextFieldWidget) w;
1035   XmTextPosition right=0, left=0, replace_from, replace_to;
1036   int prim_char_length = 0;
1037   Boolean replace_res = False;
1038   XmAnyCallbackStruct cb;
1039   Atom atoms[XtNumber(atom_names)];
1040 #ifdef CR1228
1041   _XmTextPrimSelect *prim_select = (_XmTextPrimSelect *) closure;
1042 #endif
1043 
1044   assert(XtNumber(atom_names) == NUM_ATOMS);
1045   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1046 
1047   if (!tf->text.has_focus && _XmGetFocusPolicy(w) == XmEXPLICIT)
1048     (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1049 
1050   if (ds->selection != atoms[XmACLIPBOARD] &&
1051       ds->length == 0 &&
1052       ds->type != atoms[XmANULL]) {
1053     /* Backwards compatibility for 1.0 Selections */
1054     _XmProcessLock();
1055     if (prim_select->target == atoms[XmATEXT]) {
1056       prim_select->target = XA_STRING;
1057       XmTransferValue(ds->transfer_id, XA_STRING, (XtCallbackProc) DoStuff,
1058 		      (XtPointer) prim_select, prim_select->time);
1059     }
1060     _XmProcessUnlock();
1061     XtFree((char *)ds->value);
1062     ds->value = NULL;
1063     return;
1064   }
1065 
1066   /* if ds->length == 0 and ds->type is the NULL atom we are assuming
1067    * that a DELETE target is requested.
1068    */
1069   if (ds->type == atoms[XmANULL]) {
1070     _XmProcessLock();
1071     if (prim_select->num_chars > 0 && tf->text.selection_move) {
1072       prim_char_length = prim_select->num_chars;
1073       _XmTextFieldStartSelection(tf, prim_select->position,
1074 				 prim_select->position + prim_char_length,
1075 				 prim_select->time);
1076       tf->text.pending_off = False;
1077       _XmTextFieldSetCursorPosition(tf, NULL,
1078 				    prim_select->position + prim_char_length,
1079 				    True, True);
1080       tf->text.prim_anchor = prim_select->position;
1081     }
1082     _XmProcessUnlock(); /* for prim_select */
1083   } else {
1084     int max_length = 0;
1085     Boolean local = tf->text.has_primary;
1086     Boolean dest_disjoint = True;
1087 
1088     if (tf->text.selection_move && local) {
1089       max_length = TextF_MaxLength(tf);
1090       TextF_MaxLength(tf) = INT_MAX;
1091     }
1092     _XmProcessLock();
1093     replace_from = replace_to = prim_select->position;
1094     _XmProcessUnlock();
1095     if (ds->selection == atoms[XmACLIPBOARD]) {
1096       if (tf->text.has_primary) {
1097 	left = tf->text.prim_pos_left;
1098 	right = tf->text.prim_pos_right;
1099 	if (tf->text.pending_delete &&
1100 	    replace_from >= left && replace_to <= right) {
1101           replace_from = left;
1102           replace_to = right;
1103           dest_disjoint = False;
1104 	}
1105       }
1106     }
1107 
1108     if (ds->type == atoms[XmACOMPOUND_TEXT] ||
1109 #ifdef UTF8_SUPPORTED
1110 	ds->type == atoms[XmAUTF8_STRING] ||
1111 #endif
1112 	ds->type == XA_STRING) {
1113       char *total_value;
1114 
1115       if ((total_value =
1116 	   _XmTextToLocaleText(w, ds->value, ds->type, ds->format, ds->length,
1117 			       NULL))
1118 	  != NULL) {
1119 	if (tf->text.max_char_size == 1) {
1120 	  _XmProcessLock();
1121 	  prim_select->num_chars = strlen(total_value);
1122 	  replace_res =
1123 	    _XmTextFieldReplaceText (tf, ds->event,
1124 				     replace_from,
1125 				     replace_to,
1126 				     total_value,
1127 				     prim_select->num_chars,
1128 				     ds->selection == atoms[XmACLIPBOARD]);
1129 	  _XmProcessUnlock();
1130 	  XtFree(total_value);
1131 	} else {
1132 	  wchar_t * wc_value;
1133 	  int tmp_len = strlen(total_value) + 1;
1134 
1135 	  _XmProcessLock();
1136 	  prim_select->num_chars = 0;
1137 	  wc_value = (wchar_t*)XtMalloc ((unsigned) tmp_len * sizeof(wchar_t));
1138 	  prim_select->num_chars = mbstowcs(wc_value, total_value, tmp_len);
1139 	  if (prim_select->num_chars < 0)
1140 	    prim_select->num_chars = 0;
1141 	  else
1142 	    replace_res =
1143 	      _XmTextFieldReplaceText(tf, ds->event,
1144 				      replace_from,
1145 				      replace_to,
1146 				      (char*)wc_value,
1147 				      prim_select->num_chars,
1148 				      ds->selection == atoms[XmACLIPBOARD]);
1149 	  _XmProcessUnlock();
1150 	  XtFree((char*)wc_value);
1151 	  XtFree(total_value);
1152 	}
1153       } else { /* initialize prim_select values for possible delete oper */
1154 	_XmProcessLock();
1155 	prim_select->num_chars = 0;
1156 	_XmProcessUnlock();
1157       }
1158     } else {
1159       if (tf->text.max_char_size == 1) {
1160 	/* Note: length may be truncated during cast to int */
1161 	_XmProcessLock();
1162 	prim_select->num_chars = (int) ds->length;
1163 	replace_res =
1164 	  _XmTextFieldReplaceText(tf, ds->event,
1165 				  replace_from,
1166 				  replace_to,
1167 				  (char *) ds->value,
1168 				  prim_select->num_chars,
1169 				  ds->selection == atoms[XmACLIPBOARD]);
1170 	_XmProcessUnlock();
1171       } else {
1172 	wchar_t * wc_value;
1173 	char *temp;
1174 
1175 	temp = XtMalloc((unsigned) ds->length + 1);
1176 	(void)memcpy((void*)temp, (void*)ds->value, (size_t)ds->length);
1177 	temp[(size_t)ds->length] = '\0';
1178 
1179 	wc_value = (wchar_t*)XtMalloc ((unsigned)
1180 				       ((ds->length + 1) * sizeof(wchar_t)));
1181 	_XmProcessLock();
1182 
1183 	prim_select->num_chars = mbstowcs(wc_value, (char *) temp,
1184 					  (size_t) ds->length+1);
1185 
1186 	if (prim_select->num_chars < 0)
1187 	  prim_select->num_chars = 0;
1188 	else {
1189 	  wc_value[prim_select->num_chars] = 0;
1190 	  replace_res =
1191 	    _XmTextFieldReplaceText(tf, ds->event,
1192 				    replace_from,
1193 				    replace_to,
1194 				    (char*)wc_value,
1195 				    prim_select->num_chars,
1196 				    ds->selection == atoms[XmACLIPBOARD]);
1197 	}
1198 	_XmProcessUnlock();
1199 	XtFree(temp);
1200 	XtFree((char*)wc_value);
1201       }
1202     }
1203 
1204     if (replace_res) {
1205       XmTextPosition cursorPos = 0;
1206 
1207       if (ds->selection != atoms[XmACLIPBOARD]) {
1208 	tf->text.pending_off = FALSE;
1209 	_XmProcessLock();
1210 	cursorPos = replace_from + prim_select->num_chars;
1211 	if (prim_select->num_chars > 0 && !tf->text.selection_move) {
1212 	  _XmTextFieldSetCursorPosition(tf, NULL, cursorPos,
1213 					True, True);
1214 	  (void) _XmTextFieldSetDestination(w, cursorPos, prim_select->time);
1215 	_XmProcessUnlock();
1216 	}
1217       } else {
1218 	_XmProcessLock();
1219 	(void) _XmTextFieldSetDestination(w, TextF_CursorPosition(tf),
1220 					  prim_select->time);
1221 	_XmProcessUnlock();
1222       }
1223       left = tf->text.prim_pos_left;
1224       right = tf->text.prim_pos_right;
1225       if (tf->text.has_primary) {
1226 	if (ds->selection == atoms[XmACLIPBOARD]) {
1227 	  if (left != right && (!dest_disjoint || !tf->text.add_mode))
1228 	    _XmProcessLock();
1229 	    _XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
1230 				       TextF_CursorPosition(tf),
1231 				       prim_select->time);
1232 	    _XmProcessUnlock();
1233 	} else {
1234 	  _XmProcessLock();
1235 	  if (tf->text.selection_move && left < prim_select->position)
1236 	    prim_select->position -= prim_select->num_chars;
1237 	  if (left <= cursorPos && right >= cursorPos)
1238 	    tf->text.pending_off = TRUE;
1239 	  _XmProcessUnlock();
1240 	}
1241       } else {
1242 	_XmProcessLock();
1243 	if (ds->selection == atoms[XmACLIPBOARD])
1244 	  tf->text.prim_anchor = replace_from;
1245 	else if (!tf->text.selection_move && !tf->text.add_mode &&
1246 		 prim_select->num_chars != 0)
1247 	  tf->text.prim_anchor = prim_select->position;
1248 	_XmProcessUnlock();
1249       }
1250       cb.reason = XmCR_VALUE_CHANGED;
1251       cb.event = ds->event;
1252       XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
1253 			 (XtPointer) &cb);
1254     } else {
1255       _XmProcessLock();
1256       prim_select->num_chars = 0; /* Stop SetPrimarySelection from doing
1257 				     anything */
1258       _XmProcessUnlock();
1259     }
1260 
1261     if (tf->text.selection_move && local) {
1262       TextF_MaxLength(tf) = max_length;
1263     }
1264   }
1265 
1266   XtFree((char *)ds->value);
1267   ds->value = NULL;
1268 }
1269 
1270 static void
HandleTargets(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)1271 HandleTargets(Widget w, XtPointer closure,
1272 	      XmSelectionCallbackStruct *ds)
1273 {
1274   enum { XmACOMPOUND_TEXT, XmACLIPBOARD, XmATEXT,
1275 #ifdef UTF8_SUPPORTED
1276       XmAUTF8_STRING,
1277 #endif
1278       NUM_ATOMS };
1279   static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSCLIPBOARD, XmSTEXT,
1280 #ifdef UTF8_SUPPORTED
1281       XmSUTF8_STRING
1282 #endif
1283       };
1284 
1285   XmTextFieldWidget tf = (XmTextFieldWidget) w;
1286   Atom atoms[XtNumber(atom_names)];
1287   Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
1288   XmTextPosition left, right;
1289   Boolean supports_encoding_data = False;
1290   Boolean supports_CT = False;
1291   Boolean supports_utf8_string = False;
1292   Boolean supports_text = False;
1293   XPoint *point = (XPoint *)closure;
1294   Atom *atom_ptr;
1295   Atom targets[2];
1296   XmTextPosition select_pos;
1297   int i;
1298 
1299   if (!ds->length) {
1300     XtFree((char *)ds->value);
1301     ds->value = NULL;
1302     return; /* Supports no targets, so don't bother sending anything */
1303   }
1304 
1305   assert(XtNumber(atom_names) == NUM_ATOMS);
1306   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1307 
1308   atom_ptr = (Atom *)ds->value;
1309 
1310   for (i = 0; i < ds->length; i++, atom_ptr++) {
1311     if (*atom_ptr == atoms[XmATEXT])
1312       supports_text = True;
1313 
1314     if (*atom_ptr == CS_OF_ENCODING)
1315       supports_encoding_data = True;
1316 
1317     if (*atom_ptr == atoms[XmACOMPOUND_TEXT])
1318       supports_CT = True;
1319 
1320 #ifdef UTF8_SUPPORTED
1321     if (*atom_ptr == atoms[XmAUTF8_STRING])
1322       supports_utf8_string = True;
1323 #endif
1324   }
1325 
1326 
1327   /*
1328    * Set stuff position to the x and y position of
1329    * the button pressed event for primary pastes.
1330    */
1331   if (ds->selection != atoms[XmACLIPBOARD] && point) {
1332     select_pos = XmTextFieldXYToPos((Widget)tf, (Position)point->x, 0);
1333   } else {
1334     select_pos = TextF_CursorPosition(tf);
1335   }
1336 
1337   if (ds->selection != atoms[XmACLIPBOARD]) {
1338     left = tf->text.prim_pos_left;
1339     right = tf->text.prim_pos_right;
1340     if (tf->text.has_primary &&
1341 	left != right && select_pos > left && select_pos < right) {
1342       XtFree((char *)ds->value);
1343       ds->value = NULL;
1344       return;
1345     }
1346   }
1347 
1348   _XmProcessLock();
1349   if (prim_select) {
1350     prim_select->ref_count++;
1351   } else {
1352     prim_select = (_XmTextPrimSelect *)
1353       XtMalloc((unsigned) sizeof(_XmTextPrimSelect));
1354   }
1355   prim_select->position = select_pos;
1356   prim_select->time = XtLastTimestampProcessed(XtDisplay(w));
1357   prim_select->num_chars = 0;
1358 
1359   if (supports_text && supports_encoding_data)
1360     prim_select->target = targets[0] = atoms[XmATEXT];
1361 #ifdef UTF8_SUPPORTED
1362   else if (supports_utf8_string)
1363     prim_select->target = targets[0] = atoms[XmAUTF8_STRING];
1364 #endif
1365   else if (supports_CT)
1366     prim_select->target = targets[0] = atoms[XmACOMPOUND_TEXT];
1367   else if (supports_encoding_data)
1368     prim_select->target = targets[0] = CS_OF_ENCODING;
1369   else
1370     prim_select->target = targets[0] = XA_STRING;
1371 
1372   prim_select->ref_count = 1;
1373   /* Make request to call DoStuff() with the primary selection. */
1374   XmTransferValue(ds->transfer_id, targets[0], (XtCallbackProc) DoStuff,
1375 		  (XtPointer) prim_select, prim_select->time);
1376   _XmProcessUnlock();
1377   XtFree((char *)ds->value);
1378   ds->value = NULL;
1379 }
1380 
1381 static void
HandleDrop(Widget w,XmDropProcCallbackStruct * cb,XmDestinationCallbackStruct * ds)1382 HandleDrop(Widget w,
1383 	   XmDropProcCallbackStruct *cb,
1384 	   XmDestinationCallbackStruct *ds)
1385 {
1386   Widget drag_cont, initiator;
1387   Cardinal numExportTargets, n;
1388   Atom *exportTargets;
1389   Atom desiredTarget = None;
1390   Arg args[10];
1391   XmTextPosition insert_pos, left, right;
1392   Display *display = XtDisplay(w);
1393   Boolean doTransfer = False;
1394   _XmTextDropTransferRec *transfer_rec;
1395   XtPointer tid = ds->transfer_id;
1396 
1397   drag_cont = cb->dragContext;
1398   transfer_rec = (_XmTextDropTransferRec *) NULL;
1399 
1400   n = 0;
1401   XtSetArg(args[n], XmNsourceWidget, &initiator); n++;
1402   XtSetArg(args[n], XmNexportTargets, &exportTargets); n++;
1403   XtSetArg(args[n], XmNnumExportTargets, &numExportTargets); n++;
1404   XtGetValues((Widget) drag_cont, args, n);
1405 
1406   insert_pos = XmTextFieldXYToPos(w, cb->x, 0);
1407 
1408   left = ((XmTextFieldWidget)w)->text.prim_pos_left;
1409   right = ((XmTextFieldWidget)w)->text.prim_pos_right;
1410   if (cb->operation & XmDROP_MOVE && w == initiator &&
1411       ((XmTextFieldWidget)w)->text.has_primary &&
1412       left != right && insert_pos >= left && insert_pos <= right) {
1413     /*EMPTY*/
1414   } else {
1415     enum { XmATEXT, XmACOMPOUND_TEXT,
1416 #ifdef UTF8_SUPPORTED
1417         XmAUTF8_STRING,
1418 #endif
1419 	NUM_ATOMS };
1420     static char *atom_names[] = { XmSTEXT, XmSCOMPOUND_TEXT,
1421 #ifdef UTF8_SUPPORTED
1422         XmSUTF8_STRING
1423 #endif
1424 	};
1425 
1426     Atom atoms[XtNumber(atom_names)];
1427     Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
1428     Boolean encoding_found = False;
1429     Boolean utf8_string_found = False;
1430     Boolean c_text_found = False;
1431     Boolean string_found = False;
1432     Boolean text_found = False;
1433 
1434     assert(XtNumber(atom_names) == NUM_ATOMS);
1435     XInternAtoms(display, atom_names, XtNumber(atom_names), False, atoms);
1436 
1437     /* intialize data to send to drop transfer callback */
1438     transfer_rec = (_XmTextDropTransferRec *)
1439       XtMalloc(sizeof(_XmTextDropTransferRec));
1440     transfer_rec->widget = w;
1441     transfer_rec->insert_pos = insert_pos;
1442     transfer_rec->num_chars = 0;
1443     transfer_rec->timestamp = cb->timeStamp;
1444     transfer_rec->move = False;
1445 
1446     if (cb->operation & XmDROP_MOVE) {
1447       transfer_rec->move = True;
1448     } else {
1449       transfer_rec->move = False;
1450     }
1451 
1452     for (n = 0; n < numExportTargets; n++) {
1453       if (exportTargets[n] == CS_OF_ENCODING) {
1454 	desiredTarget = CS_OF_ENCODING;
1455 	encoding_found = True;
1456 	break;
1457       }
1458 #ifdef UTF8_SUPPORTED
1459       if (exportTargets[n] == atoms[XmAUTF8_STRING]) utf8_string_found = True;
1460 #endif
1461       if (exportTargets[n] == atoms[XmACOMPOUND_TEXT]) c_text_found = True;
1462       if (exportTargets[n] == XA_STRING) string_found = True;
1463       if (exportTargets[n] == atoms[XmATEXT]) text_found = True;
1464     }
1465 
1466     n = 0;
1467     if (encoding_found || c_text_found || string_found || text_found) {
1468       if (!encoding_found) {
1469 #ifdef UTF8_SUPPORTED
1470 	if (utf8_string_found)
1471 	  desiredTarget = atoms[XmAUTF8_STRING];
1472 	else
1473 #endif
1474 	if (c_text_found)
1475 	  desiredTarget = atoms[XmACOMPOUND_TEXT];
1476 	else if (string_found)
1477 	  desiredTarget = XA_STRING;
1478 	else
1479 	  desiredTarget = atoms[XmATEXT];
1480       }
1481 
1482       if (cb->operation & XmDROP_MOVE || cb->operation & XmDROP_COPY) {
1483 	doTransfer = True;
1484       } else {
1485 	XmTransferDone(tid, XmTRANSFER_DONE_FAIL);
1486       }
1487 
1488     } else {
1489       XmTransferDone(tid, XmTRANSFER_DONE_FAIL);
1490     }
1491   }
1492   SetDropContext(w);
1493 
1494   if (doTransfer) {
1495     XmeTransferAddDoneProc(tid, (XmSelectionFinishedProc) DropDestroyCB);
1496     XmTransferValue(tid, desiredTarget,
1497 		    (XtCallbackProc) DropTransferProc,
1498 		    (XtPointer) transfer_rec, 0);
1499   }
1500 }
1501 
1502 
1503 /*ARGSUSED*/
1504 static void
TextFieldConvertCallback(Widget w,XtPointer ignore,XmConvertCallbackStruct * cs)1505 TextFieldConvertCallback(Widget w,
1506 			 XtPointer ignore, /* unused */
1507 			 XmConvertCallbackStruct *cs)
1508 {
1509   enum { XmADELETE, XmA_MOTIF_LOSE_SELECTION,
1510 	 XmA_MOTIF_EXPORT_TARGETS, XmA_MOTIF_CLIPBOARD_TARGETS,
1511 	 XmACOMPOUND_TEXT, XmATEXT, XmATARGETS, XmACLIPBOARD,
1512 #ifdef UTF8_SUPPORTED
1513          XmAUTF8_STRING,
1514 #endif
1515 	 NUM_ATOMS };
1516   static char *atom_names[] = { XmSDELETE, XmS_MOTIF_LOSE_SELECTION,
1517 	 XmS_MOTIF_EXPORT_TARGETS, XmS_MOTIF_CLIPBOARD_TARGETS,
1518 	 XmSCOMPOUND_TEXT, XmSTEXT, XmSTARGETS, XmSCLIPBOARD,
1519 #ifdef UTF8_SUPPORTED
1520          XmSUTF8_STRING
1521 #endif
1522 	 };
1523 
1524   Atom XA_CS_OF_ENCODING = XmeGetEncodingAtom(w);
1525   XtPointer value;
1526   Atom type;
1527   unsigned long size;
1528   int format;
1529   Atom atoms[XtNumber(atom_names)];
1530 
1531   assert(XtNumber(atom_names) == NUM_ATOMS);
1532   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1533 
1534   value = NULL;
1535 
1536   if (cs->target == atoms[XmA_MOTIF_LOSE_SELECTION]) {
1537     _XmTextFieldLoseSelection(w, &(cs->selection));
1538     cs->status = XmCONVERT_DONE;
1539     return;
1540   }
1541 
1542   if (cs->target == atoms[XmADELETE] &&
1543       cs->selection == XA_SECONDARY) {
1544     _XmTextFieldHandleSecondaryFinished(w, cs->event);
1545     cs->status = XmCONVERT_DONE;
1546     return;
1547   }
1548 
1549   /* When this is called as a result of a clipboard copy link,  we
1550      don't have any available targets.  Make sure to return immediately
1551      without modification */
1552   if (cs->selection == atoms[XmACLIPBOARD] &&
1553       cs->parm == (XtPointer) XmLINK &&
1554       (cs->target == atoms[XmA_MOTIF_CLIPBOARD_TARGETS] ||
1555        cs->target == atoms[XmATARGETS])) return;
1556 
1557   if (!_XmTextFieldConvert(w, &cs->selection, &cs->target,
1558 			   &type, &value, &size, &format,
1559 			   (Widget) cs->source_data, cs->event)) {
1560     value = NULL;
1561     type = XA_INTEGER;
1562     size = 0;
1563     format = 8;
1564   }
1565 
1566   if (cs->target == atoms[XmADELETE]) {
1567     cs->status = XmCONVERT_DONE;
1568     cs->type = type;
1569     cs->value = value;
1570     cs->length = size;
1571     cs->format = format;
1572     return;
1573   }
1574 
1575   if (cs->target == atoms[XmA_MOTIF_EXPORT_TARGETS] ||
1576       cs->target == atoms[XmA_MOTIF_CLIPBOARD_TARGETS]) {
1577     Atom *targs = (Atom *) XtMalloc(sizeof(Atom) * 5);
1578     int n = 0;
1579 
1580     value = (XtPointer) targs;
1581 #ifdef UTF8_SUPPORTED
1582     targs[n] = atoms[XmAUTF8_STRING]; n++;
1583 #endif
1584     targs[n] = atoms[XmACOMPOUND_TEXT]; n++;
1585     targs[n] = atoms[XmATEXT]; n++;
1586     targs[n] = XA_STRING; n++;
1587     if (XA_CS_OF_ENCODING != XA_STRING) {
1588       targs[n] = XA_CS_OF_ENCODING; n++;
1589     }
1590     format = 32;
1591     size = n;
1592     type = XA_ATOM;
1593   }
1594 
1595   _XmConvertComplete(w, value, size, format, type, cs);
1596 }
1597 
1598 /************************************************
1599  * Free data allocated for destination callback
1600  ************************************************/
1601 
1602 /*ARGSUSED*/
1603 static void
FreeLocationData(Widget w,XtEnum op,XmTransferDoneCallbackStruct * ts)1604 FreeLocationData(Widget w,     /* unused */
1605 		 XtEnum op,    /* unused */
1606 		 XmTransferDoneCallbackStruct *ts)
1607 {
1608   XmDestinationCallbackStruct *ds;
1609 
1610   ds = _XmTransferGetDestinationCBStruct(ts->transfer_id);
1611 
1612   XtFree((char*) ds->location_data);
1613 
1614   ds->location_data = NULL;
1615 }
1616 
1617 /*ARGSUSED*/
1618 static void
TextFieldDestinationCallback(Widget w,XtPointer closure,XmDestinationCallbackStruct * ds)1619 TextFieldDestinationCallback(Widget w,
1620 			     XtPointer closure, /* unused */
1621 			     XmDestinationCallbackStruct *ds)
1622 {
1623   enum { XmATARGETS, XmA_MOTIF_DROP, NUM_ATOMS };
1624   static char *atom_names[] = { XmSTARGETS, XmS_MOTIF_DROP };
1625   Atom atoms[XtNumber(atom_names)];
1626   XPoint DropPoint;
1627 
1628   assert(XtNumber(atom_names) == NUM_ATOMS);
1629   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1630 
1631   /*
1632    ** In case of a primary transfer operation where a location_data
1633    ** has been allocated, register a done proc to be called when
1634    ** the data transfer is complete to free the location_data
1635    */
1636   if (ds->selection == XA_PRIMARY && ds->location_data)
1637       XmeTransferAddDoneProc(ds->transfer_id, FreeLocationData);
1638 
1639   /* If we aren't sensitive,  don't allow transfer */
1640   if (! w -> core.sensitive ||
1641       ! w -> core.ancestor_sensitive)
1642     XmTransferDone(ds -> transfer_id, XmTRANSFER_DONE_FAIL);
1643 
1644   /* We don't handle LINKs internally */
1645   if (ds->operation == XmLINK) return;
1646 
1647   if (ds->selection == XA_PRIMARY && ds->operation == XmMOVE)
1648     XmeTransferAddDoneProc(ds->transfer_id, SetPrimarySelection);
1649   else
1650     XmeTransferAddDoneProc(ds->transfer_id, CleanPrimarySelection);
1651 
1652   if (ds->selection == atoms[XmA_MOTIF_DROP]) {
1653     XmDropProcCallbackStruct *cb =
1654       (XmDropProcCallbackStruct *) ds->destination_data;
1655 
1656     DropPoint.x = cb->x;
1657     DropPoint.y = cb->y;
1658 
1659     ds->location_data = (XtPointer) &DropPoint;
1660 
1661     if (cb->dropAction != XmDROP_HELP) {
1662       HandleDrop(w, cb, ds);
1663     }
1664   } else if (ds->selection == XA_SECONDARY) {
1665     Atom CS_OF_ENCODING;
1666 
1667     CS_OF_ENCODING = XmeGetEncodingAtom(w);
1668 
1669     _XmProcessLock();
1670     insert_select.done_status = False;
1671     insert_select.success_status = False;
1672     insert_select.event = (XSelectionRequestEvent *) ds->event;
1673     insert_select.select_type = XmDEST_SELECT;
1674 
1675     if (((Atom) ds->location_data) != CS_OF_ENCODING) {
1676       /*
1677        * Make selection request to find out which targets
1678        * the selection can provide.
1679        */
1680       XmTransferValue(ds->transfer_id, atoms[XmATARGETS],
1681 		      (XtCallbackProc) TextFieldSecondaryWrapper,
1682 		      (XtPointer) &insert_select, ds->time);
1683     } else {
1684       /*
1685        * Make selection request to replace the selection
1686        * with the insert selection.
1687        */
1688       XmTransferValue(ds->transfer_id, ((Atom) ds->location_data),
1689 		      (XtCallbackProc) TextFieldSecondaryWrapper,
1690 		      (XtPointer) &insert_select, ds->time);
1691     }
1692     _XmProcessUnlock();
1693   } else
1694     /* CLIPBOARD or PRIMARY */
1695     XmTransferValue(ds->transfer_id, atoms[XmATARGETS],
1696 		    (XtCallbackProc) HandleTargets,
1697 		    ds->location_data, ds->time);
1698 }
1699 
1700 void
_XmTextFieldInstallTransferTrait(void)1701 _XmTextFieldInstallTransferTrait(void)
1702 {
1703   XmeTraitSet((XtPointer)xmTextFieldWidgetClass, XmQTtransfer,
1704 	      (XtPointer) &textFieldTT);
1705 }
1706