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: TextF.c /main/65 1999/09/01 17:28:48 mgreess $"
31 #endif
32 #endif
33 
34 #include <stdio.h>
35 #include <limits.h>		/* required for MB_LEN_MAX definition */
36 #include <string.h>
37 #include <ctype.h>
38 #include "XmI.h"
39 #include <X11/ShellP.h>
40 #include <X11/VendorP.h>
41 #include <X11/Xatom.h>
42 #include <X11/keysym.h>
43 #include <Xm/AccColorT.h>
44 #include <Xm/AccTextT.h>
45 #include <Xm/AtomMgr.h>
46 #include <Xm/CutPaste.h>
47 #include <Xm/Display.h>
48 #include <Xm/DragC.h>
49 #include <Xm/DragIcon.h>
50 #include <Xm/DragIconP.h>
51 #include <Xm/DrawP.h>
52 #include <Xm/DropSMgr.h>
53 #include <Xm/DropTrans.h>
54 #include <Xm/ManagerP.h>
55 #include <Xm/TraitP.h>
56 #include <Xm/TransferP.h>
57 #include <Xm/TransltnsP.h>
58 #include <Xm/XmosP.h>
59 #include <Xm/VaSimpleP.h>
60 #include "DestI.h"
61 #include "DisplayI.h"
62 #include "GMUtilsI.h"
63 #include "ImageCachI.h"
64 #include "MessagesI.h"
65 #include "RepTypeI.h"
66 #include "ScreenI.h"
67 #include "TextFI.h"
68 #include "TextFSelI.h"
69 #include "TravActI.h"
70 #include "TraversalI.h"
71 #include "VendorSEI.h"
72 #include "XmStringI.h"
73 #ifdef PRINTING_SUPPORTED
74 #include <Xm/PrintSP.h>         /* for XmIsPrintShell */
75 #endif
76 #ifdef USE_XFT
77 #include <X11/Xft/Xft.h>
78 #include "XmRenderTI.h"
79 #endif
80 #include <Xm/XmP.h>
81 
82 #define FIX_1409
83 
84 #if (defined(__FreeBSD__) && (__FreeBSD__ < 4)) || \
85     (defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__))
86 /*
87  * Modification by Integrated Computer Solutions, Inc.  May 2000
88  *
89  * FreeBSD (pre-4.0), DARWIN, NetBSD, and OpenBSD do not include the necessary
90  * wide character string functions.  Use the internal _Xwc... routines and add
91  * the other missing functions as _Xmwc... routines.  The new functions are
92  * added static to this file.
93  */
94 #define wcslen(c) _Xwcslen(c)
95 #define wcscpy(d,s) _Xwcscpy(d,s)
96 #define wcsncpy(d,s,l) _Xwcsncpy(d,s,l)
97 
98 static wchar_t* _Xmwcschr(const wchar_t *ws, wchar_t wc)
99 {
100         for (;; ++ws) {
101                 if (*ws == wc)
102                         return((wchar_t *)ws);
103                 if (!*ws)
104                         return((wchar_t *)NULL);
105         }
106         /* NOTREACHED */
107 }
108 #define wcschr(w,c) _Xmwcschr(w,c)
109 
_Xmwcscat(wchar_t * ws1,const wchar_t * ws2)110 static wchar_t* _Xmwcscat(wchar_t *ws1, const wchar_t *ws2)
111 {
112         wchar_t *save = ws1;
113 
114         for (; *ws1; ++ws1);
115         while (*ws1++ = *ws2++);
116         return save;
117 }
118 #define wcscat(w1,w2) _Xmwcscat(w1,w2)
119 
_Xmwcsncat(wchar_t * ws1,const wchar_t * ws2,size_t n)120 static wchar_t* _Xmwcsncat(wchar_t *ws1, const wchar_t *ws2, size_t n)
121 {
122         if (n != 0) {
123                 register wchar_t *d = ws1;
124                 register const wchar_t *s = ws2;
125 
126                 while (*d != 0)
127                         d++;
128                 do {
129                         if ((*d = *s++) == 0)
130                                 break;
131                         d++;
132                 } while (--n != 0);
133                 *d = 0;
134         }
135         return ws1;
136 }
137 #define wcsncat(w1,w2,l) _Xmwcsncat(w1,w2,l)
138 
139 #else  /* !__FreeBSD__ */
140 #include <wchar.h>
141 #endif /* __FreeBSD__ */
142 
143 #define MSG1		_XmMMsgTextF_0000
144 #define MSG2		_XmMMsgTextF_0001
145 #define MSG3		_XmMMsgTextF_0002
146 #define MSG4		_XmMMsgTextF_0003
147 #define MSG5		_XmMMsgTextF_0004
148 #define MSG7		_XmMMsgTextF_0006
149 #define WC_MSG1		_XmMMsgTextFWcs_0000
150 #define GRABKBDERROR	_XmMMsgRowColText_0024
151 
152 #define TEXT_INCREMENT		 32
153 #define PRIM_SCROLL_INTERVAL	100
154 #define SEC_SCROLL_INTERVAL	200
155 #define XmDYNAMIC_BOOL		255
156 
157 /* For the action parameters that are processed as reptypes */
158 #define _RIGHT 0
159 #define _LEFT  1
160 
161 #define EventBindings1	_XmTextF_EventBindings1
162 #define EventBindings2	_XmTextF_EventBindings2
163 #define EventBindings3	_XmTextF_EventBindings3
164 
165 #define TEXT_MAX_INSERT_SIZE 64    /* Size of buffer for XLookupString. */
166 
167 typedef struct {
168   Boolean has_destination;
169   XmTextPosition position;
170   int replace_length;
171   Boolean quick_key;
172 } TextFDestDataRec, *TextFDestData;
173 
174 /********    Static Function Declarations    ********/
175 
176 static void MakeCopy(Widget w,
177 		     int n,
178 		     XtArgVal *value);
179 
180 static void WcsMakeCopy(Widget w,
181                         int n,
182                         XtArgVal *value);
183 
184 static void FreeContextData(Widget w,
185 			    XtPointer clientData,
186 			    XtPointer callData);
187 
188 static TextFDestData GetTextFDestData(Widget w);
189 
190 static _XmHighlightRec * FindHighlight(XmTextFieldWidget w,
191 				       XmTextPosition position);
192 
193 static void InsertHighlight(XmTextFieldWidget w,
194 			    XmTextPosition position,
195 			    XmHighlightMode mode);
196 
197 static void TextFieldSetHighlight(XmTextFieldWidget tf,
198 				  XmTextPosition left,
199 				  XmTextPosition right,
200 				  XmHighlightMode mode);
201 
202 static Boolean GetXYFromPos(XmTextFieldWidget tf,
203 			    XmTextPosition position,
204 			    Position *x,
205 			    Position *y);
206 
207 static Boolean CurrentCursorState(XmTextFieldWidget tf);
208 
209 static void PaintCursor(XmTextFieldWidget tf);
210 
211 static void BlinkInsertionPoint(XmTextFieldWidget tf);
212 
213 static void HandleTimer(XtPointer closure,
214                         XtIntervalId *id);
215 
216 static void ChangeBlinkBehavior(XmTextFieldWidget tf,
217 #if NeedWidePrototypes
218 				int turn_on);
219 
220 #else
221                                 Boolean turn_on);
222 #endif /* NeedWidePrototypes */
223 static void GetRect(XmTextFieldWidget tf,
224                     XRectangle *rect);
225 
226 static void SetFullGC(XmTextFieldWidget tf,
227                         GC gc);
228 
229 static void SetMarginGC(XmTextFieldWidget tf,
230                           GC gc);
231 
232 static void SetNormGC(XmTextFieldWidget tf,
233                         GC gc,
234 #if NeedWidePrototypes
235                         int change_stipple,
236                         int stipple);
237 #else
238                         Boolean change_stipple,
239                         Boolean stipple);
240 #endif /* NeedWidePrototypes */
241 
242 #ifdef FIX_1381
243 static void SetShadowGC(XmTextFieldWidget tf,
244                         GC gc);
245 #endif
246 
247 static void SetInvGC(XmTextFieldWidget tf,
248 		       GC gc);
249 
250 static void DrawText(XmTextFieldWidget tf,
251 		     GC gc,
252 		     int x,
253 		     int y,
254 		     char *string,
255 		     int length);
256 
257 static int FindPixelLength(XmTextFieldWidget tf,
258 			   char *string,
259 			   int length);
260 
261 static void DrawTextSegment(XmTextFieldWidget tf,
262 			    XmHighlightMode mode,
263 			    XmTextPosition prev_seg_start,
264 			    XmTextPosition seg_start,
265 			    XmTextPosition seg_end,
266 			    XmTextPosition next_seg,
267 #if NeedWidePrototypes
268 			    int stipple,
269 #else
270 			    Boolean stipple,
271 #endif /* NeedWidePrototypes */
272 			    int y,
273 			    int *x);
274 
275 static void RedisplayText(XmTextFieldWidget tf,
276 			  XmTextPosition start,
277 			  XmTextPosition end);
278 
279 static void ComputeSize(XmTextFieldWidget tf,
280                         Dimension *width,
281                         Dimension *height);
282 
283 static XtGeometryResult TryResize(XmTextFieldWidget tf,
284 #if NeedWidePrototypes
285 				  int width,
286 				  int height);
287 #else
288                                   Dimension width,
289                                   Dimension height);
290 #endif /* NeedWidePrototypes */
291 
292 static Boolean AdjustText(XmTextFieldWidget tf,
293 			  XmTextPosition position,
294 #if NeedWidePrototypes
295 			  int flag);
296 #else
297                           Boolean flag);
298 #endif /* NeedWidePrototypes */
299 
300 static void AdjustSize(XmTextFieldWidget tf);
301 
302 static Boolean ModifyVerify(XmTextFieldWidget tf,
303 			    XEvent *event,
304 			    XmTextPosition *replace_prev,
305 			    XmTextPosition *replace_next,
306 			    char **insert,
307 			    int *insert_length,
308 			    XmTextPosition *newInsert,
309 			    int *free_insert);
310 
311 static void ResetClipOrigin(XmTextFieldWidget tf);
312 
313 static void InvertImageGC(XmTextFieldWidget tf);
314 
315 static void ResetImageGC(XmTextFieldWidget tf);
316 
317 typedef enum { ForceTrue, DontCare } PassDisown;
318 static void SetCursorPosition(XmTextFieldWidget tf,
319 			      XEvent *event,
320 			      XmTextPosition position,
321 #if NeedWidePrototypes
322 			      int adjust_flag,
323 			      int call_cb,
324 			      int set_dest,
325 #else
326                               Boolean adjust_flag,
327                               Boolean call_cb,
328                               Boolean set_dest,
329 #endif /* NeedWidePrototypes */
330 			      PassDisown passDisown);
331 
332 static void VerifyBounds(XmTextFieldWidget tf,
333 			 XmTextPosition *from,
334 			 XmTextPosition *to);
335 
336 static XmTextPosition GetPosFromX(XmTextFieldWidget tf,
337 #if NeedWidePrototypes
338 				  int x);
339 #else
340                                   Position x);
341 #endif /* NeedWidePrototypes */
342 
343 static Boolean SetDestination(Widget w,
344 			      XmTextPosition position,
345 #if NeedWidePrototypes
346 			      int disown,
347 #else
348 			      Boolean disown,
349 #endif /* NeedWidePrototypes */
350 			      Time set_time);
351 
352 static Boolean VerifyLeave(XmTextFieldWidget tf,
353 			   XEvent *event);
354 
355 static Boolean _XmTextFieldIsWordBoundary(XmTextFieldWidget tf,
356 					  XmTextPosition pos1,
357 					  XmTextPosition pos2);
358 
359 static Boolean _XmTextFieldIsWSpace(wchar_t wide_char,
360 				    wchar_t *white_space,
361 				    int num_entries);
362 
363 static void FindWord(XmTextFieldWidget tf,
364 		     XmTextPosition begin,
365 		     XmTextPosition *left,
366 		     XmTextPosition *right);
367 
368 static void FindPrevWord(XmTextFieldWidget tf,
369 			 XmTextPosition *left,
370 			 XmTextPosition *right);
371 
372 static void FindNextWord(XmTextFieldWidget tf,
373 			 XmTextPosition *left,
374 			 XmTextPosition *right);
375 
376 static void CheckDisjointSelection(Widget w,
377 				   XmTextPosition position,
378 				   Time sel_time);
379 
380 static Boolean NeedsPendingDelete(XmTextFieldWidget tf);
381 
382 static Boolean NeedsPendingDeleteDisjoint(XmTextFieldWidget tf);
383 
384 static void InsertChar(Widget w,
385 		       XEvent *event,
386 		       char **params,
387 		       Cardinal *num_params);
388 
389 static void DeletePrevChar(Widget w,
390 			   XEvent *event,
391 			   char **params,
392 			   Cardinal *num_params);
393 
394 static void DeleteNextChar(Widget w,
395 			   XEvent *event,
396 			   char **params,
397 			   Cardinal *num_params);
398 
399 static void DeletePrevWord(Widget w,
400 			   XEvent *event,
401 			   char **params,
402 			   Cardinal *num_params);
403 
404 static void DeleteNextWord(Widget w,
405 			   XEvent *event,
406 			   char **params,
407 			   Cardinal *num_params);
408 
409 static void DeleteToEndOfLine(Widget w,
410 			      XEvent *event,
411 			      char **params,
412 			      Cardinal *num_params);
413 
414 static void DeleteToStartOfLine(Widget w,
415 				XEvent *event,
416 				char **params,
417 				Cardinal *num_params);
418 
419 static void ProcessCancel(Widget w,
420 			  XEvent *event,
421 			  char **params,
422 			  Cardinal *num_params);
423 
424 static void Activate(Widget w,
425 		     XEvent *event,
426 		     char **params,
427 		     Cardinal *num_params);
428 
429 static void SetAnchorBalancing(XmTextFieldWidget tf,
430 			       XmTextPosition position);
431 
432 static void SetNavigationAnchor(XmTextFieldWidget tf,
433 				XmTextPosition old_position,
434 				XmTextPosition new_position,
435 #if NeedWidePrototypes
436 				int extend);
437 #else
438                                 Boolean extend);
439 #endif /* NeedWidePrototypes */
440 
441 static void CompleteNavigation(XmTextFieldWidget tf,
442 			       XEvent *event,
443 			       XmTextPosition position,
444 			       Time time,
445 #if NeedWidePrototypes
446 			       int extend);
447 #else
448                                Boolean extend);
449 #endif /* NeedWidePrototypes */
450 
451 static void SimpleMovement(Widget w,
452 			   XEvent *event,
453 			   String *params,
454 			   Cardinal *num_params,
455 			   XmTextPosition cursorPos,
456 			   XmTextPosition position);
457 
458 static void BackwardChar(Widget w,
459 			 XEvent *event,
460 			 char **params,
461 			 Cardinal *num_params);
462 
463 static void ForwardChar(Widget w,
464                         XEvent *event,
465                         char **params,
466                         Cardinal *num_params);
467 
468 static void BackwardWord(Widget w,
469 			 XEvent *event,
470 			 char **params,
471 			 Cardinal *num_params);
472 
473 static void ForwardWord(Widget w,
474                         XEvent *event,
475                         char **params,
476                         Cardinal *num_params);
477 
478 static void EndOfLine(Widget w,
479 		      XEvent *event,
480 		      char **params,
481 		      Cardinal *num_params);
482 
483 static void BeginningOfLine(Widget w,
484 			    XEvent *event,
485 			    char **params,
486 			    Cardinal *num_params);
487 
488 static void SetSelection(XmTextFieldWidget tf,
489 			 XmTextPosition left,
490 			 XmTextPosition right,
491 #if NeedWidePrototypes
492 			 int redisplay);
493 #else
494                          Boolean redisplay);
495 #endif /* NeedWidePrototypes */
496 
497 static void ProcessHorizontalParams(Widget w,
498 				    XEvent *event,
499 				    char **params,
500 				    Cardinal *num_params,
501 				    XmTextPosition *left,
502 				    XmTextPosition *right,
503 				    XmTextPosition *position);
504 
505 static void ProcessSelectParams(Widget w,
506 				XEvent *event,
507 				XmTextPosition *left,
508 				XmTextPosition *right,
509 				XmTextPosition *position);
510 
511 static void KeySelection(Widget w,
512 			 XEvent *event,
513 			 char **params,
514 			 Cardinal *num_params);
515 
516 static void TextFocusIn(Widget w,
517                         XEvent *event,
518                         char **params,
519                         Cardinal *num_params);
520 
521 static void TextFocusOut(Widget w,
522 			 XEvent *event,
523 			 char **params,
524 			 Cardinal *num_params);
525 
526 static void SetScanIndex(XmTextFieldWidget tf,
527 			 XEvent *event);
528 
529 static void ExtendScanSelection(XmTextFieldWidget tf,
530 				XEvent *event);
531 
532 static void SetScanSelection(XmTextFieldWidget tf,
533 			     XEvent *event);
534 
535 static void StartPrimary(Widget w,
536 			 XEvent *event,
537 			 char **params,
538 			 Cardinal *num_params);
539 
540 static void MoveDestination(Widget w,
541 			    XEvent *event,
542 			    char **params,
543 			    Cardinal *num_params);
544 
545 static void ExtendPrimary(Widget w,
546 			  XEvent *event,
547 			  char **params,
548 			  Cardinal *num_params);
549 
550 static void ExtendEnd(Widget w,
551 		      XEvent *event,
552 		      char **params,
553 		      Cardinal *num_params);
554 
555 static void DoExtendedSelection(Widget w,
556 				Time time);
557 
558 static void DoSecondaryExtend(Widget w,
559 			      Time ev_time);
560 
561 static void BrowseScroll(XtPointer closure,
562 			 XtIntervalId *id);
563 
564 static Boolean CheckTimerScrolling(Widget w,
565 				   XEvent *event);
566 
567 static void RestorePrimaryHighlight(XmTextFieldWidget tf,
568 				    XmTextPosition prim_left,
569 				    XmTextPosition prim_right);
570 
571 static void StartDrag(Widget w,
572 		      XEvent *event,
573 		      String *params,
574 		      Cardinal *num_params);
575 
576 static void DragStart(XtPointer data,
577 		      XtIntervalId *id);
578 
579 static void StartSecondary(Widget w,
580 			   XEvent *event,
581 			   char **params,
582 			   Cardinal *num_params);
583 
584 static void ProcessBDrag(Widget w,
585 			 XEvent *event,
586 			 char **params,
587 			 Cardinal *num_params);
588 
589 static void ProcessBDragEvent(Widget w,
590 			       XEvent *event,
591 			       char **params,
592 			       Cardinal *num_params);
593 
594 static void ProcessBDragRelease(Widget w,
595 				XEvent *event,
596 				String *params,
597 				Cardinal *num_params);
598 
599 static Boolean InSelection(Widget w,
600 			   XEvent *event);
601 
602 static void ProcessBSelect(Widget w,
603 			   XEvent *event,
604 			   char **params,
605 			   Cardinal *num_params);
606 
607 static void ProcessBSelectEvent(Widget w,
608 				XEvent *event,
609 				char **params,
610 				Cardinal *num_params);
611 
612 static void ExtendSecondary(Widget w,
613 			    XEvent *event,
614 			    char **params,
615 			    Cardinal *num_params);
616 
617 static void Stuff(Widget w,
618 		  XEvent *event,
619 		  char **params,
620 		  Cardinal *num_params);
621 
622 static void SecondaryNotify(Widget w,
623 			    XEvent *event,
624 			    char **params,
625 			    Cardinal *num_params);
626 
627 static void ProcessCopy(Widget w,
628                         XEvent *event,
629                         char **params,
630                         Cardinal *num_params);
631 
632 static void ProcessLink(Widget w,
633                         XEvent *event,
634                         char **params,
635                         Cardinal *num_params);
636 
637 static void ProcessMove(Widget w,
638                         XEvent *event,
639                         char **params,
640                         Cardinal *num_params);
641 
642 static void DeleteSelection(Widget w,
643 			    XEvent *event,
644 			    char **params,
645 			    Cardinal *num_params);
646 
647 static void ClearSelection(Widget w,
648 			   XEvent *event,
649 			   char **params,
650 			   Cardinal *num_params);
651 
652 static void PageRight(Widget w,
653 		      XEvent *event,
654 		      char **params,
655 		      Cardinal *num_params);
656 
657 static void PageLeft(Widget w,
658 		     XEvent *event,
659 		     char **params,
660 		     Cardinal *num_params);
661 
662 static void CopyPrimary(Widget w,
663                         XEvent *event,
664                         char **params,
665                         Cardinal *num_params);
666 
667 static void CutPrimary(Widget w,
668 		       XEvent *event,
669 		       char **params,
670 		       Cardinal *num_params);
671 
672 static void LinkPrimary(Widget w,
673 		       XEvent *event,
674 		       char **params,
675 		       Cardinal *num_params);
676 
677 static void SetAnchor(Widget w,
678 		      XEvent *event,
679 		      char **params,
680 		      Cardinal *num_params);
681 
682 static void ToggleOverstrike(Widget w,
683 			     XEvent *event,
684 			     char **params,
685 			     Cardinal *num_params);
686 
687 static void ToggleAddMode(Widget w,
688 			  XEvent *event,
689 			  char **params,
690 			  Cardinal *num_params);
691 
692 static void SelectAll(Widget w,
693 		      XEvent *event,
694 		      char **params,
695 		      Cardinal *num_params);
696 
697 static void DeselectAll(Widget w,
698                         XEvent *event,
699                         char **params,
700                         Cardinal *num_params);
701 
702 static void VoidAction(Widget w,
703 		       XEvent *event,
704 		       char **params,
705 		       Cardinal *num_params);
706 
707 static void CutClipboard(Widget w,
708 			 XEvent *event,
709 			 char **params,
710 			 Cardinal *num_params);
711 
712 static void CopyClipboard(Widget w,
713 			  XEvent *event,
714 			  char **params,
715 			  Cardinal *num_params);
716 
717 static void PasteClipboard(Widget w,
718 			   XEvent *event,
719 			   char **params,
720 			   Cardinal *num_params);
721 
722 static void TraverseDown(Widget w,
723 			 XEvent *event,
724 			 char **params,
725 			 Cardinal *num_params);
726 
727 static void TraverseUp(Widget w,
728 		       XEvent *event,
729 		       char **params,
730 		       Cardinal *num_params);
731 
732 static void TraverseHome(Widget w,
733 			 XEvent *event,
734 			 char **params,
735 			 Cardinal *num_params);
736 
737 static void TraverseNextTabGroup(Widget w,
738 				 XEvent *event,
739 				 char **params,
740 				 Cardinal *num_params);
741 
742 static void TraversePrevTabGroup(Widget w,
743 				 XEvent *event,
744 				 char **params,
745 				 Cardinal *num_params);
746 
747 static void TextEnter(Widget w,
748 		      XEvent *event,
749 		      String *params,
750 		      Cardinal *num_params);
751 
752 static void TextLeave(Widget w,
753 		      XEvent *event,
754 		      String *params,
755 		      Cardinal *num_params);
756 
757 static void ClassInitialize(void);
758 
759 static void ClassPartInitialize(WidgetClass w_class);
760 
761 static void Validates(XmTextFieldWidget tf);
762 
763 static Boolean LoadFontMetrics(XmTextFieldWidget tf);
764 
765 static void ValidateString(XmTextFieldWidget tf,
766 			   char *value,
767 #if NeedWidePrototypes
768 			   int is_wchar);
769 #else
770                            Boolean is_wchar);
771 #endif /* NeedWidePrototypes */
772 
773 static void InitializeTextStruct(XmTextFieldWidget tf);
774 
775 static void LoadGCs(XmTextFieldWidget tf,
776 		    Pixel background,
777 		    Pixel foreground);
778 
779 static void MakeIBeamOffArea(XmTextFieldWidget tf,
780 #if NeedWidePrototypes
781 			     int width,
782 			     int height);
783 #else
784                              Dimension width,
785                              Dimension height);
786 #endif /* NeedWidePrototypes */
787 
788 static Pixmap FindPixmap(Screen *screen,
789 			 char *image_name,
790 			 Pixel foreground,
791 			 Pixel background,
792 			 int depth);
793 
794 static void MakeIBeamStencil(XmTextFieldWidget tf,
795 			     int line_width);
796 
797 static void MakeAddModeCursor(XmTextFieldWidget tf,
798 			      int line_width);
799 
800 static void MakeCursors(XmTextFieldWidget tf);
801 
802 static void DragProcCallback(Widget w,
803 			     XtPointer client,
804 			     XtPointer call);
805 
806 static void RegisterDropSite(Widget w);
807 
808 static void Initialize(Widget request,
809 		       Widget new_w,
810 		       ArgList args,
811 		       Cardinal *num_args);
812 
813 static void Realize(Widget w,
814 		    XtValueMask *valueMask,
815 		    XSetWindowAttributes *attributes);
816 
817 static void Destroy(Widget wid);
818 
819 static void Resize(Widget w);
820 
821 static XtGeometryResult QueryGeometry(Widget w,
822 				      XtWidgetGeometry *intended,
823 				      XtWidgetGeometry *reply);
824 
825 static void TextFieldExpose(Widget w,
826 			    XEvent *event,
827 			    Region region);
828 
829 static Boolean SetValues(Widget old,
830 			 Widget request,
831 			 Widget new_w,
832 			 ArgList args,
833 			 Cardinal *num_args);
834 
835 static Boolean TextFieldGetBaselines(Widget w,
836 				     Dimension **baselines,
837 				     int *line_count);
838 
839 static Boolean TextFieldGetDisplayRect(Widget w,
840 				       XRectangle *display_rect);
841 
842 static void TextFieldMarginsProc(Widget w,
843 				 XmBaselineMargins *margins_rec);
844 
845 static XtPointer TextFieldGetValue(Widget w,
846 				   int format);
847 
848 static void TextFieldSetValue(Widget w,
849 			      XtPointer s,
850 			      int format);
851 
852 static int TextFieldPreferredValue(Widget w);
853 
854 static void CheckSetRenderTable(Widget wid,
855 				int offset,
856 				XrmValue *value);
857 
858 static Boolean TextFieldRemove(Widget w,
859 			       XEvent *event);
860 static void TextFieldReplace(Widget w,
861 			     XmTextPosition from_pos,
862 			     XmTextPosition to_pos,
863 			     char *value,
864 			     int is_wc);
865 static void CursorPosVisDefault(
866                         Widget widget,
867                         int offset,
868                         XrmValue *value) ;
869 
870 static int PreeditStart(XIC xic,
871                         XPointer client_data,
872                         XPointer call_data);
873 
874 static void PreeditDone(XIC xic,
875                         XPointer client_data,
876                         XPointer call_data);
877 
878 static void PreeditDraw(XIC xic,
879                         XPointer client_data,
880                         XIMPreeditDrawCallbackStruct *call_data);
881 
882 static void PreeditCaret(XIC xic,
883                          XPointer client_data,
884                          XIMPreeditCaretCallbackStruct *call_data);
885 
886 static void PreeditSetCursorPosition(XmTextFieldWidget tf,
887                                      XmTextPosition position);
888 
889 static void TextFieldResetIC(Widget w);
890 static void doSetHighlight(Widget w, XmTextPosition left, XmTextPosition right,
891                          XmHighlightMode mode) ;
892 static Boolean TrimHighlights(XmTextFieldWidget tf, int *low, int *high);
893 
894 static void ResetUnder(XmTextFieldWidget tf);
895 
896 /********    End Static Function Declarations    ********/
897 
898 static XmConst XmTextScanType sarray[] = {
899   XmSELECT_POSITION, XmSELECT_WORD, XmSELECT_LINE
900 };
901 
902 static XContext _XmTextFDestContext = 0;
903 
904 /* default translations and action recs */
905 static XtActionsRec text_actions[] = {
906 /* Text Replacing Bindings */
907   {"self-insert",		InsertChar},
908   {"delete-previous-character",	DeletePrevChar},
909   {"delete-next-character",	DeleteNextChar},
910   {"delete-previous-word",	DeletePrevWord},
911   {"delete-next-word",		DeleteNextWord},
912   {"delete-to-end-of-line",	DeleteToEndOfLine},
913   {"delete-to-start-of-line",	DeleteToStartOfLine},
914 /* Miscellaneous Bindings */
915   {"activate",			Activate},
916   {"process-cancel",		ProcessCancel},
917   {"process-bdrag",		ProcessBDrag},
918   {"process-bdrag-event",	ProcessBDragEvent},
919   {"process-bselect",		ProcessBSelect},
920   {"process-bselect-event",	ProcessBSelectEvent},
921 /* Motion Bindings */
922   {"backward-character",	BackwardChar},
923   {"forward-character",		ForwardChar},
924   {"backward-word",		BackwardWord},
925   {"forward-word",		ForwardWord},
926   {"end-of-line",		EndOfLine},
927   {"beginning-of-line",		BeginningOfLine},
928   {"page-left",			PageLeft},
929   {"page-right",		PageRight},
930 /* Selection Bindings */
931   {"key-select",		KeySelection},
932   {"grab-focus",		StartPrimary},
933   {"move-destination",		MoveDestination},
934   {"extend-start",		ExtendPrimary},
935   {"extend-adjust",		ExtendPrimary},
936   {"extend-end",		ExtendEnd},
937   {"delete-selection",		DeleteSelection},
938   {"clear-selection",		ClearSelection},
939   {"cut-primary",		CutPrimary},
940   {"link-primary",		LinkPrimary},
941   {"copy-primary",		CopyPrimary},
942   {"set-anchor",		SetAnchor},
943   {"toggle-overstrike",		ToggleOverstrike},
944   {"toggle-add-mode",		ToggleAddMode},
945   {"select-all",		SelectAll},
946   {"deselect-all",		DeselectAll},
947 /* Quick Cut and Paste Bindings */
948   {"secondary-start",		StartSecondary},
949   {"secondary-adjust",		ExtendSecondary},
950   {"copy-to",			ProcessCopy},
951   {"link-to",			ProcessLink},
952   {"move-to",			ProcessMove},
953   {"quick-cut-set",		VoidAction},
954   {"quick-copy-set",		VoidAction},
955   {"do-quick-action",		VoidAction},
956 /* Clipboard Bindings */
957   {"cut-clipboard",		CutClipboard},
958   {"copy-clipboard",		CopyClipboard},
959   {"paste-clipboard",		PasteClipboard},
960 /* Traversal */
961   {"traverse-next",		TraverseDown},
962   {"traverse-prev",		TraverseUp},
963   {"traverse-home",		TraverseHome},
964   {"next-tab-group",		TraverseNextTabGroup},
965   {"prev-tab-group",		TraversePrevTabGroup},
966 /* Focus */
967   {"focusIn",			TextFocusIn},
968   {"focusOut",			TextFocusOut},
969   {"enter",			TextEnter},
970   {"leave",			TextLeave},
971 };
972 
973 static XtResource resources[] =
974 {
975   {
976     XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
977     XtOffsetOf(struct _XmTextFieldRec, text.activate_callback),
978     XmRCallback, NULL
979   },
980 
981   {
982     XmNlosingFocusCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
983     XtOffsetOf(struct _XmTextFieldRec, text.losing_focus_callback),
984     XmRCallback, NULL
985   },
986 
987   {
988     XmNfocusCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
989     XtOffsetOf(struct _XmTextFieldRec, text.focus_callback),
990     XmRCallback, NULL
991   },
992 
993   {
994     XmNmodifyVerifyCallback, XmCCallback, XmRCallback,
995     sizeof(XtCallbackList),
996     XtOffsetOf(struct _XmTextFieldRec, text.modify_verify_callback),
997     XmRCallback, NULL
998   },
999 
1000   {
1001     XmNmodifyVerifyCallbackWcs, XmCCallback, XmRCallback,
1002     sizeof(XtCallbackList),
1003     XtOffsetOf(struct _XmTextFieldRec, text.wcs_modify_verify_callback),
1004     XmRCallback, NULL
1005   },
1006 
1007   {
1008     XmNmotionVerifyCallback, XmCCallback, XmRCallback,
1009     sizeof(XtCallbackList),
1010     XtOffsetOf(struct _XmTextFieldRec, text.motion_verify_callback),
1011     XmRCallback, NULL
1012   },
1013 
1014   {
1015     XmNgainPrimaryCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
1016     XtOffsetOf(struct _XmTextFieldRec, text.gain_primary_callback),
1017     XmRCallback, NULL
1018   },
1019 
1020   {
1021     XmNlosePrimaryCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
1022     XtOffsetOf(struct _XmTextFieldRec, text.lose_primary_callback),
1023     XmRCallback, NULL
1024   },
1025 
1026   {
1027     XmNvalueChangedCallback, XmCCallback, XmRCallback,
1028     sizeof(XtCallbackList),
1029     XtOffsetOf(struct _XmTextFieldRec, text.value_changed_callback),
1030     XmRCallback, NULL
1031   },
1032 
1033   {
1034     XmNdestinationCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
1035     XtOffsetOf(struct _XmTextFieldRec, text.destination_callback),
1036     XmRCallback, NULL
1037   },
1038 
1039   {
1040     XmNvalue, XmCValue, XmRString, sizeof(String),
1041     XtOffsetOf(struct _XmTextFieldRec, text.value),
1042     XmRString, ""
1043   },
1044 
1045   {
1046     XmNvalueWcs, XmCValueWcs, XmRValueWcs, sizeof(wchar_t*),
1047     XtOffsetOf(struct _XmTextFieldRec, text.wc_value),
1048     XmRString, NULL
1049   },
1050 
1051   {
1052     XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
1053     sizeof(Dimension),
1054     XtOffsetOf(struct _XmTextFieldRec, text.margin_height),
1055     XmRImmediate, (XtPointer) 5
1056   },
1057 
1058   {
1059     XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
1060     sizeof(Dimension),
1061     XtOffsetOf(struct _XmTextFieldRec, text.margin_width),
1062     XmRImmediate, (XtPointer) 5
1063   },
1064 
1065   {
1066     XmNcursorPosition, XmCCursorPosition, XmRTextPosition,
1067     sizeof (XmTextPosition),
1068     XtOffsetOf(struct _XmTextFieldRec, text.cursor_position),
1069     XmRImmediate, (XtPointer) 0
1070   },
1071 
1072   {
1073     XmNcolumns, XmCColumns, XmRShort, sizeof(short),
1074     XtOffsetOf(struct _XmTextFieldRec, text.columns),
1075     XmRImmediate, (XtPointer) 20
1076   },
1077 
1078   {
1079     XmNmaxLength, XmCMaxLength, XmRInt, sizeof(int),
1080     XtOffsetOf(struct _XmTextFieldRec, text.max_length),
1081     XmRImmediate, (XtPointer) INT_MAX
1082   },
1083 
1084   {
1085     XmNblinkRate, XmCBlinkRate, XmRInt, sizeof(int),
1086     XtOffsetOf(struct _XmTextFieldRec, text.blink_rate),
1087     XmRImmediate, (XtPointer) 500
1088   },
1089 
1090   {
1091       "pri.vate","Pri.vate",XmRBoolean,
1092       sizeof(Boolean), XtOffsetOf(struct _XmTextFieldRec,
1093 	  text.check_set_render_table),
1094 	  XmRImmediate, (XtPointer) False
1095   },
1096 
1097   {
1098     XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
1099     XtOffsetOf(struct _XmTextFieldRec, text.font_list),
1100     XmRCallProc, (XtPointer)CheckSetRenderTable
1101   },
1102 
1103   {
1104     XmNrenderTable, XmCRenderTable, XmRRenderTable, sizeof(XmRenderTable),
1105     XtOffsetOf(struct _XmTextFieldRec, text.font_list),
1106     XmRCallProc, (XtPointer)CheckSetRenderTable
1107   },
1108 
1109   {
1110     XmNselectionArray, XmCSelectionArray, XmRPointer,
1111     sizeof(XtPointer),
1112     XtOffsetOf(struct _XmTextFieldRec, text.selection_array),
1113     XmRImmediate, (XtPointer) sarray
1114   },
1115 
1116   {
1117     XmNselectionArrayCount, XmCSelectionArrayCount, XmRInt, sizeof(int),
1118     XtOffsetOf(struct _XmTextFieldRec, text.selection_array_count),
1119     XmRImmediate, (XtPointer) XtNumber(sarray)
1120   },
1121 
1122   {
1123     XmNresizeWidth, XmCResizeWidth, XmRBoolean, sizeof(Boolean),
1124     XtOffsetOf(struct _XmTextFieldRec, text.resize_width),
1125     XmRImmediate, (XtPointer) False
1126   },
1127 
1128   {
1129     XmNpendingDelete, XmCPendingDelete, XmRBoolean, sizeof(Boolean),
1130     XtOffsetOf(struct _XmTextFieldRec, text.pending_delete),
1131     XmRImmediate, (XtPointer) True
1132   },
1133 
1134   {
1135     XmNeditable, XmCEditable, XmRBoolean, sizeof(Boolean),
1136     XtOffsetOf(struct _XmTextFieldRec, text.editable),
1137     XmRImmediate, (XtPointer) True
1138   },
1139 
1140   {
1141     XmNcursorPositionVisible, XmCCursorPositionVisible, XmRBoolean,
1142     sizeof(Boolean),
1143     XtOffsetOf(struct _XmTextFieldRec, text.cursor_position_visible),
1144     XmRCallProc, (XtPointer) CursorPosVisDefault
1145   },
1146 
1147  {
1148    XmNverifyBell, XmCVerifyBell, XmRBoolean, sizeof(Boolean),
1149    XtOffsetOf(struct _XmTextFieldRec, text.verify_bell),
1150    XmRImmediate, (XtPointer) XmDYNAMIC_BOOL
1151  },
1152 
1153  {
1154    XmNselectThreshold, XmCSelectThreshold, XmRInt, sizeof(int),
1155    XtOffsetOf(struct _XmTextFieldRec, text.threshold),
1156    XmRImmediate, (XtPointer) 5
1157  },
1158 
1159  {
1160    XmNnavigationType, XmCNavigationType, XmRNavigationType,
1161    sizeof (unsigned char),
1162    XtOffsetOf(struct _XmPrimitiveRec, primitive.navigation_type),
1163    XmRImmediate, (XtPointer) XmTAB_GROUP
1164  }
1165 };
1166 
1167 /* Definition for resources that need special processing in get values */
1168 
1169 static XmSyntheticResource syn_resources[] =
1170 {
1171  {
1172    XmNmarginWidth,
1173    sizeof(Dimension),
1174    XtOffsetOf(struct _XmTextFieldRec, text.margin_width),
1175    XmeFromHorizontalPixels,
1176    XmeToHorizontalPixels
1177  },
1178 
1179  {
1180    XmNmarginHeight,
1181    sizeof(Dimension),
1182    XtOffsetOf(struct _XmTextFieldRec, text.margin_height),
1183    XmeFromVerticalPixels,
1184    XmeToVerticalPixels
1185  },
1186 
1187  {
1188    XmNvalue,
1189    sizeof(char *),
1190    XtOffsetOf(struct _XmTextFieldRec, text.value),
1191    MakeCopy,
1192  },
1193 
1194  {
1195    XmNvalueWcs,
1196    sizeof(wchar_t *),
1197    XtOffsetOf(struct _XmTextFieldRec, text.wc_value),
1198    WcsMakeCopy,
1199  }
1200 
1201 };
1202 
1203 static XmPrimitiveClassExtRec _XmTextFPrimClassExtRec = {
1204   NULL,
1205   NULLQUARK,
1206   XmPrimitiveClassExtVersion,
1207   sizeof(XmPrimitiveClassExtRec),
1208   TextFieldGetBaselines,                  /* widget_baseline */
1209   TextFieldGetDisplayRect,               /* widget_display_rect */
1210   TextFieldMarginsProc,                  /* get/set widget margins */
1211 };
1212 
1213 
1214 externaldef(xmtextfieldclassrec) XmTextFieldClassRec xmTextFieldClassRec =
1215 {
1216   {
1217     (WidgetClass) &xmPrimitiveClassRec,		/* superclass         */
1218     "XmTextField",				/* class_name         */
1219     sizeof(XmTextFieldRec),		        /* widget_size        */
1220     ClassInitialize,				/* class_initialize   */
1221     ClassPartInitialize,			/* class_part_initiali*/
1222     FALSE,					/* class_inited       */
1223     Initialize,					/* initialize         */
1224     (XtArgsProc)NULL,				/* initialize_hook    */
1225     Realize,					/* realize            */
1226     text_actions,				/* actions            */
1227     XtNumber(text_actions),			/* num_actions        */
1228     resources,					/* resources          */
1229     XtNumber(resources),			/* num_resources      */
1230     NULLQUARK,					/* xrm_class          */
1231     TRUE,					/* compress_motion    */
1232     XtExposeCompressMaximal |			/* compress_exposure  */
1233       XtExposeNoRegion,
1234     TRUE,					/* compress_enterleave*/
1235     FALSE,					/* visible_interest   */
1236     Destroy,					/* destroy            */
1237     Resize,					/* resize             */
1238     TextFieldExpose,				/* expose             */
1239     SetValues,					/* set_values         */
1240     (XtArgsFunc)NULL,				/* set_values_hook    */
1241     XtInheritSetValuesAlmost,			/* set_values_almost  */
1242     (XtArgsProc)NULL,				/* get_values_hook    */
1243     (XtAcceptFocusProc)NULL,			/* accept_focus       */
1244     XtVersion,					/* version            */
1245     NULL,					/* callback_private   */
1246     NULL,					/* tm_table           */
1247     QueryGeometry,				/* query_geometry     */
1248     (XtStringProc)NULL,				/* display accel      */
1249     NULL,					/* extension          */
1250   },
1251 
1252   {	                          		/* Xmprimitive        */
1253     XmInheritBorderHighlight,        		/* border_highlight   */
1254     XmInheritBorderUnhighlight,              	/* border_unhighlight */
1255     NULL,					/* translations	      */
1256     (XtActionProc)NULL,             		/* arm_and_activate   */
1257     syn_resources,            			/* syn resources      */
1258     XtNumber(syn_resources),  			/* num syn_resources  */
1259     (XtPointer) &_XmTextFPrimClassExtRec,	/* extension          */
1260   },
1261 
1262   {                         			/* text class         */
1263     NULL,                     			/* extension          */
1264   }
1265 };
1266 
1267 externaldef(xmtextfieldwidgetclass) WidgetClass xmTextFieldWidgetClass =
1268 					 (WidgetClass) &xmTextFieldClassRec;
1269 
1270 /* AccessXmString Trait record for TextField */
1271 static XmConst XmAccessTextualTraitRec textFieldCS = {
1272   0,  				/* version */
1273   TextFieldGetValue,
1274   TextFieldSetValue,
1275   TextFieldPreferredValue,
1276 };
1277 
1278 static void
ClassInitialize(void)1279 ClassInitialize(void)
1280 {
1281   _XmTextFieldInstallTransferTrait();
1282   XmeTraitSet((XtPointer)xmTextFieldWidgetClass, XmQTaccessTextual,
1283 	      (XtPointer) &textFieldCS);
1284 }
1285 
1286 /*********************************************************************
1287  *
1288  * CursorPosVisDefault
1289  *
1290  *
1291  *********************************************************************/
1292 /*ARGSUSED*/
1293 static void
CursorPosVisDefault(Widget widget,int offset,XrmValue * value)1294 CursorPosVisDefault(
1295         Widget widget,
1296         int offset,		/* unused */
1297         XrmValue *value )
1298 {
1299       static Boolean cursor_pos_vis ;
1300       Widget print_shell ;
1301 
1302       value->addr = (XPointer) &cursor_pos_vis;
1303 
1304       print_shell = widget ;
1305       while(print_shell && !XmIsPrintShell(print_shell))
1306 	  print_shell = XtParent(print_shell);
1307 
1308       if (print_shell) cursor_pos_vis = False ;
1309       else             cursor_pos_vis = True ;
1310 }
1311 
1312 
1313 /* USE ITERATIONS OF mblen TO COUNT THE NUMBER OF CHARACTERS REPRESENTED
1314  * BY n_bytes BYTES POINTED TO BY ptr, a pointer to char*.
1315  * n_bytes does not include NULL terminator (if any), nor does return.
1316  */
1317 /* ARGSUSED */
1318 int
_XmTextFieldCountCharacters(XmTextFieldWidget tf,char * ptr,int n_bytes)1319 _XmTextFieldCountCharacters(XmTextFieldWidget tf,
1320 			    char *ptr,
1321 			    int n_bytes)
1322 {
1323   char * bptr;
1324   int count = 0;
1325 #ifndef NO_MULTIBYTE
1326   int char_size = 0;
1327 #else
1328   int char_size = 1;
1329 #endif
1330 
1331   if (n_bytes <= 0 || ptr == NULL || *ptr == '\0')
1332     return 0;
1333 
1334   if (tf->text.max_char_size == 1)
1335     return n_bytes;
1336 
1337   bptr = ptr;
1338 
1339 #ifndef NO_MULTIBYTE
1340   for (bptr = ptr; n_bytes > 0; count++, bptr+= char_size) {
1341     char_size = mblen(bptr, tf->text.max_char_size);
1342     if (char_size <= 0) break; /* error */
1343     n_bytes -= char_size;
1344   }
1345 #else
1346   while (*bptr++ && n_bytes--)
1347     count++;
1348 #endif
1349   return count;
1350 }
1351 
1352 /* USE ITERATIONS OF wctomb TO COUNT THE NUMBER OF BYTES REQUIRED FOR THE
1353  * MULTI-BYTE REPRESENTION OF num_chars WIDE CHARACTERS IN wc_value.
1354  * COUNT TERMINATED IF NULL ENCOUNTERED IN THE STRING.
1355  * NUMBER OF BYTES IS RETURNED.
1356  */
1357 /* ARGSUSED */
1358 int
_XmTextFieldCountBytes(XmTextFieldWidget tf,wchar_t * wc_value,int num_chars)1359 _XmTextFieldCountBytes(XmTextFieldWidget tf,
1360 		       wchar_t * wc_value,
1361 		       int num_chars)
1362 {
1363   wchar_t 	* wc_ptr;
1364   char 	tmp[MB_LEN_MAX];  /* defined in limits.h: max in any locale */
1365   int 	n_bytes = 0;
1366   int   n_bytes_per_char = 0;
1367 
1368   if (num_chars <= 0 || wc_value == NULL || *wc_value == (wchar_t)0L)
1369     return 0;
1370 
1371   if (tf->text.max_char_size == 1)
1372     return num_chars;
1373 
1374   wc_ptr = wc_value;
1375   while ((num_chars > 0) && (*wc_ptr != (wchar_t)0L)) {
1376     n_bytes_per_char = wctomb(tmp, *wc_ptr);
1377     if (n_bytes_per_char > 0 )
1378       n_bytes += n_bytes_per_char;
1379     num_chars--;
1380     wc_ptr++;
1381   }
1382   return n_bytes;
1383 }
1384 
1385 /*ARGSUSED*/
1386 static void
MakeCopy(Widget w,int n,XtArgVal * value)1387 MakeCopy(Widget w,
1388 	 int n,
1389 	 XtArgVal *value)
1390 {
1391   (*value) = (XtArgVal) XmTextFieldGetString (w);
1392 }
1393 
1394 /*ARGSUSED*/
1395 static void
WcsMakeCopy(Widget w,int n,XtArgVal * value)1396 WcsMakeCopy(Widget w,
1397 	    int n,
1398 	    XtArgVal *value)
1399 {
1400   (*value) = (XtArgVal) XmTextFieldGetStringWcs (w);
1401 }
1402 
1403 /*ARGSUSED*/
1404 static void
FreeContextData(Widget w,XtPointer clientData,XtPointer callData)1405 FreeContextData(Widget w,		/* unused */
1406 		XtPointer clientData,
1407 		XtPointer callData)	/* unused */
1408 {
1409   XmTextContextData ctx_data = (XmTextContextData) clientData;
1410   Display *display = DisplayOfScreen(ctx_data->screen);
1411   XtPointer data_ptr;
1412 
1413   if (XFindContext(display, (Window) ctx_data->screen,
1414 		   ctx_data->context, (char **) &data_ptr)) {
1415 
1416     if (ctx_data->type != '\0') {
1417       if (data_ptr)
1418 	XtFree((char *) data_ptr);
1419     }
1420 
1421     XDeleteContext (display, (Window) ctx_data->screen, ctx_data->context);
1422   }
1423 
1424   XtFree ((char *) ctx_data);
1425 }
1426 
1427 static TextFDestData
GetTextFDestData(Widget w)1428 GetTextFDestData(Widget w)
1429 {
1430   TextFDestData dest_data;
1431   Display *display = XtDisplay(w);
1432   Screen *screen = XtScreen(w);
1433   XContext loc_context;
1434 
1435   _XmProcessLock();
1436   if (_XmTextFDestContext == 0)
1437     _XmTextFDestContext = XUniqueContext();
1438   loc_context = _XmTextFDestContext;
1439   _XmProcessUnlock();
1440 
1441   if (XFindContext(display, (Window) screen,
1442 		   loc_context, (char **) &dest_data)) {
1443     XmTextContextData ctx_data;
1444     Widget xm_display = (Widget) XmGetXmDisplay(display);
1445 
1446     ctx_data = (XmTextContextData) XtMalloc(sizeof(XmTextContextDataRec));
1447 
1448     ctx_data->screen = screen;
1449     ctx_data->context = loc_context;
1450     ctx_data->type = _XM_IS_DEST_CTX;
1451 
1452     dest_data = (TextFDestData) XtCalloc((unsigned)sizeof(TextFDestDataRec),
1453 					 (unsigned) 1);
1454 
1455     XtAddCallback(xm_display, XmNdestroyCallback,
1456 		  (XtCallbackProc) FreeContextData, (XtPointer) ctx_data);
1457 
1458     XSaveContext(XtDisplay(w), (Window) screen,
1459 		 loc_context, (XPointer)dest_data);
1460   }
1461 
1462   return dest_data;
1463 }
1464 
1465 void
_XmTextFToggleCursorGC(Widget widget)1466 _XmTextFToggleCursorGC(Widget widget)
1467 {
1468   XmTextFieldWidget tf = (XmTextFieldWidget) widget;
1469   XGCValues values;
1470   unsigned long valueMask;
1471   Pixmap stipple = XmUNSPECIFIED_PIXMAP;
1472 
1473   SetFullGC(tf, tf->text.image_gc);
1474   ResetClipOrigin(tf);
1475 
1476   if (!XtIsRealized(widget)) return;
1477 
1478 #ifdef FIX_1501
1479   if (!XtIsSensitive((Widget)tf)) {
1480     valueMask = GCForeground|GCBackground|GCFillStyle|GCStipple|GCFunction;
1481     values.foreground = _XmAssignInsensitiveColor((Widget)tf);
1482     values.background = tf->core.background_pixel;
1483     values.fill_style = FillStippled;
1484 
1485     if (tf->text.overstrike) {
1486       if (tf->text.stipple_tile == XmUNSPECIFIED_PIXMAP) return;
1487       values.stipple = tf->text.stipple_tile;
1488       values.function = GXxor;
1489     } else {
1490       if (tf->text.cursor == XmUNSPECIFIED_PIXMAP) return;
1491       values.stipple = tf->text.cursor;
1492       values.function = GXcopy;
1493     }
1494   } else {
1495 #endif
1496   if (tf->text.overstrike) {
1497     valueMask = GCFillStyle|GCFunction|GCForeground|GCBackground;
1498     if (!tf->text.add_mode && XtIsSensitive(widget) &&
1499 	(tf->text.has_focus || tf->text.has_destination)) {
1500       values.fill_style = FillSolid;
1501     } else {
1502       valueMask |= GCStipple;
1503       values.fill_style = FillStippled;
1504       values.stipple = tf->text.stipple_tile;
1505     }
1506     values.foreground = values.background =
1507       tf->primitive.foreground ^ tf->core.background_pixel;
1508     values.function = GXxor;
1509   } else {
1510     valueMask = GCStipple;
1511     if (XGetGCValues(XtDisplay(widget), tf->text.image_gc,
1512 		     valueMask, &values))
1513       stipple = values.stipple;
1514     valueMask = GCFillStyle|GCFunction|GCForeground|GCBackground;
1515     if (XtIsSensitive(widget) && !tf->text.add_mode &&
1516 	(tf->text.has_focus || tf->text.has_destination)) {
1517       if (tf->text.cursor == XmUNSPECIFIED_PIXMAP) return;
1518       if (stipple != tf->text.cursor) {
1519 	values.stipple = tf->text.cursor;
1520 	valueMask |= GCStipple;
1521       }
1522     } else {
1523       if (tf->text.add_mode_cursor == XmUNSPECIFIED_PIXMAP) return;
1524       if (stipple != tf->text.add_mode_cursor) {
1525 	values.stipple = tf->text.add_mode_cursor;
1526 	valueMask |= GCStipple;
1527       }
1528     }
1529     values.fill_style = FillStippled;
1530     values.function = GXcopy;
1531     if (tf->text.have_inverted_image_gc) {
1532       values.background = tf->primitive.foreground;
1533       values.foreground = tf->core.background_pixel;
1534     } else {
1535       values.foreground = tf->primitive.foreground;
1536       values.background = tf->core.background_pixel;
1537     }
1538   }
1539 #ifdef FIX_1501
1540   }
1541 #endif
1542   XSetClipMask(XtDisplay(widget), tf->text.save_gc, None);
1543   XChangeGC(XtDisplay(widget), tf->text.image_gc, valueMask, &values);
1544 }
1545 
1546 /*
1547  * Find the highlight record corresponding to the given position.  Returns a
1548  * pointer to the record.  The third argument indicates whether we are probing
1549  * the left or right edge of a highlighting range.
1550  */
1551 static _XmHighlightRec *
FindHighlight(XmTextFieldWidget w,XmTextPosition position)1552 FindHighlight(XmTextFieldWidget w,
1553 	      XmTextPosition position)
1554 {
1555   _XmHighlightRec *l = w->text.highlight.list;
1556   int i;
1557 
1558   for (i=w->text.highlight.number - 1; i>=0; i--)
1559     if (position >= l[i].position) {
1560       l = l + i;
1561       break;
1562     }
1563 
1564   return(l);
1565 }
1566 
1567 static void
InsertHighlight(XmTextFieldWidget w,XmTextPosition position,XmHighlightMode mode)1568 InsertHighlight(XmTextFieldWidget w,
1569 		XmTextPosition position,
1570 		XmHighlightMode mode)
1571 {
1572   _XmHighlightRec *l1;
1573   _XmHighlightRec *l = w->text.highlight.list;
1574   int i, j;
1575 
1576   l1 = FindHighlight(w, position);
1577   if (l1->position == position)
1578     l1->mode = mode;
1579   else {
1580     i = (l1 - l) + 1;
1581     w->text.highlight.number++;
1582     if (w->text.highlight.number > w->text.highlight.maximum) {
1583       w->text.highlight.maximum = w->text.highlight.number;
1584       l = w->text.highlight.list = (_XmHighlightRec *)
1585 	XtRealloc((char *) l, (unsigned)(w->text.highlight.maximum *
1586 					 sizeof(_XmHighlightRec)));
1587     }
1588     for (j=w->text.highlight.number-1; j>i; j--)
1589       l[j] = l[j-1];
1590     l[i].position = position;
1591     l[i].mode = mode;
1592   }
1593 }
1594 
1595 static void
TextFieldSetHighlight(XmTextFieldWidget tf,XmTextPosition left,XmTextPosition right,XmHighlightMode mode)1596 TextFieldSetHighlight(XmTextFieldWidget tf,
1597 		      XmTextPosition left,
1598 		      XmTextPosition right,
1599 		      XmHighlightMode mode)
1600 {
1601   _XmHighlightRec *l;
1602   XmHighlightMode endmode;
1603   int i, j;
1604 
1605   if (left >= right || right <= 0) return;
1606 
1607   _XmTextFieldDrawInsertionPoint(tf, False);
1608   endmode = FindHighlight(tf, right)->mode;
1609   InsertHighlight(tf, left, mode);
1610   InsertHighlight(tf, right, endmode);
1611   l = tf->text.highlight.list;
1612   i = 1;
1613   while (i < tf->text.highlight.number) {
1614     if (l[i].position >= left && l[i].position < right)
1615       l[i].mode = mode;
1616     if (l[i].mode == l[i-1].mode) {
1617       tf->text.highlight.number--;
1618       for (j=i; j<tf->text.highlight.number; j++)
1619 	l[j] = l[j+1];
1620     } else i++;
1621   }
1622   if (TextF_CursorPosition(tf) > left && TextF_CursorPosition(tf) < right) {
1623     if (mode == XmHIGHLIGHT_SELECTED) {
1624       InvertImageGC(tf);
1625     } else if (mode != XmHIGHLIGHT_SELECTED) {
1626       ResetImageGC(tf);
1627     }
1628   }
1629   tf->text.refresh_ibeam_off = True;
1630   _XmTextFieldDrawInsertionPoint(tf, True);
1631 }
1632 
1633 /*
1634  * Get x and y based on position.
1635  */
1636 static Boolean
GetXYFromPos(XmTextFieldWidget tf,XmTextPosition position,Position * x,Position * y)1637 GetXYFromPos(XmTextFieldWidget tf,
1638 	     XmTextPosition position,
1639 	     Position *x,
1640 	     Position *y)
1641 {
1642   /* initialize the x and y positions to zero */
1643   *x = 0;
1644   *y = 0;
1645 
1646   if (position > tf->text.string_length) return False;
1647 
1648   if (tf->text.max_char_size != 1) {
1649     *x += FindPixelLength(tf, (char*)TextF_WcValue(tf), (int)position);
1650   } else {
1651     *x += FindPixelLength(tf, TextF_Value(tf), (int)position);
1652   }
1653 
1654   *y += tf->primitive.highlight_thickness + tf->primitive.shadow_thickness
1655     + tf->text.margin_top + TextF_FontAscent(tf);
1656   *x += (Position) tf->text.h_offset;
1657 
1658   return True;
1659 }
1660 
1661 static Boolean
CurrentCursorState(XmTextFieldWidget tf)1662 CurrentCursorState(XmTextFieldWidget tf)
1663 {
1664   if (tf->text.cursor_on < 0) return False;
1665   if (tf->text.blink_on || !XtIsSensitive((Widget)tf))
1666     return True;
1667   return False;
1668 }
1669 
1670 /*
1671  * Paint insert cursor
1672  */
1673 static void
PaintCursor(XmTextFieldWidget tf)1674 PaintCursor(XmTextFieldWidget tf)
1675 {
1676   Position x, y;
1677   XmTextPosition position;
1678 
1679   if (!TextF_CursorPositionVisible(tf)) return;
1680 
1681   _XmTextFToggleCursorGC((Widget)tf);
1682 
1683   position = TextF_CursorPosition(tf);
1684   (void) GetXYFromPos(tf, position, &x, &y);
1685 
1686   if (!tf->text.overstrike)
1687     x -=(tf->text.cursor_width >> 1) + 1; /* "+1" for 1 pixel left of char */
1688   else {
1689     int pxlen;
1690     if (tf->text.max_char_size != 1)
1691       pxlen = FindPixelLength(tf, (char*)&(TextF_WcValue(tf)[position]), 1);
1692     else
1693       pxlen = FindPixelLength(tf, &(TextF_Value(tf)[position]), 1);
1694     if (pxlen > tf->text.cursor_width)
1695       x += (pxlen - tf->text.cursor_width) >> 1;
1696   }
1697   y = (y + (Position) TextF_FontDescent(tf)) -
1698     (Position) tf->text.cursor_height;
1699 
1700   /* If time to paint the I Beam... first capture the IBeamOffArea, then draw
1701    * the IBeam */
1702 
1703   if (tf->text.refresh_ibeam_off == True) { /* get area under IBeam first */
1704     /* Fill is needed to realign clip rectangle with gc */
1705     XFillRectangle(XtDisplay((Widget)tf), XtWindow((Widget)tf),
1706 		   tf->text.save_gc, 0, 0, 0, 0);
1707     XCopyArea(XtDisplay(tf), XtWindow(tf), tf->text.ibeam_off,
1708 	      tf->text.save_gc, x, y, tf->text.cursor_width,
1709 	      tf->text.cursor_height, 0, 0);
1710     tf->text.refresh_ibeam_off = False;
1711   }
1712 
1713     /* redraw cursor, being very sure to keep it within the bounds of the
1714     ** text area, not spilling into the highlight area
1715     */
1716   {
1717   int cursor_width = tf->text.cursor_width;
1718   int cursor_height = tf->text.cursor_height;
1719   if ((tf->text.cursor_on >= 0) && tf->text.blink_on) {
1720         if ((int)(x + tf->text.cursor_width) > (int)(tf->core.width -
1721 		 tf->primitive.shadow_thickness -
1722 		 tf->primitive.highlight_thickness))
1723           cursor_width = (tf->core.width -
1724                                  (tf->primitive.shadow_thickness +
1725                                  tf->primitive.highlight_thickness)) - x;
1726 #ifdef FIX_1501
1727         if (cursor_width > 0 && cursor_height > 0) {
1728           if (!XtIsSensitive((Widget) tf)) {
1729             SetShadowGC(tf, tf->text.image_gc);
1730             XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.image_gc, x + 1, y + 1,
1731                            (unsigned int) cursor_width, (unsigned int) cursor_height);
1732           }
1733           _XmTextFToggleCursorGC((Widget) tf);
1734 #else
1735            if ( cursor_width > 0 && cursor_height > 0 )
1736 #endif
1737     		XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.image_gc, x, y,
1738 		   cursor_width, cursor_height);
1739 #ifdef FIX_1501
1740 	    }
1741 #endif
1742   } else {
1743         Position src_x = 0;
1744         if ((int)(x + tf->text.cursor_width) > (int)(tf->core.width -
1745                             tf->primitive.shadow_thickness -
1746                             tf->primitive.highlight_thickness)) {
1747           cursor_width = (tf->core.width -
1748                                  (tf->primitive.shadow_thickness +
1749                                  tf->primitive.highlight_thickness)) - x;
1750         }
1751          else if (x < (Position)(tf->primitive.highlight_thickness +
1752                                  tf->primitive.shadow_thickness)) {
1753              cursor_width = tf->text.cursor_width -
1754                                  (tf->primitive.highlight_thickness +
1755                                  tf->primitive.shadow_thickness - x);
1756              src_x = tf->text.cursor_width - cursor_width;
1757              x = tf->primitive.highlight_thickness +
1758                                  tf->primitive.shadow_thickness;
1759          }
1760         if ((int)(y + tf->text.cursor_height) > (int)(tf->core.height -
1761                                  (tf->primitive.highlight_thickness +
1762                                  tf->primitive.shadow_thickness))) {
1763           cursor_height = tf->text.cursor_height -
1764                                  ((y + tf->text.cursor_height) -
1765                                  (tf->core.height -
1766                                  (tf->primitive.highlight_thickness +
1767                                  tf->primitive.shadow_thickness)));
1768         }
1769            if (cursor_width > 0 && cursor_height > 0)
1770   	  	XCopyArea(XtDisplay(tf), tf->text.ibeam_off, XtWindow(tf),
1771           tf->text.save_gc, src_x, 0, cursor_width,
1772           cursor_height, x, y);
1773   	}
1774   }
1775 }
1776 
1777 void
_XmTextFieldDrawInsertionPoint(XmTextFieldWidget tf,int turn_on)1778 _XmTextFieldDrawInsertionPoint(XmTextFieldWidget tf,
1779 #if NeedWidePrototypes
1780 			       int turn_on)
1781 #else
1782                                Boolean turn_on)
1783 #endif /* NeedWidePrototypes */
1784 {
1785 
1786   if (turn_on == True) {
1787     tf->text.cursor_on += 1;
1788     if (TextF_BlinkRate(tf) == 0 || !tf->text.has_focus)
1789       tf->text.blink_on = True;
1790   } else {
1791     if (tf->text.blink_on && (tf->text.cursor_on == 0))
1792       if (tf->text.blink_on == CurrentCursorState(tf) &&
1793 	  XtIsRealized((Widget)tf)) {
1794 	tf->text.blink_on = !tf->text.blink_on;
1795 	PaintCursor(tf);
1796       }
1797     tf->text.cursor_on -= 1;
1798   }
1799 
1800   if (tf->text.cursor_on < 0 || !XtIsRealized((Widget) tf))
1801     return;
1802 
1803   PaintCursor(tf);
1804 }
1805 
1806 static void
BlinkInsertionPoint(XmTextFieldWidget tf)1807 BlinkInsertionPoint(XmTextFieldWidget tf)
1808 {
1809   if ((tf->text.cursor_on >= 0) &&
1810       (tf->text.blink_on == CurrentCursorState(tf)) &&
1811       XtIsRealized((Widget)tf)) {
1812     tf->text.blink_on = !tf->text.blink_on;
1813     PaintCursor(tf);
1814   }
1815 }
1816 
1817 
1818 
1819 /*
1820  * Handle blink on and off
1821  */
1822 /* ARGSUSED */
1823 static void
HandleTimer(XtPointer closure,XtIntervalId * id)1824 HandleTimer(XtPointer closure,
1825 	    XtIntervalId *id)
1826 {
1827   XmTextFieldWidget tf = (XmTextFieldWidget) closure;
1828 
1829   if (TextF_BlinkRate(tf) != 0)
1830     tf->text.timer_id =
1831       XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tf),
1832 		      (unsigned long)TextF_BlinkRate(tf),
1833 		      HandleTimer,
1834 		      (XtPointer) closure);
1835   if (tf->text.has_focus && XtIsSensitive((Widget)tf)) BlinkInsertionPoint(tf);
1836 }
1837 
1838 
1839 /*
1840  * Change state of blinking insert cursor on and off
1841  */
1842 static void
ChangeBlinkBehavior(XmTextFieldWidget tf,int turn_on)1843 ChangeBlinkBehavior(XmTextFieldWidget tf,
1844 #if NeedWidePrototypes
1845 		    int turn_on)
1846 #else
1847                     Boolean turn_on)
1848 #endif /* NeedWidePrototypes */
1849 {
1850 
1851   if (turn_on) {
1852     if (TextF_BlinkRate(tf) != 0 && tf->text.timer_id == (XtIntervalId)0)
1853       tf->text.timer_id =
1854 	XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tf),
1855 			(unsigned long)TextF_BlinkRate(tf),
1856 			HandleTimer,
1857 			(XtPointer) tf);
1858     tf->text.blink_on = True;
1859   } else {
1860     if (tf->text.timer_id)
1861       XtRemoveTimeOut(tf->text.timer_id);
1862     tf->text.timer_id = (XtIntervalId)0;
1863   }
1864 }
1865 
1866 static void
GetRect(XmTextFieldWidget tf,XRectangle * rect)1867 GetRect(XmTextFieldWidget tf,
1868         XRectangle *rect)
1869 {
1870   Dimension margin_width = TextF_MarginWidth(tf) +
1871     tf->primitive.shadow_thickness +
1872       tf->primitive.highlight_thickness;
1873   Dimension margin_top = tf->text.margin_top + tf->primitive.shadow_thickness +
1874     tf->primitive.highlight_thickness;
1875   Dimension margin_bottom = tf->text.margin_bottom +
1876     tf->primitive.shadow_thickness +
1877       tf->primitive.highlight_thickness;
1878 
1879   if (margin_width < tf->core.width)
1880     rect->x = margin_width;
1881   else
1882     rect->x = tf->core.width;
1883 
1884   if (margin_top  < tf->core.height)
1885     rect->y = margin_top;
1886   else
1887     rect->y = tf->core.height;
1888 
1889   if ((Dimension)(2 * margin_width) < tf->core.width)
1890     rect->width = (int) tf->core.width - (2 * margin_width);
1891   else
1892     rect->width = 0;
1893 
1894   if ((Dimension)(margin_top + margin_bottom) < tf->core.height)
1895     rect->height = (int) tf->core.height - (margin_top + margin_bottom);
1896   else
1897     rect->height = 0;
1898 }
1899 
1900 static void
SetFullGC(XmTextFieldWidget tf,GC gc)1901 SetFullGC(XmTextFieldWidget tf,
1902 	    GC gc)
1903 {
1904   XRectangle ClipRect;
1905 
1906   /* adjust clip rectangle to allow the cursor to paint into the margins */
1907   ClipRect.x = tf->primitive.shadow_thickness +
1908     tf->primitive.highlight_thickness;
1909   ClipRect.y = tf->primitive.shadow_thickness +
1910     tf->primitive.highlight_thickness;
1911   ClipRect.width = tf->core.width - (2 * (tf->primitive.shadow_thickness +
1912                                           tf->primitive.highlight_thickness));
1913   ClipRect.height = tf->core.height - (2 *(tf->primitive.shadow_thickness +
1914 					   tf->primitive.highlight_thickness));
1915 
1916   XSetClipRectangles(XtDisplay(tf), gc, 0, 0, &ClipRect, 1,
1917                      Unsorted);
1918 }
1919 
1920 static void
SetMarginGC(XmTextFieldWidget tf,GC gc)1921 SetMarginGC(XmTextFieldWidget tf,
1922 	      GC gc)
1923 {
1924   XRectangle ClipRect;
1925 
1926   GetRect(tf, &ClipRect);
1927 
1928 #ifdef USE_XFT
1929   if (TextF_UseXft(tf))
1930     _XmXftSetClipRectangles(XtDisplay(tf), XtWindow(tf), 0, 0, &ClipRect, 1);
1931 #endif
1932   XSetClipRectangles(XtDisplay(tf), gc, 0, 0, &ClipRect, 1,
1933                      Unsorted);
1934 }
1935 
1936 
1937 /*
1938  * Set new clipping rectangle for text field.  This is
1939  * done on each focus in event since the text field widgets
1940  * share the same GC.
1941  */
1942 void
_XmTextFieldSetClipRect(XmTextFieldWidget tf)1943 _XmTextFieldSetClipRect(XmTextFieldWidget tf)
1944 {
1945   XGCValues values;
1946   unsigned long valueMask = (unsigned long) 0;
1947 
1948   SetMarginGC(tf, tf->text.gc);
1949 
1950   /* Restore cached text gc to state correct for this instantiation */
1951 
1952   if (tf->text.gc) {
1953 #if USE_XFT
1954     if (!TextF_UseFontSet(tf) && !TextF_UseXft(tf) && (TextF_Font(tf) != NULL)) {
1955 #else
1956     if (!TextF_UseFontSet(tf) && (TextF_Font(tf) != NULL)) {
1957 #endif
1958       valueMask |= GCFont;
1959       values.font = TextF_Font(tf)->fid;
1960     }
1961     values.foreground = tf->primitive.foreground ^ tf->core.background_pixel;
1962     values.background = 0;
1963     XChangeGC(XtDisplay(tf), tf->text.gc, valueMask, &values);
1964   }
1965 }
1966 
1967 static void
1968 SetNormGC(XmTextFieldWidget tf,
1969 	    GC gc,
1970 #if NeedWidePrototypes
1971 	    int change_stipple,
1972 	    int stipple)
1973 #else
1974             Boolean change_stipple,
1975             Boolean stipple)
1976 #endif /* NeedWidePrototypes */
1977 {
1978   unsigned long valueMask = (GCForeground | GCBackground);
1979   XGCValues values;
1980 
1981   _XmTextFieldSetClipRect(tf);
1982   values.foreground = tf->primitive.foreground;
1983   values.background = tf->core.background_pixel;
1984 
1985   if (change_stipple) {
1986     valueMask |= GCFillStyle;
1987     if (stipple) {
1988 #ifdef FIX_1381
1989       /*generally gray insensitive foreground (instead stipple)*/
1990 		  values.foreground = _XmAssignInsensitiveColor((Widget)tf);
1991     	  values.fill_style = FillSolid;
1992 #else
1993       values.fill_style = FillStippled;
1994       valueMask |= GCStipple;
1995       values.stipple = tf->text.stipple_tile;
1996 #endif
1997     } else
1998       values.fill_style = FillSolid;
1999   }
2000 
2001   XChangeGC(XtDisplay(tf), gc, valueMask, &values);
2002 }
2003 
2004 #ifdef FIX_1381
2005 static void
2006 SetShadowGC(XmTextFieldWidget tf, GC gc)
2007 {
2008   unsigned long valueMask = (GCForeground | GCBackground);
2009   XGCValues values;
2010 
2011   values.foreground = tf->primitive.top_shadow_color;
2012   values.background = tf->core.background_pixel;
2013 
2014   XChangeGC(XtDisplay(tf), gc, valueMask, &values);
2015 }
2016 #endif
2017 
2018 static void
2019 SetInvGC(XmTextFieldWidget tf,
2020 	   GC gc)
2021 {
2022   unsigned long valueMask = (GCForeground | GCBackground);
2023   XGCValues values;
2024 
2025   _XmTextFieldSetClipRect(tf);
2026   values.foreground = tf->core.background_pixel;
2027   values.background = tf->primitive.foreground;
2028 
2029   XChangeGC(XtDisplay(tf), gc, valueMask, &values);
2030 }
2031 
2032 static void
2033 DrawText(XmTextFieldWidget tf,
2034 	 GC  gc,
2035 	 int x,
2036 	 int y,
2037 	 char * string,
2038 	 int length)
2039 {
2040   if (TextF_UseFontSet(tf)) {
2041     if (tf->text.max_char_size != 1)
2042       XwcDrawString (XtDisplay(tf), XtWindow(tf), (XFontSet)TextF_Font(tf),
2043 		     gc, x, y, (wchar_t*) string, length);
2044 
2045     else  /* one byte chars */
2046       XmbDrawString (XtDisplay(tf), XtWindow(tf), (XFontSet)TextF_Font(tf),
2047 		     gc, x, y, string, length);
2048 
2049 #ifdef USE_XFT
2050   } else if (TextF_UseXft(tf)) {
2051     if (tf->text.max_char_size != 1) { /* was passed a wchar_t*  */
2052       char stack_cache[400], *tmp;
2053       wchar_t tmp_wc;
2054       wchar_t *wc_string = (wchar_t*)string;
2055       int num_bytes = 0;
2056       /* ptr = tmp = XtMalloc((int)(length + 1)*sizeof(wchar_t)); */
2057       tmp = (char *)XmStackAlloc((Cardinal) ((length + 1)*sizeof(wchar_t)),
2058 				 stack_cache);
2059       tmp_wc = wc_string[length];
2060       wc_string[length] = 0L;
2061       num_bytes = wcstombs(tmp, wc_string,
2062 			   (int)((length + 1) * sizeof(wchar_t)));
2063       wc_string[length] = tmp_wc;
2064       if (num_bytes >= 0)
2065         _XmXftDrawString2(XtDisplay(tf), XtWindow(tf), gc, TextF_XftFont(tf),
2066 			1, x, y, tmp, num_bytes);
2067       XmStackFree(tmp, stack_cache);
2068     } else /* one byte chars */
2069         _XmXftDrawString2(XtDisplay(tf), XtWindow(tf), gc, TextF_XftFont(tf),
2070 			1, x, y, string, length);
2071 #endif
2072   } else { /* have a font struct, not a font set */
2073     if (tf->text.max_char_size != 1) { /* was passed a wchar_t*  */
2074       char stack_cache[400], *tmp;
2075       wchar_t tmp_wc;
2076       wchar_t *wc_string = (wchar_t*)string;
2077       int num_bytes = 0;
2078       /* ptr = tmp = XtMalloc((int)(length + 1)*sizeof(wchar_t)); */
2079       tmp = (char *)XmStackAlloc((Cardinal) ((length + 1)*sizeof(wchar_t)),
2080 				 stack_cache);
2081       tmp_wc = wc_string[length];
2082       wc_string[length] = 0L;
2083       num_bytes = wcstombs(tmp, wc_string,
2084 			   (int)((length + 1) * sizeof(wchar_t)));
2085       wc_string[length] = tmp_wc;
2086       if (num_bytes >= 0)
2087         { if (_XmIsISO10646(XtDisplay(tf), TextF_Font(tf))) {
2088             size_t str_len = 0;
2089             XChar2b *str = _XmUtf8ToUcs2(tmp, num_bytes, &str_len);
2090             XDrawString16(XtDisplay(tf), XtWindow(tf), gc, x, y, str, str_len);
2091             XFree(str);
2092             }
2093           else
2094             XDrawString (XtDisplay(tf), XtWindow(tf), gc, x, y, tmp, num_bytes);
2095         }
2096       XmStackFree(tmp, stack_cache);
2097     } else /* one byte chars */
2098       XDrawString (XtDisplay(tf), XtWindow(tf), gc, x, y, string, length);
2099   }
2100 }
2101 
2102 static int
2103 FindPixelLength(XmTextFieldWidget tf,
2104 		char * string,
2105 		int length)
2106 {
2107   if (TextF_UseFontSet(tf)) {
2108     if (tf->text.max_char_size != 1)
2109       return (XwcTextEscapement((XFontSet)TextF_Font(tf),
2110 				(wchar_t *) string, length));
2111     else /* one byte chars */
2112       return (XmbTextEscapement((XFontSet)TextF_Font(tf), string, length));
2113 #ifdef USE_XFT
2114   } else if (TextF_UseXft(tf)) {
2115     XGlyphInfo	ext;
2116     if (tf->text.max_char_size != 1) { /* was passed a wchar_t*  */
2117       wchar_t *wc_string = (wchar_t*)string;
2118       wchar_t wc_tmp = wc_string[length];
2119       char stack_cache[400], *tmp;
2120       int num_bytes;
2121 
2122       wc_string[length] = 0L;
2123       tmp = (char*)XmStackAlloc((Cardinal)((length + 1) * sizeof(wchar_t)),
2124 				stack_cache);
2125       num_bytes = wcstombs(tmp, wc_string,
2126 			   (int)((length + 1)*sizeof(wchar_t)));
2127       wc_string[length] = wc_tmp;
2128       XftTextExtentsUtf8(XtDisplay(tf), TextF_XftFont(tf),
2129               (FcChar8*)tmp, num_bytes, &ext);
2130       XmStackFree(tmp, stack_cache);
2131     } else /* one byte chars */
2132       XftTextExtentsUtf8(XtDisplay(tf), TextF_XftFont(tf),
2133               (FcChar8*)string, length, &ext);
2134 
2135     return ext.xOff;
2136 #endif
2137   } else { /* have font struct, not a font set */
2138     if (tf->text.max_char_size != 1) { /* was passed a wchar_t*  */
2139       wchar_t *wc_string = (wchar_t*)string;
2140       wchar_t wc_tmp = wc_string[length];
2141       char stack_cache[400], *tmp;
2142       int num_bytes, ret_len = 0;
2143 
2144       wc_string[length] = 0L;
2145       tmp = (char*)XmStackAlloc((Cardinal)((length + 1) * sizeof(wchar_t)),
2146 				stack_cache);
2147       num_bytes = wcstombs(tmp, wc_string,
2148 			   (int)((length + 1)*sizeof(wchar_t)));
2149       wc_string[length] = wc_tmp;
2150       if (num_bytes >= 0)
2151         { if (_XmIsISO10646(XtDisplay(tf), TextF_Font(tf))) {
2152             size_t str_len = 0;
2153             XChar2b *str = _XmUtf8ToUcs2(tmp, num_bytes, &str_len);
2154             ret_len = XTextWidth16(TextF_Font(tf), str, str_len);
2155             XFree(str);
2156             }
2157           else
2158             ret_len = XTextWidth(TextF_Font(tf), tmp, num_bytes);
2159         }
2160       XmStackFree(tmp, stack_cache);
2161       return (ret_len);
2162     } else /* one byte chars */
2163         return XTextWidth(TextF_Font(tf), string, length);
2164   }
2165 }
2166 
2167 static void
2168 DrawTextSegment(XmTextFieldWidget tf,
2169 		XmHighlightMode mode,
2170 		XmTextPosition prev_seg_start,
2171 		XmTextPosition seg_start,
2172 		XmTextPosition seg_end,
2173 		XmTextPosition next_seg,
2174 #if NeedWidePrototypes
2175 		int stipple,
2176 #else
2177 		Boolean stipple,
2178 #endif /* NeedWidePrototypes */
2179 		int y,
2180 		int *x)
2181 {
2182   int x_seg_len;
2183 
2184   /* update x position up to start position */
2185 
2186   if (tf->text.max_char_size != 1) {
2187     *x += FindPixelLength(tf, (char*)(TextF_WcValue(tf) + prev_seg_start),
2188 			  (int)(seg_start - prev_seg_start));
2189     x_seg_len = FindPixelLength(tf, (char*)(TextF_WcValue(tf) + seg_start),
2190 				(int)seg_end - (int)seg_start);
2191   } else {
2192     *x += FindPixelLength(tf, TextF_Value(tf) + prev_seg_start,
2193 			  (int)(seg_start - prev_seg_start));
2194     x_seg_len = FindPixelLength(tf, TextF_Value(tf) + seg_start,
2195 				(int)seg_end - (int)seg_start);
2196   }
2197   if (mode == XmHIGHLIGHT_SELECTED) {
2198     /* Draw the selected text using an inverse gc */
2199     SetNormGC(tf, tf->text.gc, False, False);
2200     XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc, *x,
2201 		   y - TextF_FontAscent(tf), x_seg_len,
2202 		   TextF_FontAscent(tf) + TextF_FontDescent(tf));
2203     SetInvGC(tf, tf->text.gc);
2204   } else {
2205     SetInvGC(tf, tf->text.gc);
2206     XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc, *x,
2207 		   y - TextF_FontAscent(tf), x_seg_len,
2208 		   TextF_FontAscent(tf) + TextF_FontDescent(tf));
2209     SetNormGC(tf, tf->text.gc, True, stipple);
2210   }
2211 #ifdef FIX_1381
2212 if (stipple){
2213     /*Draw shadow for insensitive text*/
2214     SetShadowGC(tf, tf->text.gc);
2215     if (tf->text.max_char_size != 1) {
2216       DrawText(tf, tf->text.gc, *x+1, y+1, (char*) (TextF_WcValue(tf) + seg_start),
2217 	      (int)seg_end - (int)seg_start);
2218     } else {
2219     DrawText(tf, tf->text.gc, *x+1, y+1, TextF_Value(tf) + seg_start,
2220 	      (int)seg_end - (int)seg_start);
2221     }
2222     SetNormGC(tf, tf->text.gc, True, stipple);
2223 }
2224 #endif
2225 
2226 
2227   if (tf->text.max_char_size != 1) {
2228     DrawText(tf, tf->text.gc, *x, y, (char*) (TextF_WcValue(tf) + seg_start),
2229 	     (int)seg_end - (int)seg_start);
2230   } else {
2231     DrawText(tf, tf->text.gc, *x, y, TextF_Value(tf) + seg_start,
2232 	     (int)seg_end - (int)seg_start);
2233   }
2234   if (stipple) SetNormGC(tf, tf->text.gc, True, !stipple);
2235 
2236   if (mode == XmHIGHLIGHT_SECONDARY_SELECTED)
2237     XDrawLine(XtDisplay(tf), XtWindow(tf), tf->text.gc, *x, y,
2238 	      *x + x_seg_len - 1, y);
2239 
2240   /* update x position up to the next highlight position */
2241   if (tf->text.max_char_size != 1)
2242     *x += FindPixelLength(tf, (char*) (TextF_WcValue(tf) + seg_start),
2243 			  (int)(next_seg - (int)seg_start));
2244   else
2245     *x += FindPixelLength(tf, TextF_Value(tf) + seg_start,
2246 			  (int)(next_seg - (int)seg_start));
2247 }
2248 
2249 
2250 /*
2251  * Redisplay the new adjustments that have been made the the text
2252  * field widget.
2253  */
2254 static void
2255 RedisplayText(XmTextFieldWidget tf,
2256 	      XmTextPosition start,
2257 	      XmTextPosition end)
2258 {
2259   _XmHighlightRec *l = tf->text.highlight.list;
2260   XRectangle rect;
2261   int x, y, i;
2262   Dimension margin_width = TextF_MarginWidth(tf) +
2263     tf->primitive.shadow_thickness +
2264       tf->primitive.highlight_thickness;
2265   Dimension margin_top = tf->text.margin_top + tf->primitive.shadow_thickness +
2266     tf->primitive.highlight_thickness;
2267   Dimension margin_bottom = tf->text.margin_bottom +
2268     tf->primitive.shadow_thickness +
2269       tf->primitive.highlight_thickness;
2270   Boolean stipple = False;
2271 
2272   if (!XtIsRealized((Widget)tf)) return;
2273 
2274   if (tf->text.in_setvalues) {
2275     tf->text.redisplay = True;
2276     return;
2277   }
2278 
2279   if ((int)tf->core.width - (int)(2 * margin_width) <= 0)
2280     return;
2281   if ((int)tf->core.height - (int)(margin_top + margin_bottom) <= 0)
2282     return;
2283 
2284   _XmTextFieldDrawInsertionPoint(tf, False);
2285 
2286   /* Get the current rectangle.
2287    */
2288   GetRect(tf, &rect);
2289 
2290   x = (int) tf->text.h_offset;
2291   y = margin_top + TextF_FontAscent(tf);
2292 
2293   if (!XtIsSensitive((Widget)tf)) stipple = True;
2294 
2295   /* search through the highlight array and draw the text */
2296   for (i = 0; i + 1 < tf->text.highlight.number; i++) {
2297 
2298     /* make sure start is within current highlight */
2299     if (l[i].position <= start && start < l[i+1].position &&
2300 	l[i].position < end) {
2301 
2302       if (end > l[i+1].position) {
2303 
2304 	DrawTextSegment(tf, l[i].mode, l[i].position, start,
2305 			l[i+1].position, l[i+1].position, stipple, y, &x);
2306 
2307 	/* update start position to the next highlight position */
2308 	start = l[i+1].position;
2309 
2310       } else {
2311 
2312  	if (start > end) {
2313 	    XmTextPosition tmp = start;
2314 	    start = end;
2315 	    end = tmp;
2316  	}
2317 
2318 	DrawTextSegment(tf, l[i].mode, l[i].position, start,
2319 			end, l[i+1].position, stipple, y, &x);
2320 	start = end;
2321       }
2322     } else { /* start not within current record */
2323       if (tf->text.max_char_size != 1)
2324 	x += FindPixelLength(tf, (char*)(TextF_WcValue(tf) + l[i].position),
2325 			     (int)(l[i+1].position - l[i].position));
2326       else
2327 	x += FindPixelLength(tf, TextF_Value(tf) + l[i].position,
2328 			     (int)(l[i+1].position - l[i].position));
2329     }
2330   }  /* end for loop */
2331 
2332   /* complete the drawing of the text to the end of the line */
2333   if (l[i].position < end) {
2334     DrawTextSegment(tf, l[i].mode, l[i].position, start,
2335 		    end, tf->text.string_length, stipple, y, &x);
2336   } else {
2337     if (tf->text.max_char_size != 1)
2338       x += FindPixelLength(tf, (char*) (TextF_WcValue(tf) + l[i].position),
2339 			   tf->text.string_length - (int)l[i].position);
2340     else
2341       x += FindPixelLength(tf, TextF_Value(tf) + l[i].position,
2342 			   tf->text.string_length - (int)l[i].position);
2343   }
2344 
2345   if (x < (Position)(rect.x + rect.width)) {
2346     SetInvGC(tf, tf->text.gc);
2347     XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc, x, rect.y,
2348 		   rect.x + rect.width - x, rect.height);
2349   }
2350   tf->text.refresh_ibeam_off = True;
2351   _XmTextFieldDrawInsertionPoint(tf, True);
2352 }
2353 
2354 
2355 /*
2356  * Use the font along with the resources that have been set
2357  * to determine the height and width of the text field widget.
2358  */
2359 static void
2360 ComputeSize(XmTextFieldWidget tf,
2361 	    Dimension *width,
2362 	    Dimension *height)
2363 {
2364   Dimension tmp = 0;
2365 
2366   if (TextF_ResizeWidth(tf) &&
2367       TextF_Columns(tf) < tf->text.string_length) {
2368 
2369     if (tf->text.max_char_size != 1)
2370       tmp = FindPixelLength(tf, (char *)TextF_WcValue(tf),
2371 			    tf->text.string_length);
2372     else
2373       tmp = FindPixelLength(tf, TextF_Value(tf), tf->text.string_length);
2374 
2375 
2376     *width = tmp + (2 * (TextF_MarginWidth(tf) +
2377 			 tf->primitive.shadow_thickness +
2378 			 tf->primitive.highlight_thickness));
2379   } else {
2380     *width = TextF_Columns(tf) * tf->text.average_char_width +
2381       2 * (TextF_MarginWidth(tf) + tf->primitive.shadow_thickness +
2382 	   tf->primitive.highlight_thickness);
2383   }
2384 
2385   if (height != NULL)
2386     *height = TextF_FontDescent(tf) + TextF_FontAscent(tf) +
2387       2 * (TextF_MarginHeight(tf) + tf->primitive.shadow_thickness +
2388 	   tf->primitive.highlight_thickness);
2389 }
2390 
2391 
2392 /*
2393  * TryResize - Attempts to resize the width of the text field widget.
2394  * If the attempt fails or is ineffective, return GeometryNo.
2395  */
2396 static XtGeometryResult
2397 TryResize(XmTextFieldWidget tf,
2398 #if NeedWidePrototypes
2399 	  int width,
2400 	  int height)
2401 #else
2402           Dimension width,
2403           Dimension height)
2404 #endif /* NeedWidePrototypes */
2405 {
2406   Dimension reswidth, resheight;
2407   Dimension origwidth = tf->core.width;
2408   XtGeometryResult result;
2409 
2410   result = XtMakeResizeRequest((Widget)tf, width, height,
2411 			       &reswidth, &resheight);
2412 
2413   if (result == XtGeometryAlmost) {
2414     result = XtMakeResizeRequest((Widget)tf, reswidth, resheight,
2415 				 &reswidth, &resheight);
2416 
2417     if (reswidth == origwidth)
2418       result = XtGeometryNo;
2419     return result;
2420   }
2421 
2422   /*
2423    * Caution: Some geometry managers return XtGeometryYes
2424    *	        and don't change the widget's size.
2425    */
2426   if (tf->core.width != width || tf->core.height != height)
2427     result = XtGeometryNo;
2428 
2429   return result;
2430 }
2431 
2432 
2433 /*
2434  * Function AdjustText
2435  *
2436  * AdjustText ensures that the character at the given position is entirely
2437  * visible in the Text Field widget.  If the character is not already entirely
2438  * visible, AdjustText changes the Widget's h_offset appropriately.  If
2439  * the text must be redrawn, AdjustText calls RedisplayText.
2440  *
2441  */
2442 static Boolean
2443 AdjustText(XmTextFieldWidget tf,
2444 	   XmTextPosition position,
2445 #if NeedWidePrototypes
2446 	   int flag)
2447 #else
2448            Boolean flag)
2449 #endif /* NeedWidePrototypes */
2450 {
2451   int left_edge = 0;
2452   int diff;
2453   Dimension margin_width = TextF_MarginWidth(tf) +
2454     tf->primitive.shadow_thickness +
2455       tf->primitive.highlight_thickness;
2456   Dimension thickness    = 2 * (tf->primitive.shadow_thickness +
2457 				tf->primitive.highlight_thickness);
2458   Dimension temp;
2459 
2460 
2461   if (tf->text.max_char_size != 1) {
2462     left_edge = FindPixelLength(tf, (char *) TextF_WcValue(tf),
2463 				(int)position) + (int) tf->text.h_offset;
2464   } else {
2465     left_edge = FindPixelLength(tf, TextF_Value(tf), (int)position) +
2466       (int) tf->text.h_offset;
2467   }
2468 
2469   if (left_edge <= (int)margin_width &&
2470       position == tf->text.string_length) {
2471     position = MAX(position - TextF_Columns(tf)/2, 0);
2472     if (tf->text.max_char_size != 1) {
2473       left_edge = FindPixelLength(tf, (char *) TextF_WcValue(tf),
2474 				  (int)position) + (int) tf->text.h_offset;
2475     } else {
2476       left_edge = FindPixelLength(tf, TextF_Value(tf), (int)position) +
2477 	(int) tf->text.h_offset;
2478     }
2479   }
2480 
2481   if ((diff = left_edge - margin_width) < 0) {
2482     /* We need to scroll the string to the right. */
2483     if (!XtIsRealized((Widget)tf)) {
2484       tf->text.h_offset -= diff;
2485       return True;
2486     }
2487     _XmTextFieldDrawInsertionPoint(tf, False);
2488     tf->text.h_offset -= diff;
2489     SetInvGC(tf, tf->text.gc);
2490     SetFullGC(tf, tf->text.gc);
2491     if (tf->core.height <= thickness)
2492       temp = 0;
2493     else
2494       temp = tf->core.height - thickness;
2495     XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc,
2496 		   tf->primitive.shadow_thickness +
2497 		   tf->primitive.highlight_thickness,
2498 		   tf->primitive.shadow_thickness +
2499 		   tf->primitive.highlight_thickness,
2500 		   TextF_MarginWidth(tf),
2501 		   temp);
2502     SetMarginGC(tf, tf->text.gc);
2503     RedisplayText(tf, 0, tf->text.string_length);
2504     _XmTextFieldDrawInsertionPoint(tf, True);
2505     return True;
2506   } else if ((diff = (left_edge -
2507 		      (int)(tf->core.width - margin_width))) > 0) {
2508     /* We need to scroll the string to the left. */
2509     if (!XtIsRealized((Widget)tf)) {
2510       tf->text.h_offset -= diff;
2511       return True;
2512     }
2513     _XmTextFieldDrawInsertionPoint(tf, False);
2514     tf->text.h_offset -= diff;
2515     SetInvGC(tf, tf->text.gc);
2516     SetFullGC(tf, tf->text.gc);
2517     if (tf->core.width <= thickness)
2518       temp = 0;
2519     else
2520       temp = tf->core.width - thickness;
2521     XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc,
2522 		   tf->core.width - margin_width,
2523 		   tf->primitive.shadow_thickness +
2524 		   tf->primitive.highlight_thickness,
2525 		   TextF_MarginWidth(tf),
2526 		   temp);
2527     SetMarginGC(tf, tf->text.gc);
2528     RedisplayText(tf, 0, tf->text.string_length);
2529     _XmTextFieldDrawInsertionPoint(tf, True);
2530     return True;
2531   }
2532 
2533   if (flag) RedisplayText(tf, position, tf->text.string_length);
2534 
2535   return False;
2536 }
2537 
2538 /*
2539  * AdjustSize
2540  *
2541  * Adjust size will resize the text to ensure that all the text is visible.
2542  * It will also adjust text that is shrunk.  Shrinkage is limited to the
2543  * size determined by the XmNcolumns resource.
2544  */
2545 static void
2546 AdjustSize(XmTextFieldWidget tf)
2547 {
2548   XtGeometryResult result = XtGeometryYes;
2549   int left_edge = 0;
2550   int diff;
2551   Boolean redisplay = False;
2552   Dimension margin_width = TextF_MarginWidth(tf) +
2553     tf->primitive.shadow_thickness +
2554       tf->primitive.highlight_thickness;
2555 
2556   if (tf->text.max_char_size != 1) {
2557     left_edge = FindPixelLength(tf, (char *) TextF_WcValue(tf),
2558 				tf->text.string_length) + margin_width;
2559   } else {
2560     left_edge = FindPixelLength(tf, TextF_Value(tf),
2561 				tf->text.string_length) + margin_width;
2562   }
2563 
2564   if ((diff = (left_edge - (tf->core.width - (margin_width)))) > 0) {
2565     if (tf->text.in_setvalues) {
2566       tf->core.width += diff;
2567       return;
2568     }
2569     /* Attempt to resize.  If it doesn't succeed, do scrolling.  */
2570     result = TryResize(tf, tf->core.width + diff, tf->core.height);
2571     if (result == XtGeometryYes) {
2572       XtWidgetProc resize;
2573 
2574       _XmProcessLock();
2575       resize = tf->core.widget_class->core_class.resize;
2576       _XmProcessUnlock();
2577       (*resize)((Widget)tf);
2578       return;
2579     } else {
2580       /* We need to scroll the string to the left. */
2581       tf->text.h_offset = margin_width - diff;
2582     }
2583   } else {
2584     Dimension width;
2585 
2586     /* If the new size is smaller than core size, we need
2587      * to shrink.  Note: new size will never be less than the
2588      * width determined by the columns resource.
2589      */
2590     ComputeSize(tf, &width, NULL);
2591     if (width < tf->core.width) {
2592       if (tf->text.in_setvalues) {
2593 	tf->core.width = width;
2594 	return;
2595       }
2596       result = TryResize(tf, width, tf->core.height);
2597       if (result == XtGeometryYes) {
2598 	XtWidgetProc resize;
2599 
2600 	_XmProcessLock();
2601 	resize = tf->core.widget_class->core_class.resize;
2602 	_XmProcessUnlock();
2603 	(*resize)((Widget)tf);
2604 
2605 	return;
2606       }
2607     }
2608   }
2609 
2610   redisplay = AdjustText(tf, TextF_CursorPosition(tf), False);
2611 
2612   if (!redisplay)
2613     RedisplayText(tf, 0, tf->text.string_length);
2614 }
2615 
2616 /* If MB_CUR_MAX == 1, insert is a char* pointer; else, it is a wchar_t *
2617  * pointer and must be appropriately cast.  In all cases, insert_length
2618  * is the number of characters, not the number of bytes pointed to by
2619  * insert
2620  */
2621 static Boolean
2622 ModifyVerify(XmTextFieldWidget tf,
2623 	     XEvent *event,
2624 	     XmTextPosition *replace_prev,
2625 	     XmTextPosition *replace_next,
2626 	     char **insert,
2627 	     int *insert_length,
2628 	     XmTextPosition *newInsert,
2629 	     int *free_insert)
2630 {
2631   XmTextVerifyCallbackStruct vcb;
2632   XmTextVerifyCallbackStructWcs wcs_vcb;
2633   XmTextBlockRec newblock;
2634   XmTextBlockRecWcs wcs_newblock;
2635   Boolean do_free = False;
2636   Boolean wcs_do_free = False;
2637   int count;
2638   wchar_t *wptr;
2639 
2640   *newInsert = TextF_CursorPosition(tf);
2641   *free_insert = (int)False;
2642 
2643   /* if there are no callbacks, don't waste any time... just return  True */
2644   if (!TextF_ModifyVerifyCallback(tf) && !TextF_ModifyVerifyCallbackWcs(tf))
2645     return(True);
2646 
2647   newblock.format = XmFMT_8_BIT;
2648   newblock.length = *insert_length * tf->text.max_char_size;
2649 
2650   if (*insert_length) {
2651     if (TextF_ModifyVerifyCallback(tf)) {
2652       newblock.ptr = (char *) XtMalloc((unsigned)newblock.length +
2653 				       tf->text.max_char_size);
2654       if (tf->text.max_char_size == 1) {
2655 	(void)memcpy((void*)newblock.ptr, (void*)*insert,
2656 		     newblock.length);
2657 	newblock.ptr[newblock.length]='\0';
2658       } else {
2659 	count = (int) wcstombs(newblock.ptr, (wchar_t*)*insert,
2660 			       newblock.length);
2661 	if (count < 0) { /* bad wchar; don't pass anything */
2662 	  newblock.ptr[0] = '\0';
2663 	  newblock.length = 0;
2664 	} else if (count == newblock.length) {
2665 	  newblock.ptr[newblock.length] = '\0';
2666 	} else {
2667 	  newblock.ptr[count] = '\0';
2668 	  newblock.length = count;
2669 	}
2670       }
2671       do_free = True;
2672     } else
2673       newblock.ptr = NULL;
2674   } else
2675     newblock.ptr = NULL;
2676 
2677   /* Fill in the appropriate structs */
2678   vcb.reason = XmCR_MODIFYING_TEXT_VALUE;
2679   vcb.event = (XEvent *) event;
2680   vcb.doit = True;
2681   vcb.currInsert = TextF_CursorPosition(tf);
2682   vcb.newInsert = TextF_CursorPosition(tf);
2683   vcb.text = &newblock;
2684   vcb.startPos = *replace_prev;
2685   vcb.endPos = *replace_next;
2686 
2687   /* Call the modify verify callbacks. */
2688   if (TextF_ModifyVerifyCallback(tf))
2689     XtCallCallbackList((Widget) tf, TextF_ModifyVerifyCallback(tf),
2690 		       (XtPointer) &vcb);
2691 
2692   if (TextF_ModifyVerifyCallbackWcs(tf) && vcb.doit) {
2693     if (do_free) { /* there is a char* modify verify callback; the data we
2694 		    * want is in vcb struct */
2695       wcs_newblock.wcsptr = (wchar_t *) XtMalloc((unsigned)
2696 						 (vcb.text->length + 1) *
2697 						 sizeof(wchar_t));
2698       wcs_newblock.length = mbstowcs(wcs_newblock.wcsptr, vcb.text->ptr,
2699 				     vcb.text->length);
2700       if (wcs_newblock.length < 0) { /* bad value; don't pass anything */
2701 	wcs_newblock.wcsptr[0] = 0L;
2702 	wcs_newblock.length = 0;
2703       } else
2704 	wcs_newblock.wcsptr[wcs_newblock.length] = 0L;
2705     } else { /* there was no char* modify verify callback; use data
2706 	      * passed in from caller instead of that in vcb struct. */
2707       wcs_newblock.wcsptr = (wchar_t *) XtMalloc((unsigned)
2708 						 (*insert_length + 1) *
2709 						 sizeof(wchar_t));
2710       if (tf->text.max_char_size == 1)
2711 	wcs_newblock.length = mbstowcs(wcs_newblock.wcsptr, *insert,
2712 				       *insert_length);
2713       else {
2714 	wcs_newblock.length = *insert_length;
2715 	(void)memcpy((void*)wcs_newblock.wcsptr, (void*)*insert,
2716 		     *insert_length * sizeof(wchar_t));
2717       }
2718       if (wcs_newblock.length < 0) { /* bad value; don't pass anything */
2719 	wcs_newblock.wcsptr[0] = 0L;
2720 	wcs_newblock.length = 0;
2721       } else
2722 	wcs_newblock.wcsptr[wcs_newblock.length] = 0L;
2723 
2724     }
2725     wcs_do_free = True;
2726     wcs_vcb.reason = XmCR_MODIFYING_TEXT_VALUE;
2727     wcs_vcb.event = (XEvent *) event;
2728     wcs_vcb.doit = True;
2729     wcs_vcb.currInsert = vcb.currInsert;
2730     wcs_vcb.newInsert = vcb.newInsert;
2731     wcs_vcb.text = &wcs_newblock;
2732     wcs_vcb.startPos = vcb.startPos;
2733     wcs_vcb.endPos = vcb.endPos;
2734 
2735     XtCallCallbackList((Widget) tf, TextF_ModifyVerifyCallbackWcs(tf),
2736 		       (XtPointer) &wcs_vcb);
2737 
2738   }
2739   /* copy the newblock.ptr, length, start, and end to the pointers passed */
2740   if (TextF_ModifyVerifyCallbackWcs(tf)) { /* use wcs_vcb data */
2741     *insert_length = wcs_vcb.text->length; /* length is char count*/
2742     if (wcs_vcb.doit) {
2743       if (tf->text.max_char_size == 1) { /* caller expects char */
2744 	wcs_vcb.text->wcsptr[wcs_vcb.text->length] = 0L;
2745 	if (*insert_length > 0) {
2746 	  *insert = XtMalloc((unsigned) *insert_length + 1);
2747 	  *free_insert = (int)True;
2748 	  count = wcstombs(*insert, wcs_vcb.text->wcsptr,
2749 			   *insert_length + 1);
2750 	  if (count < 0) {
2751 	    (*insert)[0] = 0;
2752 	    *insert_length = 0;
2753 	  }
2754 	}
2755       } else {  /* callback struct has wchar*; caller expects wchar* */
2756 	if (*insert_length > 0) {
2757 	  *insert =
2758 	    XtMalloc((unsigned)(*insert_length + 1) * sizeof(wchar_t));
2759 	  *free_insert = (int)True;
2760 	  (void)memcpy((void*)*insert, (void*)wcs_vcb.text->wcsptr,
2761 		       *insert_length * sizeof(wchar_t));
2762 	  wptr = (wchar_t*) *insert;
2763 	  wptr[*insert_length] = 0L;
2764 	}
2765       }
2766       *replace_prev = wcs_vcb.startPos;
2767       *replace_next = wcs_vcb.endPos;
2768       *newInsert = wcs_vcb.newInsert;
2769     }
2770   } else { /* use vcb data */
2771     if (vcb.doit) {
2772       if (tf->text.max_char_size == 1) {  /* caller expects char* */
2773 	*insert_length =  vcb.text->length;
2774 	if (*insert_length > 0) {
2775 	  *insert = XtMalloc((unsigned) *insert_length + 1);
2776 	  *free_insert = (int)True;
2777 	  (void)memcpy((void*)*insert, (void*)vcb.text->ptr,
2778 		       *insert_length);
2779 	  (*insert)[*insert_length] = 0;
2780 	}
2781       } else {                       /* caller expects wchar_t* back */
2782 	*insert_length =  _XmTextFieldCountCharacters(tf, vcb.text->ptr,
2783 						      vcb.text->length);
2784 	if (*insert_length > 0) {
2785 	  *insert =
2786 	    XtMalloc((unsigned)(*insert_length + 1) * sizeof(wchar_t));
2787 	  *free_insert = (int)True;
2788 	  count = mbstowcs((wchar_t*)*insert, vcb.text->ptr,
2789 			   *insert_length);
2790 	  wptr = (wchar_t*) *insert;
2791 	  if (count < 0) {
2792 	    wptr[0] = 0L;
2793 	    *insert_length = 0;
2794 	  } else
2795 	    wptr[count] = 0L;
2796 	}
2797       }
2798       *replace_prev = vcb.startPos;
2799       *replace_next = vcb.endPos;
2800       *newInsert = vcb.newInsert;
2801     }
2802   }
2803   if (do_free) XtFree(newblock.ptr);
2804   if (wcs_do_free) XtFree((char*)wcs_newblock.wcsptr);
2805 
2806   /* If doit becomes False, then don't allow the change. */
2807   if (TextF_ModifyVerifyCallbackWcs(tf))
2808     return wcs_vcb.doit;
2809   else
2810     return vcb.doit;
2811 }
2812 
2813 static void
2814 ResetClipOrigin(XmTextFieldWidget tf)
2815 {
2816   int x, y;
2817   Position x_pos, y_pos;
2818 
2819   (void) GetXYFromPos(tf, TextF_CursorPosition(tf), &x_pos, &y_pos);
2820 
2821   if (!XtIsRealized((Widget)tf)) return;
2822 
2823   x = (int) x_pos; y = (int) y_pos;
2824 
2825   x -=(tf->text.cursor_width >> 1) + 1;
2826 
2827   y = (y + TextF_FontDescent(tf)) - tf->text.cursor_height;
2828 
2829   XSetTSOrigin(XtDisplay(tf), tf->text.image_gc, x, y);
2830 }
2831 
2832 static void
2833 InvertImageGC (XmTextFieldWidget tf)
2834 {
2835   if (tf->text.have_inverted_image_gc) return;
2836 
2837   tf->text.have_inverted_image_gc = True;
2838 }
2839 
2840 static void
2841 ResetImageGC (XmTextFieldWidget tf)
2842 {
2843   if (!tf->text.have_inverted_image_gc) return;
2844 
2845   tf->text.have_inverted_image_gc = False;
2846 }
2847 
2848 
2849 
2850 /*
2851  * Calls the motion verify callback.  If the doit flag is true,
2852  * then reset the cursor_position and call AdjustText() to
2853  * move the text if need be.
2854  */
2855 
2856 void
2857 _XmTextFieldSetCursorPosition(XmTextFieldWidget tf,
2858 			      XEvent *event,
2859 			      XmTextPosition position,
2860 #if NeedWidePrototypes
2861 			      int adjust_flag,
2862 			      int call_cb)
2863 #else
2864                               Boolean adjust_flag,
2865                               Boolean call_cb)
2866 #endif /* NeedWidePrototypes */
2867 {
2868   SetCursorPosition(tf, event, position, adjust_flag, call_cb, True,DontCare);
2869 }
2870 
2871 static void
2872 SetCursorPosition(XmTextFieldWidget tf,
2873 		  XEvent *event,
2874 		  XmTextPosition position,
2875 #if NeedWidePrototypes
2876 		  int adjust_flag,
2877 		  int call_cb,
2878 		  int set_dest,
2879 #else
2880                   Boolean adjust_flag,
2881                   Boolean call_cb,
2882                   Boolean set_dest,
2883 #endif /* NeedWidePrototypes */
2884 		  PassDisown passDisown)
2885 {
2886   XmTextVerifyCallbackStruct cb;
2887   Boolean flag = False;
2888   XPoint xmim_point;
2889   XRectangle xmim_area;
2890   _XmHighlightRec *hl_list = tf->text.highlight.list;
2891   int i;
2892 
2893   if (position < 0) position = 0;
2894 
2895   if (position > tf->text.string_length)
2896     position = tf->text.string_length;
2897 
2898   if (TextF_CursorPosition(tf) != position && call_cb) {
2899     /* Call Motion Verify Callback before Cursor Changes Positon */
2900     cb.reason = XmCR_MOVING_INSERT_CURSOR;
2901     cb.event  = event;
2902     cb.currInsert = TextF_CursorPosition(tf);
2903     cb.newInsert = position;
2904     cb.doit = True;
2905     XtCallCallbackList((Widget) tf, TextF_MotionVerifyCallback(tf),
2906 		       (XtPointer) &cb);
2907 
2908     if (!cb.doit) {
2909       if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
2910       return;
2911     }
2912   }
2913   _XmTextFieldDrawInsertionPoint(tf, False);
2914 
2915   TextF_CursorPosition(tf) = position;
2916 
2917   if (!tf->text.add_mode && tf->text.pending_off && tf->text.has_primary) {
2918     SetSelection(tf, position, position, True);
2919     flag = True;
2920   }
2921 
2922   /* Deterimine if we need an inverted image GC or not.  Get the highlight
2923    * record for the cursor position.  If position is on a boundary of
2924    * a highlight, then we always display cursor in normal mode (i.e. set
2925    * normal image GC).  If position is within a selected highlight rec,
2926    * then make sure the image GC is inverted.  If we've moved out of a
2927    * selected highlight region, restore the normal image GC. */
2928 
2929   for (i = tf->text.highlight.number - 1; i >= 0; i--) {
2930     if (position >= hl_list[i].position || i == 0)
2931       break;
2932   }
2933 
2934   if (position == hl_list[i].position)
2935     ResetImageGC(tf);
2936   else if (hl_list[i].mode != XmHIGHLIGHT_SELECTED)
2937     ResetImageGC(tf);
2938   else
2939     InvertImageGC(tf);
2940 
2941   if (adjust_flag) (void) AdjustText(tf, position, flag);
2942 
2943   tf->text.refresh_ibeam_off = True;
2944   _XmTextFieldDrawInsertionPoint(tf, True);
2945 
2946   (void) GetXYFromPos(tf, TextF_CursorPosition(tf),
2947 		      &xmim_point.x, &xmim_point.y);
2948   (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
2949   XmImVaSetValues((Widget)tf, XmNspotLocation, &xmim_point,
2950 		  XmNarea, &xmim_area, NULL);
2951 
2952   if (set_dest)
2953     (void) SetDestination((Widget) tf, TextF_CursorPosition(tf),
2954 		(DontCare == passDisown) ? False : True,
2955 			  XtLastTimestampProcessed(XtDisplay((Widget)tf)));
2956 }
2957 
2958 
2959 /*
2960  * This routine is used to verify that the positions are within the bounds
2961  * of the current TextField widgets value.  Also, it ensures that left is
2962  * less than right.
2963  */
2964 static void
2965 VerifyBounds(XmTextFieldWidget tf,
2966 	     XmTextPosition *from,
2967 	     XmTextPosition *to)
2968 {
2969   XmTextPosition tmp;
2970 
2971   if (*from < 0)
2972     *from = 0;
2973   else if (*from > tf->text.string_length) {
2974     *from = tf->text.string_length;
2975   }
2976   if (*to < 0)
2977     *to = 0;
2978   else if (*to > tf->text.string_length) {
2979     *to = tf->text.string_length;
2980   }
2981   if (*from > *to) {
2982     tmp = *to;
2983     *to = *from;
2984     *from = tmp;
2985   }
2986 }
2987 
2988 /*
2989  * Function _XmTextFieldReplaceText
2990  *
2991  * _XmTextFieldReplaceText is a utility function for the text-modifying
2992  * action procedures below (InsertChar, DeletePrevChar, and so on).
2993  * _XmTextFieldReplaceText does the real work of editing the string,
2994  * including:
2995  *
2996  *   (1) invoking the modify verify callbacks,
2997  *   (2) allocating more memory for the string if necessary,
2998  *   (3) doing the string manipulation,
2999  *   (4) moving the selection (the insertion point), and
3000  *   (5) redrawing the text.
3001  *
3002  * Though the procedure claims to take a char* argument, MB_CUR_MAX determines
3003  * what the different routines will actually pass to it.  If MB_CUR_MAX is
3004  * greater than 1, then "insert" points to wchar_t data and we must set up
3005  * the appropriate cast.  In all cases, insert_length is the number of
3006  * characters (not bytes) to be inserted.
3007  */
3008 Boolean
3009 _XmTextFieldReplaceText(XmTextFieldWidget tf,
3010 			XEvent *event,
3011 			XmTextPosition replace_prev,
3012 			XmTextPosition replace_next,
3013 			char *insert,
3014 			int insert_length,
3015 #if NeedWidePrototypes
3016 			int move_cursor)
3017 #else
3018                         Boolean move_cursor)
3019 #endif /* NeedWidePrototypes */
3020 {
3021   int replace_length, i;
3022   char *src, *dst;
3023   wchar_t *wc_src, *wc_dst;
3024   int delta = 0;
3025   XmTextPosition cursorPos, newInsert;
3026   XmTextPosition old_pos = replace_prev;
3027   int free_insert = (int)False;
3028   char *insert_orig;
3029   int insert_length_orig;
3030   int size = 0;
3031 
3032   VerifyBounds(tf, &replace_prev, &replace_next);
3033 
3034   if (!TextF_Editable(tf)) {
3035     if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
3036     return False;
3037   }
3038 
3039   if (tf->text.programmatic_highlights)
3040   {
3041   	/*
3042 	** XmTextFieldSetHighlight called since last interaction here
3043 	** that resulted in clearing program-set highlights
3044 	*/
3045 	int low = 0, high = 0;
3046 	if (TrimHighlights(tf, &low, &high))
3047 		{
3048 	    	RedisplayText(tf, low, high);
3049 		tf->text.programmatic_highlights = False;
3050 		}
3051   }
3052 
3053   replace_length = (int) (replace_next - replace_prev);
3054   delta = insert_length - replace_length;
3055 
3056   /* Disallow insertions that go beyond max length boundries.
3057    */
3058   if ((delta >= 0) && !FUnderVerifyPreedit(tf) &&
3059       ((tf->text.string_length + delta) - (TextF_MaxLength(tf)) > 0)) {
3060     if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
3061     return False;
3062   }
3063 
3064 
3065   /* If there are modify verify callbacks, verify that we want to continue
3066    * the action.
3067    */
3068   newInsert = TextF_CursorPosition(tf);
3069 
3070   if (TextF_ModifyVerifyCallback(tf) || TextF_ModifyVerifyCallbackWcs(tf)) {
3071     /* If the function ModifyVerify() returns false then don't
3072      * continue with the action.
3073      */
3074     insert_length_orig = insert_length;
3075     if (insert_length > 0) {
3076         if (tf->text.max_char_size == 1)
3077 	    size = sizeof(char);
3078 	else
3079 	    size = sizeof(wchar_t);
3080 	insert_orig = XtMalloc(insert_length * size);
3081 	bcopy(insert, insert_orig, insert_length * size);
3082     } else
3083 	insert_orig = NULL;
3084     if (!ModifyVerify(tf, event, &replace_prev, &replace_next,
3085 		      &insert, &insert_length, &newInsert, &free_insert)) {
3086       if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
3087       if (free_insert) XtFree(insert);
3088       if (FUnderVerifyPreedit(tf)) {
3089 	FVerifyCommitNeeded(tf) = True;
3090 	PreEnd(tf) -= insert_length_orig;
3091       }
3092       return False;
3093     } else {
3094       if (FUnderVerifyPreedit(tf))
3095 	if (insert_length != insert_length_orig ||
3096           memcmp(insert, insert_orig, insert_length * size) != 0) {
3097 	  FVerifyCommitNeeded(tf) = True;
3098 	  PreEnd(tf) += insert_length - insert_length_orig;
3099 	}
3100 
3101       VerifyBounds(tf, &replace_prev, &replace_next);
3102       replace_length = (int) (replace_next - replace_prev);
3103       delta = insert_length - replace_length;
3104 
3105       /* Disallow insertions that go beyond max length boundries.
3106        */
3107       if ((delta >= 0) && !FUnderVerifyPreedit(tf) &&
3108 	  ((tf->text.string_length + delta) - (TextF_MaxLength(tf)) > 0)) {
3109 	if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
3110 	if (free_insert) XtFree(insert);
3111 	return False;
3112       }
3113 
3114     }
3115     XtFree(insert_orig);
3116   }
3117 
3118   /* make sure selections are turned off prior to changeing text */
3119   if (tf->text.has_primary &&
3120       tf->text.prim_pos_left != tf->text.prim_pos_right)
3121     doSetHighlight((Widget)tf, tf->text.prim_pos_left,
3122 			    tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
3123 
3124   _XmTextFieldDrawInsertionPoint(tf, False);
3125 
3126   /* Allocate more space if we need it.
3127    */
3128   if (tf->text.max_char_size == 1) {
3129     if (tf->text.string_length + insert_length - replace_length >=
3130 	tf->text.size_allocd) {
3131       tf->text.size_allocd += MAX(insert_length + TEXT_INCREMENT,
3132 				  (tf->text.size_allocd * 2));
3133       tf->text.value =
3134 	(char *) XtRealloc((char*)TextF_Value(tf),
3135 			   (unsigned) (tf->text.size_allocd * sizeof(char)));
3136     }
3137   } else {
3138     if ((tf->text.string_length + insert_length - replace_length) *
3139 	sizeof(wchar_t) >= tf->text.size_allocd) {
3140       tf->text.size_allocd +=
3141 	MAX((insert_length + TEXT_INCREMENT)*sizeof(wchar_t),
3142 	    (tf->text.size_allocd * 2));
3143       tf->text.wc_value =
3144 	(wchar_t *) XtRealloc((char*)TextF_WcValue(tf),
3145 			      (unsigned) tf->text.size_allocd);
3146     }
3147   }
3148 
3149   if (tf->text.has_primary && replace_prev < tf->text.prim_pos_right &&
3150       replace_next > tf->text.prim_pos_left) {
3151     if (replace_prev <= tf->text.prim_pos_left) {
3152       if (replace_next < tf->text.prim_pos_right) {
3153 	/* delete encompasses left half of the selection
3154 	 * so move left endpoint
3155 	 */
3156 	tf->text.prim_pos_left = replace_next;
3157       } else {
3158 	/* delete encompasses the selection so set selection to NULL */
3159            tf->text.prim_pos_left = tf->text.prim_pos_right;
3160         }
3161        } else {
3162         /*
3163          * the 2 cases below were incorrect, and have now
3164          * been synchronized with the corresponding block of code in
3165          * TextStrSo.c
3166          */
3167         if (replace_next > tf->text.prim_pos_right) {
3168           /* delete encompasses the right half of the selection
3169            * so move right endpoint
3170            */
3171            tf->text.prim_pos_right = replace_prev;
3172         } else {
3173           /* delete is completely within the selection
3174            * so decrease size of selection.
3175            */
3176            tf->text.prim_pos_right -= (replace_next - replace_prev);
3177         }
3178 
3179        }
3180     }
3181 
3182   if (tf->text.max_char_size == 1) {
3183     if (replace_length > insert_length)
3184       /* We need to shift the text at and after replace_next to the left. */
3185       for (src = TextF_Value(tf) + replace_next,
3186 	   dst = src + (insert_length - replace_length),
3187 	   i = (int) ((tf->text.string_length + 1) - replace_next);
3188 	   i > 0;
3189 	   ++src, ++dst, --i)
3190 	*dst = *src;
3191     else if (replace_length < insert_length)
3192       /* We need to shift the text at and after replace_next to the right. */
3193       /* Need to add 1 to string_length to handle the NULL terminator on */
3194       /* the string. */
3195       for (src = TextF_Value(tf) + tf->text.string_length,
3196 	   dst = src + (insert_length - replace_length),
3197 	   i = (int) ((tf->text.string_length + 1) - replace_next);
3198 	   i > 0;
3199 	   --src, --dst, --i)
3200 	*dst = *src;
3201 
3202     /* Update the string.
3203      */
3204     if (insert_length != 0) {
3205       for (src = insert,
3206 	   dst = TextF_Value(tf) + replace_prev,
3207 	   i = insert_length;
3208 	   i > 0;
3209 	   ++src, ++dst, --i)
3210 	*dst = *src;
3211     }
3212   } else {  /* have wchar_t* data */
3213     if (replace_length > insert_length)
3214       /* We need to shift the text at and after replace_next to the left. */
3215       for (wc_src = TextF_WcValue(tf) + replace_next,
3216 	   wc_dst = wc_src + (insert_length - replace_length),
3217 	   i = (int) ((tf->text.string_length + 1) - replace_next);
3218 	   i > 0;
3219 	   ++wc_src, ++wc_dst, --i)
3220 	*wc_dst = *wc_src;
3221     else if (replace_length < insert_length)
3222       /* We need to shift the text at and after replace_next to the right. */
3223       /* Need to add 1 to string_length to handle the NULL terminator on */
3224       /* the string. */
3225       for (wc_src = TextF_WcValue(tf) + tf->text.string_length,
3226 	   wc_dst = wc_src + (insert_length - replace_length),
3227 	   i = (int) ((tf->text.string_length + 1) - replace_next);
3228 	   i > 0;
3229 	   --wc_src, --wc_dst, --i)
3230 	*wc_dst = *wc_src;
3231 
3232     /* Update the string.
3233      */
3234     if (insert_length != 0) {
3235       for (wc_src = (wchar_t *)insert,
3236 	   wc_dst = TextF_WcValue(tf) + replace_prev,
3237 	   i = insert_length;
3238 	   i > 0;
3239 	   ++wc_src, ++wc_dst, --i)
3240 	*wc_dst = *wc_src;
3241     }
3242   }
3243 
3244   if (tf->text.has_primary &&
3245       tf->text.prim_pos_left != tf->text.prim_pos_right) {
3246     if (replace_prev <= tf->text.prim_pos_left) {
3247       tf->text.prim_pos_left += delta;
3248       tf->text.prim_pos_right += delta;
3249     }
3250     if (tf->text.prim_pos_left > tf->text.prim_pos_right)
3251       tf->text.prim_pos_right = tf->text.prim_pos_left;
3252   }
3253 
3254   /* make sure the selection are redisplay,
3255      since they were turned off earlier */
3256   if (tf->text.has_primary &&
3257       tf->text.prim_pos_left != tf->text.prim_pos_right)
3258     doSetHighlight((Widget)tf, tf->text.prim_pos_left,
3259 			    tf->text.prim_pos_right, XmHIGHLIGHT_SELECTED);
3260 
3261   tf->text.string_length += insert_length - replace_length;
3262 
3263   if (move_cursor) {
3264     if (TextF_CursorPosition(tf) != newInsert) {
3265       if (newInsert > tf->text.string_length) {
3266 	cursorPos = tf->text.string_length;
3267       } else if (newInsert < 0) {
3268 	cursorPos = 0;
3269       } else {
3270 	cursorPos = newInsert;
3271       }
3272     } else
3273       cursorPos = replace_next + (insert_length - replace_length);
3274     if (event != NULL) {
3275       (void)SetDestination((Widget)tf, cursorPos, False, event->xkey.time);
3276     } else {
3277       (void) SetDestination((Widget)tf, cursorPos, False,
3278 			    XtLastTimestampProcessed(XtDisplay((Widget)tf)));
3279     }
3280     _XmTextFieldSetCursorPosition(tf, event, cursorPos, False, True);
3281   }
3282 
3283   if (TextF_ResizeWidth(tf) && tf->text.do_resize) {
3284     AdjustSize(tf);
3285   } else {
3286     AdjustText(tf, TextF_CursorPosition(tf), False);
3287     RedisplayText(tf, old_pos, tf->text.string_length);
3288   }
3289 
3290   _XmTextFieldDrawInsertionPoint(tf, True);
3291   if (free_insert) XtFree(insert);
3292   return True;
3293 }
3294 
3295 
3296 /*
3297  * Reset selection flag and selection positions and then display
3298  * the new settings.
3299  */
3300 void
3301 _XmTextFieldDeselectSelection(Widget w,
3302 #if NeedWidePrototypes
3303 			      int disown,
3304 #else
3305 			      Boolean disown,
3306 #endif /* NeedWidePrototypes */
3307 			      Time sel_time)
3308 {
3309   XmTextFieldWidget tf = (XmTextFieldWidget) w;
3310 
3311   if (w != NULL && disown) {
3312     if (!sel_time) sel_time = _XmValidTimestamp(w);
3313     /*
3314      * Disown the primary selection (This function is a no-op if
3315      * this widget doesn't own the primary selection)
3316      */
3317     XtDisownSelection(w, XA_PRIMARY, sel_time);
3318   }
3319   if (tf != NULL) {
3320     _XmTextFieldDrawInsertionPoint(tf, False);
3321     tf->text.has_primary = False;
3322     tf->text.take_primary = True;
3323     TextFieldSetHighlight(tf, tf->text.prim_pos_left,
3324 			  tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
3325     tf->text.prim_pos_left = tf->text.prim_pos_right =
3326       tf->text.prim_anchor = TextF_CursorPosition(tf);
3327 
3328     if (!tf->text.has_focus && tf->text.add_mode)
3329       tf->text.add_mode = False;
3330 
3331     RedisplayText(tf, 0, tf->text.string_length);
3332 
3333     _XmTextFieldDrawInsertionPoint(tf, True);
3334   }
3335 }
3336 
3337 /*
3338  * Finds the cursor position from the given X value.
3339  */
3340 static XmTextPosition
3341 GetPosFromX(XmTextFieldWidget tf,
3342 #if NeedWidePrototypes
3343 	    int x)
3344 #else
3345             Position x)
3346 #endif /* NeedWidePrototypes */
3347 {
3348   XmTextPosition position;
3349   int temp_x = 0;
3350   int next_char_width = 0;
3351 
3352   /* Decompose the x to equal the length of the text string */
3353   temp_x += (int) tf->text.h_offset;
3354 
3355   /* Next width is an offset allowing button presses on the left side
3356    * of a character to select that character, while button presses
3357    * on the rigth side of the character select the  NEXT character.
3358    */
3359 
3360   if (tf->text.string_length > 0) {
3361 
3362     if (tf->text.max_char_size != 1) {
3363       next_char_width = FindPixelLength(tf, (char*)TextF_WcValue(tf), 1);
3364     } else {
3365       next_char_width = FindPixelLength(tf, TextF_Value(tf), 1);
3366     }
3367   }
3368 
3369   for (position = 0; temp_x + next_char_width/2 < (int) x &&
3370        position < tf->text.string_length; position++) {
3371 
3372     temp_x+=next_char_width;    /*
3373 				 * We still haven't reached the x pos.
3374 				 * Add the width and find the next chars
3375 				 * width.
3376 				 */
3377 
3378     /*
3379      * If there is a next position, find its width.  Otherwise, use the
3380      * current "next" width.
3381      */
3382 
3383     if (tf->text.string_length > position + 1) {
3384       if (tf->text.max_char_size != 1) {
3385 	next_char_width =
3386 	  FindPixelLength(tf, (char*)(TextF_WcValue(tf) + position + 1), 1);
3387       } else {
3388 	next_char_width = FindPixelLength(tf,
3389 					  TextF_Value(tf) + position + 1, 1);
3390       }
3391     }
3392   } /* for */
3393 
3394   return position;
3395 }
3396 
3397 
3398 /* ARGSUSED */
3399 static Boolean
3400 SetDestination(Widget w,
3401 	       XmTextPosition position,
3402 #if NeedWidePrototypes
3403 	       int disown,
3404 #else
3405 	       Boolean disown,
3406 #endif /* NeedWidePrototypes */
3407 	       Time set_time)
3408 {
3409   XmTextFieldWidget tf = (XmTextFieldWidget) w;
3410   Boolean result = TRUE;
3411   Atom MOTIF_DESTINATION = XInternAtom(XtDisplay(w),
3412 				       XmS_MOTIF_DESTINATION, False);
3413 
3414   if (!XtIsRealized(w)) return False;
3415 
3416   _XmTextFieldDrawInsertionPoint(tf, False);
3417 
3418   if (!disown) {
3419     if (!tf->text.has_destination) {
3420       if (!set_time) set_time = _XmValidTimestamp(w);
3421       result = XmeSecondarySink(w, set_time);
3422       tf->text.dest_time = set_time;
3423       tf->text.has_destination = result;
3424 
3425       if (result) _XmSetDestination(XtDisplay(w), w);
3426     }
3427   } else {
3428     if (tf->text.has_destination) {
3429       if (!set_time) set_time = _XmValidTimestamp(w);
3430       XtDisownSelection(w, MOTIF_DESTINATION, set_time);
3431 
3432       /* Call XmGetDestination(dpy) to get widget that last had
3433 	 destination cursor. */
3434       if (w == XmGetDestination(XtDisplay(w)))
3435 	_XmSetDestination(XtDisplay(w), (Widget)NULL);
3436 
3437       tf->text.has_destination = False;
3438     }
3439   }
3440 
3441   _XmTextFieldDrawInsertionPoint(tf, True);
3442 
3443   return result;
3444 }
3445 
3446 Boolean
3447 _XmTextFieldSetDestination(Widget w,
3448 			   XmTextPosition position,
3449 			   Time set_time)
3450 {
3451   Boolean result;
3452 
3453   result = SetDestination(w, position, False, set_time);
3454 
3455   return result;
3456 }
3457 
3458 
3459 /*
3460  * Calls the losing focus verify callback to verify that the application
3461  * want to traverse out of the text field widget.  Returns the result.
3462  */
3463 static Boolean
3464 VerifyLeave(XmTextFieldWidget tf,
3465 	    XEvent *event)
3466 {
3467   XmTextVerifyCallbackStruct  cbdata;
3468 
3469   cbdata.reason = XmCR_LOSING_FOCUS;
3470   cbdata.event = event;
3471   cbdata.doit = True;
3472   cbdata.currInsert = TextF_CursorPosition(tf);
3473   cbdata.newInsert = TextF_CursorPosition(tf);
3474   cbdata.startPos = TextF_CursorPosition(tf);
3475   cbdata.endPos = TextF_CursorPosition(tf);
3476   cbdata.text = NULL;
3477   XtCallCallbackList((Widget) tf, TextF_LosingFocusCallback(tf),
3478 		     (XtPointer) &cbdata);
3479   tf->text.take_primary = True;
3480   return(cbdata.doit);
3481 }
3482 
3483 /* This routine is used to determine if two adjacent wchar_t characters
3484  * constitute a word boundary */
3485 /* ARGSUSED */
3486 static Boolean
3487 _XmTextFieldIsWordBoundary(XmTextFieldWidget tf,
3488 			   XmTextPosition pos1 ,
3489 			   XmTextPosition pos2)
3490 {
3491   int size_pos1 = 0;
3492   int size_pos2 = 0;
3493   char s1[MB_LEN_MAX];
3494   char s2[MB_LEN_MAX];
3495 
3496   /* if positions aren't adjacent, return False */
3497   if(pos1 < pos2 && ((pos2 - pos1) != 1))
3498     return False;
3499   else if(pos2 < pos1 && ((pos1 - pos2) != 1))
3500     return False;
3501 
3502   if (tf->text.max_char_size == 1) { /* data is char* and one-byte per char */
3503     if (isspace((unsigned char)TextF_Value(tf)[pos1]) ||
3504 	isspace((unsigned char)TextF_Value(tf)[pos2])) return True;
3505   } else {
3506     size_pos1 = wctomb(s1, TextF_WcValue(tf)[pos1]);
3507     size_pos2 = wctomb(s2, TextF_WcValue(tf)[pos2]);
3508     if (size_pos1 == 1 && (size_pos2 != 1 || isspace((unsigned char)*s1)))
3509       return True;
3510     if (size_pos2 == 1 && (size_pos1 != 1 || isspace((unsigned char)*s2)))
3511       return True;
3512   }
3513   return False;
3514 }
3515 
3516 /* This routine accepts an array of wchar_t's containing wchar encodings
3517  * of whitespace characters (and the number of array elements), comparing
3518  * the wide character passed to each element of the array.  If a match
3519  * is found, we got a white space.  This routine exists only because
3520  * iswspace(3c) is not yet standard.  If a system has isw* available,
3521  * calls to this routine should be changed to iswspace(3c) (and callers
3522  * should delete initialization of the array), and this routine should
3523  * be deleted.  Its a stop gap measure to avoid allocating an instance
3524  * variable for the white_space array and/or declaring a widget wide
3525  * global for the data and using a macro.  Its ugly, but it works and
3526  * in the long run will be replaced by standard functionality. */
3527 
3528 /* ARGSUSED */
3529 static Boolean
3530 _XmTextFieldIsWSpace(wchar_t wide_char,
3531 		     wchar_t * white_space ,
3532 		     int num_entries)
3533 {
3534   int i;
3535 
3536   for (i=0; i < num_entries; i++) {
3537     if (wide_char == white_space[i]) return True;
3538   }
3539   return False;
3540 }
3541 
3542 static void
3543 FindWord(XmTextFieldWidget tf,
3544 	 XmTextPosition begin,
3545 	 XmTextPosition *left,
3546 	 XmTextPosition *right)
3547 {
3548   XmTextPosition start, end;
3549   wchar_t white_space[3];
3550 
3551   if (tf->text.max_char_size == 1) {
3552     for (start = begin; start > 0; start--) {
3553       if (isspace((unsigned char)TextF_Value(tf)[start - 1])) {
3554 	break;
3555       }
3556     }
3557     *left = start;
3558 
3559     for (end = begin; end <= tf->text.string_length; end++) {
3560       if (isspace((unsigned char)TextF_Value(tf)[end])) {
3561 	end++;
3562 	break;
3563       }
3564     }
3565     *right = end - 1;
3566   } else { /* check for iswspace and iswordboundary in each direction */
3567     (void)mbtowc(&white_space[0], " ", 1);
3568     (void)mbtowc(&white_space[1], "\n", 1);
3569     (void)mbtowc(&white_space[2], "\t", 1);
3570     for (start = begin; start > 0; start --) {
3571       if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[start-1],white_space, 3)
3572 	  || _XmTextFieldIsWordBoundary(tf, (XmTextPosition) start - 1,
3573 					start)) {
3574 	break;
3575       }
3576     }
3577     *left = start;
3578 
3579     for (end = begin; end <= tf->text.string_length; end++) {
3580       if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[end], white_space, 3)) {
3581 	end++;
3582 	break;
3583       } else if (end < tf->text.string_length) {
3584 	if (_XmTextFieldIsWordBoundary(tf, end, (XmTextPosition)end + 1)) {
3585 	  end += 2; /* want to return position of next word; end + 1 */
3586 	  break;    /* is that position && *right = end - 1... */
3587 	}
3588       }
3589     }
3590     *right = end - 1;
3591   }
3592 }
3593 
3594 static void
3595 FindPrevWord(XmTextFieldWidget tf,
3596 	     XmTextPosition *left,
3597 	     XmTextPosition *right)
3598 {
3599 
3600   XmTextPosition start = TextF_CursorPosition(tf);
3601   wchar_t white_space[3];
3602 
3603   if (tf->text.max_char_size != 1) {
3604     (void)mbtowc(&white_space[0], " ", 1);
3605     (void)mbtowc(&white_space[1], "\n", 1);
3606     (void)mbtowc(&white_space[2], "\t", 1);
3607   }
3608 
3609 
3610   if (tf->text.max_char_size == 1) {
3611     if ((start > 0) &&
3612 	(isspace((unsigned char)TextF_Value(tf)[start - 1]))) {
3613       for (; start > 0; start--) {
3614 	if (!isspace((unsigned char)TextF_Value(tf)[start - 1])) {
3615 	  start--;
3616 	  break;
3617 	}
3618       }
3619     }
3620     FindWord(tf, start, left, right);
3621   } else {
3622     if ((start > 0) && (_XmTextFieldIsWSpace(TextF_WcValue(tf)[start - 1],
3623 					     white_space, 3))) {
3624       for (; start > 0; start--) {
3625 	if (!_XmTextFieldIsWSpace(TextF_WcValue(tf)[start -1],
3626 				  white_space, 3)) {
3627 	  start--;
3628 	  break;
3629 	}
3630       }
3631     } else if ((start > 0) &&
3632 	       _XmTextFieldIsWordBoundary(tf, (XmTextPosition) start - 1,
3633 					  start)) {
3634       start--;
3635     }
3636     FindWord(tf, start, left, right);
3637   }
3638 }
3639 
3640 static void
3641 FindNextWord(XmTextFieldWidget tf,
3642 	     XmTextPosition *left,
3643 	     XmTextPosition *right)
3644 {
3645 
3646   XmTextPosition end = TextF_CursorPosition(tf);
3647   wchar_t white_space[3];
3648 
3649   if (tf->text.max_char_size != 1) {
3650     (void)mbtowc(&white_space[0], " ", 1);
3651     (void)mbtowc(&white_space[1], "\n", 1);
3652     (void)mbtowc(&white_space[2], "\t", 1);
3653   }
3654 
3655 
3656   if(tf->text.max_char_size == 1) {
3657     if (isspace((unsigned char)TextF_Value(tf)[end])) {
3658       for (end = TextF_CursorPosition(tf);
3659 	   end < tf->text.string_length; end++) {
3660 	if (!isspace((unsigned char)TextF_Value(tf)[end])) {
3661 	  break;
3662 	}
3663       }
3664     }
3665     FindWord(tf, end, left, right);
3666     /*
3667      * Set right to the last whitespace following the end of the
3668      * current word.
3669      */
3670     while (*right < tf->text.string_length &&
3671 	   isspace((unsigned char)TextF_Value(tf)[(int)*right]))
3672       *right = *right + 1;
3673     if (*right < tf->text.string_length)
3674       *right = *right - 1;
3675   } else {
3676     if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[end], white_space, 3)) {
3677       for (; end < tf->text.string_length; end ++) {
3678 	if (!_XmTextFieldIsWSpace(TextF_WcValue(tf)[end], white_space, 3)) {
3679 	  break;
3680 	}
3681       }
3682     } else { /* if for other reasons at word boundry, advance to next word */
3683       if ((end < tf->text.string_length) &&
3684 	  _XmTextFieldIsWordBoundary(tf, end, (XmTextPosition) end + 1))
3685 	end++;
3686     }
3687     FindWord(tf, end, left, right);
3688     /*
3689      * If word boundary caused by whitespace, set right to the last
3690      * whitespace following the end of the current word.
3691      */
3692     if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[(int)*right], white_space, 3)) {
3693       while (*right < tf->text.string_length &&
3694 	     _XmTextFieldIsWSpace(TextF_WcValue(tf)[(int)*right],
3695 				  white_space, 3)) {
3696 	*right = *right + 1;
3697       }
3698       if (*right < tf->text.string_length)
3699 	*right = *right - 1;
3700     }
3701   }
3702 }
3703 
3704 static void
3705 CheckDisjointSelection(Widget w,
3706 		       XmTextPosition position,
3707 		       Time sel_time)
3708 {
3709   XmTextFieldWidget tf = (XmTextFieldWidget) w;
3710   XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
3711 
3712   if (tf->text.add_mode ||
3713       (tf->text.has_primary && left != right &&
3714        position >= left && position <= right))
3715     tf->text.pending_off = FALSE;
3716   else
3717     tf->text.pending_off = TRUE;
3718 
3719   if (left == right) {
3720     (void) SetDestination(w, position, False, sel_time);
3721     tf->text.prim_anchor = position;
3722   } else {
3723     (void) SetDestination(w, position, False, sel_time);
3724     if (!tf->text.add_mode) tf->text.prim_anchor = position;
3725   }
3726 }
3727 
3728 static Boolean
3729 NeedsPendingDelete(XmTextFieldWidget tf)
3730 {
3731   return (tf->text.add_mode ?
3732 	  (TextF_PendingDelete(tf) &&
3733 	   tf->text.has_primary &&
3734 	   tf->text.prim_pos_left != tf->text.prim_pos_right &&
3735 	   tf->text.prim_pos_left <= TextF_CursorPosition(tf) &&
3736 	   tf->text.prim_pos_right >= TextF_CursorPosition(tf)) :
3737 	  (tf->text.has_primary &&
3738 	   tf->text.prim_pos_left != tf->text.prim_pos_right));
3739 }
3740 
3741 static Boolean
3742 NeedsPendingDeleteDisjoint(XmTextFieldWidget tf)
3743 {
3744   return (TextF_PendingDelete(tf) &&
3745 	  tf->text.has_primary &&
3746 	  tf->text.prim_pos_left != tf->text.prim_pos_right &&
3747 	  tf->text.prim_pos_left <= TextF_CursorPosition(tf) &&
3748 	  tf->text.prim_pos_right >= TextF_CursorPosition(tf));
3749 }
3750 
3751 
3752 /*ARGSUSED*/
3753 static Boolean
3754 PrintableString(XmTextFieldWidget tf,
3755 		char* str,
3756 		int n,
3757 		Boolean use_wchar) /* sometimes unused */
3758 {
3759 #ifdef SUPPORT_ZERO_WIDTH
3760   /* some locales (such as Thai) have characters that are
3761    * printable but non-spacing. These should be inserted,
3762    * even if they have zero width.
3763    */
3764   if (tf->text.max_char_size == 1) {
3765     int i;
3766     if (!use_wchar) {
3767       for (i = 0; i < n; i++) {
3768 	if (!isprint((unsigned char)str[i])) {
3769 	  return False;
3770 	}
3771       }
3772     } else {
3773       char scratch[8];
3774       wchar_t *ws = (wchar_t *) str;
3775       for (i = 0; i < n; i++) {
3776 	if (wctomb(scratch, ws[i]) <= 0)
3777 	  return False;
3778 	if (!isprint((unsigned char)scratch[0])) {
3779 	  return False;
3780 	}
3781       }
3782     }
3783     return True;
3784   } else {
3785     /* tf->text.max_char_size > 1 */
3786 #ifdef HAS_WIDECHAR_FUNCTIONS
3787     if (use_wchar) {
3788       int i;
3789       wchar_t *ws = (wchar_t *) str;
3790       for (i = 0; i < n; i++) {
3791 	if (!iswprint(ws[i])) {
3792 	  return False;
3793 	}
3794       }
3795       return True;
3796     } else {
3797       int i, csize;
3798       wchar_t wc;
3799 #ifndef NO_MULTIBYTE
3800       for (i = 0, csize = mblen(str, tf->text.max_char_size);
3801 	   i < n;
3802 	   i += csize, csize=mblen(&(str[i]), tf->text.max_char_size))
3803 #else
3804       for (i = 0, csize = *str ? 1 : 0; i < n;
3805 	   i += csize, csize = str[i] ? 1 : 0)
3806 #endif
3807 	{
3808 	  if (csize < 0)
3809 	    return False;
3810 	  if (mbtowc(&wc, &(str[i]), tf->text.max_char_size) <= 0)
3811 	    return False;
3812 	  if (!iswprint(wc)) {
3813 	    return False;
3814 	  }
3815 	}
3816     }
3817 #else /* HAS_WIDECHAR_FUNCTIONS */
3818     /*
3819      * This will only check if any single-byte characters are non-
3820      * printable. Better than nothing...
3821      */
3822     int i, csize;
3823     if (!use_wchar) {
3824 #ifndef NO_MULTIBYTE
3825       for (i = 0, csize = mblen(str, tf->text.max_char_size);
3826 	   i < n;
3827 	   i += csize, csize=mblen(&(str[i]), tf->text.max_char_size))
3828 #else
3829       for (i = 0, csize = *str ? 1 : 0; i < n;
3830 	   i += csize, csize = str[i] ? 1 : 0)
3831 #endif
3832 	{
3833 	  if (csize < 0)
3834 	    return False;
3835 	  if (csize == 1 && !isprint((unsigned char)str[i])) {
3836 	    return False;
3837 	  }
3838 	}
3839     } else {
3840       char scratch[8];
3841       wchar_t *ws = (wchar_t *) str;
3842       for (i = 0; i < n; i++) {
3843 	if ((csize = wctomb(scratch, ws[i])) <= 0)
3844 	  return False;
3845 	if (csize == 1 && !isprint((unsigned char)scratch[0])) {
3846 	  return False;
3847 	}
3848       }
3849     }
3850 #endif /* HAS_WIDECHAR_FUNCTIONS */
3851     return True;
3852   }
3853 #else /* SUPPORT_ZERO_WIDTH */
3854   if (TextF_UseFontSet(tf)) {
3855       if(use_wchar)
3856 	  return (XwcTextEscapement((XFontSet)TextF_Font(tf), (wchar_t *)str, n) != 0);
3857       else
3858 	  return (XmbTextEscapement((XFontSet)TextF_Font(tf), str, n) != 0);
3859 #ifdef USE_XFT
3860   } else if (TextF_UseXft(tf)) {
3861     XGlyphInfo	ext;
3862 
3863     XftTextExtentsUtf8(XtDisplay(tf), TextF_XftFont(tf),
3864             (FcChar8*)str, n, &ext);
3865 
3866     return ext.xOff != 0;
3867 #endif
3868   }
3869   else {
3870     if (use_wchar) {
3871       char cache[100];
3872       char *tmp, *cache_ptr;
3873       wchar_t *tmp_str;
3874       int ret_val, buf_size, count;
3875       Boolean is_printable;
3876       buf_size = (n * MB_CUR_MAX) + 1;
3877       cache_ptr = tmp = XmStackAlloc(buf_size, cache);
3878 
3879       tmp_str = (wchar_t *)str;
3880       // Fixed MZ BZ#1257: by Brad Despres <brad@sd.aonix.com>
3881       count = 0;
3882       do {
3883 	ret_val = wctomb(tmp, *tmp_str);
3884 	count += 1;
3885 	tmp += ret_val;
3886 	buf_size -= ret_val;
3887 	tmp_str++;
3888       } while ( (ret_val > 0)&& (buf_size >= MB_CUR_MAX) && (count < n) ) ;
3889       if (ret_val == -1)    /* bad character */
3890 	return (False);
3891       is_printable = XTextWidth(TextF_Font(tf), cache_ptr, tmp - cache_ptr);
3892       XmStackFree(cache_ptr, cache);
3893       return (is_printable);
3894     }
3895     else {
3896       return (XTextWidth(TextF_Font(tf), str, n) != 0);
3897     }
3898   }
3899 #endif /* SUPPORT_ZERO_WIDTH */
3900 }
3901 
3902 /****************************************************************
3903  *
3904  * Input functions defined in the action table.
3905  *
3906  ****************************************************************/
3907 
3908 /* ARGSUSED */
3909 static void
3910 InsertChar(Widget w,
3911 	   XEvent *event,
3912 	   char **params,
3913 	   Cardinal *num_params)
3914 {
3915   XmTextFieldWidget tf = (XmTextFieldWidget) w;
3916   char insert_string[TEXT_MAX_INSERT_SIZE + 1]; /* NULL-terminated below */
3917   XmTextPosition cursorPos =0 , nextPos = 0;
3918   wchar_t * wc_insert_string;
3919   int insert_length, i;
3920   int num_chars;
3921   Boolean replace_res;
3922   Boolean pending_delete = False;
3923   Status status_return;
3924   XmAnyCallbackStruct cb;
3925 
3926   /* Determine what was pressed.
3927    */
3928   insert_length = XmImMbLookupString(w, (XKeyEvent *) event, insert_string,
3929 		                     TEXT_MAX_INSERT_SIZE, (KeySym *) NULL,
3930 				     &status_return);
3931 
3932   if (insert_length > 0 && !TextF_Editable(tf)) {
3933     if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
3934     return;
3935   }
3936 
3937   /* If there is more data than we can handle, bail out */
3938   if (status_return == XBufferOverflow || insert_length > TEXT_MAX_INSERT_SIZE)
3939     return;
3940 
3941   /* *LookupString in some cases can return the NULL as a character, such
3942    * as when the user types <Ctrl><back_quote> or <Ctrl><@>.  Text widget
3943    * can't handle the NULL as a character, so we dump it here.
3944    */
3945 
3946   for (i=0; i < insert_length; i++)
3947     if (insert_string[i] == 0) insert_length = 0; /* toss out input string */
3948 
3949   if (insert_length > 0) {
3950     /* do not insert non-printing characters */
3951     if (!PrintableString(tf, insert_string, insert_length, False))
3952       return;
3953 
3954     _XmTextFieldDrawInsertionPoint(tf, False);
3955     if (NeedsPendingDeleteDisjoint(tf)) {
3956       if (!tf->text.has_primary ||
3957 	  (cursorPos = tf->text.prim_pos_left) ==
3958 	  (nextPos = tf->text.prim_pos_right)) {
3959 	tf->text.prim_anchor = TextF_CursorPosition(tf);
3960       }
3961       pending_delete = True;
3962 
3963       tf->text.prim_anchor = TextF_CursorPosition(tf);
3964 
3965     } else {
3966       cursorPos = nextPos = TextF_CursorPosition(tf);
3967     }
3968 
3969 
3970     if (tf->text.max_char_size == 1) {
3971       if (tf->text.overstrike) nextPos += insert_length;
3972       if (nextPos > tf->text.string_length) nextPos = tf->text.string_length;
3973       replace_res = _XmTextFieldReplaceText(tf, (XEvent *) event, cursorPos,
3974 					    nextPos, insert_string,
3975 					    insert_length, True);
3976     } else {
3977       char stack_cache[100];
3978       insert_string[insert_length] = '\0'; /* NULL terminate for mbstowcs */
3979       wc_insert_string = (wchar_t*)XmStackAlloc((Cardinal)(insert_length+1) *
3980 						sizeof(wchar_t), stack_cache);
3981       num_chars = mbstowcs(wc_insert_string, insert_string, insert_length+1);
3982       if (num_chars < 0) num_chars = 0;
3983       if (tf->text.overstrike) nextPos += num_chars;
3984       if (nextPos > tf->text.string_length) nextPos = tf->text.string_length;
3985       replace_res = _XmTextFieldReplaceText(tf, (XEvent *) event, cursorPos,
3986 					    nextPos, (char*) wc_insert_string,
3987 					    num_chars, True);
3988       XmStackFree((char *)wc_insert_string, stack_cache);
3989     }
3990 
3991     if (replace_res) {
3992       if (pending_delete) {
3993 	_XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
3994 				   TextF_CursorPosition(tf), event->xkey.time);
3995 	tf->text.pending_off = False;
3996       }
3997       CheckDisjointSelection(w, TextF_CursorPosition(tf),
3998 			     event->xkey.time);
3999       _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
4000 				    False, True);
4001       cb.reason = XmCR_VALUE_CHANGED;
4002       cb.event = event;
4003       XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4004 			 (XtPointer) &cb);
4005     }
4006     _XmTextFieldDrawInsertionPoint(tf, True);
4007   }
4008 }
4009 
4010 /* ARGSUSED */
4011 static void
4012 DeletePrevChar(Widget w,
4013 	       XEvent *event,
4014 	       char **params,
4015 	       Cardinal *num_params)
4016 {
4017   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4018   XmAnyCallbackStruct cb;
4019 
4020   /* if pending delete is on and there is a selection */
4021   _XmTextFieldDrawInsertionPoint(tf, False);
4022   if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
4023   else {
4024     if (tf->text.has_primary &&
4025 	tf->text.prim_pos_left != tf->text.prim_pos_right) {
4026       if (TextF_CursorPosition(tf) - 1 >= 0)
4027 	if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf) - 1,
4028 				    TextF_CursorPosition(tf), NULL, 0, True)) {
4029 	  CheckDisjointSelection(w, TextF_CursorPosition(tf),
4030 				 event->xkey.time);
4031 	  _XmTextFieldSetCursorPosition(tf, event,
4032 					TextF_CursorPosition(tf),
4033 					False, True);
4034 	  cb.reason = XmCR_VALUE_CHANGED;
4035 	  cb.event = event;
4036 	  XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4037 			     (XtPointer) &cb);
4038 	}
4039     } else if (TextF_CursorPosition(tf) - 1 >= 0) {
4040       if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf) - 1,
4041 				  TextF_CursorPosition(tf), NULL, 0, True)) {
4042 	CheckDisjointSelection(w, TextF_CursorPosition(tf),
4043 			       event->xkey.time);
4044 	_XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
4045 				      False, True);
4046 	cb.reason = XmCR_VALUE_CHANGED;
4047 	cb.event = event;
4048 	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4049 			   (XtPointer) &cb);
4050       }
4051     }
4052   }
4053   _XmTextFieldDrawInsertionPoint(tf, True);
4054 }
4055 
4056 /* ARGSUSED */
4057 static void
4058 DeleteNextChar(Widget w,
4059 	       XEvent *event,
4060 	       char **params,
4061 	       Cardinal *num_params)
4062 {
4063   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4064   XmAnyCallbackStruct cb;
4065 
4066   /* if pending delete is on and there is a selection */
4067   _XmTextFieldDrawInsertionPoint(tf, False);
4068   if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
4069   else {
4070     if (tf->text.has_primary &&
4071 	tf->text.prim_pos_left != tf->text.prim_pos_right) {
4072       if (TextF_CursorPosition(tf) < tf->text.string_length)
4073 	if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
4074 				    TextF_CursorPosition(tf) + 1, NULL, 0,
4075 				    True)) {
4076 	  CheckDisjointSelection(w, TextF_CursorPosition(tf),
4077 				 event->xkey.time);
4078 	  _XmTextFieldSetCursorPosition(tf, event,
4079 					TextF_CursorPosition(tf),
4080 					False, True);
4081 	  cb.reason = XmCR_VALUE_CHANGED;
4082 	  cb.event = event;
4083 	  XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4084 			     (XtPointer) &cb);
4085 	}
4086     } else if (TextF_CursorPosition(tf) < tf->text.string_length)
4087       if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
4088 				  TextF_CursorPosition(tf) + 1, NULL,
4089 				  0, True)) {
4090 	CheckDisjointSelection(w, TextF_CursorPosition(tf),
4091 			       event->xkey.time);
4092 	_XmTextFieldSetCursorPosition(tf, event,
4093 				      TextF_CursorPosition(tf),
4094 				      False, True);
4095 	cb.reason = XmCR_VALUE_CHANGED;
4096 	cb.event = event;
4097 	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4098 			   (XtPointer) &cb);
4099       }
4100   }
4101   _XmTextFieldDrawInsertionPoint(tf, True);
4102 }
4103 
4104 /* ARGSUSED */
4105 static void
4106 DeletePrevWord(Widget w,
4107 	       XEvent *event,
4108 	       char **params,
4109 	       Cardinal *num_params)
4110 {
4111   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4112   XmTextPosition left, right;
4113   XmAnyCallbackStruct cb;
4114 
4115   /* if pending delete is on and there is a selection */
4116   _XmTextFieldDrawInsertionPoint(tf, False);
4117   if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
4118   else {
4119     FindPrevWord(tf, &left, &right);
4120     if (tf->text.has_primary &&
4121 	tf->text.prim_pos_left != tf->text.prim_pos_right) {
4122       if (_XmTextFieldReplaceText(tf, event, left, TextF_CursorPosition(tf),
4123 				  NULL, 0, True)) {
4124 	CheckDisjointSelection(w, TextF_CursorPosition(tf),
4125 			       event->xkey.time);
4126 	_XmTextFieldSetCursorPosition(tf, event,
4127 				      TextF_CursorPosition(tf),
4128 				      False, True);
4129 	cb.reason = XmCR_VALUE_CHANGED;
4130 	cb.event = event;
4131 	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4132 			   (XtPointer) &cb);
4133       }
4134     } else if (TextF_CursorPosition(tf) - 1 >= 0)
4135       if (_XmTextFieldReplaceText(tf, event, left, TextF_CursorPosition(tf),
4136 				  NULL, 0, True)) {
4137 	CheckDisjointSelection(w, TextF_CursorPosition(tf),
4138 			       event->xkey.time);
4139 	_XmTextFieldSetCursorPosition(tf, event,
4140 				      TextF_CursorPosition(tf),
4141 				      False, True);
4142 	cb.reason = XmCR_VALUE_CHANGED;
4143 	cb.event = event;
4144 	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4145 			   (XtPointer) &cb);
4146       }
4147   }
4148   _XmTextFieldDrawInsertionPoint(tf, True);
4149 }
4150 
4151 /* ARGSUSED */
4152 static void
4153 DeleteNextWord(Widget w,
4154 	       XEvent *event,
4155 	       char **params,
4156 	       Cardinal *num_params)
4157 {
4158   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4159   XmTextPosition left, right;
4160   XmAnyCallbackStruct cb;
4161 
4162   /* if pending delete is on and there is a selection */
4163   _XmTextFieldDrawInsertionPoint(tf, False);
4164   if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
4165   else {
4166     FindNextWord(tf, &left, &right);
4167     if (tf->text.has_primary &&
4168 	tf->text.prim_pos_left != tf->text.prim_pos_right) {
4169       if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
4170 				  right, NULL, 0, True)) {
4171 	CheckDisjointSelection(w, TextF_CursorPosition(tf),
4172 			       event->xkey.time);
4173 	_XmTextFieldSetCursorPosition(tf, event,
4174 				      TextF_CursorPosition(tf),
4175 				      False, True);
4176 	cb.reason = XmCR_VALUE_CHANGED;
4177 	cb.event = event;
4178 	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4179 			   (XtPointer) &cb);
4180       }
4181     } else if (TextF_CursorPosition(tf) < tf->text.string_length)
4182       if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
4183 				  right, NULL, 0, True)) {
4184 	CheckDisjointSelection(w, TextF_CursorPosition(tf),
4185 			       event->xkey.time);
4186 	_XmTextFieldSetCursorPosition(tf, event,
4187 				      TextF_CursorPosition(tf),
4188 				      False, True);
4189 	cb.reason = XmCR_VALUE_CHANGED;
4190 	cb.event = event;
4191 	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4192 			   (XtPointer) &cb);
4193       }
4194   }
4195   _XmTextFieldDrawInsertionPoint(tf, True);
4196 }
4197 
4198 
4199 /* ARGSUSED */
4200 static void
4201 DeleteToEndOfLine(Widget w,
4202 		  XEvent *event,
4203 		  char **params,
4204 		  Cardinal *num_params)
4205 {
4206   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4207   XmAnyCallbackStruct cb;
4208 
4209   /* if pending delete is on and there is a selection */
4210   _XmTextFieldDrawInsertionPoint(tf, False);
4211   if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
4212   else if (TextF_CursorPosition(tf) < tf->text.string_length) {
4213     if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
4214 				tf->text.string_length, NULL, 0, True)) {
4215       CheckDisjointSelection(w, TextF_CursorPosition(tf),
4216 			     event->xkey.time);
4217       _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
4218 				    False, True);
4219       cb.reason = XmCR_VALUE_CHANGED;
4220       cb.event = event;
4221       XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4222 			 (XtPointer) &cb);
4223     }
4224   }
4225   _XmTextFieldDrawInsertionPoint(tf, True);
4226 }
4227 
4228 
4229 /* ARGSUSED */
4230 static void
4231 DeleteToStartOfLine(Widget w,
4232 		    XEvent *event,
4233 		    char **params,
4234 		    Cardinal *num_params)
4235 {
4236   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4237   XmAnyCallbackStruct cb;
4238 
4239   /* if pending delete is on and there is a selection */
4240   _XmTextFieldDrawInsertionPoint(tf, False);
4241   if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
4242   else if (TextF_CursorPosition(tf) - 1 >= 0) {
4243     if (_XmTextFieldReplaceText(tf, event, 0,
4244 			        TextF_CursorPosition(tf), NULL, 0, True)) {
4245       CheckDisjointSelection(w, TextF_CursorPosition(tf),
4246 			     event->xkey.time);
4247       _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
4248 				    False, True);
4249       cb.reason = XmCR_VALUE_CHANGED;
4250       cb.event = event;
4251       XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
4252 			 (XtPointer) &cb);
4253     }
4254   }
4255   _XmTextFieldDrawInsertionPoint(tf, True);
4256 }
4257 
4258 /* ARGSUSED */
4259 static void
4260 ProcessCancel(Widget w,
4261 	      XEvent *event,
4262 	      char **params,
4263 	      Cardinal *num_params)
4264 {
4265   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4266 
4267   XmParentInputActionRec  p_event;
4268 
4269   p_event.process_type = XmINPUT_ACTION;
4270   p_event.action = XmPARENT_CANCEL;
4271   p_event.event = event;/* Pointer to XEvent. */
4272   p_event.params = params; /* Or use what you have if   */
4273   p_event.num_params = num_params;/* input is from translation.*/
4274 
4275   _XmTextFieldDrawInsertionPoint(tf, False);
4276   if (tf->text.has_secondary) {
4277     tf->text.cancel = True;
4278     /* This will mark the has_secondary field to False. */
4279     _XmTextFieldSetSel2(w, 1, 0, False, event->xkey.time);
4280     XtUngrabKeyboard(w, CurrentTime);
4281   }
4282 
4283   if (tf->text.has_primary && tf->text.extending) {
4284     tf->text.cancel = True;
4285     /* reset orig_left and orig_right */
4286     _XmTextFieldStartSelection(tf, tf->text.orig_left,
4287 			       tf->text.orig_right, event->xkey.time);
4288     tf->text.pending_off = False;
4289     _XmTextFieldSetCursorPosition(tf, NULL, tf->text.stuff_pos, True, True);
4290   }
4291 
4292   if (!tf->text.cancel)
4293     (void) _XmParentProcess(XtParent(tf), (XmParentProcessData) &p_event);
4294 
4295   if (tf->text.select_id) {
4296     XtRemoveTimeOut(tf->text.select_id);
4297     tf->text.select_id = 0;
4298   }
4299   _XmTextFieldDrawInsertionPoint(tf, True);
4300 
4301 }
4302 
4303 /* ARGSUSED */
4304 static void
4305 Activate(Widget w,
4306 	 XEvent *event,
4307 	 char **params,
4308 	 Cardinal *num_params)
4309 {
4310   XmAnyCallbackStruct cb;
4311   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4312   XmParentInputActionRec  p_event;
4313 
4314   p_event.process_type = XmINPUT_ACTION;
4315   p_event.action = XmPARENT_ACTIVATE;
4316   p_event.event = event;/* Pointer to XEvent. */
4317   p_event.params = params; /* Or use what you have if   */
4318   p_event.num_params = num_params;/* input is from translation.*/
4319 
4320   cb.reason = XmCR_ACTIVATE;
4321   cb.event  = event;
4322   XtCallCallbackList(w, TextF_ActivateCallback(tf), (XtPointer) &cb);
4323 
4324   (void) _XmParentProcess(XtParent(w), (XmParentProcessData) &p_event);
4325 }
4326 
4327 static void
4328 SetAnchorBalancing(XmTextFieldWidget tf,
4329 		   XmTextPosition position)
4330 {
4331   XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
4332   float bal_point;
4333 
4334   if (!tf->text.has_primary ||
4335       left == right) {
4336     tf->text.prim_anchor = position;
4337   } else {
4338     bal_point = (float)(((float)(right - left) / 2.0) + (float)left);
4339 
4340     /* shift anchor and direction to opposite end of the selection */
4341     if ((float)position < bal_point) {
4342       tf->text.prim_anchor = tf->text.orig_right;
4343     } else if ((float)position > bal_point) {
4344       tf->text.prim_anchor = tf->text.orig_left;
4345     }
4346   }
4347 }
4348 
4349 static void
4350 SetNavigationAnchor(XmTextFieldWidget tf,
4351 		    XmTextPosition old_position,
4352 		    XmTextPosition new_position,
4353 #if NeedWidePrototypes
4354 		    int extend)
4355 #else
4356                     Boolean extend)
4357 #endif /* NeedWidePrototypes */
4358 {
4359   XmTextPosition left = tf->text.prim_pos_left,
4360                  right = tf->text.prim_pos_right;
4361   Boolean has_selection = tf->text.has_primary && left != right;
4362 
4363   if (!tf->text.add_mode) {
4364     if (extend) {
4365       if (old_position < left || old_position > right)
4366       {
4367 	/* start outside selection - anchor at start position */
4368 	tf->text.prim_anchor = old_position;
4369     }
4370       else if (!has_selection ||
4371           ((left <= new_position) && (new_position <= right)))
4372       {
4373 	/* no selection, or moving into selection */
4374 	SetAnchorBalancing(tf, old_position);
4375     }
4376       else
4377       {
4378 	/* moving to outside selection */
4379 	SetAnchorBalancing(tf, new_position);
4380     }
4381     } else {
4382       if (has_selection) {
4383 	SetSelection(tf, old_position, old_position, True);
4384 	tf->text.prim_anchor = old_position;
4385       }
4386     }
4387   } else if (extend) {
4388     if (old_position < left || old_position > right)
4389     {
4390       /* start outside selection - anchor at start position */
4391       tf->text.prim_anchor = old_position;
4392   }
4393     else if (!has_selection ||
4394         ((left <= new_position )&& (new_position <= right)))
4395     {
4396       /* no selection, or moving into selection */
4397       SetAnchorBalancing(tf, old_position);
4398   }
4399     else
4400     {
4401       /* moving to outside selection */
4402       SetAnchorBalancing(tf, new_position);
4403   }
4404   }
4405 }
4406 
4407 static void
4408 CompleteNavigation(XmTextFieldWidget tf,
4409 		   XEvent *event,
4410 		   XmTextPosition position,
4411 		   Time time,
4412 #if NeedWidePrototypes
4413 		   int extend)
4414 #else
4415                    Boolean extend)
4416 #endif /* NeedWidePrototypes */
4417 {
4418   XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
4419 
4420   if ((tf->text.add_mode &&
4421        tf->text.has_primary &&
4422        position >= left && position <= right) || extend)
4423     tf->text.pending_off = FALSE;
4424   else
4425     tf->text.pending_off = TRUE;
4426 
4427   _XmTextFieldSetCursorPosition(tf, event, position, True, True);
4428 
4429   if (extend) {
4430     if (tf->text.prim_anchor > position) {
4431       left = position;
4432       right = tf->text.prim_anchor;
4433     } else {
4434       left = tf->text.prim_anchor;
4435       right = position;
4436     }
4437     _XmTextFieldStartSelection(tf, left, right, time);
4438     tf->text.pending_off = False;
4439 
4440     tf->text.orig_left = left;
4441     tf->text.orig_right = right;
4442   }
4443 }
4444 
4445 /* ARGSUSED */
4446 static void
4447 SimpleMovement(Widget w,
4448 	       XEvent *event,
4449 	       String *params,
4450 	       Cardinal *num_params,
4451 	       XmTextPosition cursorPos,
4452 	       XmTextPosition position)
4453 {
4454   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4455   Boolean extend = False;
4456   int value;
4457 
4458   if (*num_params > 0)
4459   {
4460       /* There is only one valid reptype value for this reptype, i.e.
4461 	 "extend". If we found a match then set the Boolean to true. */
4462       if (_XmConvertActionParamToRepTypeId((Widget) w,
4463 			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
4464 			   params[0], False, &value) == True)
4465       {
4466 	  extend = True;
4467       }
4468   }
4469 
4470   _XmTextFieldDrawInsertionPoint(tf, False);
4471   SetNavigationAnchor(tf, cursorPos, position, extend);
4472   CompleteNavigation(tf, event, position, event->xkey.time, extend);
4473   _XmTextFieldDrawInsertionPoint(tf, True);
4474 }
4475 
4476 /* ARGSUSED */
4477 static void
4478 BackwardChar(Widget w,
4479 	     XEvent *event,
4480 	     char **params,
4481 	     Cardinal *num_params)
4482 {
4483   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4484   XmTextPosition cursorPos, position;
4485 
4486   cursorPos = TextF_CursorPosition(tf);
4487 
4488   if (cursorPos > 0) {
4489     _XmTextFieldDrawInsertionPoint(tf, False);
4490     position = cursorPos - 1;
4491     SimpleMovement((Widget) tf, event, params, num_params,
4492 		   cursorPos, position);
4493     _XmTextFieldDrawInsertionPoint(tf, True);
4494   }
4495 }
4496 
4497 /* ARGSUSED */
4498 static void
4499 ForwardChar(Widget w,
4500 	    XEvent *event,
4501 	    char **params,
4502 	    Cardinal *num_params)
4503 {
4504   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4505   XmTextPosition cursorPos, position;
4506 
4507   cursorPos = TextF_CursorPosition(tf);
4508 
4509   if (cursorPos < tf->text.string_length) {
4510     _XmTextFieldDrawInsertionPoint(tf, False);
4511     position = cursorPos + 1;
4512     SimpleMovement((Widget) tf, event, params, num_params,
4513 		   cursorPos, position);
4514     _XmTextFieldDrawInsertionPoint(tf, True);
4515   }
4516 }
4517 
4518 /* ARGSUSED */
4519 static void
4520 BackwardWord(Widget w,
4521 	     XEvent *event,
4522 	     char **params,
4523 	     Cardinal *num_params)
4524 {
4525   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4526   XmTextPosition cursorPos, position, dummy;
4527 
4528   cursorPos = TextF_CursorPosition(tf);
4529 
4530   if (cursorPos > 0) {
4531     _XmTextFieldDrawInsertionPoint(tf, False);
4532     FindPrevWord(tf, &position, &dummy);
4533     SimpleMovement((Widget) tf, event, params, num_params,
4534 		   cursorPos, position);
4535     _XmTextFieldDrawInsertionPoint(tf, True);
4536   }
4537 }
4538 
4539 /* ARGSUSED */
4540 static void
4541 ForwardWord(Widget w,
4542 	    XEvent *event,
4543 	    char **params,
4544 	    Cardinal *num_params)
4545 {
4546   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4547   XmTextPosition cursorPos, position, dummy;
4548   wchar_t white_space[3];
4549 
4550   if (tf->text.max_char_size != 1) {
4551     (void)mbtowc(&white_space[0], " ", 1);
4552     (void)mbtowc(&white_space[1], "\n", 1);
4553     (void)mbtowc(&white_space[2], "\t", 1);
4554   }
4555 
4556   cursorPos = TextF_CursorPosition(tf);
4557 
4558   _XmTextFieldDrawInsertionPoint(tf, False);
4559   if (cursorPos < tf->text.string_length) {
4560     if (tf->text.max_char_size == 1) {
4561       if (isspace((unsigned char)TextF_Value(tf)[cursorPos]))
4562 	FindWord(tf, cursorPos, &dummy, &position);
4563       else
4564 	FindNextWord(tf, &dummy, &position);
4565       if(isspace((unsigned char)TextF_Value(tf)[position])) {
4566 	for (;position < tf->text.string_length; position++) {
4567 	  if (!isspace((unsigned char)TextF_Value(tf)[position]))
4568 	    break;
4569 	}
4570       }
4571     } else {
4572       if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[cursorPos],
4573 			       white_space, 3))
4574 	FindWord(tf, cursorPos, &dummy, &position);
4575       else
4576 	FindNextWord(tf, &dummy, &position);
4577       if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[position],
4578 			       white_space, 3)) {
4579 	for (; position < tf->text.string_length; position++) {
4580 	  if (!_XmTextFieldIsWSpace(TextF_WcValue(tf)[position],
4581 				    white_space, 3))
4582 	    break;
4583 	}
4584       }
4585     }
4586     SimpleMovement((Widget) tf, event, params, num_params,
4587 		   cursorPos, position);
4588   }
4589   _XmTextFieldDrawInsertionPoint(tf, True);
4590 }
4591 
4592 
4593 /* ARGSUSED */
4594 static void
4595 EndOfLine(Widget w,
4596 	  XEvent *event,
4597 	  char **params,
4598 	  Cardinal *num_params)
4599 {
4600   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4601   XmTextPosition cursorPos, position;
4602 
4603   cursorPos = TextF_CursorPosition(tf);
4604 
4605   if (cursorPos < tf->text.string_length) {
4606     _XmTextFieldDrawInsertionPoint(tf, False);
4607     position = tf->text.string_length;
4608     SimpleMovement((Widget) tf, event, params, num_params,
4609 		   cursorPos, position);
4610     _XmTextFieldDrawInsertionPoint(tf, True);
4611   }
4612 }
4613 
4614 
4615 /* ARGSUSED */
4616 static void
4617 BeginningOfLine(Widget w,
4618 		XEvent *event,
4619 		char **params,
4620 		Cardinal *num_params)
4621 {
4622   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4623   XmTextPosition cursorPos, position;
4624 
4625   cursorPos = TextF_CursorPosition(tf);
4626 
4627   if (cursorPos > 0) {
4628     position = 0;
4629     _XmTextFieldDrawInsertionPoint(tf, False);
4630     SimpleMovement((Widget) tf, event, params, num_params,
4631 		   cursorPos, position);
4632     _XmTextFieldDrawInsertionPoint(tf, True);
4633   }
4634 }
4635 
4636 static void
4637 SetSelection(XmTextFieldWidget tf,
4638 	     XmTextPosition left,
4639 	     XmTextPosition right,
4640 #if NeedWidePrototypes
4641 	     int redisplay)
4642 #else
4643              Boolean redisplay)
4644 #endif /* NeedWidePrototypes */
4645 {
4646   XmTextPosition display_left, display_right;
4647   XmTextPosition old_prim_left, old_prim_right;
4648 
4649   if (left < 0) left = 0;
4650   if (right < 0) right = 0;
4651 
4652   if (left > tf->text.string_length)
4653     left = tf->text.string_length;
4654   if (right > tf->text.string_length)
4655     right = tf->text.string_length;
4656 
4657   if (left == right && tf->text.prim_pos_left != tf->text.prim_pos_right &&
4658       tf->text.add_mode) {
4659     _XmTextFieldDrawInsertionPoint(tf, False);
4660     tf->text.add_mode = False;
4661     _XmTextFieldDrawInsertionPoint(tf, True);
4662   }
4663   if (left == tf->text.prim_pos_left && right == tf->text.prim_pos_right)
4664     return;
4665 
4666   TextFieldSetHighlight(tf, tf->text.prim_pos_left,
4667 			tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
4668 
4669   old_prim_left = tf->text.prim_pos_left;
4670   old_prim_right = tf->text.prim_pos_right;
4671 
4672   if (left > right) {
4673     tf->text.prim_pos_left = right;
4674     tf->text.prim_pos_right = left;
4675   } else {
4676     tf->text.prim_pos_left = left;
4677     tf->text.prim_pos_right = right;
4678   }
4679 
4680   TextFieldSetHighlight(tf, tf->text.prim_pos_left,
4681 			tf->text.prim_pos_right, XmHIGHLIGHT_SELECTED);
4682 
4683   if (redisplay) {
4684     if (old_prim_left > tf->text.prim_pos_left) {
4685       display_left = tf->text.prim_pos_left;
4686     } else if (old_prim_left < tf->text.prim_pos_left) {
4687       display_left = old_prim_left;
4688     } else
4689       display_left = (old_prim_right > tf->text.prim_pos_right) ?
4690 	tf->text.prim_pos_right : old_prim_right;
4691 
4692     if (old_prim_right < tf->text.prim_pos_right) {
4693       display_right = tf->text.prim_pos_right;
4694     } else if (old_prim_right > tf->text.prim_pos_right) {
4695       display_right = old_prim_right;
4696     } else
4697       display_right = (old_prim_left < tf->text.prim_pos_left) ?
4698 	tf->text.prim_pos_left : old_prim_left;
4699 
4700     if (display_left > tf->text.string_length)
4701       display_left = tf->text.string_length;
4702 
4703     if (display_right > tf->text.string_length)
4704       display_right = tf->text.string_length;
4705 
4706     RedisplayText(tf, display_left, display_right);
4707   }
4708   tf->text.refresh_ibeam_off = True;
4709 }
4710 
4711 
4712 /*
4713  * Begin the selection by gaining ownership of the selection
4714  * and setting the selection parameters.
4715  */
4716 void
4717 _XmTextFieldStartSelection(XmTextFieldWidget tf,
4718 			   XmTextPosition left,
4719 			   XmTextPosition right,
4720 			   Time sel_time)
4721 {
4722   if (!XtIsRealized((Widget)tf)) return;
4723 
4724   /* if we don't already own the selection */
4725   if (tf->text.take_primary ||
4726       (tf->text.prim_pos_left == tf->text.prim_pos_right && left != right)) {
4727     if (!sel_time) sel_time = _XmValidTimestamp((Widget)tf);
4728     /* Try to gain ownership. */
4729     if (XmePrimarySource((Widget) tf, sel_time)) {
4730       XmAnyCallbackStruct cb;
4731 
4732       tf->text.prim_time = sel_time;
4733       _XmTextFieldDrawInsertionPoint(tf, False);
4734       if (tf->text.prim_pos_left != tf->text.prim_pos_right)
4735 	doSetHighlight((Widget)tf, tf->text.prim_pos_left,
4736 				tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
4737       tf->text.has_primary = True;
4738       tf->text.take_primary = False;
4739       tf->text.prim_pos_left = tf->text.prim_pos_right =
4740 	tf->text.prim_anchor = TextF_CursorPosition(tf);
4741       /*
4742        * Set the selection boundries for highlighting the text,
4743        * and marking the selection.
4744        */
4745       SetSelection(tf, left, right, True);
4746 
4747       _XmTextFieldDrawInsertionPoint(tf, True);
4748 
4749       /* Call the gain selection callback */
4750       cb.reason = XmCR_GAIN_PRIMARY;
4751       cb.event = NULL;
4752       XtCallCallbackList((Widget) tf, tf->text.gain_primary_callback,
4753 			 (XtPointer) &cb);
4754 
4755     } else
4756       /*
4757        * Failed to gain ownership of the selection so make sure
4758        * the text does not think it owns the selection.
4759        * (this might be overkill)
4760        */
4761       _XmTextFieldDeselectSelection((Widget)tf, True, sel_time);
4762   } else {
4763     _XmTextFieldDrawInsertionPoint(tf, False);
4764     doSetHighlight((Widget)tf, tf->text.prim_pos_left,
4765 			    tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
4766     tf->text.prim_pos_left = tf->text.prim_pos_right =
4767       tf->text.prim_anchor = TextF_CursorPosition(tf);
4768     /*
4769      * Set the new selection boundries for highlighting the text,
4770      * and marking the selection.
4771      */
4772     SetSelection(tf, left, right, True);
4773 
4774     _XmTextFieldDrawInsertionPoint(tf, True);
4775   }
4776 }
4777 
4778 /* ARGSUSED */
4779 static void
4780 ProcessHorizontalParams(Widget w,
4781 			XEvent *event,
4782 			char **params,
4783 			Cardinal *num_params,
4784 			XmTextPosition *left,
4785 			XmTextPosition *right,
4786 			XmTextPosition *position)
4787 {
4788   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4789   XmTextPosition old_cursorPos = TextF_CursorPosition(tf);
4790   int direction;
4791 
4792   *position = TextF_CursorPosition(tf);
4793 
4794   if (!tf->text.has_primary ||
4795       (*left = tf->text.prim_pos_left) == (*right = tf->text.prim_pos_right)) {
4796     tf->text.orig_left = tf->text.orig_right = tf->text.prim_anchor;
4797     *left = *right = old_cursorPos;
4798   }
4799 
4800   if (*num_params > 0)
4801   {
4802       /* Process the parameters. We can only have a single parameter which
4803 	 will be either "right" or "left". */
4804       if (_XmConvertActionParamToRepTypeId((Widget) w,
4805 			   XmRID_TEXTFIELD_DIRECTION_ACTION_PARAMS,
4806 			   params[0], False, &direction) == True)
4807       {
4808 	  if (direction == _RIGHT) {
4809 	      if (*position >= tf->text.string_length) return;
4810 	      (*position)++;
4811 	  }
4812 	  else if (direction == _LEFT) {
4813 	      if (*position <= 0) return;
4814 	      (*position)--;
4815 	  }
4816       }
4817   }
4818 }
4819 
4820 
4821 /* ARGSUSED */
4822 static void
4823 ProcessSelectParams(Widget w,
4824 		    XEvent *event,
4825 		    XmTextPosition *left,
4826 		    XmTextPosition *right,
4827 		    XmTextPosition *position)
4828 {
4829   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4830 
4831   *position = TextF_CursorPosition(tf);
4832 
4833   if (!tf->text.has_primary ||
4834       tf->text.prim_pos_left == tf->text.prim_pos_right) {
4835     if (*position > tf->text.prim_anchor) {
4836       *left = tf->text.prim_anchor;
4837       *right = *position;
4838     } else {
4839       *left = *position;
4840       *right = tf->text.prim_anchor;
4841     }
4842   }
4843 }
4844 
4845 
4846 /* ARGSUSED */
4847 static void
4848 KeySelection(Widget w,
4849 	     XEvent *event,
4850 	     char **params,
4851 	     Cardinal *num_params)
4852 {
4853   XmTextPosition position = 0, left, right;
4854   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4855   XmTextPosition cursorPos;
4856   int direction;
4857 
4858   TextFieldResetIC(w);
4859   _XmTextFieldDrawInsertionPoint(tf,False); /* Turn off I beam blink
4860 					       during selection */
4861 
4862   tf->text.orig_left = tf->text.prim_pos_left;
4863   tf->text.orig_right = tf->text.prim_pos_right;
4864 
4865   cursorPos = TextF_CursorPosition(tf);
4866   if (*num_params > 0)
4867   {
4868       /* Process the parameters. The only legal values are "right" and
4869 	 "left". */
4870       if (_XmConvertActionParamToRepTypeId((Widget) w,
4871 			   XmRID_TEXTFIELD_DIRECTION_ACTION_PARAMS,
4872 			   params[0], False, &direction) == True)
4873       {
4874 	  SetAnchorBalancing(tf, cursorPos);
4875       }
4876   }
4877 
4878   tf->text.extending = True;
4879 
4880   if (*num_params == 0)
4881   {
4882     position = cursorPos;
4883     ProcessSelectParams(w, event, &left, &right, &position);
4884   }
4885   else if (*num_params > 0)
4886   {
4887       /* Process the parameters. The only legal values are "right" and
4888 	 "left". */
4889       if (_XmConvertActionParamToRepTypeId((Widget) w,
4890 			   XmRID_TEXTFIELD_DIRECTION_ACTION_PARAMS,
4891 			   params[0], False, &direction) == True)
4892       {
4893 	  ProcessHorizontalParams(w, event, params, num_params, &left,
4894 				  &right, &position);
4895       }
4896   }
4897 
4898   cursorPos = position;
4899 
4900   if (position < 0 || position > tf->text.string_length) {
4901     _XmTextFieldDrawInsertionPoint(tf,True); /* Turn on I beam now
4902 						that we are done */
4903     tf->text.extending = False;
4904     return;
4905   }
4906 
4907   /* shift anchor and direction to opposite end of the selection */
4908   if (position > tf->text.prim_anchor) {
4909     right = cursorPos = position;
4910     left = tf->text.prim_anchor;
4911   } else {
4912     left = cursorPos = position;
4913     right = tf->text.prim_anchor;
4914   }
4915 
4916   if (left > right) {
4917     XmTextPosition tempIndex = left;
4918     left = right;
4919     right = tempIndex;
4920   }
4921 
4922   if (tf->text.take_primary)
4923     _XmTextFieldStartSelection(tf, left, right, event->xbutton.time);
4924   else
4925     SetSelection(tf, left, right, True);
4926 
4927   tf->text.pending_off = False;
4928 
4929   _XmTextFieldSetCursorPosition(tf, event, cursorPos, True, True);
4930   (void) SetDestination(w, cursorPos, False, event->xkey.time);
4931 
4932   tf->text.orig_left = tf->text.prim_pos_left;
4933   tf->text.orig_right = tf->text.prim_pos_right;
4934 
4935   tf->text.extending = False;
4936   _XmTextFieldDrawInsertionPoint(tf,True); /* Turn on I beam now
4937 					      that we are done */
4938 
4939 }
4940 
4941 /* ARGSUSED */
4942 static void
4943 TextFocusIn(Widget w,
4944 	    XEvent *event,
4945 	    char **params,
4946 	    Cardinal *num_params)
4947 {
4948   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4949   XmAnyCallbackStruct cb;
4950   XRectangle xmim_area;
4951   XPoint xmim_point;
4952 
4953   if (event->xfocus.send_event && !(tf->text.has_focus)) {
4954     tf->text.has_focus = True;
4955     _XmTextFieldDrawInsertionPoint(tf, False);
4956     tf->text.blink_on = False;
4957 
4958     tf->text.refresh_ibeam_off = True;
4959     if (_XmGetFocusPolicy(w) == XmEXPLICIT) {
4960       if (((XmTextFieldWidgetClass)
4961 	   XtClass(w))->primitive_class.border_highlight) {
4962 	(*((XmTextFieldWidgetClass)
4963 	   XtClass(w))->primitive_class.border_highlight)(w);
4964       }
4965       if (!tf->text.has_destination && !tf->text.sel_start)
4966 	(void) SetDestination(w, TextF_CursorPosition(tf), False,
4967 			      XtLastTimestampProcessed(XtDisplay(w)));
4968     }
4969     if (XtIsSensitive(w)) ChangeBlinkBehavior(tf, True);
4970     _XmTextFieldDrawInsertionPoint(tf, True);
4971     (void) GetXYFromPos(tf, TextF_CursorPosition(tf),
4972 			&xmim_point.x, &xmim_point.y);
4973     (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
4974     XmImVaSetFocusValues(w, XmNspotLocation, &xmim_point,
4975 			 XmNarea, &xmim_area, NULL);
4976 
4977     cb.reason = XmCR_FOCUS;
4978     cb.event = event;
4979     XtCallCallbackList (w, tf->text.focus_callback, (XtPointer) &cb);
4980   }
4981 
4982   _XmPrimitiveFocusIn(w, event, params, num_params);
4983 }
4984 
4985 
4986 /* ARGSUSED */
4987 static void
4988 TextFocusOut(Widget w,
4989 	     XEvent *event,
4990 	     char **params,
4991 	     Cardinal *num_params)
4992 {
4993   XmTextFieldWidget tf = (XmTextFieldWidget) w;
4994 
4995   if (event->xfocus.send_event && tf->text.has_focus) {
4996     ChangeBlinkBehavior(tf, False);
4997     _XmTextFieldDrawInsertionPoint(tf, False);
4998     tf->text.has_focus = False;
4999     tf->text.blink_on = True;
5000     _XmTextFieldDrawInsertionPoint(tf, True);
5001     if (((XmTextFieldWidgetClass) XtClass(tf))
5002 	->primitive_class.border_unhighlight) {
5003       (*((XmTextFieldWidgetClass) XtClass(tf))
5004        ->primitive_class.border_unhighlight)((Widget) tf);
5005     }
5006     XmImUnsetFocus(w);
5007   }
5008 
5009   /* If traversal is on, then the leave verification callback is called in
5010      the traversal event handler */
5011   if (event->xfocus.send_event && !tf->text.traversed &&
5012       _XmGetFocusPolicy(w) == XmEXPLICIT) {
5013     if (!VerifyLeave(tf, event)) {
5014       if (tf->text.verify_bell) XBell(XtDisplay(w), 0);
5015       return;
5016     }
5017   } else
5018     if (tf->text.traversed) {
5019       tf->text.traversed = False;
5020     }
5021 }
5022 
5023 static void
5024 SetScanIndex(XmTextFieldWidget tf,
5025 	     XEvent *event)
5026 {
5027   Time sel_time;
5028 
5029   if (event->type == ButtonPress) sel_time = event->xbutton.time;
5030   else sel_time = event->xkey.time;
5031 
5032 
5033   if (sel_time > tf->text.last_time &&
5034       sel_time - tf->text.last_time < XtGetMultiClickTime(XtDisplay(tf))) {
5035     /*
5036      * Fix for HaL DTS 9841 - Increment the sarray_index first, then check to
5037      *			  see if it is greater that the count.  Otherwise,
5038      *			  an error will occur.
5039      */
5040     tf->text.sarray_index++;
5041     if (tf->text.sarray_index >= TextF_SelectionArrayCount(tf)) {
5042       tf->text.sarray_index = 0;
5043     }
5044     /*
5045      * End fix for HaL DTS 9841
5046      */
5047   } else
5048     tf->text.sarray_index = 0;
5049 
5050   tf->text.last_time = sel_time;
5051 }
5052 
5053 static void
5054 ExtendScanSelection(XmTextFieldWidget tf,
5055 		    XEvent *event)
5056 {
5057   XmTextPosition pivot_left, pivot_right;
5058   XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
5059   XmTextPosition new_position = GetPosFromX(tf, (Position) event->xbutton.x);
5060   XmTextPosition cursorPos = TextF_CursorPosition(tf);
5061   Boolean pivot_modify = False;
5062   float bal_point;
5063 
5064   if (!tf->text.has_primary ||
5065       left == right) {
5066     tf->text.orig_left = tf->text.orig_right =
5067       tf->text.prim_anchor = TextF_CursorPosition(tf);
5068     bal_point = (XmTextPosition) tf->text.prim_anchor ;
5069   } else
5070     bal_point = (float)(((float)(right - left) / 2.0) + (float)left);
5071 
5072   if (!tf->text.extending)
5073   {
5074     if ((float)new_position < bal_point)
5075     {
5076       tf->text.prim_anchor = tf->text.orig_right;
5077     }
5078     else if ((float)new_position > bal_point)
5079     {
5080       tf->text.prim_anchor = tf->text.orig_left;
5081     }
5082 }
5083   tf->text.extending = True;
5084 
5085   switch (TextF_SelectionArray(tf)[tf->text.sarray_index]) {
5086   case XmSELECT_POSITION:
5087     if (tf->text.take_primary && new_position != tf->text.prim_anchor)
5088       _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
5089 				 new_position, event->xbutton.time);
5090     else if (tf->text.has_primary)
5091       SetSelection(tf, tf->text.prim_anchor, new_position, True);
5092     tf->text.pending_off = False;
5093     cursorPos = new_position;
5094     break;
5095   case XmSELECT_WHITESPACE:
5096   case XmSELECT_WORD:
5097     FindWord(tf, new_position, &left, &right);
5098     FindWord(tf, tf->text.prim_anchor,
5099 	     &pivot_left, &pivot_right);
5100     tf->text.pending_off = False;
5101     if (left != pivot_left || right != pivot_right) {
5102       if (left > pivot_left)
5103 	left = pivot_left;
5104       if (right < pivot_right)
5105 	right = pivot_right;
5106       pivot_modify = True;
5107     }
5108     if (tf->text.take_primary)
5109       _XmTextFieldStartSelection(tf, left, right, event->xbutton.time);
5110     else
5111       SetSelection(tf, left, right, True);
5112 
5113     if (pivot_modify) {
5114       if ((((right - left) / 2) + left) <= new_position) {
5115 	cursorPos = right;
5116       } else
5117 	cursorPos = left;
5118     } else {
5119       if (left >= TextF_CursorPosition(tf))
5120 	cursorPos = left;
5121       else
5122 	cursorPos = right;
5123     }
5124     break;
5125   default:
5126     break;
5127   }
5128   if (cursorPos != TextF_CursorPosition(tf)) {
5129     (void) SetDestination((Widget)tf, cursorPos, False, event->xkey.time);
5130     _XmTextFieldSetCursorPosition(tf, event, cursorPos, True, True);
5131   }
5132 }
5133 
5134 static void
5135 SetScanSelection(XmTextFieldWidget tf,
5136 		 XEvent *event)
5137 {
5138   XmTextPosition left, right;
5139   XmTextPosition new_position = 0;
5140   XmTextPosition cursorPos = TextF_CursorPosition(tf);
5141   Position dummy = 0;
5142   Boolean update_position = False;
5143 
5144   SetScanIndex(tf, event);
5145 
5146   if (event->type == ButtonPress)
5147     new_position = GetPosFromX(tf, (Position) event->xbutton.x);
5148   else
5149     new_position = TextF_CursorPosition(tf);
5150 
5151   _XmTextFieldDrawInsertionPoint(tf,False); /* Turn off I beam
5152 					       blink during selection */
5153 
5154   switch (TextF_SelectionArray(tf)[tf->text.sarray_index]) {
5155   case XmSELECT_POSITION:
5156     tf->text.prim_anchor = new_position;
5157     if (tf->text.has_primary) {
5158       SetSelection(tf, new_position, new_position, True);
5159       tf->text.pending_off = False;
5160     }
5161     cursorPos = new_position;
5162     update_position = True;
5163     break;
5164   case XmSELECT_WHITESPACE:
5165   case XmSELECT_WORD:
5166     FindWord(tf, TextF_CursorPosition(tf), &left, &right);
5167     if (tf->text.take_primary)
5168       _XmTextFieldStartSelection(tf, left, right, event->xbutton.time);
5169     else
5170       SetSelection(tf, left, right, True);
5171     tf->text.pending_off = False;
5172     if ((((right - left) / 2) + left) <= new_position)
5173       cursorPos = right;
5174     else
5175       cursorPos = left;
5176     break;
5177   case XmSELECT_LINE:
5178   case XmSELECT_OUT_LINE:
5179   case XmSELECT_PARAGRAPH:
5180   case XmSELECT_ALL:
5181     if (tf->text.take_primary)
5182       _XmTextFieldStartSelection(tf, 0, tf->text.string_length,
5183 				 event->xbutton.time);
5184     else
5185       SetSelection(tf, 0, tf->text.string_length, True);
5186     tf->text.pending_off = False;
5187     if (event->type == ButtonPress)
5188     {
5189       if ((tf->text.string_length) / 2 <= new_position)
5190       {
5191 	cursorPos = tf->text.string_length;
5192       }
5193       else
5194       {
5195 	cursorPos = 0;
5196       }
5197     }
5198     break;
5199   }
5200 
5201   (void) SetDestination((Widget)tf, cursorPos, False, event->xkey.time);
5202   if (cursorPos != TextF_CursorPosition(tf) || update_position) {
5203     _XmTextFieldSetCursorPosition(tf, event, cursorPos, True, True);
5204   }
5205   GetXYFromPos(tf, cursorPos, &(tf->text.select_pos_x),
5206 	       &dummy);
5207   _XmTextFieldDrawInsertionPoint(tf,True);
5208 }
5209 
5210 
5211 /* ARGSUSED */
5212 static void
5213 StartPrimary(Widget w,
5214 	     XEvent *event,
5215 	     char **params,
5216 	     Cardinal *num_params)
5217 {
5218   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5219 
5220   TextFieldResetIC(w);
5221   if (!tf->text.has_focus && _XmGetFocusPolicy(w) == XmEXPLICIT)
5222     (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
5223 
5224   _XmTextFieldDrawInsertionPoint(tf,False);
5225   SetScanSelection(tf, event); /* use scan type to set the selection */
5226   tf->text.stuff_pos = TextF_CursorPosition(tf);
5227   _XmTextFieldDrawInsertionPoint(tf,True);
5228 }
5229 
5230 
5231 /* ARGSUSED */
5232 static void
5233 MoveDestination(Widget w,
5234 		XEvent *event,
5235 		char **params,
5236 		Cardinal *num_params)
5237 {
5238   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5239   XmTextPosition left = tf->text.prim_pos_left,
5240                  right = tf->text.prim_pos_right;
5241   XmTextPosition new_position;
5242   Boolean old_has_focus = tf->text.has_focus;
5243   Boolean reset_cursor = False;
5244 
5245   TextFieldResetIC(w);
5246   new_position = GetPosFromX(tf, (Position) event->xbutton.x);
5247 
5248   _XmTextFieldDrawInsertionPoint(tf, False);
5249   if (tf->text.has_primary && (right != left))
5250     (void) SetDestination(w, new_position, False, event->xbutton.time);
5251 
5252   tf->text.pending_off = False;
5253 
5254   if (!tf->text.has_focus && _XmGetFocusPolicy(w) == XmEXPLICIT)
5255     (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
5256 
5257   /* Doing the the MoveDestination caused a traversal into my, causing
5258    * me to gain focus... Cursor is now on when it shouldn't be. */
5259   if ((reset_cursor = !old_has_focus && tf->text.has_focus) != False)
5260     _XmTextFieldDrawInsertionPoint(tf, False);
5261 
5262   _XmTextFieldSetCursorPosition(tf, event, new_position,
5263 				True, True);
5264   if (new_position < left && new_position > right)
5265     tf->text.pending_off = True;
5266 
5267   /*
5268    * if cursor was turned off as a result of the focus state changing
5269    * then we need to undo the decrement to the cursor_on variable
5270    * by redrawing the insertion point.
5271    */
5272   if (reset_cursor)
5273     _XmTextFieldDrawInsertionPoint(tf, True);
5274   _XmTextFieldDrawInsertionPoint(tf, True);
5275 }
5276 
5277 
5278 /* ARGSUSED */
5279 static void
5280 ExtendPrimary(Widget w,
5281 	      XEvent *event,
5282 	      char **params,
5283 	      Cardinal *num_params)
5284 {
5285   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5286 
5287   TextFieldResetIC(w);
5288 
5289   if (tf->text.cancel) return;
5290 
5291   _XmTextFieldDrawInsertionPoint(tf, False);
5292   tf->text.do_drop = False;
5293 
5294   if (event->type == ButtonPress)
5295     tf->text.stuff_pos = TextF_CursorPosition(tf);
5296 
5297   if (!CheckTimerScrolling(w, event)) {
5298     if (event->type == ButtonPress)
5299       DoExtendedSelection(w, event->xbutton.time);
5300     else
5301       DoExtendedSelection(w, event->xkey.time);
5302   } else
5303     ExtendScanSelection(tf, event); /* use scan type to set the selection */
5304 
5305   _XmTextFieldDrawInsertionPoint(tf, True);
5306 }
5307 
5308 
5309 /* ARGSUSED */
5310 static void
5311 ExtendEnd(Widget w,
5312 	  XEvent *event,
5313 	  char **params,
5314 	  Cardinal *num_params)
5315 {
5316   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5317 
5318 
5319   if (tf->text.prim_pos_left == 0 && tf->text.prim_pos_right == 0)
5320     tf->text.orig_left = tf->text.orig_right = TextF_CursorPosition(tf);
5321   else {
5322     tf->text.orig_left = tf->text.prim_pos_left;
5323     tf->text.orig_right = tf->text.prim_pos_right;
5324     tf->text.cancel = False;
5325   }
5326 
5327   if (tf->text.select_id) {
5328     XtRemoveTimeOut(tf->text.select_id);
5329     tf->text.select_id = 0;
5330   }
5331   tf->text.select_pos_x = 0;
5332   tf->text.extending = False;
5333 }
5334 
5335 /* ARGSUSED */
5336 static void
5337 DoExtendedSelection(Widget w,
5338 		    Time time)
5339 {
5340   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5341   XmTextPosition position, cursorPos;
5342   XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
5343   XmTextPosition pivot_left, pivot_right;
5344   Boolean pivot_modify = False;
5345   float bal_point;
5346 
5347   if (tf->text.cancel) {
5348     if (tf->text.select_id)
5349 	{
5350         XtRemoveTimeOut(tf->text.select_id);
5351         tf->text.select_id = 0;
5352 	}
5353     return;
5354   }
5355 
5356   cursorPos = TextF_CursorPosition(tf);
5357   _XmTextFieldDrawInsertionPoint(tf, False);
5358   if (!tf->text.has_primary || left == right) {
5359     tf->text.prim_anchor = tf->text.cursor_position;
5360     left = right = TextF_CursorPosition(tf);
5361     tf->text.orig_left = tf->text.orig_right = tf->text.prim_anchor;
5362     bal_point = tf->text.prim_anchor;
5363   } else
5364     bal_point = (float)(((float)(tf->text.orig_right - tf->text.orig_left)
5365 			 / 2.0) + (float)tf->text.orig_left);
5366 
5367   position = GetPosFromX(tf, tf->text.select_pos_x);
5368 
5369   if (!tf->text.extending)
5370   {
5371     if ((float)position < bal_point) {
5372       tf->text.prim_anchor = tf->text.orig_right;
5373     } else if ((float)position > bal_point) {
5374       tf->text.prim_anchor = tf->text.orig_left;
5375     }
5376   }
5377 
5378   tf->text.extending = True;
5379 
5380   /* Extend selection in same way as ExtendScan would do */
5381 
5382   switch (TextF_SelectionArray(tf)[tf->text.sarray_index]) {
5383   case XmSELECT_POSITION:
5384     if (tf->text.take_primary && position != tf->text.prim_anchor)
5385       _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
5386 				 position, time);
5387     else if (tf->text.has_primary)
5388       SetSelection(tf, tf->text.prim_anchor, position, True);
5389     tf->text.pending_off = False;
5390     cursorPos = position;
5391     break;
5392   case XmSELECT_WHITESPACE:
5393   case XmSELECT_WORD:
5394     FindWord(tf, position, &left, &right);
5395     FindWord(tf, tf->text.prim_anchor,
5396 	     &pivot_left, &pivot_right);
5397     tf->text.pending_off = False;
5398     if (left != pivot_left || right != pivot_right) {
5399       if (left > pivot_left)
5400 	left = pivot_left;
5401       if (right < pivot_right)
5402 	right = pivot_right;
5403       pivot_modify = True;
5404     }
5405     if (tf->text.take_primary)
5406       _XmTextFieldStartSelection(tf, left, right, time);
5407     else
5408       SetSelection(tf, left, right, True);
5409 
5410     if (pivot_modify) {
5411       if ((((right - left) / 2) + left) <= position) {
5412 	cursorPos = right;
5413       } else
5414 	cursorPos = left;
5415     } else {
5416       if (left >= TextF_CursorPosition(tf))
5417 	cursorPos = left;
5418       else
5419 	cursorPos = right;
5420     }
5421     break;
5422   default:
5423     break;
5424   }
5425   if (cursorPos != TextF_CursorPosition(tf)) {
5426     (void) SetDestination((Widget)tf, cursorPos, False, time);
5427     _XmTextFieldSetCursorPosition(tf, NULL, cursorPos, True, True);
5428   }
5429   _XmTextFieldDrawInsertionPoint(tf, True);
5430 }
5431 
5432 /* ARGSUSED */
5433 static void
5434 DoSecondaryExtend(Widget w,
5435 		  Time ev_time)
5436 {
5437   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5438 
5439   XmTextPosition position = GetPosFromX(tf, tf->text.select_pos_x);
5440 
5441   if (tf->text.cancel) return;
5442 
5443   if (position < tf->text.sec_anchor) {
5444     if (tf->text.sec_pos_left > 0)
5445       _XmTextFieldSetSel2(w, position, tf->text.sec_anchor, False, ev_time);
5446     if (tf->text.sec_pos_left >= 0) AdjustText(tf, tf->text.sec_pos_left, True);
5447   } else if (position > tf->text.sec_anchor) {
5448     if (tf->text.sec_pos_right < tf->text.string_length)
5449       _XmTextFieldSetSel2(w, tf->text.sec_anchor, position, False, ev_time);
5450     if (tf->text.sec_pos_right >= 0)
5451       AdjustText(tf, tf->text.sec_pos_right, True);
5452   } else {
5453     _XmTextFieldSetSel2(w, position, position, False, ev_time);
5454     if (position >= 0) AdjustText(tf, position, True);
5455   }
5456 
5457   tf->text.sec_extending = True;
5458 }
5459 
5460 
5461 
5462 /************************************************************************
5463  *                                                                      *
5464  * BrowseScroll - timer proc that scrolls the list if the user has left *
5465  *              the window with the button down. If the button has been *
5466  *              released, call the standard click stuff.                *
5467  *                                                                      *
5468  ************************************************************************/
5469 /* ARGSUSED */
5470 static void
5471 BrowseScroll(XtPointer closure,
5472 	     XtIntervalId *id)
5473 {
5474   Widget w = (Widget) closure;
5475   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5476 
5477   if (tf->text.cancel) {
5478     tf->text.select_id = 0;
5479     return;
5480   }
5481 
5482   if (!tf->text.select_id) return;
5483 
5484   _XmTextFieldDrawInsertionPoint(tf, False);
5485   if (tf->text.sec_extending)
5486     DoSecondaryExtend(w, XtLastTimestampProcessed(XtDisplay(w)));
5487   else if (tf->text.extending)
5488     DoExtendedSelection(w, XtLastTimestampProcessed(XtDisplay(w)));
5489 
5490   XSync (XtDisplay(w), False);
5491 
5492   _XmTextFieldDrawInsertionPoint(tf, True);
5493 
5494   tf->text.select_id = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
5495 				       (unsigned long) PRIM_SCROLL_INTERVAL,
5496 				       BrowseScroll, (XtPointer) w);
5497 }
5498 
5499 
5500 /* ARGSUSED */
5501 static Boolean
5502 CheckTimerScrolling(Widget w,
5503 		    XEvent *event)
5504 {
5505   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5506   Dimension margin_size = TextF_MarginWidth(tf) +
5507     tf->primitive.shadow_thickness +
5508       tf->primitive.highlight_thickness;
5509   Dimension top_margin = TextF_MarginHeight(tf) +
5510     tf->primitive.shadow_thickness +
5511       tf->primitive.highlight_thickness;
5512 
5513   tf->text.select_pos_x = event->xmotion.x;
5514 
5515   if ((event->xmotion.x > (int) margin_size) &&
5516       (event->xmotion.x < (int) (tf->core.width - margin_size))  &&
5517       (event->xmotion.y > (int) top_margin) &&
5518       (event->xmotion.y < (int) (top_margin + TextF_FontAscent(tf) +
5519                                  TextF_FontDescent(tf)))) {
5520 
5521     if (tf->text.select_id) {
5522       XtRemoveTimeOut(tf->text.select_id);
5523       tf->text.select_id = 0;
5524     }
5525   } else {
5526     /* to the left of the text */
5527     if (event->xmotion.x <= (int) margin_size)
5528       tf->text.select_pos_x = (Position) (margin_size -
5529                                           (tf->text.average_char_width + 1));
5530     /* to the right of the text */
5531     else if (event->xmotion.x >= (int) (tf->core.width - margin_size))
5532       tf->text.select_pos_x = (Position) ((tf->core.width - margin_size) +
5533 					  tf->text.average_char_width + 1);
5534     if (!tf->text.select_id)
5535       tf->text.select_id = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
5536 					   (unsigned long) SEC_SCROLL_INTERVAL,
5537 					   BrowseScroll, (XtPointer) w);
5538     return True;
5539   }
5540   return False;
5541 }
5542 
5543 static void
5544 RestorePrimaryHighlight(XmTextFieldWidget tf,
5545 			XmTextPosition prim_left,
5546 			XmTextPosition prim_right)
5547 {
5548   if (tf->text.sec_pos_right >= prim_left &&
5549       tf->text.sec_pos_right <= prim_right) {
5550     /* secondary selection is totally inside primary selection */
5551     if (tf->text.sec_pos_left >= prim_left) {
5552       TextFieldSetHighlight(tf, prim_left, tf->text.sec_pos_left,
5553                             XmHIGHLIGHT_SELECTED);
5554       TextFieldSetHighlight(tf, tf->text.sec_pos_left,
5555 			    tf->text.sec_pos_right,
5556 			    XmHIGHLIGHT_NORMAL);
5557       TextFieldSetHighlight(tf, tf->text.sec_pos_right, prim_right,
5558 			    XmHIGHLIGHT_SELECTED);
5559       /* right side of secondary selection is inside primary selection */
5560     } else {
5561       TextFieldSetHighlight(tf, tf->text.sec_pos_left, prim_left,
5562 			    XmHIGHLIGHT_NORMAL);
5563       TextFieldSetHighlight(tf, prim_left, tf->text.sec_pos_right,
5564 			    XmHIGHLIGHT_SELECTED);
5565     }
5566   } else {
5567     /* left side of secondary selection is inside primary selection */
5568     if (tf->text.sec_pos_left <= prim_right &&
5569 	tf->text.sec_pos_left >= prim_left) {
5570       TextFieldSetHighlight(tf, tf->text.sec_pos_left, prim_right,
5571 			    XmHIGHLIGHT_SELECTED);
5572       TextFieldSetHighlight(tf, prim_right, tf->text.sec_pos_right,
5573 			    XmHIGHLIGHT_NORMAL);
5574     } else  {
5575       /* secondary selection encompasses the primary selection */
5576       if (tf->text.sec_pos_left <= prim_left &&
5577 	  tf->text.sec_pos_right >= prim_right) {
5578 	TextFieldSetHighlight(tf, tf->text.sec_pos_left, prim_left,
5579 			      XmHIGHLIGHT_NORMAL);
5580 	TextFieldSetHighlight(tf, prim_left, prim_right,
5581 			      XmHIGHLIGHT_SELECTED);
5582 	TextFieldSetHighlight(tf, prim_right, tf->text.sec_pos_right,
5583 			      XmHIGHLIGHT_NORMAL);
5584 	/* secondary selection is outside primary selection */
5585       } else {
5586 	TextFieldSetHighlight(tf, prim_left, prim_right,
5587 			      XmHIGHLIGHT_SELECTED);
5588 	TextFieldSetHighlight(tf, tf->text.sec_pos_left,
5589 			      tf->text.sec_pos_right,
5590 			      XmHIGHLIGHT_NORMAL);
5591       }
5592     }
5593   }
5594 }
5595 
5596 void
5597 _XmTextFieldSetSel2(Widget w,
5598 		    XmTextPosition left,
5599 		    XmTextPosition right,
5600 #if NeedWidePrototypes
5601 		    int disown,
5602 #else
5603 		    Boolean disown,
5604 #endif /* NeedWidePrototypes */
5605 		    Time sel_time)
5606 {
5607   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5608   Boolean result;
5609 
5610   if (tf->text.has_secondary) {
5611     if (left == tf->text.sec_pos_left && right == tf->text.sec_pos_right)
5612       return;
5613 
5614     /* If the widget has the primary selection, make sure the selection
5615      * highlight is restored appropriately.
5616      */
5617     if (tf->text.has_primary)
5618       RestorePrimaryHighlight(tf, tf->text.prim_pos_left,
5619 			      tf->text.prim_pos_right);
5620     else
5621       TextFieldSetHighlight(tf, tf->text.sec_pos_left,
5622 			    tf->text.sec_pos_right, XmHIGHLIGHT_NORMAL);
5623   }
5624 
5625   if (left < right) {
5626     if (!tf->text.has_secondary) {
5627       if (!sel_time) sel_time = _XmValidTimestamp(w);
5628       result = XmeSecondarySource(w, sel_time);
5629       tf->text.sec_time = sel_time;
5630       tf->text.has_secondary = result;
5631       if (result) {
5632 	tf->text.sec_pos_left = left;
5633 	tf->text.sec_pos_right = right;
5634       }
5635     } else {
5636       tf->text.sec_pos_left = left;
5637       tf->text.sec_pos_right = right;
5638     }
5639     tf->text.sec_drag = True;
5640   } else {
5641     if (left > right)
5642       tf->text.has_secondary = False;
5643     tf->text.sec_pos_left = tf->text.sec_pos_right = left;
5644     if (disown) {
5645       if (!sel_time) sel_time = _XmValidTimestamp(w);
5646       XtDisownSelection(w, XA_SECONDARY, sel_time);
5647       tf->text.has_secondary = False;
5648     }
5649   }
5650 
5651   TextFieldSetHighlight((XmTextFieldWidget) w, tf->text.sec_pos_left,
5652 			tf->text.sec_pos_right,
5653 			XmHIGHLIGHT_SECONDARY_SELECTED);
5654 
5655   /* This can be optimized for performance enhancement */
5656 
5657   RedisplayText(tf, 0, tf->text.string_length);
5658 }
5659 
5660 /* ARGSUSED */
5661 static void
5662 StartDrag(Widget w,
5663 	  XEvent *event,
5664 	  String *params,
5665 	  Cardinal *num_params)
5666 {
5667   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5668   Widget drag_icon;
5669   Arg args[6];
5670   int n;
5671 
5672   drag_icon = XmeGetTextualDragIcon(w);
5673 
5674   n = 0;
5675   XtSetArg(args[n], XmNcursorBackground, tf->core.background_pixel);  n++;
5676   XtSetArg(args[n], XmNcursorForeground, tf->primitive.foreground);  n++;
5677   XtSetArg(args[n], XmNsourceCursorIcon, drag_icon);  n++;
5678   if (TextF_Editable(tf)) {
5679     XtSetArg(args[n], XmNdragOperations, (XmDROP_MOVE | XmDROP_COPY)); n++;
5680   } else {
5681     XtSetArg(args[n], XmNdragOperations, XmDROP_COPY); n++;
5682   }
5683   (void) XmeDragSource(w, (XtPointer) w, event, args, n);
5684 }
5685 
5686 /*ARGSUSED*/
5687 static	void
5688 DragStart(XtPointer data,
5689 	  XtIntervalId *id)	/* unused */
5690 {
5691   XmTextFieldWidget tf = (XmTextFieldWidget)data;
5692 
5693   tf->text.drag_id = 0;
5694   StartDrag((Widget)tf, tf->text.transfer_action->event,
5695 	    tf->text.transfer_action->params,
5696 	    tf->text.transfer_action->num_params);
5697 }
5698 
5699 /* ARGSUSED */
5700 static void
5701 StartSecondary(Widget w,
5702 	       XEvent *event,
5703 	       char **params,
5704 	       Cardinal *num_params)
5705 {
5706   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5707   XmTextPosition position = GetPosFromX(tf, (Position) event->xbutton.x);
5708   int status;
5709 
5710   tf->text.sel_start = True;
5711   XAllowEvents(XtDisplay(w), AsyncBoth, event->xbutton.time);
5712   tf->text.sec_anchor = position;
5713   tf->text.selection_move = FALSE;
5714   tf->text.selection_link = FALSE;
5715 
5716   status = XtGrabKeyboard(w, False, GrabModeAsync, GrabModeAsync,
5717 			  event->xbutton.time);
5718 
5719   if (status != GrabSuccess)
5720     XmeWarning(w, GRABKBDERROR);
5721 }
5722 
5723 
5724 /* ARGSUSED */
5725 static void
5726 ProcessBDrag(Widget w,
5727 	     XEvent *event,
5728 	     char **params,
5729 	     Cardinal *num_params)
5730 {
5731   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5732 
5733   TextFieldResetIC(w);
5734   if (tf->text.extending)
5735     return;
5736 
5737    /* if the user has clicked twice very quickly, don't lose the original left
5738    ** position
5739    */
5740    if (!tf->text.has_secondary || (tf->text.sec_pos_left == tf->text.sec_pos_right))
5741     tf->text.sec_pos_left = GetPosFromX(tf, (Position) event->xbutton.x);
5742 
5743   _XmTextFieldDrawInsertionPoint(tf, False);
5744   if (InSelection(w, event)) {
5745     tf->text.sel_start = False;
5746     StartDrag(w, event, params, num_params);
5747   } else {
5748     StartSecondary(w, event, params, num_params);
5749   }
5750   _XmTextFieldDrawInsertionPoint(tf, True);
5751 }
5752 
5753 static void
5754 ProcessBDragEvent(Widget w,
5755 		  XEvent *event,
5756 		  String *params,
5757 		  Cardinal *num_params)
5758 {
5759   XtEnum drag_on_btn1 = XmOFF;
5760   XmDisplay dpy;
5761 
5762   dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
5763   drag_on_btn1 = dpy->display.enable_btn1_transfer;
5764 
5765   if (drag_on_btn1 == XmBUTTON2_ADJUST && *num_params > 0)
5766     XtCallActionProc(w, params[0], event, NULL, 0);
5767   else if (*num_params > 1)
5768     XtCallActionProc(w, params[1], event, NULL, 0);
5769 }
5770 
5771 /* ARGSUSED */
5772 static Boolean
5773 InSelection(Widget w,
5774 	    XEvent *event)
5775 {
5776   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5777   XmTextPosition position;
5778   XmTextPosition left = tf->text.prim_pos_left,
5779                  right = tf->text.prim_pos_right;
5780   Position left_x, right_x, dummy;
5781 
5782   position = GetPosFromX(tf, (Position) event->xbutton.x);
5783 
5784   return (tf->text.has_primary &&
5785 	  left != right &&
5786 	  ( (position > left && position < right) ||
5787 	    ( position == left &&
5788 	      GetXYFromPos(tf, left, &left_x, &dummy) &&
5789 	      event->xbutton.x > left_x) ||
5790 	    ( position == right &&
5791 	      GetXYFromPos(tf, right, &right_x, &dummy) &&
5792 	      event->xbutton.x < right_x)));
5793 }
5794 
5795 /* ARGSUSED */
5796 static void
5797 ProcessBSelect(Widget w,
5798 	       XEvent *event,
5799 	       char **params,
5800 	       Cardinal *num_params)
5801 {
5802 #define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)
5803 
5804   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5805   XtEnum drag_on_btn1 = XmOFF;
5806   Time event_time = event->xbutton.time;
5807   XmDisplay dpy;
5808 
5809   dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
5810   drag_on_btn1 = dpy->display.enable_btn1_transfer;
5811 
5812   if (!drag_on_btn1) {
5813     if (*num_params > 0)
5814       XtCallActionProc(w, params[0], event, NULL, 0);
5815     return;
5816   }
5817 
5818   if (*num_params == 0) {
5819     if (event->type == ButtonPress &&
5820 	InSelection(w, event))
5821       StartDrag(w, event, params, num_params);
5822   } else {
5823     switch (event->type) {
5824     case ButtonPress:
5825       if (!InSelection(w, event) ||
5826 	  (event_time > tf->text.last_time &&
5827 	   event_time - tf->text.last_time <
5828 	   XtGetMultiClickTime(XtDisplay(w)))) {
5829 	if (*num_params > 0)
5830 	  XtCallActionProc(w, params[0], event, NULL, 0);
5831       } else {
5832 	if (tf->text.drag_id)
5833 	  XtRemoveTimeOut(tf->text.drag_id);
5834 	if (tf->text.transfer_action == NULL) {
5835 	  tf->text.transfer_action =
5836 	    (_XmTextActionRec *) XtMalloc(sizeof(_XmTextActionRec));
5837 	  tf->text.transfer_action->event = (XEvent *)XtMalloc(sizeof(XEvent));
5838 	}
5839 	memcpy((void *)tf->text.transfer_action->event, (void *)event,
5840 	       sizeof(XEvent));
5841 	tf->text.transfer_action->params = params;
5842 	tf->text.transfer_action->num_params = num_params;
5843 	tf->text.drag_id = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
5844 					   XtGetMultiClickTime(XtDisplay(w)),
5845 					   DragStart, (XtPointer)w);
5846       }
5847       break;
5848     case ButtonRelease:
5849       if (tf->text.drag_id) {
5850 	XtRemoveTimeOut(tf->text.drag_id);
5851 	tf->text.drag_id = 0;
5852 	if (*tf->text.transfer_action->num_params) {
5853 	  XtCallActionProc(w, tf->text.transfer_action->params[0],
5854 			   tf->text.transfer_action->event, NULL, 0);
5855 	}
5856       }
5857       XtCallActionProc(w, params[0], event, NULL, 0);
5858       break;
5859     case MotionNotify:
5860       if (tf->text.drag_id) {
5861 	XEvent *press = tf->text.transfer_action->event;
5862 	if (ABS_DELTA(press->xbutton.x_root, event->xmotion.x_root) >
5863 	    tf->text.threshold ||
5864 	    ABS_DELTA(press->xbutton.y_root, event->xmotion.y_root) >
5865 	    tf->text.threshold) {
5866 	  XtRemoveTimeOut(tf->text.drag_id);
5867 	  tf->text.drag_id = 0;
5868 	  StartDrag(w, event, params, num_params);
5869 	}
5870       } else if (*num_params > 0)
5871 	XtCallActionProc(w, params[0], event, NULL, 0);
5872       break;
5873     }
5874   }
5875 }
5876 
5877 static void
5878 ProcessBSelectEvent(Widget w,
5879 		  XEvent *event,
5880 		  String *params,
5881 		  Cardinal *num_params)
5882 {
5883   XtEnum drag_on_btn1 = XmOFF;
5884   XmDisplay dpy;
5885 
5886   dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
5887   drag_on_btn1 = dpy->display.enable_btn1_transfer;
5888 
5889   if (drag_on_btn1 == XmBUTTON2_TRANSFER && *num_params > 0)
5890     XtCallActionProc(w, params[0], event, NULL, 0);
5891   else if (*num_params > 1)
5892     XtCallActionProc(w, params[1], event, NULL, 0);
5893 }
5894 
5895 /* ARGSUSED */
5896 static void
5897 ExtendSecondary(Widget w,
5898 		XEvent *event,
5899 		char **params,
5900 		Cardinal *num_params)
5901 {
5902   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5903   XmTextPosition position = GetPosFromX(tf, (Position) event->xbutton.x);
5904 
5905   TextFieldResetIC(w);
5906 
5907   if (tf->text.cancel) return;
5908 
5909   _XmTextFieldDrawInsertionPoint(tf, False);
5910   if (position < tf->text.sec_anchor) {
5911     _XmTextFieldSetSel2(w, position, tf->text.sec_anchor,
5912 			False, event->xbutton.time);
5913   } else if (position > tf->text.sec_anchor) {
5914     _XmTextFieldSetSel2(w, tf->text.sec_anchor, position,
5915 			False, event->xbutton.time);
5916   } else {
5917     _XmTextFieldSetSel2(w, position, position, False, event->xbutton.time);
5918   }
5919 
5920   tf->text.sec_extending = True;
5921 
5922   if (!CheckTimerScrolling(w, event))
5923     DoSecondaryExtend(w, event->xmotion.time);
5924 
5925   _XmTextFieldDrawInsertionPoint(tf, True);
5926 }
5927 
5928 
5929 
5930 /* ARGSUSED */
5931 static void
5932 Stuff(Widget w,
5933       XEvent *event,
5934       char **params,
5935       Cardinal *num_params)
5936 {
5937   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5938   XPoint *point = NULL;
5939 
5940   /* Request targets from the selection owner so you can decide what to
5941    * request.  The decision process and request for the selection is
5942    * taken care of in HandleTargets().
5943    */
5944   if (event && event->type == ButtonRelease) {
5945       /* WARNING: do not free the following memory in this module.  It
5946        * will be freed in FreeLocationData, triggered at the end of
5947        * the data transfer operation.
5948        */
5949       point = (XPoint *) XtMalloc(sizeof(XPoint));
5950       point->x = event->xbutton.x;
5951       point->y = event->xbutton.y;
5952   }
5953 
5954   if (tf->text.selection_link)
5955     XmePrimarySink(w, XmLINK, (XtPointer) point,
5956 		   event->xbutton.time);
5957   else if (tf->text.selection_move)
5958     XmePrimarySink(w, XmMOVE, (XtPointer) point,
5959 		   event->xbutton.time);
5960   else
5961     XmePrimarySink(w, XmCOPY, (XtPointer) point,
5962 		   event->xbutton.time);
5963 }
5964 
5965 /* ARGSUSED */
5966 void
5967 _XmTextFieldHandleSecondaryFinished(Widget w,
5968 			 XEvent *event)
5969 {
5970   XmTextFieldWidget tf = (XmTextFieldWidget) w;
5971   TextFDestData dest_data;
5972   XmTextPosition left, right;
5973   int adjustment = 0;
5974   Time time = XtLastTimestampProcessed(XtDisplay(w));
5975   XmAnyCallbackStruct cb;
5976 
5977   dest_data = GetTextFDestData(w);
5978 
5979   if (dest_data->has_destination) {
5980     adjustment = (int) (tf->text.sec_pos_right - tf->text.sec_pos_left);
5981 
5982     doSetHighlight(w, tf->text.sec_pos_left,
5983 			    tf->text.sec_pos_right, XmHIGHLIGHT_NORMAL);
5984     if (dest_data->position <= tf->text.sec_pos_left) {
5985       tf->text.sec_pos_left += adjustment - dest_data->replace_length;
5986       tf->text.sec_pos_right += adjustment - dest_data->replace_length;
5987     } else if (dest_data->position > tf->text.sec_pos_left &&
5988 	       dest_data->position < tf->text.sec_pos_right) {
5989       tf->text.sec_pos_left -= dest_data->replace_length;
5990       tf->text.sec_pos_right += adjustment - dest_data->replace_length;
5991     }
5992   }
5993 
5994   left = tf->text.sec_pos_left;
5995   right = tf->text.sec_pos_right;
5996 
5997   /* This will mark the has_secondary field to False. */
5998   (void) _XmTextFieldSetSel2(w, 1, 0, False, time);
5999 
6000   if (_XmTextFieldReplaceText(tf, event, left, right, NULL, 0, False /* don't adjust cursor position */)) {
6001     XmTextPosition cursorPos;
6002     if (dest_data->has_destination && TextF_CursorPosition(tf) > right) {
6003       cursorPos = TextF_CursorPosition(tf) - (right - left);
6004       if (!dest_data->quick_key)
6005 	_XmTextFieldSetCursorPosition(tf, NULL, cursorPos, True, True);
6006       (void) SetDestination((Widget) tf, cursorPos, False, time);
6007     }
6008     if (!dest_data->has_destination) {
6009       /* make some adjustments necessary -- cursor position may refer to
6010       ** text which is gone
6011       */
6012       cursorPos = TextF_CursorPosition(tf);
6013       if (left < cursorPos)
6014 		cursorPos -= (right - left);
6015       tf->text.prim_anchor = cursorPos;
6016       if (tf->text.add_mode) {
6017 	_XmTextFieldDrawInsertionPoint(tf, False);
6018 	tf->text.add_mode = False;
6019         TextF_CursorPosition(tf) = cursorPos;
6020 	_XmTextFieldDrawInsertionPoint(tf, True);
6021       }
6022       else if (cursorPos != TextF_CursorPosition(tf))
6023 	{
6024 		/* if it changed, redraw, carefully using internal routines
6025 		** to avoid calling _XmSetDestination
6026 		*/
6027 		_XmTextFieldDrawInsertionPoint(tf, False);
6028         	TextF_CursorPosition(tf) = cursorPos;
6029 		SetCursorPosition(tf, NULL, cursorPos, False, False, True, ForceTrue);
6030 		_XmTextFieldDrawInsertionPoint(tf, True);
6031 	}
6032     }
6033 
6034     cb.reason = XmCR_VALUE_CHANGED;
6035     cb.event = event;
6036     XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
6037 		       (XtPointer) &cb);
6038   }
6039 }
6040 
6041 
6042 /*
6043  * Notify the primary selection that the secondary selection
6044  * wants to insert it's selection data into the primary selection.
6045  */
6046    /* REQUEST TARGETS FROM SELECTION RECEIVER; THEN CALL HANDLETARGETS
6047     * WHICH LOOKS AT THE TARGET LIST AND DETERMINE WHAT TARGET TO PLACE
6048     * IN THE PAIR.  IT WILL THEN DO ANY NECESSARY CONVERSIONS BEFORE
6049     * TELLING THE RECEIVER WHAT TO REQUEST AS THE SELECTION VALUE.
6050     * THIS WILL GUARANTEE THE BEST CHANCE AT A SUCCESSFUL EXCHANGE.
6051     */
6052 /* ARGSUSED */
6053 static void
6054 SecondaryNotify(Widget w,
6055 		XEvent *event,
6056 		char **params,
6057 		Cardinal *num_params)
6058 {
6059   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6060   Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
6061   TextFDestData dest_data;
6062   XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
6063 
6064   if (tf->text.selection_move == TRUE && tf->text.has_destination &&
6065       TextF_CursorPosition(tf) >= tf->text.sec_pos_left &&
6066       TextF_CursorPosition(tf) <= tf->text.sec_pos_right) {
6067       /* This will mark the has_secondary field to False. */
6068       (void) _XmTextFieldSetSel2(w, 1, 0, False, event->xbutton.time);
6069       return;
6070   }
6071 
6072   /*
6073    * Determine what the reciever supports so you can tell 'em what to
6074    * request.
6075    */
6076 
6077   dest_data = GetTextFDestData(w);
6078 
6079   dest_data->has_destination = tf->text.has_destination;
6080   dest_data->position = TextF_CursorPosition(tf);
6081   dest_data->replace_length = 0;
6082 
6083   if (*(num_params) == 1) dest_data->quick_key = True;
6084   else dest_data->quick_key = False;
6085 
6086   if (tf->text.has_primary && left != right) {
6087     if (dest_data->position >= left && dest_data->position <= right)
6088       dest_data->replace_length = (int) (right - left);
6089   }
6090 
6091   /*
6092    * Make a request for the primary selection to convert to
6093    * type INSERT_SELECTION as per ICCCM.
6094    */
6095 
6096   if (tf->text.selection_link)
6097     XmeSecondaryTransfer(w, CS_OF_ENCODING, XmLINK, event->xbutton.time);
6098   else if (tf->text.selection_move)
6099     XmeSecondaryTransfer(w, CS_OF_ENCODING, XmMOVE, event->xbutton.time);
6100   else
6101     XmeSecondaryTransfer(w, CS_OF_ENCODING, XmCOPY, event->xbutton.time);
6102 }
6103 
6104    /*
6105     * LOOKS AT THE TARGET LIST AND DETERMINE WHAT TARGET TO PLACE
6106     * IN THE PAIR.  IT WILL THEN DO ANY NECESSARY CONVERSIONS BEFORE
6107     * TELLING THE RECEIVER WHAT TO REQUEST AS THE SELECTION VALUE.
6108     * THIS WILL GUARANTEE THE BEST CHANCE AT A SUCCESSFUL EXCHANGE.
6109     */
6110 
6111 static void
6112 ProcessBDragRelease(Widget w,
6113 		    XEvent *event,
6114 		    String *params,
6115 		    Cardinal *num_params)
6116 {
6117   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6118   XButtonEvent      *ev = (XButtonEvent *) event;
6119   XmTextPosition position;
6120 
6121   if (tf->text.extending)
6122     return;
6123 
6124   /* Work around for intrinsic bug.  Remove once bug is fixed. */
6125   XtUngrabPointer(w, ev->time);
6126 
6127   _XmTextFieldDrawInsertionPoint(tf, False);
6128   if (!tf->text.cancel) XtUngrabKeyboard(w, CurrentTime);
6129 
6130   position = GetPosFromX(tf, (Position) event->xbutton.x);
6131 
6132   if (tf->text.sel_start) {
6133     if (tf->text.has_secondary &&
6134 	tf->text.sec_pos_left != tf->text.sec_pos_right) {
6135       if ((Dimension)ev->x > tf->core.width || ev->x < 0 ||
6136 	  (Dimension)ev->y > tf->core.height || ev->y < 0) {
6137 	  /* This will mark the has_secondary field to False. */
6138 	  _XmTextFieldSetSel2(w, 1, 0, False, event->xkey.time);
6139       } else {
6140 	  SecondaryNotify(w, event, params, num_params);
6141       }
6142     } else if (!tf->text.sec_drag && !tf->text.cancel &&
6143 	       tf->text.sec_pos_left == position) {
6144       /*
6145        * Copy contents of primary selection to the stuff position found above.
6146        */
6147       Stuff(w, event, params, num_params);
6148     }
6149   }
6150 
6151   if (tf->text.select_id) {
6152     XtRemoveTimeOut(tf->text.select_id);
6153     tf->text.select_id = 0;
6154   }
6155 
6156   tf->text.sec_extending = False;
6157 
6158   tf->text.sec_drag = False;
6159   tf->text.sel_start = False;
6160   tf->text.cancel = False;
6161   _XmTextFieldDrawInsertionPoint(tf, True);
6162 }
6163 
6164 static void
6165 ProcessCopy(Widget w,
6166 	    XEvent *event,
6167 	    char **params,
6168 	    Cardinal *num_params)
6169 {
6170   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6171 
6172   _XmTextFieldDrawInsertionPoint(tf, False);
6173   tf->text.selection_move = FALSE;
6174   tf->text.selection_link = FALSE;
6175   ProcessBDragRelease(w, event, params, num_params);
6176   _XmTextFieldDrawInsertionPoint(tf, True);
6177 }
6178 
6179 static void
6180 ProcessLink(Widget w,
6181 	    XEvent *event,
6182 	    char **params,
6183 	    Cardinal *num_params)
6184 {
6185   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6186 
6187   _XmTextFieldDrawInsertionPoint(tf, False);
6188   tf->text.selection_move = FALSE;
6189   tf->text.selection_link = TRUE;
6190   ProcessBDragRelease(w, event, params, num_params);
6191   _XmTextFieldDrawInsertionPoint(tf, True);
6192 }
6193 
6194 static void
6195 ProcessMove(Widget w,
6196 	    XEvent *event,
6197 	    char **params,
6198 	    Cardinal *num_params)
6199 {
6200   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6201 
6202   _XmTextFieldDrawInsertionPoint(tf, False);
6203   tf->text.selection_move = TRUE;
6204   tf->text.selection_link = FALSE;
6205   ProcessBDragRelease(w, event, params, num_params);
6206   _XmTextFieldDrawInsertionPoint(tf, True);
6207 }
6208 
6209 
6210 /* ARGSUSED */
6211 static void
6212 DeleteSelection(Widget w,
6213 		XEvent *event,
6214 		char **params,
6215 		Cardinal *num_params)
6216 {
6217   (void) TextFieldRemove(w, event);
6218 }
6219 
6220 /* ARGSUSED */
6221 static void
6222 ClearSelection(Widget w,
6223 	       XEvent *event,
6224 	       char **params,
6225 	       Cardinal *num_params)
6226 {
6227   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6228   XmTextPosition left = tf->text.prim_pos_left;
6229   XmTextPosition right = tf->text.prim_pos_right;
6230   int num_spaces = 0;
6231   XmAnyCallbackStruct cb;
6232   Boolean rep_result = False;
6233 
6234   if (left < right)
6235     num_spaces = (int)(right - left);
6236   else
6237     num_spaces = (int)(left - right);
6238 
6239   if (num_spaces) {
6240     _XmTextFieldDrawInsertionPoint(tf, False);
6241     if (tf->text.max_char_size == 1) {
6242       char spaces_cache[100];
6243       Cardinal spaces_size;
6244       char *spaces;
6245       int i;
6246 
6247       spaces_size = num_spaces + 1;
6248 
6249       spaces = (char *)XmStackAlloc(spaces_size, spaces_cache);
6250 
6251       for (i = 0; i < num_spaces; i++) spaces[i] = ' ';
6252       spaces[num_spaces] = 0;
6253 
6254       rep_result = _XmTextFieldReplaceText(tf, (XEvent *)event, left, right,
6255 					    spaces, num_spaces, False);
6256       XmStackFree(spaces, spaces_cache);
6257     } else {
6258       wchar_t *wc_spaces;
6259       int i;
6260 
6261       wc_spaces = (wchar_t *)XtMalloc((unsigned)
6262 				      (num_spaces + 1) * sizeof(wchar_t));
6263 
6264       for (i = 0; i < num_spaces; i++) {
6265 	(void)mbtowc(&wc_spaces[i], " ", 1);
6266       }
6267 
6268       rep_result = _XmTextFieldReplaceText(tf, (XEvent *)event, left, right,
6269 					    (char*)wc_spaces, num_spaces,
6270 					    False);
6271 
6272       XtFree((char*)wc_spaces);
6273     }
6274     if (rep_result) {
6275       cb.reason = XmCR_VALUE_CHANGED;
6276       cb.event = event;
6277       XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
6278 			 (XtPointer) &cb);
6279     }
6280     _XmTextFieldDrawInsertionPoint(tf, True);
6281   }
6282 }
6283 
6284 /* ARGSUSED */
6285 static void
6286 PageRight(Widget w,
6287 	  XEvent *event,
6288 	  char **params,
6289 	  Cardinal *num_params)
6290 {
6291   Position x, y;
6292   int length = 0, value;
6293   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6294   Dimension margin_width = TextF_MarginWidth(tf) +
6295     tf->primitive.shadow_thickness +
6296       tf->primitive.highlight_thickness;
6297 
6298   TextFieldResetIC(w);
6299   if (tf->text.max_char_size != 1) {
6300     length = FindPixelLength(tf, (char*)TextF_WcValue(tf),
6301 			     tf->text.string_length);
6302   } else {
6303     length = FindPixelLength(tf, TextF_Value(tf), tf->text.string_length);
6304   }
6305 
6306   /* if widget is wider than text, ignore page-right action*/
6307   if (length <= (int)(tf->core.width - (2 * margin_width)))
6308     return;
6309 
6310   _XmTextFieldDrawInsertionPoint(tf, False);
6311 
6312   if (*num_params > 0)
6313   {
6314       /* There is only one valid reptype value for this reptype, i.e.
6315 	 "extend". A True return value means that parameter was "extend". */
6316       if (_XmConvertActionParamToRepTypeId((Widget) w,
6317 			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
6318 			   params[0], False, &value) == True)
6319       {
6320 	  SetAnchorBalancing(tf, TextF_CursorPosition(tf));
6321       }
6322   }
6323 
6324   GetXYFromPos(tf, TextF_CursorPosition(tf), &x, &y);
6325 
6326   if ((int)(length - ((int)(tf->core.width - (2 * margin_width)) -
6327 		tf->text.h_offset) ) > (int)(tf->core.width - (2 * margin_width)))
6328     tf->text.h_offset -= tf->core.width - (2 * margin_width);
6329   else
6330     tf->text.h_offset = -(length - (tf->core.width - (2 * margin_width)));
6331 
6332   RedisplayText(tf, 0, tf->text.string_length);
6333   _XmTextFieldSetCursorPosition(tf, event, GetPosFromX(tf, x),
6334 				True, True);
6335 
6336   if (*num_params > 0)
6337   {
6338       /* There is only one valid reptype value for this reptype, i.e.
6339 	 "extend". A True return value means that parameter was "extend". */
6340       if (_XmConvertActionParamToRepTypeId((Widget) w,
6341 			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
6342 			   params[0], False, &value) == True)
6343       {
6344 	  KeySelection(w, event, params, num_params);
6345       }
6346   }
6347 
6348   _XmTextFieldDrawInsertionPoint(tf, True);
6349 }
6350 
6351 /* ARGSUSED */
6352 static void
6353 PageLeft(Widget w,
6354 	 XEvent *event,
6355 	 char **params,
6356 	 Cardinal *num_params)
6357 {
6358   Position x, y;
6359   int value;
6360   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6361   int margin_width = (int)TextF_MarginWidth(tf) +
6362     tf->primitive.shadow_thickness +
6363       tf->primitive.highlight_thickness;
6364 
6365   TextFieldResetIC(w);
6366 
6367   _XmTextFieldDrawInsertionPoint(tf, False);
6368 
6369   if (*num_params > 0)
6370   {
6371       /* There is only one valid reptype value for this reptype, i.e.
6372 	 "extend". A True return value means that parameter was "extend". */
6373       if (_XmConvertActionParamToRepTypeId((Widget) w,
6374 			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
6375 			   params[0], False, &value) == True)
6376       {
6377 	  SetAnchorBalancing(tf, TextF_CursorPosition(tf));
6378       }
6379   }
6380 
6381   GetXYFromPos(tf, TextF_CursorPosition(tf), &x, &y);
6382   if (margin_width  <= tf->text.h_offset +
6383       ((int)tf->core.width - (2 * margin_width)))
6384     tf->text.h_offset = margin_width;
6385   else
6386     tf->text.h_offset += tf->core.width - (2 * margin_width);
6387 
6388   RedisplayText(tf, 0, tf->text.string_length);
6389   _XmTextFieldSetCursorPosition(tf, event, GetPosFromX(tf, x),
6390 				True, True);
6391 
6392   if (*num_params > 0)
6393   {
6394       /* There is only one valid reptype value for this reptype, i.e.
6395 	 "extend". A True return value means that parameter was "extend". */
6396       if (_XmConvertActionParamToRepTypeId((Widget) w,
6397 			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
6398 			   params[0], False, &value) == True)
6399       {
6400 	  KeySelection(w, event, params, num_params);
6401       }
6402   }
6403 
6404   _XmTextFieldDrawInsertionPoint(tf, True);
6405 }
6406 
6407 static void
6408 CopyPrimary(Widget w,
6409 	    XEvent *event,
6410 	    char **params,
6411 	    Cardinal *num_params)
6412 {
6413   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6414 
6415   TextFieldResetIC(w);
6416   _XmTextFieldDrawInsertionPoint(tf, False);
6417   tf->text.selection_move = False;
6418   tf->text.selection_link = False;
6419 
6420   /* perform the primary paste action */
6421   Stuff(w, event, params, num_params);
6422   _XmTextFieldDrawInsertionPoint(tf, True);
6423 }
6424 
6425 static void
6426 CutPrimary(Widget w,
6427 	   XEvent *event,
6428 	   char **params,
6429 	   Cardinal *num_params)
6430 {
6431   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6432 
6433   TextFieldResetIC(w);
6434   _XmTextFieldDrawInsertionPoint(tf, False);
6435   tf->text.selection_move = True;
6436   tf->text.selection_link = False;
6437 
6438   Stuff(w, event, params, num_params);
6439   _XmTextFieldDrawInsertionPoint(tf, True);
6440 }
6441 
6442 static void
6443 LinkPrimary(Widget w,
6444 	   XEvent *event,
6445 	   char **params,
6446 	   Cardinal *num_params)
6447 {
6448   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6449 
6450   _XmTextFieldDrawInsertionPoint(tf, False);
6451   tf->text.selection_move = False;
6452   tf->text.selection_link = True;
6453   Stuff(w, event, params, num_params);
6454   _XmTextFieldDrawInsertionPoint(tf, True);
6455 }
6456 
6457 /* ARGSUSED */
6458 static void
6459 SetAnchor(Widget w,
6460 	  XEvent *event,
6461 	  char **params,
6462 	  Cardinal *num_params)
6463 {
6464   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6465 
6466   tf->text.prim_anchor = TextF_CursorPosition(tf);
6467   (void) SetDestination(w, tf->text.prim_anchor, False, event->xkey.time);
6468   if (tf->text.has_primary) {
6469     _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
6470 			       tf->text.prim_anchor, event->xkey.time);
6471     if (tf->text.add_mode) {
6472       _XmTextFieldDrawInsertionPoint(tf, False);
6473       tf->text.add_mode = False;
6474       _XmTextFieldDrawInsertionPoint(tf, True);
6475     }
6476   }
6477 }
6478 
6479 /* ARGSUSED */
6480 static void
6481 ToggleOverstrike(Widget w,
6482 		 XEvent *event,
6483 		 char **params,
6484 		 Cardinal *num_params)
6485 {
6486   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6487 
6488   TextFieldResetIC(w);
6489   _XmTextFieldDrawInsertionPoint(tf, False);
6490   tf->text.overstrike = !tf->text.overstrike;
6491   tf->text.refresh_ibeam_off = True;
6492   if (tf->text.overstrike)
6493     tf->text.cursor_width = tf->text.cursor_height >> 1;
6494   else {
6495     tf->text.cursor_width = 5;
6496     if (tf->text.cursor_height > 19)
6497       tf->text.cursor_width++;
6498   }
6499   _XmTextFieldDrawInsertionPoint(tf, True);
6500 }
6501 
6502 /* ARGSUSED */
6503 static void
6504 ToggleAddMode(Widget w,
6505 	      XEvent *event,
6506 	      char **params,
6507 	      Cardinal *num_params)
6508 {
6509   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6510 
6511   _XmTextFieldDrawInsertionPoint(tf, False);
6512 
6513   tf->text.add_mode = !tf->text.add_mode;
6514   if (tf->text.add_mode &&
6515       (!tf->text.has_primary ||
6516        tf->text.prim_pos_left == tf->text.prim_pos_right))
6517     tf->text.prim_anchor = TextF_CursorPosition(tf);
6518 
6519   _XmTextFieldDrawInsertionPoint(tf, True);
6520 }
6521 
6522 /* ARGSUSED */
6523 static void
6524 SelectAll(Widget w,
6525 	  XEvent *event,
6526 	  char **params,
6527 	  Cardinal *num_params)
6528 {
6529   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6530 
6531   TextFieldResetIC(w);
6532   _XmTextFieldDrawInsertionPoint(tf, False);
6533   if (tf->text.take_primary)
6534     _XmTextFieldStartSelection(tf, 0, tf->text.string_length,
6535 			       event->xbutton.time);
6536   else
6537     SetSelection(tf, 0, tf->text.string_length, True);
6538 
6539   /* Call _XmTextFieldSetCursorPosition to force image gc to be updated
6540    * in case the i-beam is contained within the selection */
6541 
6542   tf->text.pending_off = False;
6543 
6544   _XmTextFieldSetCursorPosition(tf, NULL, TextF_CursorPosition(tf),
6545 				False, False);
6546   tf->text.prim_anchor = 0;
6547 
6548   (void) SetDestination(w, TextF_CursorPosition(tf),
6549 			False, event->xkey.time);
6550   _XmTextFieldDrawInsertionPoint(tf, True);
6551 }
6552 
6553 /* ARGSUSED */
6554 static void
6555 DeselectAll(Widget w,
6556 	    XEvent *event,
6557 	    char **params,
6558 	    Cardinal *num_params)
6559 {
6560   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6561 
6562   _XmTextFieldDrawInsertionPoint(tf, False);
6563   SetSelection(tf, TextF_CursorPosition(tf), TextF_CursorPosition(tf), True);
6564   tf->text.pending_off = True;
6565   _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
6566 				True, True);
6567   tf->text.prim_anchor = TextF_CursorPosition(tf);
6568   (void) SetDestination(w, TextF_CursorPosition(tf),
6569 			False, event->xkey.time);
6570   _XmTextFieldDrawInsertionPoint(tf, True);
6571 }
6572 
6573 /* ARGSUSED */
6574 static void
6575 VoidAction(Widget w,
6576 	   XEvent *event,
6577 	   char **params,
6578 	   Cardinal *num_params)
6579 {
6580   /* Do Nothing */
6581 }
6582 
6583 /* ARGSUSED */
6584 static void
6585 CutClipboard(Widget w,
6586 	     XEvent *event,
6587 	     char **params,
6588 	     Cardinal *num_params)
6589 {
6590   XmTextFieldWidget tf = (XmTextFieldWidget)w;
6591 
6592   _XmTextFieldDrawInsertionPoint(tf, False);
6593   if (TextF_Editable(tf) && tf->text.prim_pos_left != tf->text.prim_pos_right)
6594     (void) XmeClipboardSource(w, XmMOVE, event->xkey.time);
6595   _XmTextFieldDrawInsertionPoint(tf, True);
6596 }
6597 
6598 /* ARGSUSED */
6599 static void
6600 CopyClipboard(Widget w,
6601 	      XEvent *event,
6602 	      char **params,
6603 	      Cardinal *num_params)
6604 {
6605   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6606 
6607   _XmTextFieldDrawInsertionPoint(tf, False);
6608   if (tf->text.prim_pos_left != tf->text.prim_pos_right)
6609     (void) XmeClipboardSource(w, XmCOPY, event->xkey.time);
6610   (void) SetDestination(w, TextF_CursorPosition(tf), False, event->xkey.time);
6611   _XmTextFieldDrawInsertionPoint(tf, True);
6612 }
6613 
6614 /* ARGSUSED */
6615 static void
6616 PasteClipboard(Widget w,
6617 	       XEvent *event,
6618 	       char **params,
6619 	       Cardinal *num_params)
6620 {
6621   _XmTextFieldDrawInsertionPoint((XmTextFieldWidget)w, False);
6622   ((XmTextFieldWidget)w)->text.selection_move = FALSE;
6623   ((XmTextFieldWidget)w)->text.selection_link = FALSE;
6624   XmeClipboardSink(w, XmCOPY, NULL);
6625   _XmTextFieldDrawInsertionPoint((XmTextFieldWidget)w, True);
6626 }
6627 
6628 Boolean
6629 XmTextFieldPaste(Widget w)
6630 {
6631   Boolean status;
6632   _XmWidgetToAppContext(w);
6633 
6634   _XmAppLock(app);
6635   TextFieldResetIC(w);
6636   ((XmTextFieldWidget)w)->text.selection_move = FALSE;
6637   ((XmTextFieldWidget)w)->text.selection_link = FALSE;
6638   status = XmeClipboardSink(w, XmCOPY, NULL);
6639 
6640   _XmAppUnlock(app);
6641   return(status);
6642 }
6643 
6644 Boolean
6645 XmTextFieldPasteLink(Widget w)
6646 {
6647   Boolean status;
6648   _XmWidgetToAppContext(w);
6649 
6650   _XmAppLock(app);
6651   ((XmTextFieldWidget)w)->text.selection_move = FALSE;
6652   ((XmTextFieldWidget)w)->text.selection_link = TRUE;
6653   status = XmeClipboardSink(w, XmLINK, NULL);
6654 
6655   _XmAppUnlock(app);
6656   return(status);
6657 }
6658 
6659 /* ARGSUSED */
6660 static void
6661 TraverseDown(Widget w,
6662 	     XEvent *event,
6663 	     char **params,
6664 	     Cardinal *num_params)
6665 {
6666   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6667 
6668   if (tf->primitive.navigation_type == XmNONE && VerifyLeave(tf, event)) {
6669     tf->text.traversed = True;
6670     if (!_XmMgrTraversal(w, XmTRAVERSE_DOWN))
6671       tf->text.traversed = False;
6672   }
6673 }
6674 
6675 
6676 /* ARGSUSED */
6677 static void
6678 TraverseUp(Widget w,
6679 	   XEvent *event,
6680 	   char **params,
6681 	   Cardinal *num_params)
6682 {
6683   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6684 
6685   if (tf->primitive.navigation_type == XmNONE && VerifyLeave(tf, event)) {
6686     tf->text.traversed = True;
6687     if (!_XmMgrTraversal(w, XmTRAVERSE_UP))
6688       tf->text.traversed = False;
6689   }
6690 }
6691 
6692 /* ARGSUSED */
6693 static void
6694 TraverseHome(Widget w,
6695 	     XEvent *event,
6696 	     char **params,
6697 	     Cardinal *num_params)
6698 {
6699   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6700 
6701   /* Allow the verification routine to control the traversal */
6702   if (tf->primitive.navigation_type == XmNONE && VerifyLeave(tf, event)) {
6703     tf->text.traversed = True;
6704     if (!_XmMgrTraversal(w, XmTRAVERSE_HOME))
6705       tf->text.traversed = False;
6706   }
6707 }
6708 
6709 
6710 /* ARGSUSED */
6711 static void
6712 TraverseNextTabGroup(Widget w,
6713 		     XEvent *event,
6714 		     char **params,
6715 		     Cardinal *num_params)
6716 {
6717   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6718 
6719   /* Allow the verification routine to control the traversal */
6720   if (VerifyLeave(tf, event)) {
6721     XmTraversalDirection dir;
6722     XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
6723     Boolean enable_button_tab = xm_dpy->display.enable_button_tab;
6724 
6725     dir = (enable_button_tab ?
6726 	   XmTRAVERSE_GLOBALLY_FORWARD : XmTRAVERSE_NEXT_TAB_GROUP);
6727 
6728     tf->text.traversed = True;
6729     if (!_XmMgrTraversal(w, dir))
6730       tf->text.traversed = False;
6731   }
6732 }
6733 
6734 
6735 /* ARGSUSED */
6736 static void
6737 TraversePrevTabGroup(Widget w,
6738 		     XEvent *event,
6739 		     char **params,
6740 		     Cardinal *num_params)
6741 {
6742   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6743 
6744   /* Allow the verification routine to control the traversal */
6745   if (VerifyLeave(tf, event)) {
6746     XmTraversalDirection dir;
6747     XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
6748     Boolean enable_button_tab = xm_dpy->display.enable_button_tab;
6749 
6750     dir = (enable_button_tab ?
6751 	   XmTRAVERSE_GLOBALLY_BACKWARD : XmTRAVERSE_PREV_TAB_GROUP);
6752 
6753     tf->text.traversed = True;
6754     if (!_XmMgrTraversal(w, dir))
6755       tf->text.traversed = False;
6756   }
6757 }
6758 
6759 
6760 /* ARGSUSED */
6761 static void
6762 TextEnter(Widget w,
6763 	  XEvent *event,
6764 	  String *params,
6765 	  Cardinal *num_params)
6766 {
6767   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6768   XmAnyCallbackStruct cb;
6769   XRectangle xmim_area;
6770   XPoint xmim_point;
6771 
6772   /* Use != NotifyInferior along with event->xcrossing.focus to avoid
6773    * sending input method info if reason for the event is pointer moving
6774    * from TextF widget to over-the-spot window (case when over-the-spot
6775    * is child of TextF widget). */
6776   if (_XmGetFocusPolicy(w) != XmEXPLICIT && !(tf->text.has_focus) &&
6777       event->xcrossing.focus &&
6778       (event->xcrossing.detail != NotifyInferior)) {
6779     _XmTextFieldDrawInsertionPoint(tf, False);
6780     tf->text.blink_on = False;
6781     tf->text.has_focus = True;
6782     if (XtIsSensitive(w)) ChangeBlinkBehavior(tf, True);
6783     _XmTextFieldDrawInsertionPoint(tf, True);
6784     GetXYFromPos(tf, TextF_CursorPosition(tf), &xmim_point.x,
6785 		 &xmim_point.y);
6786     (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
6787     XmImVaSetFocusValues(w, XmNspotLocation, &xmim_point,
6788 			 XmNarea, &xmim_area, NULL);
6789     cb.reason = XmCR_FOCUS;
6790     cb.event = event;
6791     XtCallCallbackList (w, tf->text.focus_callback, (XtPointer) &cb);
6792   }
6793 
6794   _XmPrimitiveEnter(w, event, params, num_params);
6795 }
6796 
6797 
6798 /* ARGSUSED */
6799 static void
6800 TextLeave(Widget w,
6801 	  XEvent *event,
6802 	  String *params,
6803 	  Cardinal *num_params)
6804 {
6805   XmTextFieldWidget tf = (XmTextFieldWidget) w;
6806 
6807   /* use detail!= NotifyInferior to handle focus change due to pointer
6808    * wandering into over-the-spot input window - we don't want to change
6809    * IM's focus state in this case. */
6810   if (_XmGetFocusPolicy(w) != XmEXPLICIT && tf->text.has_focus &&
6811       event->xcrossing.focus &&
6812       (event->xcrossing.detail != NotifyInferior)) {
6813     if (XtIsSensitive(w)) ChangeBlinkBehavior(tf, False);
6814     _XmTextFieldDrawInsertionPoint(tf, False);
6815     tf->text.has_focus = False;
6816     tf->text.blink_on = True;
6817     _XmTextFieldDrawInsertionPoint(tf, True);
6818     (void) VerifyLeave(tf, event);
6819     XmImUnsetFocus(w);
6820   }
6821 
6822   _XmPrimitiveLeave(w, event, params, num_params);
6823 }
6824 
6825 /****************************************************************
6826  *
6827  * Private definitions.
6828  *
6829  ****************************************************************/
6830 
6831 /*
6832  * ClassPartInitialize sets up the fast subclassing for the widget.i
6833  * It also merges translation tables.
6834  */
6835 static void
6836 ClassPartInitialize(WidgetClass w_class)
6837 {
6838   char *event_bindings;
6839 
6840   _XmFastSubclassInit (w_class, XmTEXT_FIELD_BIT);
6841   event_bindings = (char *)XtMalloc((unsigned) (strlen(EventBindings1) +
6842 						strlen(EventBindings2) +
6843 						strlen(EventBindings3) + 1));
6844 
6845   strcpy(event_bindings, EventBindings1);
6846   strcat(event_bindings, EventBindings2);
6847   strcat(event_bindings, EventBindings3);
6848   w_class->core_class.tm_table =
6849     (String) XtParseTranslationTable(event_bindings);
6850   XtFree(event_bindings);
6851 }
6852 
6853 /****************************************************************
6854  *
6855  * Private functions used in Initialize.
6856  *
6857  ****************************************************************/
6858 
6859 /*
6860  * Verify that the resource settings are valid.  Print a warning
6861  * message and reset the s if the are invalid.
6862  */
6863 static void
6864 Validates(XmTextFieldWidget tf)
6865 {
6866   XtPointer temp_ptr;
6867 
6868   if (TextF_CursorPosition(tf) < 0) {
6869     XmeWarning ((Widget)tf, MSG1);
6870     TextF_CursorPosition(tf) = 0;
6871   }
6872 
6873   if (TextF_Columns(tf) <= 0) {
6874     XmeWarning ((Widget)tf, MSG2);
6875     TextF_Columns(tf) = 20;
6876   }
6877 
6878   if (TextF_SelectionArray(tf) == NULL)
6879     TextF_SelectionArray(tf) = (XmTextScanType *) sarray;
6880 
6881   if (TextF_SelectionArrayCount(tf) <= 0)
6882     TextF_SelectionArrayCount(tf) = XtNumber(sarray);
6883 
6884   /*
6885    * Fix for HaL DTS 9841 - copy the selectionArray into dedicated memory.
6886    */
6887   temp_ptr = (XtPointer)TextF_SelectionArray(tf);
6888   TextF_SelectionArray(tf) =
6889     (XmTextScanType *)XtMalloc(TextF_SelectionArrayCount(tf) *
6890 			       sizeof(XmTextScanType));
6891   memcpy((void *)TextF_SelectionArray(tf), (void *)temp_ptr,
6892 	 (TextF_SelectionArrayCount(tf) * sizeof(XmTextScanType)));
6893   /*
6894    * End fix for HaL DTS 9841
6895    */
6896 }
6897 
6898 static Boolean
6899 LoadFontMetrics(XmTextFieldWidget tf)
6900 {
6901   XmFontContext context;
6902   XmFontListEntry next_entry;
6903   XmFontType type_return = XmFONT_IS_FONT;
6904   XtPointer tmp_font;
6905   Boolean have_font_struct = False;
6906   Boolean have_font_set = False;
6907 #ifdef USE_XFT
6908   Boolean have_xft_font = False;
6909 #endif
6910   XFontSetExtents *fs_extents;
6911   XFontStruct *font;
6912   unsigned long charwidth = 0;
6913   char* font_tag = NULL;
6914 
6915   if (!XmFontListInitFontContext(&context, TextF_FontList(tf)))
6916     XmeWarning ((Widget)tf, MSG3);
6917 
6918   do {
6919     next_entry = XmFontListNextEntry(context);
6920     if (next_entry
6921         && (tmp_font = XmFontListEntryGetFont(next_entry, &type_return))) {
6922       if (type_return == XmFONT_IS_FONTSET) {
6923 	font_tag = XmFontListEntryGetTag(next_entry);
6924 	if (!have_font_set) { /* this saves the first fontset found, just in
6925 			       * case we don't find a default tag set.
6926 			       */
6927 	  TextF_UseFontSet(tf) = True;
6928 #ifdef USE_XFT
6929 	  TextF_UseXft(tf) = False;
6930 #endif
6931 	  tf->text.font = (XFontStruct *)tmp_font;
6932 	  have_font_struct = True; /* we have a font set, so no need to
6933 				    * consider future font structs */
6934 	  have_font_set = True;    /* we have a font set. */
6935 
6936 	  if (!strcmp(XmFONTLIST_DEFAULT_TAG, font_tag)) {
6937 	    if (font_tag) XtFree(font_tag);
6938 	    break; /* Break out!  We've found the one we want. */
6939 	  }
6940 	} else if (!strcmp(XmFONTLIST_DEFAULT_TAG, font_tag)) {
6941 	  tf->text.font = (XFontStruct *)tmp_font;
6942 	  have_font_set = True;    /* we have a font set. */
6943 	  if (font_tag) XtFree(font_tag);
6944 	  break; /* Break out!  We've found the one we want. */
6945 	}
6946 	if (font_tag) XtFree(font_tag);
6947       } else if (type_return == XmFONT_IS_FONT && !have_font_struct) {
6948         /* return_type must be XmFONT_IS_FONT */
6949 	TextF_UseFontSet(tf) = False;
6950 #ifdef USE_XFT
6951 	TextF_UseXft(tf) = False;
6952 #endif
6953 	tf->text.font=(XFontStruct*)tmp_font; /* save the first font
6954 						* struct in case no font
6955 						* set is found */
6956 	have_font_struct = True;
6957 #ifdef USE_XFT
6958       } else if (type_return == XmFONT_IS_XFT && !have_xft_font) {
6959 	TextF_UseFontSet(tf) = False;
6960 	TextF_UseXft(tf) = True;
6961 	have_xft_font = True;
6962 	tf->text.font = tmp_font;
6963 #endif
6964       }
6965     }
6966   } while(next_entry != NULL);
6967 
6968   XmFontListFreeFontContext(context);
6969 
6970 #if USE_XFT
6971   if (!have_font_struct && !have_font_set && !have_xft_font) {
6972 #else
6973   if (!have_font_struct && !have_font_set) {
6974 #endif
6975     XmeWarning ((Widget)tf, MSG4);
6976     return False;
6977   }
6978 
6979   if(TextF_UseFontSet(tf)) {
6980     fs_extents = XExtentsOfFontSet((XFontSet)TextF_Font(tf));
6981     charwidth = (unsigned long)fs_extents->max_logical_extent.width;
6982     /* max_logical_extent.y is number of pixels from origin to top of
6983      * rectangle (i.e. y is negative) */
6984     TextF_FontAscent(tf) = -fs_extents->max_logical_extent.y;
6985     TextF_FontDescent(tf) = fs_extents->max_logical_extent.height +
6986       fs_extents->max_logical_extent.y;
6987 #ifdef USE_XFT
6988   } else if (TextF_UseXft(tf)) {
6989 #ifdef FIX_1415
6990 	  _XmXftFontAverageWidth((Widget) tf, TextF_XftFont(tf), (int *)&charwidth);
6991 #else
6992     charwidth = TextF_XftFont(tf)->max_advance_width;
6993 #endif
6994     TextF_FontAscent(tf) = TextF_XftFont(tf)->ascent;
6995     TextF_FontDescent(tf) = TextF_XftFont(tf)->descent;
6996 #endif
6997   } else {
6998     font = TextF_Font(tf);
6999     if (!XGetFontProperty(font, XA_QUAD_WIDTH, &charwidth) ||
7000 	charwidth == 0) {
7001       if (font->per_char && font->min_char_or_byte2 <= '0' &&
7002 	  font->max_char_or_byte2 >= '0')
7003 	charwidth = font->per_char['0' - font->min_char_or_byte2].width;
7004       else
7005 	charwidth = font->max_bounds.width;
7006     }
7007     TextF_FontAscent(tf) = font->max_bounds.ascent;
7008     TextF_FontDescent(tf) = font->max_bounds.descent;
7009   }
7010   tf->text.average_char_width = (Dimension) charwidth;
7011   return True;
7012 }
7013 
7014 
7015 /* ValidateString makes the following assumption:  if MB_CUR_MAX == 1, value
7016  * is a char*, otherwise value is a wchar_t*.  The Boolean "is_wchar" indicates
7017  * if value points to char* or wchar_t* data.
7018  *
7019  * It is ValidateString's task to verify that "value" contains only printing
7020  * characters; all others are discarded.  ValidateString then mallocs data
7021  * to store the value and assignes it to tf->text.value (if MB_CUR_MAX == 1)
7022  * or to tf->text.wc_value (if MB_CUR_MAX != 1), setting the opposite
7023  * pointer to NULL.  It is the callers responsibility to free data before
7024  * calling ValidateString.
7025  */
7026 static void
7027 ValidateString(XmTextFieldWidget tf,
7028 	       char *value,
7029 #if NeedWidePrototypes
7030 	       int is_wchar)
7031 #else
7032                Boolean is_wchar)
7033 #endif /* NeedWidePrototypes */
7034 {
7035   /* if value is wchar_t *, must count the characters; else use strlen */
7036 
7037   int str_len = 0;
7038   int i, j;
7039   char stack_cache[400];
7040 
7041   if (!is_wchar) {
7042     char *temp_str, *curr_str, *start_temp;
7043 
7044     str_len = strlen(value);
7045     temp_str = (char*)XmStackAlloc((Cardinal)str_len + 1, stack_cache);
7046     start_temp = temp_str;
7047     curr_str = value;
7048 
7049     for (i = 0; i < str_len;) {
7050       if (tf->text.max_char_size == 1) {
7051 	if (PrintableString(tf, curr_str, 1, False)) {
7052 	  *temp_str = *curr_str;
7053 	  temp_str++;
7054 	} else {
7055 	  char *params[1], err_str[5];
7056 	  sprintf(err_str, "\\%o", (unsigned char) *curr_str);
7057 	  params[0] = err_str;
7058 	  _XmWarningMsg ((Widget)tf, "Unsupported char", MSG5, params, 1);
7059 	}
7060 	curr_str++;
7061 	i++;
7062       } else {
7063 	wchar_t tmp;
7064 	int num_conv;
7065         Boolean printable;
7066 
7067 #ifdef USE_XFT
7068         if (TextF_UseXft(tf)) {
7069           num_conv = strlen(curr_str);
7070 	  printable = (num_conv >= 0
7071                   && PrintableString(tf, curr_str, num_conv, True));
7072         } else
7073 #endif
7074 	{
7075 	  num_conv = mbtowc(&tmp, curr_str, tf->text.max_char_size);
7076 	  printable = (num_conv >= 0
7077                   && PrintableString(tf, (char*)&tmp, 1, True));
7078         }
7079 	if (printable) {
7080 	  for (j = 0; j < num_conv; j++) {
7081 	    *temp_str = *curr_str;
7082 	    temp_str++;
7083 	    curr_str++;
7084 	    i++;
7085 	  }
7086 	} else {
7087 	  char *params[1], *err_str;
7088 
7089 	  if (num_conv >= 0) {
7090 	    int i;
7091 
7092 	    err_str = XtMalloc((4 * num_conv) + 1);
7093 	    for (i = 0; i < num_conv; i++) {
7094 	      sprintf(err_str + (i * 4), "\\%o", (unsigned char) curr_str[i]);
7095 	    }
7096 	  }
7097 	  else {
7098 	    err_str = XtMalloc(5);
7099 	    sprintf(err_str, "\\%o", (unsigned char) *curr_str);
7100 	    num_conv = 1;
7101 	  }
7102 	  params[0] = err_str;
7103 	  _XmWarningMsg ((Widget)tf, "Unsupported char", MSG5, params, 1);
7104 	  XtFree(err_str);
7105 	  if (num_conv > 0) {
7106 	      curr_str += num_conv;
7107 	      i += num_conv;
7108 	  }
7109 	  else {
7110 	      curr_str++;
7111 	      i++;
7112 	  }
7113 	}
7114       }
7115     }
7116     *temp_str = '\0';
7117 
7118     /* value contains validated string; now stuff it into the proper
7119      * instance pointer. */
7120     if (tf->text.max_char_size == 1) {
7121       tf->text.string_length = strlen(start_temp);
7122       /* malloc the space for the text value */
7123       TextF_Value(tf) =
7124 	(char *) memcpy(XtMalloc((unsigned)(tf->text.string_length + 30)),
7125 			(void *)start_temp, tf->text.string_length + 1);
7126       tf->text.size_allocd = tf->text.string_length + 30;
7127       TextF_WcValue(tf) = NULL;
7128     } else { /* Need wchar_t* data to set as the widget's value */
7129       /* count number of wchar's */
7130       str_len = strlen(start_temp);
7131       tf->text.string_length = str_len;
7132 
7133       tf->text.size_allocd = (tf->text.string_length + 30)*sizeof(wchar_t);
7134       TextF_WcValue(tf) = (wchar_t*)XtMalloc((unsigned)tf->text.size_allocd);
7135       tf->text.string_length = mbstowcs(TextF_WcValue(tf), start_temp,
7136 					tf->text.string_length + 30);
7137       if (tf->text.string_length < 0) tf->text.string_length = 0;
7138       TextF_Value(tf) = NULL;
7139     }
7140     XmStackFree(start_temp, stack_cache);
7141   } else {  /* pointer passed points to wchar_t* data */
7142     wchar_t *wc_value, *wcs_temp_str, *wcs_start_temp, *wcs_curr_str;
7143     char scratch[8];
7144     int new_len = 0;
7145     int csize = 1;
7146 
7147     wc_value = (wchar_t *) value;
7148     for (str_len = 0, i = 0; *wc_value != (wchar_t)0L; str_len++)
7149       wc_value++; /* count number of wchars */
7150     wcs_temp_str=(wchar_t *)XmStackAlloc((Cardinal)
7151 					 ((str_len+1) * sizeof(wchar_t)),
7152 					 stack_cache);
7153     wcs_start_temp = wcs_temp_str;
7154     wcs_curr_str = (wchar_t *) value;
7155 
7156     for (i = 0; i < str_len; i++, wcs_curr_str++) {
7157       if (tf->text.max_char_size == 1) {
7158 	csize = wctomb(scratch, *wcs_curr_str);
7159 	if (csize >= 0 && PrintableString(tf, scratch, csize, False)) {
7160 	  *wcs_temp_str = *wcs_curr_str;
7161 	  wcs_temp_str++;
7162 	  new_len++;
7163 	} else {
7164 	  char *params[1];
7165           char *err_str;
7166 	  if (csize >= 0) {
7167 	      int i;
7168 
7169 	      err_str = XtMalloc((4 * csize) + 1);
7170 	      for (i = 0; i < csize; i++) {
7171                 sprintf(err_str + (i * 4), "\\%o", (unsigned char) scratch[i]);
7172 	      }
7173 	  }
7174 	  else {
7175 	      err_str = XtMalloc(1);
7176 	      err_str[0] = '\0';
7177 	  }
7178           params[0] = err_str;
7179 	  _XmWarningMsg ((Widget)tf, "Unsupported wchar", WC_MSG1, params, 1);
7180           XtFree(err_str);
7181 	}
7182       } else {
7183 	if (PrintableString(tf, (char*)wcs_curr_str, 1, True)) {
7184 	  *wcs_temp_str = *wcs_curr_str;
7185 	  wcs_temp_str++;
7186 	  new_len++;
7187 	} else {
7188 	  char *params[1];
7189           char *err_str;
7190 	  csize = wctomb(scratch, *wcs_curr_str);
7191 	  if (csize >= 0) {
7192 	      int i;
7193 
7194 	      err_str = XtMalloc((4 * csize) + 1);
7195 	      for (i = 0; i < csize; i++) {
7196                 sprintf(err_str + (i * 4), "\\%o", (unsigned char) scratch[i]);
7197 	      }
7198 	  }
7199 	  else {
7200 	      err_str = XtMalloc(1);
7201 	      err_str[0] = '\0';
7202 	  }
7203 	  params[0] = err_str;
7204 	  _XmWarningMsg ((Widget)tf, "Unsupported wchar", WC_MSG1, params, 1);
7205 	  XtFree(err_str);
7206 	}
7207       }
7208     }
7209     str_len = new_len;
7210 
7211     *wcs_temp_str = (wchar_t)0L; /* terminate with a wchar_t NULL */
7212 
7213     tf->text.string_length = str_len; /* This is *wrong* if MB_CUR_MAX > 2
7214 				       * with no font set... but what can
7215 				       * ya do? Spec says let it dump core. */
7216 
7217     tf->text.size_allocd = (str_len + 30) * sizeof(wchar_t);
7218     if (tf->text.max_char_size == 1) { /* Need to store data as char* */
7219       int ret_val = 0;
7220       TextF_Value(tf) = XtMalloc((unsigned)tf->text.size_allocd);
7221       ret_val = wcstombs(TextF_Value(tf), wcs_start_temp,
7222 			 tf->text.size_allocd);
7223       if (ret_val < 0) tf->text.value[0] = '\0';
7224       TextF_WcValue(tf) = NULL;
7225     } else { /* Need to store data as wchar_t* */
7226       TextF_WcValue(tf) = (wchar_t*)memcpy(XtMalloc((unsigned)
7227 						    tf->text.size_allocd),
7228 					   (void*)wcs_start_temp,
7229 					   (1 + str_len) *
7230 					   sizeof(wchar_t));
7231       TextF_Value(tf) = NULL;
7232     }
7233     XmStackFree((char *)wcs_start_temp, stack_cache);
7234   }
7235 }
7236 
7237 /*
7238  * Initialize the s in the text fields instance record.
7239  */
7240 static void
7241 InitializeTextStruct(XmTextFieldWidget tf)
7242 {
7243   /* Flag used in losing focus verification to indicate that a traversal
7244    * key was pressed.  Must be initialized to False.
7245    */
7246   XIMCallback xim_cb[5];        /* on the spot im callbacks */
7247   Arg args[11];                 /* To set initial values to input method */
7248   Cardinal n = 0;
7249   XPoint xmim_point;
7250   XRectangle xmim_area;
7251   tf->text.traversed = False;
7252 
7253   tf->text.add_mode = False;
7254   tf->text.has_focus = False;
7255   tf->text.blink_on = True;
7256   tf->text.cursor_on = 0;
7257   tf->text.has_rect = False;
7258   tf->text.has_primary = False;
7259   tf->text.take_primary = True;
7260   tf->text.has_secondary = False;
7261   tf->text.has_destination = False;
7262   tf->text.overstrike = False;
7263   tf->text.selection_move = False;
7264   tf->text.sel_start = False;
7265   tf->text.pending_off = True;
7266   tf->text.fontlist_created = False;
7267   tf->text.cancel = False;
7268   tf->text.extending = False;
7269   tf->text.prim_time = 0;
7270   tf->text.dest_time = 0;
7271   tf->text.select_id = 0;
7272   tf->text.select_pos_x = 0;
7273   tf->text.sec_extending = False;
7274   tf->text.sec_drag = False;
7275   tf->text.changed_visible = False;
7276   tf->text.refresh_ibeam_off = True;
7277   tf->text.in_setvalues = False;
7278   tf->text.do_resize = True;
7279   tf->text.have_inverted_image_gc = False;
7280   tf->text.margin_top = TextF_MarginHeight(tf);
7281   tf->text.margin_bottom = TextF_MarginHeight(tf);
7282   tf->text.programmatic_highlights = False;
7283   /* tf->text.rt_save = False; */
7284 
7285   tf->text.max_char_size = MB_CUR_MAX;
7286 
7287   /* copy over the font list */
7288   if (TextF_FontList(tf) == NULL) {
7289     TextF_FontList(tf) =
7290       XmeGetDefaultRenderTable((Widget)tf, (unsigned char) XmTEXT_FONTLIST);
7291 
7292     TextF_FontList(tf) = (XmFontList)XmFontListCopy(TextF_FontList(tf));
7293     (void)LoadFontMetrics(tf);
7294    } else {
7295      TextF_FontList(tf) = (XmFontList)XmFontListCopy(TextF_FontList(tf));
7296      if(!LoadFontMetrics(tf)) {/*if failed use default */
7297         XmFontListFree(TextF_FontList(tf));
7298         TextF_FontList(tf) =
7299           XmeGetDefaultRenderTable((Widget)tf, (unsigned char) XmTEXT_FONTLIST);
7300 
7301         TextF_FontList(tf) = (XmFontList)XmFontListCopy(TextF_FontList(tf));
7302         (void)LoadFontMetrics(tf);
7303      }
7304    }
7305 
7306   tf->text.gc = NULL;
7307   tf->text.image_gc = NULL;
7308   tf->text.save_gc = NULL;
7309   tf->text.cursor_gc = NULL;
7310 
7311   tf->text.h_offset = (TextF_MarginWidth(tf) +
7312 		       tf->primitive.shadow_thickness +
7313 		       tf->primitive.highlight_thickness);
7314 
7315   /* ValidateString will verify value contents, convert to appropriate
7316    * storage form (i.e. char* or wchar_t*), place in the appropriate
7317    * location (text.value or text.wc_value), and null out opposite
7318    * pointer.  */
7319 
7320   if (TextF_WcValue(tf) != NULL) { /* XmNvalueWcs was set - it rules */
7321     TextF_Value(tf) = NULL;
7322     ValidateString(tf, (char*)TextF_WcValue(tf), True);
7323   } else if (TextF_Value(tf) != NULL)
7324     ValidateString(tf, TextF_Value(tf), False);
7325   else /* TextF_Value(tf) is null pointer */
7326     ValidateString(tf, "", False);
7327 
7328   if (TextF_CursorPosition(tf) > tf->text.string_length)
7329     TextF_CursorPosition(tf) = tf->text.string_length;
7330 
7331   tf->text.orig_left = tf->text.orig_right = tf->text.prim_pos_left =
7332     tf->text.prim_pos_right = tf->text.prim_anchor = TextF_CursorPosition(tf);
7333 
7334   tf->text.sec_pos_left = tf->text.sec_pos_right =
7335     tf->text.sec_anchor = TextF_CursorPosition(tf);
7336 
7337   tf->text.cursor_height = tf->text.cursor_width = 0;
7338   tf->text.stipple_tile = _XmGetInsensitiveStippleBitmap((Widget) tf);
7339 
7340   tf->text.add_mode_cursor = XmUNSPECIFIED_PIXMAP;
7341   tf->text.cursor = XmUNSPECIFIED_PIXMAP;
7342   tf->text.ibeam_off = XmUNSPECIFIED_PIXMAP;
7343   tf->text.image_clip = XmUNSPECIFIED_PIXMAP;
7344 
7345   tf->text.last_time = 0;
7346 
7347   tf->text.sarray_index = 0;
7348 
7349   /* Initialize highlight elements */
7350   tf->text.highlight.number = tf->text.highlight.maximum = 1;
7351   tf->text.highlight.list =
7352     (_XmHighlightRec *)XtMalloc((unsigned)sizeof(_XmHighlightRec));
7353   tf->text.highlight.list[0].position = 0;
7354   tf->text.highlight.list[0].mode = XmHIGHLIGHT_NORMAL;
7355 
7356   tf->text.timer_id = (XtIntervalId)0;
7357   tf->text.drag_id = (XtIntervalId)0;
7358   tf->text.transfer_action = NULL;
7359 
7360   XmTextFieldSetEditable((Widget)tf, TextF_Editable(tf));
7361 
7362   if (TextF_Editable(tf)) {
7363     XmImRegister((Widget)tf, (unsigned int) NULL);
7364     GetXYFromPos(tf, TextF_CursorPosition(tf), &xmim_point.x, &xmim_point.y);
7365     (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
7366     n = 0;
7367     XtSetArg(args[n], XmNfontList, TextF_FontList(tf)); n++;
7368     XtSetArg(args[n], XmNbackground, tf->core.background_pixel); n++;
7369     XtSetArg(args[n], XmNforeground, tf->primitive.foreground); n++;
7370     XtSetArg(args[n], XmNbackgroundPixmap,tf->core.background_pixmap);n++;
7371     XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
7372     XtSetArg(args[n], XmNarea, &xmim_area); n++;
7373     XtSetArg(args[n], XmNlineSpace,
7374 	     TextF_FontAscent(tf) + TextF_FontDescent(tf)); n++;
7375 
7376     /*
7377      * On the spot support. Register preedit callbacks during initialize.
7378      */
7379     xim_cb[0].client_data = (XPointer)tf;
7380     xim_cb[0].callback = (XIMProc)PreeditStart;
7381     xim_cb[1].client_data = (XPointer)tf;
7382     xim_cb[1].callback = (XIMProc)PreeditDone;
7383     xim_cb[2].client_data = (XPointer)tf;
7384     xim_cb[2].callback = (XIMProc)PreeditDraw;
7385     xim_cb[3].client_data = (XPointer)tf;
7386     xim_cb[3].callback = (XIMProc)PreeditCaret;
7387     XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
7388     XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
7389     XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
7390     XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;
7391 
7392     XmImSetValues((Widget)tf, args, n);
7393   }
7394 
7395   /*
7396    * Initialize on the spot data in tf structure
7397    */
7398   tf->text.onthespot = (OnTheSpotData)XtMalloc(sizeof(OnTheSpotDataRec));
7399   tf->text.onthespot->start = tf->text.onthespot->end =
7400     tf->text.onthespot->cursor = 0;
7401   tf->text.onthespot->under_preedit = False;
7402   tf->text.onthespot->under_verify_preedit = False;
7403   tf->text.onthespot->verify_commit = False;
7404 }
7405 
7406 /*
7407  * Get the graphics context for filling the background, and for drawing
7408  * and inverting text.  Used a unique pixmap so all text field widgets
7409  * share common GCs.
7410  */
7411 static void
7412 LoadGCs(XmTextFieldWidget tf,
7413         Pixel background,
7414         Pixel foreground)
7415 {
7416   XGCValues values;
7417   unsigned long valueMask = (GCFunction | GCForeground | GCBackground |
7418 			     GCGraphicsExposures);
7419   unsigned long dynamicMask = GCClipMask;
7420   unsigned long unusedMask = GCClipXOrigin | GCClipYOrigin | GCFont;
7421 
7422   /*
7423    * Get GC for saving area under the cursor.
7424    */
7425   values.function = GXcopy;
7426   values.foreground = tf->primitive.foreground;
7427   values.background = tf->core.background_pixel;
7428   values.graphics_exposures = (Bool) False;
7429   if (tf->text.save_gc != NULL)
7430     XtReleaseGC((Widget)tf, tf->text.save_gc);
7431   tf->text.save_gc = XtAllocateGC((Widget) tf, tf->core.depth, valueMask,
7432 				  &values, dynamicMask, unusedMask);
7433 
7434   /*
7435    * Get GC for drawing text.
7436    */
7437 
7438 #if USE_XFT
7439   if (!TextF_UseFontSet(tf) && !TextF_UseXft(tf)) {
7440 #else
7441   if (!TextF_UseFontSet(tf)) {
7442 #endif
7443     valueMask |= GCFont;
7444     values.font = TextF_Font(tf)->fid;
7445   }
7446   values.foreground = foreground ^ background;
7447   values.background = 0;
7448   values.graphics_exposures = (Bool) True;
7449   if (tf->text.gc != NULL)
7450     XtReleaseGC((Widget)tf, tf->text.gc);
7451   dynamicMask |= GCForeground | GCBackground | GCFillStyle | GCStipple;
7452   tf->text.gc = XtAllocateGC((Widget) tf, tf->core.depth, valueMask,
7453 			     &values, dynamicMask, 0);
7454 
7455   /* Create a temporary GC - change it later in make IBEAM */
7456   valueMask |= GCStipple | GCFillStyle;
7457   values.stipple = tf->text.stipple_tile;
7458   values.fill_style = FillStippled;
7459   values.graphics_exposures = (Bool) False;
7460   if (tf->text.image_gc != NULL)
7461     XtReleaseGC((Widget)tf, tf->text.image_gc);
7462   dynamicMask |= (GCTileStipXOrigin | GCTileStipYOrigin | GCFunction);
7463   tf->text.image_gc = XtAllocateGC((Widget) tf, tf->core.depth, valueMask,
7464 				   &values, dynamicMask, 0);
7465 }
7466 
7467 static void
7468 MakeIBeamOffArea(XmTextFieldWidget tf,
7469 #if NeedWidePrototypes
7470 		 int width,
7471 		 int height)
7472 #else
7473                  Dimension width,
7474                  Dimension height)
7475 #endif /* NeedWidePrototypes */
7476 {
7477   Display *dpy = XtDisplay(tf);
7478   Screen  *screen = XtScreen(tf);
7479 
7480   /* Create a pixmap for storing the screen data where the I-Beam will
7481    * be painted */
7482 
7483   tf->text.ibeam_off = XCreatePixmap(dpy, RootWindowOfScreen(screen), width,
7484 				     height, tf->core.depth);
7485   tf->text.refresh_ibeam_off = True;
7486 }
7487 
7488 static Pixmap
7489 FindPixmap(
7490     Screen *screen,
7491     char *image_name,
7492     Pixel foreground,
7493     Pixel background,
7494     int depth )
7495 {
7496     XmAccessColorDataRec acc_color_rec;
7497 
7498     acc_color_rec.foreground = foreground;
7499     acc_color_rec.background = background;
7500     acc_color_rec.top_shadow_color = XmUNSPECIFIED_PIXEL;
7501     acc_color_rec.bottom_shadow_color = XmUNSPECIFIED_PIXEL;
7502     acc_color_rec.select_color = XmUNSPECIFIED_PIXEL;
7503     acc_color_rec.highlight_color = XmUNSPECIFIED_PIXEL;
7504     return  _XmGetColoredPixmap(screen, image_name,
7505 				&acc_color_rec, depth, True);
7506 }
7507 
7508 static void
7509 MakeIBeamStencil(XmTextFieldWidget tf,
7510 		 int line_width)
7511 {
7512   Screen *screen = XtScreen(tf);
7513   char pixmap_name[64];
7514   XGCValues values;
7515   unsigned long valueMask;
7516 
7517   sprintf(pixmap_name, "_XmText_%d_%d", tf->text.cursor_height, line_width);
7518   tf->text.cursor = FindPixmap(screen, pixmap_name, 1, 0, 1);
7519 
7520   if (tf->text.cursor == XmUNSPECIFIED_PIXMAP) {
7521     Display *dpy = XtDisplay(tf);
7522     XSegment segments[3];
7523 
7524     /* Create a pixmap for the I-Beam stencil */
7525     tf->text.cursor = XCreatePixmap(dpy, XtWindow(tf), tf->text.cursor_width,
7526 				    tf->text.cursor_height, 1);
7527 
7528 
7529     /* Fill in the stencil with a solid in preparation
7530      * to "cut out" the I-Beam
7531      */
7532     values.foreground = 0;
7533     values.line_width = 0;
7534     values.fill_style = FillSolid;
7535     values.function = GXcopy;
7536     valueMask = GCForeground | GCLineWidth | GCFillStyle | GCFunction;
7537     XChangeGC(dpy, tf->text.cursor_gc, valueMask, &values);
7538 
7539     XFillRectangle(dpy, tf->text.cursor, tf->text.cursor_gc, 0, 0,
7540 		   tf->text.cursor_width, tf->text.cursor_height);
7541 
7542     /* Change the GC for use in "cutting out" the I-Beam shape */
7543     values.foreground = 1;
7544     values.line_width = line_width;
7545     XChangeGC(dpy, tf->text.cursor_gc, GCForeground | GCLineWidth, &values);
7546 
7547     /* Draw the segments of the I-Beam */
7548     /* 1st segment is the top horizontal line of the 'I' */
7549     segments[0].x1 = 0;
7550     segments[0].y1 = line_width - 1;
7551     segments[0].x2 = tf->text.cursor_width;
7552     segments[0].y2 = line_width - 1;
7553 
7554     /* 2nd segment is the bottom horizontal line of the 'I' */
7555     segments[1].x1 = 0;
7556     segments[1].y1 = tf->text.cursor_height - 1;
7557     segments[1].x2 = tf->text.cursor_width;
7558     segments[1].y2 = tf->text.cursor_height - 1;
7559 
7560     /* 3rd segment is the vertical line of the 'I' */
7561     segments[2].x1 = tf->text.cursor_width >> 1;
7562     segments[2].y1 = line_width;
7563     segments[2].x2 = tf->text.cursor_width >> 1;
7564     segments[2].y2 = tf->text.cursor_height - 1;
7565 
7566     /* Draw the segments onto the cursor */
7567     XDrawSegments(dpy, tf->text.cursor, tf->text.cursor_gc, segments, 3);
7568 
7569     /* Install the cursor for pixmap caching */
7570     (void) _XmCachePixmap(tf->text.cursor, XtScreen(tf), pixmap_name, 1, 0,
7571 			    1, tf->text.cursor_width, tf->text.cursor_height);
7572   }
7573 
7574   /* Get/create the image_gc used to paint the I-Beam */
7575 
7576   valueMask = (GCStipple | GCForeground | GCBackground | GCFillStyle);
7577   if (!tf->text.overstrike) {
7578     values.foreground = tf->primitive.foreground;
7579     values.background = tf->core.background_pixel;
7580   } else
7581     values.background = values.foreground =
7582       tf->core.background_pixel ^ tf->primitive.foreground;
7583   values.stipple = tf->text.cursor;
7584   values.fill_style = FillStippled;
7585   XChangeGC(XtDisplay(tf), tf->text.image_gc, valueMask, &values);
7586 
7587 }
7588 
7589 
7590 /* The IBeam Stencil must have already been created before this routine
7591  * is called.
7592  */
7593 
7594 static void
7595 MakeAddModeCursor(XmTextFieldWidget tf,
7596 		  int line_width)
7597 {
7598   Screen *screen = XtScreen(tf);
7599   char pixmap_name[64];
7600 
7601   sprintf(pixmap_name, "_XmText_AddMode_%d_%d",
7602 	  tf->text.cursor_height, line_width);
7603 
7604   tf->text.add_mode_cursor = FindPixmap(screen, pixmap_name, 1, 0, 1);
7605 
7606   if (tf->text.add_mode_cursor == XmUNSPECIFIED_PIXMAP) {
7607     XtGCMask  valueMask;
7608     XGCValues values;
7609     Display *dpy = XtDisplay(tf);
7610 
7611     tf->text.add_mode_cursor = XCreatePixmap(dpy, XtWindow(tf),
7612 					     tf->text.cursor_width,
7613 					     tf->text.cursor_height, 1);
7614 
7615     values.function = GXcopy;
7616     valueMask = GCFunction;
7617     XChangeGC(dpy, tf->text.cursor_gc, valueMask, &values);
7618 
7619     XCopyArea(dpy, tf->text.cursor, tf->text.add_mode_cursor,
7620 	      tf->text.cursor_gc, 0, 0,
7621 	      tf->text.cursor_width, tf->text.cursor_height, 0, 0);
7622 
7623     valueMask = (GCForeground | GCBackground | GCTile | GCFillStyle |
7624 		 GCFunction | GCTileStipXOrigin);
7625 
7626     values.function = GXand;
7627     values.tile = tf->text.stipple_tile;
7628     values.fill_style = FillTiled;
7629     values.ts_x_origin = -1;
7630     values.foreground = tf->primitive.foreground;
7631     values.background = tf->core.background_pixel;
7632 
7633     XChangeGC(dpy, tf->text.cursor_gc, valueMask, &values);
7634 
7635     XFillRectangle(dpy, tf->text.add_mode_cursor, tf->text.cursor_gc,
7636 		   0, 0, tf->text.cursor_width, tf->text.cursor_height);
7637 
7638     /* Install the pixmap for pixmap caching */
7639     _XmCachePixmap(tf->text.add_mode_cursor,
7640 		     XtScreen(tf), pixmap_name, 1, 0,
7641 		     1, tf->text.cursor_width, tf->text.cursor_height);
7642   }
7643 }
7644 
7645 
7646 static void
7647 MakeCursors(XmTextFieldWidget tf)
7648 {
7649   Screen *screen = XtScreen(tf);
7650   int line_width = 1;
7651   int oldwidth = tf->text.cursor_width;
7652   int oldheight = tf->text.cursor_height;
7653 
7654   if (!XtIsRealized((Widget) tf)) return;
7655 
7656   tf->text.cursor_width = 5;
7657   tf->text.cursor_height = TextF_FontAscent(tf) + TextF_FontDescent(tf);
7658 
7659   /* setup parameters to make a thicker I-Beam */
7660   if (tf->text.cursor_height > 19) {
7661     tf->text.cursor_width++;
7662     line_width = 2;
7663   }
7664 
7665   if (tf->text.cursor == XmUNSPECIFIED_PIXMAP ||
7666       tf->text.add_mode_cursor == XmUNSPECIFIED_PIXMAP ||
7667       tf->text.ibeam_off == XmUNSPECIFIED_PIXMAP ||
7668       oldheight != tf->text.cursor_height ||
7669       oldwidth != tf->text.cursor_width) {
7670 
7671     if (tf->text.cursor_gc == NULL) {
7672       unsigned long valueMask = 0;
7673       XGCValues values;
7674       unsigned long dynamicMask =
7675 	GCForeground | GCLineWidth | GCTile | GCFillStyle |
7676 	GCBackground | GCFunction | GCTileStipXOrigin;
7677 
7678       tf->text.cursor_gc = XtAllocateGC((Widget)tf, 1, valueMask, &values,
7679 					dynamicMask, 0);
7680     }
7681 
7682     /* Remove old ibeam off area */
7683     if (tf->text.ibeam_off != XmUNSPECIFIED_PIXMAP)
7684       XFreePixmap(XtDisplay((Widget)tf), tf->text.ibeam_off);
7685 
7686     /* Remove old insert cursor */
7687     if (tf->text.cursor != XmUNSPECIFIED_PIXMAP) {
7688       (void) XmDestroyPixmap(screen, tf->text.cursor);
7689       tf->text.cursor = XmUNSPECIFIED_PIXMAP;
7690     }
7691 
7692     /* Remove old add mode cursor */
7693     if (tf->text.add_mode_cursor != XmUNSPECIFIED_PIXMAP) {
7694       (void) XmDestroyPixmap(screen, tf->text.add_mode_cursor);
7695       tf->text.add_mode_cursor = XmUNSPECIFIED_PIXMAP;
7696     }
7697 
7698     /* Create area in which to save text located underneath I beam */
7699     MakeIBeamOffArea(tf, MAX(tf->text.cursor_height>>1,tf->text.cursor_height),
7700 		     tf->text.cursor_height);
7701 
7702     /* Create a new i-beam cursor */
7703     MakeIBeamStencil(tf, line_width);
7704 
7705     /* Create a new add_mode cursor */
7706     MakeAddModeCursor(tf, line_width);
7707   }
7708 
7709   if (tf->text.overstrike)
7710     tf->text.cursor_width = tf->text.cursor_height >> 1;
7711 }
7712 
7713 /* ARGSUSED */
7714 static void
7715 DragProcCallback(Widget w,
7716 		 XtPointer client,
7717 		 XtPointer call)
7718 {
7719   enum { XmACOMPOUND_TEXT, XmATEXT, XmAUTF8_STRING, NUM_ATOMS };
7720   static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSTEXT, XmSUTF8_STRING };
7721 
7722   XmDragProcCallbackStruct *cb = (XmDragProcCallbackStruct *)call;
7723   Widget drag_cont;
7724   Atom targets[5];
7725   Arg args[10];
7726   Atom *exp_targets;
7727   Cardinal num_exp_targets, n;
7728   Atom atoms[XtNumber(atom_names)];
7729 
7730   assert(XtNumber(atom_names) == NUM_ATOMS);
7731   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
7732 
7733   targets[0] = XmeGetEncodingAtom(w);
7734   targets[1] = atoms[XmACOMPOUND_TEXT];
7735   targets[2] = XA_STRING;
7736   targets[3] = atoms[XmATEXT];
7737   targets[4] = atoms[XmAUTF8_STRING];
7738 
7739   drag_cont = cb->dragContext;
7740 
7741   n = 0;
7742   XtSetArg(args[n], XmNexportTargets, &exp_targets); n++;
7743   XtSetArg(args[n], XmNnumExportTargets, &num_exp_targets); n++;
7744   XtGetValues(drag_cont, args, n);
7745 
7746   switch(cb->reason) {
7747   case XmCR_DROP_SITE_ENTER_MESSAGE:
7748     if (XmTargetsAreCompatible(XtDisplay(drag_cont), exp_targets,
7749 			       num_exp_targets, targets, 4))
7750       cb->dropSiteStatus = XmVALID_DROP_SITE;
7751     else
7752       cb->dropSiteStatus = XmINVALID_DROP_SITE;
7753     break;
7754   case XmCR_DROP_SITE_LEAVE_MESSAGE:
7755   case XmCR_DROP_SITE_MOTION_MESSAGE:
7756   case XmCR_OPERATION_CHANGED:
7757     break;
7758   default:
7759     /* other messages we consider invalid */
7760     cb->dropSiteStatus = XmINVALID_DROP_SITE;
7761     break;
7762   }
7763 
7764   if (cb -> dropSiteStatus == XmVALID_DROP_SITE) {
7765     if (cb -> operation != XmDROP_COPY &&
7766 	cb -> operation != XmDROP_MOVE)
7767       cb -> dropSiteStatus = XmINVALID_DROP_SITE;
7768   }
7769 }
7770 
7771 static void
7772 RegisterDropSite(Widget w)
7773 {
7774   enum { XmACOMPOUND_TEXT, XmATEXT, XmAUTF8_STRING, NUM_ATOMS };
7775   static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSTEXT, XmSUTF8_STRING };
7776 
7777   Atom targets[5];
7778   Arg args[10];
7779   int n;
7780   Atom atoms[XtNumber(atom_names)];
7781 
7782   assert(XtNumber(atom_names) == NUM_ATOMS);
7783   XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
7784 
7785   targets[0] = XmeGetEncodingAtom(w);
7786   targets[1] = atoms[XmACOMPOUND_TEXT];
7787   targets[2] = XA_STRING;
7788   targets[3] = atoms[XmATEXT];
7789   targets[4] = atoms[XmAUTF8_STRING];
7790 
7791   n = 0;
7792   XtSetArg(args[n], XmNimportTargets, targets); n++;
7793   XtSetArg(args[n], XmNnumImportTargets, 5); n++;
7794   XtSetArg(args[n], XmNdragProc, DragProcCallback); n++;
7795   XmeDropSink(w, args, n);
7796 }
7797 
7798 /*
7799  * Initialize
7800  *    Intializes the text data and ensures that the data in new
7801  * is valid.
7802  */
7803 
7804 /* ARGSUSED */
7805 static void
7806 Initialize(Widget request,
7807 	   Widget new_w,
7808 	   ArgList args,
7809 	   Cardinal *num_args)
7810 {
7811   XmTextFieldWidget req_tf = (XmTextFieldWidget) request;
7812   XmTextFieldWidget new_tf = (XmTextFieldWidget) new_w;
7813   Dimension width, height;
7814 
7815   Validates(new_tf);
7816 
7817   InitializeTextStruct(new_tf);
7818 
7819   LoadGCs(new_tf, new_tf->core.background_pixel,
7820 	  new_tf->primitive.foreground);
7821 
7822   ComputeSize(new_tf, &width, &height);
7823 
7824   if (req_tf->core.width == 0)
7825     new_tf->core.width = width;
7826   if (req_tf->core.height == 0)
7827     new_tf->core.height = height;
7828 
7829   RegisterDropSite(new_w);
7830 
7831   if (new_tf->text.verify_bell == (Boolean) XmDYNAMIC_BOOL) {
7832     if (_XmGetAudibleWarning(new_w) == XmBELL)
7833       new_tf->text.verify_bell = True;
7834     else
7835       new_tf->text.verify_bell = False;
7836   }
7837 }
7838 
7839 static void
7840 Realize(Widget w,
7841         XtValueMask *valueMask,
7842         XSetWindowAttributes *attributes)
7843 {
7844   XmTextFieldWidget tf = (XmTextFieldWidget) w;
7845   Arg args[11];                 /* To set initial values to input method */
7846   XIMCallback xim_cb[5];        /* on the spot im callback data */
7847   Cardinal n = 0;
7848 
7849   XtCreateWindow(w, (unsigned int) InputOutput,
7850 		 (Visual *) CopyFromParent, *valueMask, attributes);
7851   MakeCursors(tf);
7852 
7853   if (TextF_Editable(tf)){
7854   /*
7855    * On the spot support. Register preedit callbacks.
7856    */
7857     xim_cb[0].client_data = (XPointer)tf;
7858     xim_cb[0].callback = (XIMProc)PreeditStart;
7859     xim_cb[1].client_data = (XPointer)tf;
7860     xim_cb[1].callback = (XIMProc)PreeditDone;
7861     xim_cb[2].client_data = (XPointer)tf;
7862     xim_cb[2].callback = (XIMProc)PreeditDraw;
7863     xim_cb[3].client_data = (XPointer)tf;
7864     xim_cb[3].callback = (XIMProc)PreeditCaret;
7865     XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
7866     XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
7867     XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
7868     XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;
7869     XmImSetValues((Widget)tf, args, n);
7870   }
7871 }
7872 
7873 static void
7874 Destroy(Widget wid)
7875 {
7876   XmTextFieldWidget tf = (XmTextFieldWidget) wid;
7877   Widget dest = XmGetDestination(XtDisplay(wid));
7878 
7879   if (dest == wid)
7880     _XmSetDestination(XtDisplay(wid), NULL);
7881 
7882   if (tf->text.timer_id)
7883     XtRemoveTimeOut(tf->text.timer_id);
7884 
7885   if (tf->text.drag_id)
7886     XtRemoveTimeOut(tf->text.drag_id);
7887 
7888   if (tf->text.select_id)
7889     {
7890     XtRemoveTimeOut(tf->text.select_id);
7891     tf->text.select_id = 0;
7892     }
7893 
7894   if (tf->text.transfer_action) {
7895     XtFree((char *)tf->text.transfer_action->event);
7896     XtFree((char *)tf->text.transfer_action);
7897   }
7898 
7899   if (tf->text.max_char_size == 1)
7900     XtFree(TextF_Value(tf));
7901   else
7902     XtFree((char *)TextF_WcValue(tf));
7903 
7904   XtReleaseGC(wid, tf->text.gc);
7905   XtReleaseGC(wid, tf->text.image_gc);
7906   XtReleaseGC(wid, tf->text.save_gc);
7907   XtReleaseGC(wid, tf->text.cursor_gc);
7908 
7909   XtFree((char *)tf->text.highlight.list);
7910 
7911   XmFontListFree((XmFontList)TextF_FontList(tf));
7912 
7913   if (tf->text.add_mode_cursor != XmUNSPECIFIED_PIXMAP)
7914     (void) XmDestroyPixmap(XtScreen(tf), tf->text.add_mode_cursor);
7915 
7916   if (tf->text.cursor != XmUNSPECIFIED_PIXMAP)
7917     (void) XmDestroyPixmap(XtScreen(tf), tf->text.cursor);
7918 
7919   if (tf->text.ibeam_off != XmUNSPECIFIED_PIXMAP)
7920     XFreePixmap(XtDisplay((Widget)tf), tf->text.ibeam_off);
7921 
7922   if (tf->text.onthespot != NULL)
7923     XtFree((char *)tf->text.onthespot);
7924 
7925   /*
7926    * Fix for HaL DTS 9841 - release the data for the selectionArray.
7927    */
7928   XtFree((char *)TextF_SelectionArray(tf));
7929 
7930   XmImUnregister(wid);
7931 }
7932 
7933 static void
7934 Resize(Widget w)
7935 {
7936   XmTextFieldWidget tf = (XmTextFieldWidget) w;
7937   int text_width, new_width, offset;
7938 
7939   tf->text.do_resize = False;
7940 
7941 #ifdef AS_TEXTFIELD
7942   tf->text.h_offset = TextF_MarginWidth(tf) + tf->primitive.shadow_thickness +
7943     tf->primitive.highlight_thickness;
7944 #else
7945   new_width = tf->core.width - (2 * (TextF_MarginWidth(tf) +
7946 				     tf->primitive.shadow_thickness +
7947 				     tf->primitive.highlight_thickness));
7948   offset = tf->text.h_offset - (TextF_MarginWidth(tf) +
7949 				tf->primitive.shadow_thickness +
7950 				tf->primitive.highlight_thickness);
7951   if (tf->text.max_char_size != 1)
7952     text_width = FindPixelLength(tf, (char *)TextF_WcValue(tf),
7953 				 tf->text.string_length);
7954   else
7955     text_width = FindPixelLength(tf, TextF_Value(tf), tf->text.string_length);
7956 
7957   if (text_width - new_width < -offset)
7958   {
7959     if (text_width - new_width >= 0)
7960     {
7961       tf->text.h_offset = (new_width - text_width) + TextF_MarginWidth(tf) +
7962 	tf->primitive.shadow_thickness +
7963 	tf->primitive.highlight_thickness;
7964   }
7965     else
7966     {
7967       tf->text.h_offset = TextF_MarginWidth(tf) +
7968 	tf->primitive.shadow_thickness +
7969 	tf->primitive.highlight_thickness;
7970   }
7971 }
7972 
7973 #endif
7974 
7975   tf->text.refresh_ibeam_off = True;
7976 
7977   (void) AdjustText(tf, TextF_CursorPosition(tf), True);
7978 
7979   tf->text.do_resize = True;
7980 }
7981 
7982 
7983 /************************************************************************
7984  *
7985  *  QueryGeometry
7986  *
7987  ************************************************************************/
7988 static XtGeometryResult
7989 QueryGeometry(Widget widget,
7990 	      XtWidgetGeometry *intended,
7991 	      XtWidgetGeometry *desired)
7992 {
7993   /* this function deals with resizeWidth False */
7994   ComputeSize((XmTextFieldWidget) widget,
7995 	      &desired->width, &desired->height);
7996 
7997   return XmeReplyToQueryGeometry(widget, intended, desired);
7998 }
7999 
8000 
8001 /*
8002  * Redisplay will redraw shadows, borders, and text.
8003  */
8004 /* ARGSUSED */
8005 static void
8006 TextFieldExpose(Widget w,
8007 		XEvent *event,
8008 		Region region)
8009 {
8010   XmTextFieldWidget tf = (XmTextFieldWidget) w;
8011   XGCValues values;
8012 
8013 
8014   if (event->xany.type != Expose) return;
8015 
8016   tf->text.do_resize = False;
8017 
8018   /* I can get here even though the widget isn't visible (i.e. my parent is
8019    * sized so that I have nothing visible.  In this case, capturing the putback
8020    * area yields garbage...  And if this area is not in an area where text
8021    * will be drawn (i.e. forcing something new/valid to be there next time I
8022    * go to capture it) the garbage persists.  To prevent this, initialize the
8023    * putback area and then update it to a solid background color.
8024    */
8025 
8026   tf->text.refresh_ibeam_off = False;
8027   values.clip_mask = None;
8028   values.foreground = tf->core.background_pixel;
8029   XChangeGC(XtDisplay(w), tf->text.save_gc, GCForeground|GCClipMask, &values);
8030   XFillRectangle(XtDisplay(w), tf->text.ibeam_off, tf->text.save_gc, 0, 0,
8031 		 tf->text.cursor_width, tf->text.cursor_height);
8032   values.foreground = tf->primitive.foreground;
8033   XChangeGC(XtDisplay(w), tf->text.save_gc, GCForeground, &values);
8034 
8035   _XmTextFieldDrawInsertionPoint(tf, False);
8036 
8037   if (XtIsRealized((Widget)tf)) {
8038     if (tf->primitive.shadow_thickness > 0)
8039       XmeDrawShadows(XtDisplay(tf), XtWindow(tf),
8040 		     tf->primitive.bottom_shadow_GC,
8041 		     tf->primitive.top_shadow_GC,
8042 		     (int) tf->primitive.highlight_thickness,
8043 		     (int) tf->primitive.highlight_thickness,
8044 		     (int) (tf->core.width -
8045 			    (2 * tf->primitive.highlight_thickness)),
8046 		     (int) (tf->core.height -
8047 			    (2 * tf->primitive.highlight_thickness)),
8048 		     (int) tf->primitive.shadow_thickness,
8049 		     XmSHADOW_OUT);
8050 
8051 
8052     if (tf->primitive.highlighted) {
8053       if (((XmTextFieldWidgetClass)XtClass(tf))
8054 	  ->primitive_class.border_highlight) {
8055 	(*((XmTextFieldWidgetClass) XtClass(tf))
8056 	 ->primitive_class.border_highlight)((Widget) tf);
8057       }
8058     } else {
8059       if (((XmTextFieldWidgetClass) XtClass(tf))
8060 	  ->primitive_class.border_unhighlight) {
8061 	(*((XmTextFieldWidgetClass) XtClass(tf))
8062 	 ->primitive_class.border_unhighlight)((Widget) tf);
8063       }
8064     }
8065 
8066     RedisplayText(tf, 0, tf->text.string_length);
8067   }
8068 
8069   tf->text.refresh_ibeam_off = True;
8070 
8071   _XmTextFieldDrawInsertionPoint(tf, True);
8072 
8073   tf->text.do_resize = True;
8074 }
8075 
8076 /*
8077  *
8078  * SetValues
8079  *    Checks the new text data and ensures that the data is valid.
8080  * Invalid values will be rejected and changed back to the old
8081  * values.
8082  *
8083  */
8084 /* ARGSUSED */
8085 static Boolean
8086 SetValues(Widget old,
8087 	  Widget request,
8088 	  Widget new_w,
8089 	  ArgList args,
8090 	  Cardinal *num_args)
8091 {
8092   XmTextFieldWidget new_tf = (XmTextFieldWidget) new_w;
8093   XmTextFieldWidget old_tf = (XmTextFieldWidget) old;
8094   Boolean cursor_pos_set = False;
8095   Boolean new_size = False;
8096   Boolean redisplay = False;
8097   Boolean redisplay_text = False;
8098   Boolean new_font = False;
8099   Boolean mod_ver_ret = False;
8100   Boolean diff_values = False;
8101   Dimension new_width = new_tf->core.width;
8102   Dimension new_height = new_tf->core.height;
8103   Arg im_args[10];
8104   XPoint xmim_point;
8105   XRectangle xmim_area;
8106   XmTextPosition new_position = 0;
8107   XmTextPosition newInsert;
8108   int n = 0;
8109 
8110   if (new_w->core.being_destroyed) return False;
8111   TextFieldResetIC(old);
8112 
8113   new_tf->text.in_setvalues = True;
8114   new_tf->text.redisplay = False;
8115 
8116   /* If new cursor position, copy the old cursor pos to the new widget
8117    * so that when we turn off the i-beam, the current location (old
8118    * widget) is used, but the new i-beam parameters (on/off, state, ...)
8119    * are utilized.  Then move the cursor.  Otherwise, just turn off
8120    * the i-beam. */
8121 
8122   if (TextF_CursorPosition(new_tf) != TextF_CursorPosition(old_tf)) {
8123     new_position = TextF_CursorPosition(new_tf);
8124     TextF_CursorPosition(new_tf) = TextF_CursorPosition(old_tf);
8125     _XmTextFieldDrawInsertionPoint(old_tf, False);
8126     new_tf->text.blink_on = old_tf->text.blink_on;
8127     new_tf->text.cursor_on = old_tf->text.cursor_on;
8128     _XmTextFieldSetCursorPosition(new_tf, NULL, new_position,
8129 				  True, True);
8130     (void) SetDestination(new_w, TextF_CursorPosition(new_tf), False,
8131 			  XtLastTimestampProcessed(XtDisplay(new_w)));
8132     cursor_pos_set = True;
8133   } else {
8134     int ix;
8135 
8136     for (ix = 0; ix < *num_args; ix++)
8137       if (strcmp(args[ix].name, XmNcursorPosition) == 0) {
8138 	cursor_pos_set = True;
8139 	new_position = TextF_CursorPosition(new_tf);
8140 	break;
8141       }
8142 
8143     _XmTextFieldDrawInsertionPoint(old_tf, False);
8144     new_tf->text.blink_on = old_tf->text.blink_on;
8145     new_tf->text.cursor_on = old_tf->text.cursor_on;
8146   }
8147 
8148   if (!XtIsSensitive(new_w) &&
8149       new_tf->text.has_destination) {
8150     (void) SetDestination(new_w, TextF_CursorPosition(new_tf),
8151 			  True, XtLastTimestampProcessed(XtDisplay(new_w)));
8152   }
8153 
8154   if (TextF_SelectionArray(new_tf) == NULL)
8155     TextF_SelectionArray(new_tf) = TextF_SelectionArray(old_tf);
8156 
8157   if (TextF_SelectionArrayCount(new_tf) <= 0)
8158     TextF_SelectionArrayCount(new_tf) = TextF_SelectionArrayCount(old_tf);
8159 
8160   /*
8161    * Fix for HaL DTS 9841 - If the new and old selectionArrays do not match,
8162    *			  free the old array and then copy the new array.
8163    */
8164   if (TextF_SelectionArray(new_tf) != TextF_SelectionArray(old_tf)) {
8165     XtPointer temp_ptr;
8166 
8167     XtFree((char *)TextF_SelectionArray(old_tf));
8168     temp_ptr = (XtPointer)TextF_SelectionArray(new_tf);
8169     TextF_SelectionArray(new_tf) =
8170       (XmTextScanType *)XtMalloc(TextF_SelectionArrayCount(new_tf) *
8171 				 sizeof(XmTextScanType));
8172     memcpy((void *)TextF_SelectionArray(new_tf), (void *)temp_ptr,
8173 	   (TextF_SelectionArrayCount(new_tf) * sizeof(XmTextScanType)));
8174   }
8175   /*
8176    * End fix for HaL DTS 9841
8177    */
8178 
8179 
8180   /* Make sure the new_tf cursor position is a valid value.
8181    */
8182   if (TextF_CursorPosition(new_tf) < 0) {
8183     XmeWarning (new_w, MSG1);
8184     TextF_CursorPosition(new_tf) = TextF_CursorPosition(old_tf);
8185     cursor_pos_set = False;
8186   }
8187 
8188   if (TextF_FontList(new_tf)!= TextF_FontList(old_tf)) {
8189     new_font = True;
8190     if (TextF_FontList(new_tf) == NULL)
8191       TextF_FontList(new_tf) =
8192 	XmeGetDefaultRenderTable(new_w, XmTEXT_FONTLIST);
8193     TextF_FontList(new_tf) =
8194       (XmFontList)XmFontListCopy(TextF_FontList(new_tf));
8195     if (!LoadFontMetrics(new_tf)) { /* Fails if font set required but not
8196                                    * available. */
8197       XmFontListFree((XmFontList)TextF_FontList(new_tf));
8198       TextF_FontList(new_tf) = TextF_FontList(old_tf);
8199       (void)LoadFontMetrics(new_tf); /* it *was* correct, so re-use it */
8200       new_font = False;
8201     } else {
8202       XtSetArg(im_args[n], XmNfontList, TextF_FontList(new_tf)); n++;
8203       redisplay = True;
8204     }
8205   }
8206 
8207   /* Four cases to handle for value:
8208    *   1. user set both XmNvalue and XmNwcValue.
8209    *   2. user set the opposite resource (i.e. value is a char*
8210    *      and user set XmNwcValue, or vice versa).
8211    *   3. user set the corresponding resource (i.e. value is a char*
8212    *      and user set XmNValue, or vice versa).
8213    *   4. user set neither XmNValue nor XmNwcValue
8214    */
8215 
8216   /* OSF says:  if XmNvalueWcs set, it overrides all else */
8217 
8218   if (new_tf->text.max_char_size == 1) {
8219     /* wc_value on new will be NULL unless XmNvalueWcs was set.   */
8220     if (TextF_WcValue(new_tf) != NULL) { /* must be new if MB_CUR... == 1 */
8221       ValidateString(new_tf, (char*) TextF_WcValue(new_tf), True);
8222       diff_values = True;
8223     } else if (TextF_Value(new_tf) != TextF_Value(old_tf)) {
8224       diff_values = True;
8225       if (TextF_Value(new_tf) == NULL) {
8226 	ValidateString(new_tf, "", False);
8227       } else
8228 	ValidateString(new_tf, TextF_Value(new_tf), False);
8229     } /* else, no change so don't do anything */
8230   } else {
8231     if (TextF_WcValue(new_tf) != TextF_WcValue(old_tf)) {
8232       diff_values = True;
8233       if (TextF_WcValue(new_tf) == NULL) {
8234 	TextF_WcValue(new_tf) = (wchar_t*) XtMalloc(sizeof(wchar_t));
8235 	*TextF_WcValue(new_tf) = (wchar_t)NULL;
8236       }
8237       ValidateString(new_tf, (char*)TextF_WcValue(new_tf), True);
8238     } else if (TextF_Value(new_tf) != TextF_Value(old_tf)) {
8239       /* Someone set XmNvalue */
8240       diff_values = True;
8241       if (TextF_Value(new_tf) == NULL)
8242 	ValidateString(new_tf, "", True);
8243       else
8244 	ValidateString(new_tf, TextF_Value(new_tf), False);
8245 
8246     } /* else, no change so don't do anything */
8247   }
8248 
8249   if (diff_values) { /* old value != new value */
8250     Boolean do_it = True;
8251     /* If there are modify verify callbacks, verify that we want to continue
8252      * the action.
8253      */
8254     if (TextF_ModifyVerifyCallback(new_tf) ||
8255 	TextF_ModifyVerifyCallbackWcs(new_tf)) {
8256       /* If the function ModifyVerify() returns false then don't
8257        * continue with the action.
8258        */
8259       char *temp, *old;
8260       int free_insert = (int)False;
8261       XmTextPosition fromPos = 0, toPos;
8262       int ret_val = 0;
8263 
8264       toPos = old_tf->text.string_length;
8265       if (new_tf->text.max_char_size == 1) {
8266 	temp = TextF_Value(new_tf);
8267 	mod_ver_ret = ModifyVerify(new_tf, NULL, &fromPos, &toPos,
8268 				   &temp, &new_tf->text.string_length,
8269 				   &newInsert, &free_insert);
8270       } else {
8271 	old = temp = XtMalloc((unsigned)((new_tf->text.string_length + 1) *
8272 					 new_tf->text.max_char_size));
8273 	ret_val = wcstombs(temp, TextF_WcValue(new_tf),
8274 			   (new_tf->text.string_length + 1) *
8275 			   new_tf->text.max_char_size);
8276 	if (ret_val < 0) temp[0] = '\0';
8277 
8278 /* Fixed bug #1214. ModifyVerify needs wchar_t*, not char*. */
8279 /* old code:
8280 	mod_ver_ret = ModifyVerify(new_tf, NULL, &fromPos, &toPos, &temp,
8281 				   &new_tf->text.string_length, &newInsert,
8282 				   &free_insert);
8283 */
8284 #ifdef FIX_1409
8285 	mod_ver_ret = ModifyVerify(new_tf, NULL, &fromPos, &toPos,
8286 	                           &temp, &ret_val, &newInsert, &free_insert);
8287 #else
8288 	mod_ver_ret = ModifyVerify(new_tf, NULL, &fromPos, &toPos,
8289 	                           (char**)&TextF_WcValue(new_tf),
8290 				   &ret_val, &newInsert, &free_insert);
8291 #endif
8292 /* end if fix of bug #1214 */
8293 
8294 	if (old != temp) XtFree (old);
8295       }
8296       if (free_insert) XtFree(temp);
8297       if (!mod_ver_ret) {
8298 	if (new_tf->text.verify_bell) XBell(XtDisplay(new_w), 0);
8299 	if (new_tf->text.max_char_size == 1) {
8300 	  TextF_Value(new_tf) =
8301 	    (char *) memcpy(XtRealloc(TextF_Value(new_tf),
8302 				      (unsigned)old_tf->text.size_allocd),
8303 			    (void*)TextF_Value(old_tf),
8304 			    old_tf->text.string_length + 1);
8305 	  new_tf->text.string_length = old_tf->text.string_length;
8306 	  new_tf->text.size_allocd = old_tf->text.size_allocd;
8307 	  XtFree(TextF_Value(old_tf));
8308 	} else {
8309 	  /* realloc to old size, cast to wchar_t*, and copy the data */
8310 	  TextF_WcValue(new_tf) =
8311 	    (wchar_t*)memcpy( XtRealloc((char *)TextF_WcValue(new_tf),
8312 					(unsigned)old_tf->text.size_allocd),
8313 			     (void*)TextF_WcValue(old_tf),
8314 			     (size_t) old_tf->text.size_allocd);
8315 
8316 	  new_tf->text.string_length = old_tf->text.string_length;
8317 	  new_tf->text.size_allocd = old_tf->text.size_allocd;
8318 	  XtFree((char *)TextF_WcValue(old_tf));
8319 	}
8320 	do_it = False;
8321       }
8322     }
8323 
8324     if (do_it) {
8325       XmAnyCallbackStruct cb;
8326 
8327       if (new_tf->text.max_char_size == 1)
8328 	XtFree(TextF_Value(old_tf));
8329       else
8330 	XtFree((char *)TextF_WcValue(old_tf));
8331 
8332       doSetHighlight(new_w, new_tf->text.prim_pos_left,
8333 			      new_tf->text.prim_pos_right,
8334 			      XmHIGHLIGHT_NORMAL);
8335 
8336       new_tf->text.pending_off = True;
8337 
8338       /* if new_position was > old_tf->text.string_length, last time
8339        * the SetCursorPosition didn't take.
8340        */
8341       if (!cursor_pos_set || new_position > old_tf->text.string_length) {
8342 	_XmTextFieldSetCursorPosition(new_tf, NULL, new_position,
8343 				      True, False);
8344 	if (new_tf->text.has_destination)
8345 	  (void) SetDestination(new_w, TextF_CursorPosition(new_tf), False,
8346 				XtLastTimestampProcessed(XtDisplay(new_w)));
8347       }
8348 
8349       if (TextF_ResizeWidth(new_tf) && new_tf->text.do_resize)
8350 	AdjustSize(new_tf);
8351       else {
8352 	new_tf->text.h_offset = TextF_MarginWidth(new_tf) +
8353 	  new_tf->primitive.shadow_thickness +
8354 	    new_tf->primitive.highlight_thickness;
8355 	if (!AdjustText(new_tf, TextF_CursorPosition(new_tf), False))
8356 	  redisplay_text = True;
8357       }
8358 
8359       cb.reason = XmCR_VALUE_CHANGED;
8360       cb.event = NULL;
8361       XtCallCallbackList(new_w, TextF_ValueChangedCallback(new_tf),
8362 			 (XtPointer) &cb);
8363 
8364     }
8365   }
8366 
8367   if (new_tf->primitive.foreground != old_tf->primitive.foreground ||
8368       TextF_FontList(new_tf)!= TextF_FontList(old_tf) ||
8369       new_tf->core.background_pixel != old_tf->core.background_pixel) {
8370     LoadGCs(new_tf, new_tf->primitive.foreground,
8371 	    new_tf->core.background_pixel);
8372     MakeCursors(new_tf);
8373     redisplay = True;
8374     XtSetArg(im_args[n], XmNbackground, new_tf->core.background_pixel); n++;
8375     XtSetArg(im_args[n], XmNforeground, new_tf->primitive.foreground); n++;
8376   }
8377 
8378   if (new_tf->text.has_focus && XtIsSensitive((Widget)new_tf) &&
8379       TextF_BlinkRate(new_tf) != TextF_BlinkRate(old_tf)) {
8380 
8381     if (TextF_BlinkRate(new_tf) == 0) {
8382       new_tf->text.blink_on = True;
8383       if (new_tf->text.timer_id) {
8384 	XtRemoveTimeOut(new_tf->text.timer_id);
8385 	new_tf->text.timer_id = (XtIntervalId)0;
8386       }
8387     } else if (new_tf->text.timer_id == (XtIntervalId)0) {
8388       new_tf->text.timer_id =
8389 	XtAppAddTimeOut(XtWidgetToApplicationContext(new_w),
8390 			(unsigned long)TextF_BlinkRate(new_tf),
8391 			HandleTimer,
8392 			(XtPointer) new_tf);
8393     }
8394     BlinkInsertionPoint(new_tf);
8395   }
8396 
8397   if (TextF_MarginHeight(new_tf) != TextF_MarginHeight(old_tf)) {
8398     new_tf->text.margin_top = TextF_MarginHeight(new_tf);
8399     new_tf->text.margin_bottom = TextF_MarginHeight(new_tf);
8400   }
8401 
8402   new_size = TextF_MarginWidth(new_tf) != TextF_MarginWidth(old_tf) ||
8403              TextF_MarginHeight(new_tf) != TextF_MarginHeight(old_tf) ||
8404 	     TextF_FontList(new_tf) != TextF_FontList(old_tf) ||
8405 	     new_tf->primitive.highlight_thickness !=
8406 	       old_tf->primitive.highlight_thickness ||
8407 	     new_tf->primitive.shadow_thickness !=
8408 	       old_tf->primitive.shadow_thickness;
8409 
8410 
8411   if (TextF_Columns(new_tf) < 0) {
8412     XmeWarning (new_w, MSG7);
8413     TextF_Columns(new_tf) = TextF_Columns(old_tf);
8414   }
8415 
8416   if (!(new_width != old_tf->core.width &&
8417 	new_height != old_tf->core.height)) {
8418     if (TextF_Columns(new_tf) != TextF_Columns(old_tf) || new_size) {
8419       Dimension width, height;
8420 
8421       ComputeSize(new_tf, &width, &height);
8422       AdjustText(new_tf, 0, False);
8423 
8424       if (new_width == old_tf->core.width)
8425 	new_w->core.width = width;
8426       if (new_height == old_tf->core.height)
8427 	new_w->core.height = height;
8428       new_tf->text.h_offset = TextF_MarginWidth(new_tf) +
8429 	new_tf->primitive.shadow_thickness +
8430 	  new_tf->primitive.highlight_thickness;
8431       redisplay = True;
8432     }
8433   } else {
8434     if (new_width != new_tf->core.width)
8435       new_tf->core.width = new_width;
8436     if (new_height != new_tf->core.height)
8437       new_tf->core.height = new_height;
8438   }
8439 
8440   new_tf->text.refresh_ibeam_off = True; /* force update of putback area */
8441 
8442   _XmTextFieldDrawInsertionPoint(new_tf, True);
8443 
8444   if (XtIsSensitive((Widget)new_tf) != XtIsSensitive((Widget)old_tf)) {
8445     if (XtIsSensitive(new_w)) {
8446       _XmTextFieldDrawInsertionPoint(new_tf, False);
8447       new_tf->text.blink_on = False;
8448       _XmTextFieldDrawInsertionPoint(new_tf, True);
8449     } else {
8450       if (new_tf->text.has_focus) {
8451 	ChangeBlinkBehavior(new_tf, False);
8452 	_XmTextFieldDrawInsertionPoint(new_tf, False);
8453 	new_tf->text.has_focus = False;
8454 	new_tf->text.blink_on = True;
8455 	_XmTextFieldDrawInsertionPoint(new_tf, True);
8456 	(void) VerifyLeave(new_tf, NULL);
8457       }
8458     }
8459     if (new_tf->text.string_length > 0) redisplay = True;
8460   }
8461 
8462   (void)TextFieldGetDisplayRect((Widget)new_tf, &xmim_area);
8463   GetXYFromPos(new_tf, TextF_CursorPosition(new_tf), &xmim_point.x,
8464 	       &xmim_point.y);
8465 
8466   if (TextF_Editable(old_tf) != TextF_Editable(new_tf)) {
8467     Boolean editable = TextF_Editable(new_tf);
8468     TextF_Editable(new_tf) = TextF_Editable(old_tf);
8469     XmTextFieldSetEditable(new_w, editable);
8470   } else if (new_font && TextF_Editable(new_tf)) {
8471     /* We want to be able to connect to an IM if XmNfontList has changed. */
8472     TextF_Editable(new_tf) = False;
8473     XmTextFieldSetEditable(new_w, True);
8474   }
8475 
8476   XtSetArg(im_args[n], XmNbackgroundPixmap,
8477 	   new_tf->core.background_pixmap); n++;
8478   XtSetArg(im_args[n], XmNspotLocation, &xmim_point); n++;
8479   XtSetArg(im_args[n], XmNarea, &xmim_area); n++;
8480   XtSetArg(im_args[n], XmNlineSpace,
8481 	   TextF_FontAscent(new_tf) + TextF_FontDescent(new_tf)); n++;
8482   XmImSetValues((Widget)new_tf, im_args, n);
8483 
8484   if (new_font) XmFontListFree((XmFontList)TextF_FontList(old_tf));
8485 
8486   if (!redisplay) redisplay = new_tf->text.redisplay;
8487 
8488   /* If I'm forced to redisplay, then actual widget won't be updated
8489    * until the expose proc.  Force the ibeam putback to be refreshed
8490    * at expose time so that it reflects true visual state of the
8491    * widget.  */
8492 
8493   if (redisplay) new_tf->text.refresh_ibeam_off = True;
8494 
8495   new_tf->text.in_setvalues = False;
8496 
8497   if ((!TextF_Editable(new_tf) || !XtIsSensitive(new_w)) &&
8498       new_tf->text.has_destination)
8499     (void) SetDestination(new_w, 0, False, (Time)0);
8500 
8501   /* don't shrink to nothing */
8502   if (new_tf->core.width == 0) new_tf->core.width = old_tf->core.width;
8503   if (new_tf->core.height == 0) new_tf->core.height = old_tf->core.height;
8504 
8505   if (!redisplay && redisplay_text)
8506     RedisplayText(new_tf, 0, new_tf->text.string_length);
8507 
8508   return redisplay;
8509 }
8510 
8511 /********************************************
8512  * AccessTextual trait method implementation
8513  ********************************************/
8514 
8515 static XtPointer
8516 TextFieldGetValue(Widget w, int format)
8517 {
8518   char *str;
8519   XmString tmp;
8520 
8521   switch(format) {
8522   case XmFORMAT_XmSTRING:
8523     str = XmTextFieldGetString(w);
8524     tmp = XmStringCreateLocalized(str);
8525     if (str != NULL) XtFree(str);
8526     return((XtPointer) tmp);
8527   case XmFORMAT_MBYTE:
8528     return((XtPointer) XmTextFieldGetString(w));
8529   case XmFORMAT_WCS:
8530     return((XtPointer) XmTextFieldGetStringWcs(w));
8531   }
8532 
8533   return(NULL);
8534 }
8535 
8536 static void
8537 TextFieldSetValue(Widget w, XtPointer s, int format)
8538 {
8539   char *str;
8540 
8541   switch(format) {
8542   case XmFORMAT_XmSTRING:
8543     str = _XmStringGetTextConcat((XmString) s);
8544     XmTextFieldSetString(w, str);
8545     if (str != NULL) XtFree(str);
8546     break;
8547   case XmFORMAT_MBYTE:
8548     XmTextFieldSetString(w, (char*) s);
8549     break;
8550   case XmFORMAT_WCS:
8551     XmTextFieldSetStringWcs(w, (wchar_t *) s);
8552   }
8553 }
8554 
8555 /*ARGSUSED*/
8556 static int
8557 TextFieldPreferredValue(Widget w) /* unused */
8558 {
8559   return(XmFORMAT_MBYTE);
8560 }
8561 
8562 /*
8563  * XmRCallProc routine for checking text.font_list before setting it to NULL
8564  * if no value is specified for both XmNrenderTable and XmNfontList.
8565  * If "check_set_render_table" == True, then function has been called twice
8566  * on same widget, thus resource needs to be set NULL, otherwise leave it
8567  * alone.
8568  */
8569 /* ARGSUSED */
8570 static void
8571 CheckSetRenderTable(Widget wid,
8572 		    int offset,
8573 		    XrmValue *value)
8574 {
8575   XmTextFieldWidget tf = (XmTextFieldWidget)wid;
8576 
8577   if (tf->text.check_set_render_table)
8578 	value->addr = NULL;
8579   else {
8580 	tf->text.check_set_render_table = True;
8581 	value->addr = (char*)&(tf->text.font_list);
8582   }
8583 }
8584 
8585 static Boolean
8586 TextFieldRemove(Widget w,
8587 		XEvent *event)
8588 {
8589   XmTextFieldWidget tf = (XmTextFieldWidget) w;
8590   XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
8591   XmAnyCallbackStruct cb;
8592 
8593   if (TextF_Editable(tf) == False)
8594     return False;
8595 
8596   TextFieldResetIC(w);
8597   if (!tf->text.has_primary || left == right) {
8598     tf->text.prim_anchor = TextF_CursorPosition(tf);
8599     return False;
8600   }
8601 
8602   if (_XmTextFieldReplaceText(tf, event, left, right, NULL, 0, True)) {
8603     _XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
8604 			       TextF_CursorPosition(tf),
8605 			       XtLastTimestampProcessed(XtDisplay(w)));
8606     tf->text.pending_off = False;
8607     cb.reason = XmCR_VALUE_CHANGED;
8608     cb.event = event;
8609     XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
8610 		       (XtPointer) &cb);
8611   }
8612 
8613   tf->text.prim_anchor = TextF_CursorPosition(tf);
8614 
8615   return True;
8616 }
8617 
8618 /* ARGSUSED */
8619 static Boolean
8620 TextFieldGetBaselines(Widget w,
8621 		      Dimension ** baselines,
8622 		      int *line_count)
8623 {
8624   XmTextFieldWidget tf = (XmTextFieldWidget) w;
8625   Dimension *base_array;
8626 
8627   *line_count = 1;
8628 
8629   base_array = (Dimension *) XtMalloc(sizeof(Dimension));
8630 
8631   base_array[0] = tf->text.margin_top + tf->primitive.shadow_thickness +
8632     tf->primitive.highlight_thickness + TextF_FontAscent(tf);
8633 
8634   *baselines = base_array;
8635 
8636   return (TRUE);
8637 }
8638 
8639 static Boolean
8640 TextFieldGetDisplayRect(Widget w,
8641 			XRectangle * display_rect)
8642 {
8643   XmTextFieldWidget tf = (XmTextFieldWidget) w;
8644   Position margin_width = TextF_MarginWidth(tf) +
8645     tf->primitive.shadow_thickness +
8646       tf->primitive.highlight_thickness;
8647   Position margin_top = tf->text.margin_top + tf->primitive.shadow_thickness +
8648     tf->primitive.highlight_thickness;
8649   Position margin_bottom = tf->text.margin_bottom +
8650     tf->primitive.shadow_thickness +
8651       tf->primitive.highlight_thickness;
8652   (*display_rect).x = margin_width;
8653   (*display_rect).y = margin_top;
8654   (*display_rect).width = tf->core.width - (2 * margin_width);
8655   (*display_rect).height = tf->core.height - (margin_top + margin_bottom);
8656 
8657   return(TRUE);
8658 }
8659 
8660 
8661 /* ARGSUSED */
8662 static void
8663 TextFieldMarginsProc(Widget w,
8664 		     XmBaselineMargins *margins_rec)
8665 {
8666   XmTextFieldWidget tf = (XmTextFieldWidget) w;
8667 
8668   if (margins_rec->get_or_set == XmBASELINE_SET) {
8669     tf->text.margin_top = margins_rec->margin_top;
8670   } else {
8671     margins_rec->margin_top = tf->text.margin_top;
8672     margins_rec->margin_bottom = tf->text.margin_bottom;
8673     margins_rec->text_height = TextF_FontAscent(tf) + TextF_FontDescent(tf);
8674     margins_rec->shadow = tf->primitive.shadow_thickness;
8675     margins_rec->highlight = tf->primitive.highlight_thickness;
8676     margins_rec->margin_height = 0;
8677   }
8678 }
8679 
8680 
8681 /*
8682  * This procedure and _XmTextFieldReplaceText are almost same.
8683  * The difference is that this function doesn't call user's callbacks,
8684  * like XmNmodifyVerifyCallback.
8685  */
8686 static Boolean
8687 _XmTextFieldReplaceTextForPreedit(XmTextFieldWidget tf,
8688                                   XmTextPosition replace_prev,
8689                                   XmTextPosition replace_next,
8690                                   char *insert,
8691                                   int insert_length,
8692                                   Boolean move_cursor )
8693 {
8694   int replace_length, i;
8695   char *src, *dst;
8696   wchar_t *wc_src, *wc_dst;
8697   XmAnyCallbackStruct cb;
8698   int delta = 0;
8699   XmTextPosition cursorPos, newInsert;
8700   XmTextPosition old_pos = replace_prev;
8701   XmTextPosition redisplay_start;
8702   int free_insert = (int)False;
8703 
8704   VerifyBounds(tf, &replace_prev, &replace_next);
8705 
8706   if (!TextF_Editable(tf)) {
8707      if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
8708      return False;
8709  }
8710 
8711   /*
8712    * If composite sequences were supported, we had to
8713    * redisplay from the nearest composite sequence break.
8714    * But for current implementation, just use old_pos.
8715    */
8716   redisplay_start = old_pos;
8717 
8718   replace_length = (int) (replace_next - replace_prev);
8719   delta = insert_length - replace_length;
8720 
8721  /* Disallow insertions that go beyond max length boundries.
8722   */
8723   if ((delta >= 0) &&
8724       ((tf->text.string_length + delta) - (TextF_MaxLength(tf)) > 0)) {
8725       if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
8726       return False;
8727   }
8728 
8729   newInsert = TextF_CursorPosition(tf);
8730 
8731  /* make sure selections are turned off prior to changeing text */
8732   if (tf->text.has_primary &&
8733       tf->text.prim_pos_left != tf->text.prim_pos_right)
8734      doSetHighlight((Widget)tf, tf->text.prim_pos_left,
8735                              tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
8736 
8737   _XmTextFieldDrawInsertionPoint(tf, False);
8738 
8739   /* Allocate more space if we need it.
8740    */
8741   if (tf->text.max_char_size == 1){
8742   if (tf->text.string_length + insert_length - replace_length >=
8743       tf->text.size_allocd)
8744     {
8745       tf->text.size_allocd += MAX(insert_length + TEXT_INCREMENT,
8746                                         (tf->text.size_allocd * 2));
8747       tf->text.value = (char *) XtRealloc((char*)TextF_Value(tf),
8748                               (unsigned) (tf->text.size_allocd * sizeof(char)));
8749     }
8750   } else {
8751  if ((tf->text.string_length + insert_length - replace_length) *
8752                                         sizeof(wchar_t) >= tf->text.size_allocd)
8753     {
8754       tf->text.size_allocd += MAX(insert_length + TEXT_INCREMENT,
8755                                         (tf->text.size_allocd * 2));
8756       tf->text.wc_value = (wchar_t *) XtRealloc((char*)TextF_WcValue(tf),
8757                            (unsigned) (sizeof(wchar_t) * tf->text.size_allocd));
8758     }
8759   }
8760 
8761   if (tf->text.max_char_size == 1) {
8762      if (replace_length > insert_length)
8763        /* We need to shift the text at and after replace_next to the left. */
8764        for (src = TextF_Value(tf) + replace_next,
8765             dst = src + (insert_length - replace_length),
8766             i = (int) ((tf->text.string_length + 1) - replace_next);
8767             i > 0;
8768             ++src, ++dst, --i)
8769          *dst = *src;
8770      else if (replace_length < insert_length)
8771        /* We need to shift the text at and after replace_next to the right. */
8772        /* Need to add 1 to string_length to handle the NULL terminator on */
8773        /* the string. */
8774        for (src = TextF_Value(tf) + tf->text.string_length,
8775             dst = src + (insert_length - replace_length),
8776             i = (int) ((tf->text.string_length + 1) - replace_next);
8777             i > 0;
8778             --src, --dst, --i)
8779          *dst = *src;
8780 
8781     /* Update the string.
8782      */
8783      if (insert_length != 0) {
8784         for (src = insert,
8785              dst = TextF_Value(tf) + replace_prev,
8786              i = insert_length;
8787              i > 0;
8788              ++src, ++dst, --i)
8789           *dst = *src;
8790      }
8791    } else {  /* have wchar_t* data */
8792      if (replace_length > insert_length)
8793        /* We need to shift the text at and after replace_next to the left. */
8794        for (wc_src = TextF_WcValue(tf) + replace_next,
8795             wc_dst = wc_src + (insert_length - replace_length),
8796             i = (int) ((tf->text.string_length + 1) - replace_next);
8797             i > 0;
8798             ++wc_src, ++wc_dst, --i)
8799          *wc_dst = *wc_src;
8800      else if (replace_length < insert_length)
8801        /* We need to shift the text at and after replace_next to the right. */
8802        /* Need to add 1 to string_length to handle the NULL terminator on */
8803        /* the string. */
8804        for (wc_src = TextF_WcValue(tf) + tf->text.string_length,
8805             wc_dst = wc_src + (insert_length - replace_length),
8806             i = (int) ((tf->text.string_length + 1) - replace_next);
8807             i > 0;
8808             --wc_src, --wc_dst, --i)
8809          *wc_dst = *wc_src;
8810 
8811     /* Update the string.
8812      */
8813      if (insert_length != 0) {
8814        for (wc_src = (wchar_t *)insert,
8815              wc_dst = TextF_WcValue(tf) + replace_prev,
8816              i = insert_length;
8817              i > 0;
8818              ++wc_src, ++wc_dst, --i)
8819           *wc_dst = *wc_src;
8820      }
8821    }
8822 
8823   tf->text.string_length += insert_length - replace_length;
8824 
8825   if (move_cursor) {
8826      if (TextF_CursorPosition(tf) != newInsert) {
8827         if (newInsert > tf->text.string_length) {
8828            cursorPos = tf->text.string_length;
8829         } else if (newInsert < 0) {
8830            cursorPos = 0;
8831         } else {
8832            cursorPos = newInsert;
8833         }
8834      } else
8835       cursorPos = replace_next + (insert_length - replace_length);
8836      (void) SetDestination((Widget)tf, cursorPos, False,
8837                         XtLastTimestampProcessed(XtDisplay((Widget)tf)));
8838      PreeditSetCursorPosition(tf, cursorPos);
8839   }
8840 
8841   if (TextF_ResizeWidth(tf) && tf->text.do_resize) {
8842      AdjustSize(tf);
8843   } else {
8844      AdjustText(tf, TextF_CursorPosition(tf), False);
8845 
8846      /*
8847       * If composite sequences where supported, we had to
8848       * adjust redisplay_start once more here, since the widget
8849       * value was updated.
8850       * But for current implementation, there is no need
8851       * to do so.
8852       */
8853 
8854      RedisplayText(tf, redisplay_start, tf->text.string_length);
8855   }
8856 
8857   _XmTextFieldDrawInsertionPoint(tf, True);
8858   if (free_insert) XtFree(insert);
8859   return True;
8860 }
8861 
8862 /*
8863  * This function shows the correspondence of rendition data between the input
8864  * server and XmTextField
8865  */
8866 static XmHighlightMode
8867 _XimFeedbackToXmHighlightMode(XIMFeedback fb)
8868 {
8869     switch (fb) {
8870       case XIMReverse:
8871         return(XmHIGHLIGHT_SELECTED);
8872       case XIMUnderline:
8873         return(XmHIGHLIGHT_SECONDARY_SELECTED);
8874       case XIMHighlight:
8875         return(XmHIGHLIGHT_NORMAL);
8876       case XIMPrimary:
8877 	return(XmHIGHLIGHT_SELECTED);
8878       case XIMSecondary:
8879 	return(XmHIGHLIGHT_SECONDARY_SELECTED);
8880       case XIMTertiary:
8881         return(XmHIGHLIGHT_SELECTED);
8882       default:
8883         return(XmHIGHLIGHT_NORMAL);
8884     }
8885 }
8886 /*
8887  * This function treats the rendition data.
8888  */
8889 static void
8890 PreeditSetRendition(Widget w,
8891                     XIMPreeditDrawCallbackStruct* data)
8892 {
8893     XIMText *text = data->text;
8894     int cnt;
8895     XIMFeedback fb;
8896     XmTextPosition prestart = PreStart((XmTextFieldWidget)w)+data->chg_first, left, right;
8897     XmHighlightMode mode;
8898     XmTextFieldWidget tf = (XmTextFieldWidget)w;
8899 
8900     if (!text->length) {
8901         return;
8902     }
8903 
8904     if (!text->feedback)
8905         return;
8906 
8907     fb = text->feedback[0];     /* initial feedback */
8908     left = right = prestart;    /* mode start/end position */
8909     mode = _XimFeedbackToXmHighlightMode(fb); /* mode */
8910     cnt = 1;                    /* counter initialize */
8911 
8912     while (cnt < (int)text->length) {
8913         if (fb != text->feedback[cnt]) {
8914             right = prestart + cnt;
8915             doSetHighlight(w, left, right, mode);
8916 
8917             left = right;       /* start position update */
8918             fb = text->feedback[cnt]; /* feedback update */
8919             mode = _XimFeedbackToXmHighlightMode(fb);
8920         }
8921         cnt++;                  /* counter increment */
8922     }
8923     doSetHighlight(w, left, (prestart + cnt), mode);
8924                                 /* for the last segment */
8925 }
8926 
8927 /*
8928  * This function and _XmTextFieldSetCursorPosition are almost same. The
8929  * difference is that this function don't call user's callbacks link
8930  * XmNmotionVerifyCallback.
8931  */
8932 static void
8933 PreeditSetCursorPosition(XmTextFieldWidget tf,
8934                          XmTextPosition position)
8935 {
8936     int i;
8937     _XmHighlightRec *hl_list = tf->text.highlight.list;
8938 
8939     if (position < 0) position = 0;
8940 
8941     if (position > tf->text.string_length)
8942        position = tf->text.string_length;
8943 
8944     _XmTextFieldDrawInsertionPoint(tf, False);
8945 
8946     TextF_CursorPosition(tf) = position;
8947     for (i = tf->text.highlight.number - 1; i >= 0; i--){
8948        if (position >= hl_list[i].position || i == 0)
8949           break;
8950     }
8951 
8952     if (position == hl_list[i].position)
8953        ResetImageGC(tf);
8954     else if (hl_list[i].mode != XmHIGHLIGHT_SELECTED)
8955        ResetImageGC(tf);
8956     else
8957        InvertImageGC(tf);
8958 
8959     ResetClipOrigin(tf);
8960 
8961     tf->text.refresh_ibeam_off = True;
8962     _XmTextFieldDrawInsertionPoint(tf, True);
8963 }
8964 
8965 
8966 static void PreeditVerifyReplace(XmTextFieldWidget tf,
8967 				 XmTextPosition start,
8968 				 XmTextPosition end,
8969 				 char *insert,
8970 				 char insert_length,
8971 				 XmTextPosition cursor,
8972 				 Boolean *end_preedit)
8973 
8974 {
8975   FUnderVerifyPreedit(tf) = True;
8976   _XmTextFieldReplaceText(tf, NULL, start, end, insert, insert_length, True);
8977   FUnderVerifyPreedit(tf) = False;
8978   if (FVerifyCommitNeeded(tf)) {
8979     TextFieldResetIC((Widget) tf);
8980     *end_preedit = True;
8981   }
8982   _XmTextFieldSetCursorPosition(tf, NULL, cursor, False, True);
8983 }
8984 
8985 
8986 
8987 /*
8988  * This is the function set to XNPreeditStartCallback resource.
8989  * This function is called when the preedit process starts.
8990  * Initialize the preedit data and also treat pending delete.
8991  */
8992 static int
8993 PreeditStart(XIC xic,
8994              XPointer client_data,
8995              XPointer call_data)
8996 {
8997     XmTextPosition cursorPos, nextPos, lastPos;
8998     Boolean replace_res, pending_delete = False;
8999     wchar_t *wc;
9000     char *mb;
9001     Widget w = (Widget) client_data;
9002     XmTextFieldWidget tf = (XmTextFieldWidget) client_data;
9003 
9004     tf->text.onthespot->over_len = 0;
9005     tf->text.onthespot->over_str = NULL;
9006     tf->text.onthespot->over_maxlen = 0;
9007 
9008     /* If TextField is not editable, returns 0. So input server never */
9009     /* call Preedit Draw callback */
9010     if (!TextF_Editable(tf)) {
9011         if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
9012         tf->text.onthespot->under_preedit = False;
9013         return 0;
9014     }
9015 
9016     if (NeedsPendingDeleteDisjoint(tf)){
9017         _XmTextFieldDrawInsertionPoint(tf, False);
9018         if (!XmTextFieldGetSelectionPosition(w, &cursorPos, &nextPos) ||
9019                                                 cursorPos == nextPos) {
9020           tf->text.prim_anchor = TextF_CursorPosition(tf);
9021         }
9022         pending_delete = True;
9023 
9024         tf->text.prim_anchor = TextF_CursorPosition(tf);
9025 
9026         replace_res = _XmTextFieldReplaceText(tf,
9027                         NULL, cursorPos, nextPos, NULL, 0, True);
9028 
9029         if (replace_res){
9030             if (pending_delete)
9031                 XmTextFieldSetSelection(w, TextF_CursorPosition(tf),
9032                         TextF_CursorPosition(tf),
9033                         XtLastTimestampProcessed(XtDisplay((Widget)tf)));
9034 
9035             CheckDisjointSelection(w, TextF_CursorPosition(tf),
9036                         XtLastTimestampProcessed(XtDisplay((Widget)tf)));
9037 
9038             _XmTextFieldSetCursorPosition(tf,
9039                         NULL,
9040                         TextF_CursorPosition(tf), False, True);
9041         }
9042         _XmTextFieldDrawInsertionPoint(tf, True);
9043     }
9044 
9045     PreStart(tf) = PreEnd(tf) = PreCursor(tf)
9046         = TextF_CursorPosition(tf);
9047     tf->text.onthespot->under_preedit = True;
9048 
9049     if (tf->text.overstrike) {
9050        lastPos = tf->text.string_length;
9051        tf->text.onthespot->over_len = lastPos - PreCursor(tf);
9052 
9053             if (tf->text.max_char_size == 1){
9054                 mb = XtMalloc(tf->text.onthespot->over_len + 1);
9055                 bcopy(&tf->text.value[PreStart(tf)], mb,
9056                                         tf->text.onthespot->over_len);
9057                 mb[tf->text.onthespot->over_len] = '\0';
9058                 tf->text.onthespot->over_str = mb;
9059             } else {
9060                 wc = (wchar_t *) XtMalloc(
9061                         (tf->text.onthespot->over_len+1)*sizeof(wchar_t));
9062                 bcopy((char *)&tf->text.wc_value[PreStart(tf)], (char *)wc,
9063                                 tf->text.onthespot->over_len*sizeof(wchar_t));
9064                 wc[tf->text.onthespot->over_len] = (wchar_t)'\0';
9065                 tf->text.onthespot->over_str = (char *)wc;
9066             }
9067     }
9068 
9069     return (-1);
9070 }
9071 
9072 /*
9073  * This is the function set to XNPreeditDoneCallback resource.
9074  * This function is called when the preedit process is finished.
9075  */
9076 static void
9077 PreeditDone(XIC xic,
9078             XPointer client_data,
9079             XPointer call_data)
9080 {
9081     Boolean replace_res;
9082     XmTextFieldWidget tf = (XmTextFieldWidget)client_data;
9083     Widget p = (Widget) tf;
9084     Boolean need_verify, end_preedit = False;
9085 
9086     if (!TextF_Editable(tf))
9087         return;
9088 
9089     while (!XtIsShell(p))
9090 	p = XtParent(p);
9091     XtVaGetValues(p, XmNverifyPreedit, &need_verify, NULL);
9092 
9093     if (PreEnd(tf) > PreStart(tf)) {
9094       if (need_verify) {
9095         PreeditVerifyReplace(tf, PreStart(tf), PreEnd(tf), NULL, 0,
9096                                 PreStart(tf), &end_preedit);
9097         if (end_preedit) return;
9098       }
9099       else
9100         _XmTextFieldReplaceTextForPreedit(tf, PreStart(tf),
9101                         PreEnd(tf), NULL, 0, True );
9102     }
9103 
9104     if (tf->text.overstrike){
9105       if (need_verify) {
9106 	int cur = PreStart(tf);
9107  	PreeditVerifyReplace(tf, PreStart(tf), PreStart(tf),
9108 				(char*) tf->text.onthespot->over_str,
9109 				tf->text.onthespot->over_maxlen,
9110                                 PreStart(tf), &end_preedit);
9111 	if (end_preedit) return;
9112       }
9113       else {
9114         _XmTextFieldDrawInsertionPoint(tf, False);
9115         replace_res = _XmTextFieldReplaceTextForPreedit(tf, PreStart(tf),
9116                         PreStart(tf), (char*) tf->text.onthespot->over_str,
9117                         tf->text.onthespot->over_maxlen, True);
9118         TextF_CursorPosition(tf) = PreStart(tf);
9119         PreeditSetCursorPosition(tf, TextF_CursorPosition(tf));
9120         _XmTextFieldDrawInsertionPoint(tf, True);
9121       }
9122       XtFree((char *)tf->text.onthespot->over_str);
9123       tf->text.onthespot->over_len = tf->text.onthespot->over_maxlen = 0;
9124     }
9125 
9126     PreStart(tf) = PreEnd(tf) = PreCursor(tf) = 0;
9127     tf->text.onthespot->under_preedit = False;
9128 }
9129 
9130 /*
9131  * This is the function set to XNPreeditDrawCallback resource.
9132  * This function is called when the input server requests XmTextField
9133  * to draw a preedit string.
9134  */
9135 static void
9136 PreeditDraw(XIC xic,
9137             XPointer client_data,
9138             XIMPreeditDrawCallbackStruct *call_data)
9139 {
9140     Widget w = (Widget) client_data;
9141     XmTextFieldWidget tf = (XmTextFieldWidget) client_data;
9142     int escapement, insert_length = 0;
9143     char *mb = NULL, *over_mb = NULL;
9144     wchar_t *wc = NULL, *over_wc = NULL, *tab_wc = NULL , *recover_wc = NULL;
9145     XmTextPosition startPos, endPos, cursorPos, rest_len =0 , tmp_end;
9146     Boolean replace_res;
9147     XRectangle overall_ink;
9148     int i;
9149     int recover_len=0;
9150     char *ptr=NULL;
9151     Widget p =w;
9152     Boolean need_verify, end_preedit = False;
9153 
9154     if (!TextF_Editable(tf))
9155         return;
9156 
9157     if (call_data->text &&
9158         (insert_length = call_data->text->length) > TEXT_MAX_INSERT_SIZE)
9159         return;
9160 
9161     if (call_data->chg_length>PreEnd(tf)-PreStart(tf))
9162         call_data->chg_length = PreEnd(tf)-PreStart(tf);
9163 
9164     while (!XtIsShell(p))
9165 	p = XtParent(p);
9166     XtVaGetValues(p, XmNverifyPreedit, &need_verify, NULL);
9167 
9168     _XmTextFieldDrawInsertionPoint(tf, False);
9169     doSetHighlight(w, PreStart(tf)+call_data->chg_first,
9170         PreStart(tf)+call_data->chg_first + call_data->chg_length,
9171         XmHIGHLIGHT_NORMAL);
9172 
9173 
9174     if (!tf->text.overstrike && (!call_data->text || !insert_length)) {
9175         startPos = PreStart(tf) + call_data->chg_first;
9176         endPos = startPos + call_data->chg_length;
9177 	PreEnd(tf) -= endPos - startPos;
9178 	if (need_verify) {
9179 	  PreeditVerifyReplace(tf, startPos, endPos, NULL, 0,
9180 					startPos, &end_preedit);
9181 	  if (end_preedit) {
9182 	    _XmTextFieldDrawInsertionPoint(tf, True);
9183 	    return;
9184 	  }
9185 	}
9186 	else {
9187           replace_res = _XmTextFieldReplaceTextForPreedit(tf, startPos,
9188                                              endPos, NULL, 0, True);
9189 	}
9190 	_XmTextFieldDrawInsertionPoint(tf, True);
9191         return;
9192     }
9193 
9194     if (call_data->text) {
9195     if ((call_data->text->encoding_is_wchar &&
9196          !call_data->text->string.wide_char) ||
9197         (!call_data->text->encoding_is_wchar &&
9198          !call_data->text->string.multi_byte)){
9199 
9200         PreeditSetRendition(w, call_data);
9201 
9202         PreeditSetCursorPosition(tf, TextF_CursorPosition(tf));
9203         _XmTextFieldDrawInsertionPoint(tf, True);
9204         return;
9205     }
9206     }
9207 
9208     if (insert_length > 0){
9209         if (TextF_UseFontSet(tf)){
9210 
9211             if (call_data->text->encoding_is_wchar){
9212                 escapement = XwcTextExtents((XFontSet)TextF_Font(tf),
9213                         call_data->text->string.wide_char, insert_length,
9214                         &overall_ink, NULL);
9215            	tab_wc = (wchar_t*) XtMalloc((unsigned)(1+1) * sizeof(wchar_t));
9216                 mbstowcs(tab_wc, "\t", 1);
9217                 if ( escapement == 0 && overall_ink.width == 0 &&
9218                     wcschr(call_data->text->string.wide_char, *tab_wc) == 0){
9219                         /* cursor on */
9220 		    XtFree((char *) tab_wc);
9221                     return;
9222                 }
9223 	        XtFree((char *) tab_wc);
9224             } else {
9225                 mb = XtMalloc((insert_length+1)*(tf->text.max_char_size));
9226                 strcpy(mb, call_data->text->string.multi_byte);
9227                 escapement = XmbTextExtents((XFontSet)TextF_Font(tf),
9228                         mb, strlen(mb), &overall_ink, NULL);
9229                 if ( escapement == 0 && overall_ink.width == 0 &&
9230                     strchr(call_data->text->string.multi_byte, '\t') == 0){
9231                         /* cursor on */
9232                     if (mb)
9233                        XtFree(mb);
9234                     return;
9235                 }
9236             }
9237         }
9238     }
9239     else {
9240         mb = XtMalloc(4);
9241         mb[0] = '\0';
9242         wc = (wchar_t *) XtMalloc((unsigned) sizeof(wchar_t));
9243         wc[0] = (wchar_t) '\0';
9244     }
9245 
9246     startPos = PreStart(tf) + call_data->chg_first;
9247     endPos = startPos + call_data->chg_length;
9248 
9249    if (tf->text.overstrike){
9250         startPos = PreStart(tf) + call_data->chg_first;
9251         tmp_end = (XmTextPosition)(PreEnd(tf) + insert_length -
9252                                                 call_data->chg_length);
9253         if (tf->text.onthespot->over_maxlen < tmp_end - PreStart(tf)){
9254             if (tmp_end - PreStart(tf) > tf->text.onthespot->over_len){
9255                 endPos = startPos + call_data->chg_length;
9256                 tf->text.onthespot->over_maxlen = tf->text.onthespot->over_len;
9257             } else {
9258                 endPos = PreEnd(tf) + tmp_end - PreStart(tf) -
9259                                 tf->text.onthespot->over_maxlen;
9260                 tf->text.onthespot->over_maxlen = tmp_end - PreStart(tf);
9261             }
9262         } else
9263         if (tf->text.onthespot->over_maxlen > tmp_end - PreStart(tf)) {
9264             endPos = PreEnd(tf);
9265             recover_len = tf->text.onthespot->over_maxlen - tmp_end +
9266                                 PreStart(tf);
9267             tf->text.onthespot->over_maxlen = tmp_end - PreStart(tf);
9268         } else
9269             endPos = startPos + call_data->chg_length;
9270 
9271         rest_len = (XmTextPosition)(PreEnd(tf) - PreStart(tf) -
9272                         call_data->chg_first - call_data->chg_length);
9273         if (rest_len){
9274             if (tf->text.max_char_size == 1){
9275                 over_mb = XtMalloc(rest_len+1);
9276                bcopy(&tf->text.value[PreStart(tf)+call_data->chg_first+
9277                                 call_data->chg_length], over_mb, rest_len);
9278                 over_mb[rest_len] = '\0';
9279             } else {
9280                 over_wc = (wchar_t *)XtMalloc((rest_len+1)*sizeof(wchar_t));
9281                 bcopy((char *)&tf->text.wc_value[PreStart(tf)+
9282                         call_data->chg_first+call_data->chg_length],
9283                         (char *)over_wc, rest_len*sizeof(wchar_t));
9284                 over_wc[rest_len] = (wchar_t)'\0';
9285             }
9286         }
9287     }
9288 
9289     if (tf->text.overstrike)
9290         PreEnd(tf) = startPos + insert_length;
9291     else
9292         PreEnd(tf) += insert_length - endPos + startPos;
9293 
9294     if (PreEnd(tf) < PreStart(tf))
9295         PreEnd(tf) = PreStart(tf);
9296 
9297     PreCursor(tf) = PreStart(tf) + call_data->caret;
9298 
9299     if (tf->text.max_char_size == 1) {
9300         if (call_data->text) {
9301         if (call_data->text->encoding_is_wchar){
9302             mb = XtMalloc((insert_length+1)*sizeof(char));
9303             wcstombs(mb, call_data->text->string.wide_char, insert_length);
9304             mb[insert_length] = '\0';
9305         } else
9306         {
9307             mb = XtMalloc((insert_length+1)*sizeof(char));
9308             strcpy(mb, call_data->text->string.multi_byte);
9309         }
9310 	}
9311 
9312         if (tf->text.overstrike && rest_len){
9313             mb = XtRealloc(mb, strlen(mb)+strlen(over_mb)+1);
9314             strcat(mb, over_mb);
9315             XtFree(over_mb);
9316         }
9317 
9318         if (tf->text.overstrike && recover_len > 0) {
9319            mb = XtRealloc(mb, strlen(mb)+(recover_len+1));
9320            ptr = tf->text.onthespot->over_str + tf->text.onthespot->over_maxlen;
9321            i = strlen(mb);
9322            strncat(mb, ptr, recover_len);
9323            mb[i+recover_len] = '\0';
9324         }
9325 
9326 	if (need_verify) {
9327 	  PreeditVerifyReplace(tf, startPos, endPos, mb, strlen(mb),
9328 				PreCursor(tf), &end_preedit);
9329 	  if (end_preedit) {
9330 	    _XmTextFieldDrawInsertionPoint(tf, True);
9331 	    return;
9332 	  }
9333 	}
9334 	else {
9335           replace_res = _XmTextFieldReplaceTextForPreedit(tf, startPos,
9336                                              endPos, mb,
9337                                              strlen(mb), True);
9338     	  PreeditSetCursorPosition(tf, PreCursor(tf));
9339 	}
9340 
9341     } else {
9342         if (call_data->text) {
9343         if (!call_data->text->encoding_is_wchar){
9344             wc = (wchar_t*)XtMalloc((unsigned)(insert_length+1) *
9345                                              sizeof(wchar_t));
9346             mbstowcs( wc, call_data->text->string.multi_byte,
9347                                                         insert_length);
9348         } else
9349         {
9350             wc = (wchar_t*)XtMalloc((unsigned)(insert_length+1) *
9351                                              sizeof(wchar_t));
9352             wcscpy(wc, call_data->text->string.wide_char);
9353         }
9354         wc[insert_length] = (wchar_t) '\0';
9355         }
9356 
9357         if (tf->text.overstrike && rest_len){
9358             wc = (wchar_t *)XtRealloc((char *)wc,
9359                         (insert_length+rest_len+1)*sizeof(wchar_t));
9360             wcscat(wc, over_wc);
9361             XtFree((char *)over_wc);
9362         }
9363 
9364         if (tf->text.overstrike && recover_len > 0) {
9365            wc = (wchar_t *)XtRealloc((char *)wc,
9366                        wcslen(wc)+(recover_len+1)*sizeof(wchar_t));
9367            ptr = XtMalloc((tf->text.onthespot->over_len+1)*sizeof(char));
9368            wcstombs(ptr, (wchar_t *)tf->text.onthespot->over_str,
9369                             tf->text.onthespot->over_len);
9370            ptr[tf->text.onthespot->over_len] = '\0';
9371 
9372            for (i=0; i < tf->text.onthespot->over_maxlen; i++) {
9373                ptr += mblen(ptr, 4);
9374            }
9375 
9376            recover_wc = (wchar_t*) XtMalloc((unsigned)(recover_len+1) *
9377                                                        sizeof(wchar_t));
9378            mbstowcs(recover_wc, ptr, recover_len);
9379            i = wcslen(wc);
9380            wcsncat(wc, recover_wc, recover_len);
9381            wc[i+recover_len] = (wchar_t) '\0';
9382            XtFree((char *) recover_wc);
9383            if (ptr)
9384               XtFree(ptr);
9385         }
9386 
9387 	if (need_verify) {
9388           PreeditVerifyReplace(tf, startPos, endPos, (char *)wc,
9389 				wcslen(wc), PreCursor(tf), &end_preedit);
9390           if (end_preedit) {
9391 	    _XmTextFieldDrawInsertionPoint(tf, True);
9392 	    return;
9393 	  }
9394         }
9395         else {
9396           replace_res = _XmTextFieldReplaceTextForPreedit(tf, startPos,
9397                                              endPos, (char *)wc,
9398                                              wcslen(wc), True);
9399           PreeditSetCursorPosition(tf, PreCursor(tf));
9400         }
9401     }
9402 
9403     if (insert_length > 0)
9404        PreeditSetRendition(w, call_data);
9405 
9406     _XmTextFieldDrawInsertionPoint(tf, True);
9407 
9408     if (mb)
9409        XtFree(mb);
9410     if (wc)
9411        XtFree((char *) wc);
9412 }
9413 
9414 /*
9415  * This is the function set to XNPreeditCaretCallback resource.
9416  * This function is called when the input server requests XmTextField to move
9417  * the caret.
9418  */
9419 static void
9420 PreeditCaret(XIC xic,
9421              XPointer client_data,
9422              XIMPreeditCaretCallbackStruct *call_data)
9423 {
9424     XmTextPosition new_position;
9425     XmTextFieldWidget tf = (XmTextFieldWidget)client_data;
9426     Widget p = (Widget) tf;
9427     Boolean need_verify;
9428 
9429     if (!TextF_Editable(tf))
9430         return;
9431 
9432     while (!XtIsShell(p))
9433 	p = XtParent(p);
9434     XtVaGetValues(p, XmNverifyPreedit, &need_verify, NULL);
9435 
9436     _XmTextFieldDrawInsertionPoint(tf, False);
9437     switch (call_data->direction) {
9438         case XIMForwardChar:
9439           new_position = PreCursor(tf) + 1 - PreStart(tf);
9440           break;
9441         case XIMBackwardChar:
9442           new_position = PreCursor(tf) - 1 - PreStart(tf);
9443           break;
9444         case XIMAbsolutePosition:
9445           new_position = (XmTextPosition) call_data->position;
9446           break;
9447         default:
9448           new_position = PreCursor(tf) - PreStart(tf);
9449     }
9450 
9451     TextF_CursorPosition(tf) = PreCursor(tf) = PreStart(tf) + new_position;
9452     if (need_verify) {
9453 	FUnderVerifyPreedit(tf) = True;
9454 	_XmTextFieldSetCursorPosition(tf, NULL, PreCursor(tf), False, True);
9455 	FUnderVerifyPreedit(tf) = False;
9456     } else
9457     	PreeditSetCursorPosition(tf, TextF_CursorPosition(tf));
9458     _XmTextFieldDrawInsertionPoint(tf, True);
9459 }
9460 
9461 /*
9462  * 1. Call XmImMbResetIC to reset the input method and get the current
9463  *    preedit string.
9464  * 2. Set the string to XmTextField
9465  */
9466 static void
9467 TextFieldResetIC(Widget w)
9468 {
9469     int insert_length, escapement, num_chars;
9470     char *mb, *str=NULL;
9471     Boolean replace_res;
9472     wchar_t *wc_insert_string;
9473     XRectangle overall_ink;
9474     XmTextPosition cursorPos, nextPos;
9475     XmTextFieldWidget tf = (XmTextFieldWidget)w;
9476 
9477     if (!(tf->text.onthespot->under_preedit))
9478         return;
9479 
9480     if (FVerifyCommitNeeded(tf)) {
9481 	FVerifyCommitNeeded(tf) = False;
9482 	str = XtMalloc((PreEnd(tf) - PreStart(tf)+1)*sizeof(wchar_t));
9483 	if (tf->text.max_char_size == 1) {
9484 	  bcopy(&tf->text.value[PreStart(tf)], str,
9485 				PreEnd(tf) - PreStart(tf));
9486 	  str[PreEnd(tf) - PreStart(tf)] = '\0';
9487 	}
9488 	else {
9489 	  int num_bytes;
9490 	  wchar_t *wc_string;
9491 	  wc_string = (wchar_t *)XtMalloc((PreEnd(tf) - PreStart(tf)+1)
9492                                                         *sizeof(wchar_t));
9493           bcopy((char *)&tf->text.wc_value[PreStart(tf)], (char *)wc_string,
9494                                 (PreEnd(tf) - PreStart(tf))*sizeof(wchar_t));
9495           wc_string[PreEnd(tf) - PreStart(tf)] = (wchar_t)'\0';
9496 	  num_bytes = wcstombs(str, wc_string,
9497 				(PreEnd(tf) - PreStart(tf)+1)*sizeof(wchar_t));
9498 	  str[num_bytes] = '\0';
9499 	  XtFree((char *)wc_string);
9500 	}
9501 	XmImMbResetIC(w, &mb);
9502 	mb = str;
9503     }
9504     else
9505     	XmImMbResetIC(w, &mb);
9506 
9507     if (!mb) {
9508         ResetUnder(tf);
9509         return;
9510     }
9511 
9512     if (!TextF_Editable(tf)) {
9513         if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
9514     }
9515 
9516     if ((insert_length = strlen(mb)) > TEXT_MAX_INSERT_SIZE) {
9517         ResetUnder(tf);
9518         return;
9519     }
9520 
9521     if (insert_length > 0) {
9522         if (TextF_UseFontSet(tf)){
9523             escapement = XmbTextExtents((XFontSet)TextF_Font(tf), mb,
9524                         insert_length, &overall_ink, NULL );
9525             if ( escapement == 0 && overall_ink.width == 0 ) {
9526                 ResetUnder(tf);
9527                 return;
9528 	    }
9529 #ifdef USE_XFT
9530         } else if (TextF_UseXft(tf)) {
9531           XGlyphInfo	ext;
9532 
9533           XftTextExtentsUtf8(XtDisplay((Widget)tf), TextF_XftFont(tf),
9534 	      (FcChar8*)mb, insert_length, &ext);
9535 
9536           if (!ext.xOff) {
9537               ResetUnder(tf);
9538 	      return;
9539 	  }
9540 #endif
9541         } else {
9542             if (!XTextWidth(TextF_Font(tf), mb, insert_length)) {
9543                 ResetUnder(tf);
9544                 return;
9545 	    }
9546         }
9547    }
9548 
9549     cursorPos = nextPos = TextF_CursorPosition(tf);
9550 
9551     if (tf->text.overstrike) {
9552         if (nextPos != tf->text.string_length) nextPos++;
9553     }
9554     if (tf->text.max_char_size == 1) {
9555         replace_res = _XmTextFieldReplaceText(tf, NULL, cursorPos,
9556                                              nextPos, mb,
9557                                              insert_length, True);
9558     } else {
9559         mb[insert_length] = '\0';
9560         wc_insert_string = (wchar_t*)XtMalloc((unsigned)(insert_length+1) *
9561                                              sizeof(wchar_t));
9562         num_chars = mbstowcs( wc_insert_string, mb, insert_length+1);
9563         replace_res = _XmTextFieldReplaceText(tf, NULL, cursorPos,
9564                 nextPos, (char*) wc_insert_string, num_chars, True);
9565         XtFree((char *)wc_insert_string);
9566     }
9567 
9568     if (replace_res)
9569         _XmTextFieldSetCursorPosition(tf, NULL,
9570                                       TextF_CursorPosition(tf), False, True);
9571     _XmTextFieldDrawInsertionPoint(tf, True);
9572     if (str) XtFree(str);
9573 
9574     ResetUnder(tf);
9575 }
9576 
9577 
9578 static void
9579 ResetUnder(XmTextFieldWidget tf)
9580 {
9581     if (XmImGetXICResetState((Widget)tf) != XIMPreserveState)
9582       tf->text.onthespot->under_preedit = False;
9583 }
9584 
9585 /***********************************<->***************************************
9586 
9587  *                              Public Functions                             *
9588  ***********************************<->***************************************/
9589 
9590 char *
9591 XmTextFieldGetString(Widget w)
9592 {
9593   XmTextFieldWidget tf = (XmTextFieldWidget) w;
9594   char *temp_str;
9595   int ret_val = 0;
9596   _XmWidgetToAppContext(w);
9597 
9598   _XmAppLock(app);
9599   if (tf->text.string_length > 0) {
9600     if (tf->text.max_char_size == 1) {
9601       temp_str = XtNewString(TextF_Value(tf));
9602       _XmAppUnlock(app);
9603       return temp_str;
9604     } else {
9605       temp_str = (char *) XtMalloc((unsigned) tf->text.max_char_size *
9606 				   (tf->text.string_length + 1));
9607       ret_val = wcstombs(temp_str, TextF_WcValue(tf),
9608 			 (tf->text.string_length + 1)*tf->text.max_char_size);
9609       if (ret_val < 0) temp_str[0] = '\0';
9610       _XmAppUnlock(app);
9611       return temp_str;
9612     }
9613   }
9614   else {
9615     _XmAppUnlock(app);
9616     return(XtNewString(""));
9617   }
9618 }
9619 
9620 int
9621 XmTextFieldGetSubstring(Widget widget,
9622 			XmTextPosition start,
9623 			int num_chars,
9624 			int buf_size,
9625 			char *buffer)
9626 {
9627   XmTextFieldWidget tf = (XmTextFieldWidget) widget;
9628   int ret_value = XmCOPY_SUCCEEDED;
9629   int n_bytes = 0;
9630   int wcs_ret = 0;
9631   _XmWidgetToAppContext(widget);
9632 
9633   _XmAppLock(app);
9634   if (tf->text.max_char_size != 1)
9635     n_bytes = _XmTextFieldCountBytes(tf, TextF_WcValue(tf)+start, num_chars);
9636   else
9637     n_bytes = num_chars;
9638 
9639   if (buf_size < n_bytes + 1) {
9640     _XmAppUnlock(app);
9641     return XmCOPY_FAILED;
9642   }
9643 
9644   if (start + num_chars > tf->text.string_length) {
9645     num_chars = (int) (tf->text.string_length - start);
9646     if (tf->text.max_char_size != 1)
9647       n_bytes = _XmTextFieldCountBytes(tf, TextF_WcValue(tf)+start,
9648 				       num_chars);
9649     else
9650       n_bytes = num_chars;
9651     ret_value = XmCOPY_TRUNCATED;
9652   }
9653 
9654   if (num_chars > 0) {
9655     if (tf->text.max_char_size == 1) {
9656       (void)memcpy((void*)buffer, (void*)&TextF_Value(tf)[start], num_chars);
9657     } else {
9658       wcs_ret = wcstombs(buffer, &TextF_WcValue(tf)[start], n_bytes);
9659       if (wcs_ret < 0) n_bytes = 0;
9660     }
9661     buffer[n_bytes] = '\0';
9662   } else
9663     ret_value = XmCOPY_FAILED;
9664 
9665   _XmAppUnlock(app);
9666   return (ret_value);
9667 }
9668 
9669 
9670 wchar_t *
9671 XmTextFieldGetStringWcs(Widget w)
9672 {
9673   XmTextFieldWidget tf = (XmTextFieldWidget) w;
9674   wchar_t *temp_wcs;
9675   int num_wcs = 0;
9676   _XmWidgetToAppContext(w);
9677 
9678   _XmAppLock(app);
9679   if (tf->text.string_length > 0) {
9680     temp_wcs = (wchar_t*) XtMalloc((unsigned) sizeof(wchar_t) *
9681 				   (tf->text.string_length + 1));
9682     if (tf->text.max_char_size != 1) {
9683       (void)memcpy((void*)temp_wcs, (void*)TextF_WcValue(tf),
9684 		   sizeof(wchar_t) * (tf->text.string_length + 1));
9685     } else {
9686       num_wcs = mbstowcs(temp_wcs, TextF_Value(tf),
9687 			 tf->text.string_length + 1);
9688       if (num_wcs < 0) temp_wcs[0] = (wchar_t)0L;
9689     }
9690     _XmAppUnlock(app);
9691     return temp_wcs;
9692   } else {
9693     temp_wcs = (wchar_t*) XtMalloc((unsigned) sizeof(wchar_t));
9694     temp_wcs[0] = (wchar_t)0L; /* put a wchar_t NULL in position 0 */
9695     _XmAppUnlock(app);
9696     return temp_wcs;
9697   }
9698 }
9699 
9700 int
9701 XmTextFieldGetSubstringWcs(Widget widget,
9702 			   XmTextPosition start,
9703 			   int num_chars,
9704 			   int buf_size,
9705 			   wchar_t *buffer)
9706 {
9707   XmTextFieldWidget tf = (XmTextFieldWidget) widget;
9708   int ret_value = XmCOPY_SUCCEEDED;
9709   int num_wcs = 0;
9710   _XmWidgetToAppContext(widget);
9711 
9712   _XmAppLock(app);
9713   if (start + num_chars > tf->text.string_length) {
9714     num_chars = (int) (tf->text.string_length - start);
9715     ret_value = XmCOPY_TRUNCATED;
9716   }
9717 
9718   if (buf_size < num_chars + 1) {
9719     _XmAppUnlock(app);
9720     return XmCOPY_FAILED;
9721   }
9722 
9723   if (num_chars > 0) {
9724     if (tf->text.max_char_size == 1) {
9725       num_wcs = mbstowcs(buffer, &TextF_Value(tf)[start], num_chars);
9726       if (num_wcs < 0) num_chars = 0;
9727     } else {
9728       (void)memcpy((void*)buffer, (void*)&TextF_WcValue(tf)[start],
9729 		   (size_t) num_chars * sizeof(wchar_t));
9730     }
9731     buffer[num_chars] = '\0';
9732   } else if (num_chars == 0) {
9733     buffer[num_chars] = '\0';
9734   } else
9735     ret_value = XmCOPY_FAILED;
9736 
9737   _XmAppUnlock(app);
9738   return (ret_value);
9739 }
9740 
9741 
9742 XmTextPosition
9743 XmTextFieldGetLastPosition(Widget w)
9744 {
9745   XmTextFieldWidget tf = (XmTextFieldWidget) w;
9746   XmTextPosition ret_val;
9747   _XmWidgetToAppContext(w);
9748 
9749   _XmAppLock(app);
9750   ret_val = (tf->text.string_length);
9751   _XmAppUnlock(app);
9752   return ret_val;
9753 }
9754 
9755 void
9756 XmTextFieldSetString(Widget w,
9757 		     char *value)
9758 {
9759   XmTextFieldWidget tf = (XmTextFieldWidget) w;
9760   XmAnyCallbackStruct cb;
9761   XmTextPosition fromPos, toPos, newInsert;
9762   int length;
9763   int free_insert = False;
9764   int ret_val = 0;
9765   char * tmp_ptr;
9766   char * mod_value = NULL;
9767   _XmWidgetToAppContext(w);
9768 
9769   _XmAppLock(app);
9770   TextFieldResetIC(w);
9771   fromPos = 0;
9772 
9773   if (value == NULL) value = "";
9774   toPos = tf->text.string_length;
9775   if (tf->text.max_char_size == 1)
9776       length = strlen(value);
9777   else {
9778       for (length = 0, tmp_ptr = value, ret_val = mblen(tmp_ptr, MB_CUR_MAX);
9779 	   ret_val > 0;
9780 	   ret_val = mblen(tmp_ptr, MB_CUR_MAX)){
9781 	 if (ret_val < 0){
9782 	    length = 0; /* If error, treat the whole string as bad */
9783 	    break;
9784 	 } else {
9785 	    length += ret_val;
9786 	    tmp_ptr += ret_val;
9787 	 }
9788       }
9789     }
9790 
9791   if (XtIsSensitive(w) && tf->text.has_focus)
9792     ChangeBlinkBehavior(tf, False);
9793   _XmTextFieldDrawInsertionPoint(tf, False);
9794 
9795   if (TextF_ModifyVerifyCallback(tf) || TextF_ModifyVerifyCallbackWcs(tf)) {
9796     /* If the function ModifyVerify() returns false then don't
9797      * continue with the action.
9798      */
9799       if (tf->text.max_char_size == 1) {
9800 	  if (!ModifyVerify(tf, NULL, &fromPos, &toPos,
9801 			    &value, &length, &newInsert, &free_insert)) {
9802 	      if (tf->text.verify_bell) XBell(XtDisplay(w), 0);
9803 	      if (free_insert) XtFree(value);
9804 	      _XmAppUnlock(app);
9805 	      return;
9806 	  }
9807       } else {
9808 	  wchar_t * wbuf;
9809 	  wchar_t * orig_wbuf;
9810 	  wbuf = (wchar_t*)XtMalloc((unsigned)
9811 				    ((strlen(value) + 1) * sizeof(wchar_t)));
9812 	  length = mbstowcs(wbuf, value, (size_t)(strlen(value) + 1));
9813 	  if (length < 0) length = 0;
9814 	  orig_wbuf = wbuf; /* save the pointer to free later */
9815 
9816 	  if (!ModifyVerify(tf, NULL, &fromPos, &toPos, (char**)&wbuf,
9817 			    &length, &newInsert, &free_insert)) {
9818 	      if (tf->text.verify_bell) XBell(XtDisplay(w), 0);
9819 	      if (free_insert) XtFree((char*)wbuf);
9820 	      XtFree((char*)orig_wbuf);
9821 	      _XmAppUnlock(app);
9822 	      return;
9823 	  }
9824 	  else {
9825 	      mod_value = XtMalloc((unsigned)
9826 				   ((length + 1) * tf->text.max_char_size));
9827 	      ret_val = wcstombs(mod_value, wbuf, (size_t)
9828 				 ((length + 1) * tf->text.max_char_size));
9829 	      if (free_insert) {
9830 		  XtFree((char*)wbuf);
9831 		  free_insert = False;
9832 	      }
9833 	      XtFree((char*)orig_wbuf);
9834 	      if (ret_val < 0){
9835 		  XtFree(mod_value);
9836 		  length = strlen(value);
9837 	      } else {
9838 		  value = mod_value;
9839 	      }
9840 	  }
9841       }
9842   }
9843 
9844   TextFieldSetHighlight((XmTextFieldWidget) w, 0,
9845 			tf->text.string_length, XmHIGHLIGHT_NORMAL);
9846 
9847   if (tf->text.max_char_size == 1)
9848     XtFree(TextF_Value(tf));
9849   else   /* convert to wchar_t before calling ValidateString */
9850     XtFree((char *)TextF_WcValue(tf));
9851 
9852   ValidateString(tf, value, False);
9853   if(mod_value) XtFree(mod_value);
9854 
9855   tf->text.pending_off = True;
9856 
9857   SetCursorPosition(tf, NULL, 0, True, True, False, DontCare);
9858 
9859   if (TextF_ResizeWidth(tf) && tf->text.do_resize)
9860     AdjustSize(tf);
9861   else {
9862     tf->text.h_offset = TextF_MarginWidth(tf) +
9863       tf->primitive.shadow_thickness +
9864 	tf->primitive.highlight_thickness;
9865     if (!AdjustText(tf, TextF_CursorPosition(tf), False))
9866       RedisplayText(tf, 0, tf->text.string_length);
9867   }
9868 
9869   cb.reason = XmCR_VALUE_CHANGED;
9870   cb.event = NULL;
9871   XtCallCallbackList(w, TextF_ValueChangedCallback(tf), (XtPointer) &cb);
9872 
9873   tf->text.refresh_ibeam_off = True;
9874 
9875   if (XtIsSensitive(w) && tf->text.has_focus)
9876     ChangeBlinkBehavior(tf, True);
9877   _XmTextFieldDrawInsertionPoint(tf, True);
9878   if (free_insert) XtFree(value);
9879   _XmAppUnlock(app);
9880 }
9881 
9882 
9883 void
9884 XmTextFieldSetStringWcs(Widget w,
9885 			wchar_t *wc_value)
9886 {
9887   XmTextFieldWidget tf = (XmTextFieldWidget) w;
9888   char * tmp;
9889   wchar_t *tmp_wc;
9890   int num_chars = 0;
9891   int result;
9892   _XmWidgetToAppContext(w);
9893 
9894   _XmAppLock(app);
9895   TextFieldResetIC(w);
9896   for (num_chars = 0, tmp_wc = wc_value; *tmp_wc != (wchar_t)0L; num_chars++)
9897     tmp_wc++;  /* count number of wchar_t's */
9898 
9899   tmp = XtMalloc((unsigned) (num_chars + 1) * tf->text.max_char_size);
9900   result = wcstombs(tmp, wc_value, (num_chars + 1) * tf->text.max_char_size);
9901 
9902   if (result == (size_t) -1) /* if wcstombs fails, it returns (size_t) -1 */
9903     tmp = "";               /* if invalid data, pass in the empty string */
9904 
9905   XmTextFieldSetString(w, tmp);
9906 
9907   XtFree(tmp);
9908   _XmAppUnlock(app);
9909 }
9910 
9911 
9912 static void
9913 TextFieldReplace(Widget w,
9914 		 XmTextPosition from_pos,
9915 		 XmTextPosition to_pos,
9916 		 char *value,
9917 		 int is_wc)
9918 {
9919   XmTextFieldWidget tf = (XmTextFieldWidget) w;
9920   int save_maxlength = TextF_MaxLength(tf);
9921   Boolean save_editable = TextF_Editable(tf);
9922   Boolean deselected = False;
9923   Boolean rep_result = False;
9924   wchar_t *wc_value = (wchar_t *)value;
9925   int length = 0;
9926   XmAnyCallbackStruct cb;
9927   _XmWidgetToAppContext(w);
9928 
9929   _XmAppLock(app);
9930   if (value == NULL) value = "";
9931 
9932   VerifyBounds(tf, &from_pos, &to_pos);
9933 
9934   if (tf->text.has_primary) {
9935     if ((tf->text.prim_pos_left > from_pos &&
9936 	 tf->text.prim_pos_left < to_pos) ||
9937 	(tf->text.prim_pos_right >from_pos &&
9938 	 tf->text.prim_pos_right < to_pos) ||
9939 	(tf->text.prim_pos_left <= from_pos &&
9940 	 tf->text.prim_pos_right >= to_pos)) {
9941       _XmTextFieldDeselectSelection(w, False,
9942 				    XtLastTimestampProcessed(XtDisplay(w)));
9943       deselected = True;
9944     }
9945   }
9946 
9947   TextF_Editable(tf) = True;
9948   TextF_MaxLength(tf) = INT_MAX;
9949   if (is_wc) {
9950     /* Count the number of wide chars in the array */
9951     for (length = 0; wc_value[length] != (wchar_t)0L; length++)
9952       /*EMPTY*/;
9953     if (tf->text.max_char_size != 1) {
9954       rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos, to_pos,
9955 					 (char*)wc_value, length, False);
9956     } else {  /* need to convert to char* before calling Replace */
9957       value = XtMalloc((unsigned) (length + 1) * tf->text.max_char_size);
9958       length = wcstombs(value, wc_value,
9959 			   (length + 1) * tf->text.max_char_size);
9960       if (length < 0) {        /* if wcstombs fails, it returns -1 */
9961 	value = "";            /* if invalid data, pass in the empty string */
9962 	length = 0;
9963       }
9964       rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos, to_pos,
9965 					   (char*)value, length, False);
9966       XtFree(value);
9967     }
9968   } else {
9969     if (tf->text.max_char_size == 1) {
9970       length = strlen(value);
9971       rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos,
9972 					   to_pos, value, length, False);
9973     } else { /* need to convert to wchar_t* before calling Replace */
9974       wc_value = (wchar_t *) XtMalloc((unsigned) sizeof(wchar_t) *
9975 				      (1 + strlen(value)));
9976       length = mbstowcs(wc_value, value, (unsigned) (strlen(value) + 1));
9977       if (length < 0) {
9978 	wc_value[0] = (wchar_t) 0L;/* if invalid data, pass in empty string */
9979 	length = 0;
9980       }
9981       rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos, to_pos,
9982 					   (char*)wc_value, length, False);
9983       XtFree((char *)wc_value);
9984     }
9985   }
9986   if (from_pos <= TextF_CursorPosition(tf)) {
9987     XmTextPosition cursorPos;
9988     /* Replace will not move us, we still want this to happen */
9989     if (TextF_CursorPosition(tf) < to_pos) {
9990       if (TextF_CursorPosition(tf) - from_pos <= length)
9991 	cursorPos = TextF_CursorPosition(tf);
9992       else
9993 	cursorPos = from_pos + length;
9994     } else {
9995       cursorPos = TextF_CursorPosition(tf) - (to_pos - from_pos) + length;
9996     }
9997     SetCursorPosition(tf, NULL, cursorPos, True, True, False, DontCare);
9998   }
9999   TextF_Editable(tf) = save_editable;
10000   TextF_MaxLength(tf) = save_maxlength;
10001 
10002   /*
10003    * Replace Text utilizes an optimization in deciding which text to redraw;
10004    * in the case that the selection has been changed (as above), this can
10005    * cause part/all of the replaced text to NOT be redrawn.  The following
10006    * AdjustText call ensures that it IS drawn in this case.
10007    */
10008 
10009   if (deselected)
10010     AdjustText(tf, from_pos, True);
10011 
10012   (void) SetDestination(w, TextF_CursorPosition(tf), False,
10013 			XtLastTimestampProcessed(XtDisplay(w)));
10014   if (rep_result) {
10015     cb.reason = XmCR_VALUE_CHANGED;
10016     cb.event = NULL;
10017     XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
10018 		       (XtPointer) &cb);
10019   }
10020   _XmAppUnlock(app);
10021 }
10022 
10023 void
10024 XmTextFieldReplace(Widget w,
10025 		   XmTextPosition from_pos,
10026 		   XmTextPosition to_pos,
10027 		   char *value)
10028 {
10029   _XmWidgetToAppContext(w);
10030 
10031   _XmAppLock(app);
10032   TextFieldReplace(w, from_pos, to_pos, value, False);
10033   _XmAppUnlock(app);
10034 }
10035 
10036 
10037 void
10038 XmTextFieldReplaceWcs(Widget w,
10039 		      XmTextPosition from_pos,
10040 		      XmTextPosition to_pos,
10041 		      wchar_t *wc_value)
10042 {
10043   _XmWidgetToAppContext(w);
10044 
10045   _XmAppLock(app);
10046   TextFieldReplace(w, from_pos, to_pos, (char *)wc_value, True);
10047   _XmAppUnlock(app);
10048 }
10049 
10050 
10051 void
10052 XmTextFieldInsert(Widget w,
10053 		  XmTextPosition position,
10054 		  char *value)
10055 {
10056   _XmWidgetToAppContext(w);
10057 
10058   _XmAppLock(app);
10059   /* XmTextFieldReplace takes care of converting to wchar_t* if needed */
10060   XmTextFieldReplace(w, position, position, value);
10061   _XmAppUnlock(app);
10062 }
10063 
10064 void
10065 XmTextFieldInsertWcs(Widget w,
10066 		     XmTextPosition position,
10067 		     wchar_t *wcstring)
10068 {
10069   _XmWidgetToAppContext(w);
10070 
10071   _XmAppLock(app);
10072   /* XmTextFieldReplaceWcs takes care of converting to wchar_t* if needed */
10073   XmTextFieldReplaceWcs(w, position, position, wcstring);
10074   _XmAppUnlock(app);
10075 }
10076 
10077 void
10078 XmTextFieldSetAddMode(Widget w,
10079 #if NeedWidePrototypes
10080 		      int state)
10081 #else
10082                       Boolean state)
10083 #endif /* NeedWidePrototypes */
10084 {
10085   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10086   _XmWidgetToAppContext(w);
10087 
10088   _XmAppLock(app);
10089   if (tf->text.add_mode == state) {
10090     _XmAppUnlock(app);
10091     return;
10092   }
10093 
10094   _XmTextFieldDrawInsertionPoint(tf, False);
10095   tf->text.add_mode = state;
10096   _XmTextFieldDrawInsertionPoint(tf, True);
10097   _XmAppUnlock(app);
10098 }
10099 
10100 Boolean
10101 XmTextFieldGetAddMode(Widget w)
10102 {
10103   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10104   Boolean ret_val;
10105   _XmWidgetToAppContext(w);
10106 
10107   _XmAppLock(app);
10108   ret_val = tf->text.add_mode;
10109   _XmAppUnlock(app);
10110   return ret_val;
10111 }
10112 
10113 Boolean
10114 XmTextFieldGetEditable(Widget w)
10115 {
10116   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10117   Boolean ret_val;
10118   _XmWidgetToAppContext(w);
10119 
10120   _XmAppLock(app);
10121   ret_val = TextF_Editable(tf);
10122   _XmAppUnlock(app);
10123   return ret_val;
10124 }
10125 
10126 void
10127 XmTextFieldSetEditable(Widget w,
10128 #if NeedWidePrototypes
10129 		       int editable)
10130 #else
10131                        Boolean editable)
10132 #endif /* NeedWidePrototypes */
10133 {
10134   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10135   XPoint xmim_point;
10136   XRectangle xmim_area;
10137   Arg args[11];                 /* To set initial values to input method */
10138   XIMCallback xim_cb[5];        /* on the spot im callbacks */
10139   Cardinal n = 0;
10140   _XmWidgetToAppContext(w);
10141 
10142   _XmAppLock(app);
10143   /* if widget previously wasn't editable, no input method has yet been
10144    * registered.  So, if we're making it editable now, register the IM and
10145    * give the IM the relevent values. */
10146 
10147   if (!TextF_Editable(tf) && editable) {
10148     XmImRegister((Widget)tf, (unsigned int) NULL);
10149 
10150     GetXYFromPos(tf, TextF_CursorPosition(tf), &xmim_point.x,
10151 		 &xmim_point.y);
10152     (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
10153     n = 0;
10154     XtSetArg(args[n], XmNfontList, TextF_FontList(tf)); n++;
10155     XtSetArg(args[n], XmNbackground, tf->core.background_pixel); n++;
10156     XtSetArg(args[n], XmNforeground, tf->primitive.foreground); n++;
10157     XtSetArg(args[n], XmNbackgroundPixmap,tf->core.background_pixmap);n++;
10158     XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
10159     XtSetArg(args[n], XmNarea, &xmim_area); n++;
10160     XtSetArg(args[n], XmNlineSpace,
10161 	     TextF_FontAscent(tf)+ TextF_FontDescent(tf)); n++;
10162 
10163     /*
10164      * On the spot support. Register preedit callbacks.
10165      */
10166     xim_cb[0].client_data = (XPointer)tf;
10167     xim_cb[0].callback = (XIMProc)PreeditStart;
10168     xim_cb[1].client_data = (XPointer)tf;
10169     xim_cb[1].callback = (XIMProc)PreeditDone;
10170     xim_cb[2].client_data = (XPointer)tf;
10171     xim_cb[2].callback = (XIMProc)PreeditDraw;
10172     xim_cb[3].client_data = (XPointer)tf;
10173     xim_cb[3].callback = (XIMProc)PreeditCaret;
10174     XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
10175     XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
10176     XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
10177     XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;
10178 
10179     if (tf->text.has_focus)
10180        XmImSetFocusValues((Widget)tf, args, n);
10181     else
10182        XmImSetValues((Widget)tf, args, n);
10183 
10184   } else if (TextF_Editable(tf) && !editable) {
10185     XmImUnregister(w);
10186   }
10187 
10188   TextF_Editable(tf) = editable;
10189 
10190   n = 0;
10191   if (editable) {
10192     XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_ACTIVE); n++;
10193   } else {
10194     XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_INACTIVE); n++;
10195   }
10196 
10197   XmDropSiteUpdate((Widget)tf, args, n);
10198   _XmAppUnlock(app);
10199 }
10200 
10201 int
10202 XmTextFieldGetMaxLength(Widget w)
10203 {
10204   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10205   int ret_val;
10206   _XmWidgetToAppContext(w);
10207 
10208   _XmAppLock(app);
10209   ret_val = TextF_MaxLength(tf);
10210   _XmAppUnlock(app);
10211   return ret_val;
10212 }
10213 
10214 void
10215 XmTextFieldSetMaxLength(Widget w,
10216 			int max_length)
10217 {
10218   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10219   _XmWidgetToAppContext(w);
10220 
10221   _XmAppLock(app);
10222   TextF_MaxLength(tf) = max_length;
10223   _XmAppUnlock(app);
10224 }
10225 
10226 XmTextPosition
10227 XmTextFieldGetInsertionPosition(Widget w)
10228 {
10229   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10230   XmTextPosition ret_val;
10231   _XmWidgetToAppContext(w);
10232 
10233   _XmAppLock(app);
10234   ret_val = TextF_CursorPosition(tf);
10235   _XmAppUnlock(app);
10236   return ret_val;
10237 }
10238 
10239 void
10240 XmTextFieldSetInsertionPosition(Widget w,
10241 				XmTextPosition position)
10242 {
10243   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10244   _XmWidgetToAppContext(w);
10245 
10246   _XmAppLock(app);
10247   TextFieldResetIC(w);
10248   SetCursorPosition(tf, NULL, position, True, True, False, DontCare);
10249   _XmAppUnlock(app);
10250 }
10251 
10252 Boolean
10253 XmTextFieldGetSelectionPosition(Widget w,
10254 				XmTextPosition *left,
10255 				XmTextPosition *right)
10256 {
10257   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10258   _XmWidgetToAppContext(w);
10259 
10260   _XmAppLock(app);
10261 
10262   if (tf->text.has_primary) {
10263     *left = tf->text.prim_pos_left;
10264     *right = tf->text.prim_pos_right;
10265   }
10266   _XmAppUnlock(app);
10267   return tf->text.has_primary;
10268 }
10269 
10270 char *
10271 XmTextFieldGetSelection(Widget w)
10272 {
10273   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10274   size_t length, num_chars;
10275   char *value;
10276   _XmWidgetToAppContext(w);
10277 
10278   _XmAppLock(app);
10279 
10280   if (tf->text.prim_pos_left == tf->text.prim_pos_right) {
10281     _XmAppUnlock(app);
10282     return NULL;
10283   }
10284   num_chars = (size_t) (tf->text.prim_pos_right - tf->text.prim_pos_left);
10285   length = num_chars;
10286   if (tf->text.max_char_size == 1) {
10287     value = XtMalloc((unsigned) num_chars + 1);
10288     (void) memcpy((void*)value,
10289 		  (void*)(TextF_Value(tf) + tf->text.prim_pos_left),
10290 		  num_chars);
10291   } else {
10292     value = XtMalloc((unsigned) ((num_chars + 1) * tf->text.max_char_size));
10293     length = wcstombs(value, TextF_WcValue(tf) + tf->text.prim_pos_left,
10294 		      (num_chars + 1) * tf->text.max_char_size);
10295     if (length == (size_t) -1) {
10296       length = 0;
10297     } else {
10298       for(length = 0;num_chars > 0; num_chars--)
10299 #ifndef NO_MULTIBYTE
10300 	length += mblen(&value[length], tf->text.max_char_size);
10301 #else
10302         length += value[length] ? 1 : 0;
10303 #endif
10304     }
10305   }
10306   value[length] = (char)'\0';
10307   _XmAppUnlock(app);
10308   return (value);
10309 }
10310 
10311 wchar_t *
10312 XmTextFieldGetSelectionWcs(Widget w)
10313 {
10314   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10315   size_t length;
10316   wchar_t *wc_value;
10317   int return_val = 0;
10318   _XmWidgetToAppContext(w);
10319 
10320   _XmAppLock(app);
10321   if (tf->text.prim_pos_left == tf->text.prim_pos_right)
10322   {
10323     _XmAppUnlock(app);
10324     return NULL;
10325   }
10326   length = (size_t) (tf->text.prim_pos_right - tf->text.prim_pos_left);
10327 
10328   wc_value = (wchar_t*)XtMalloc((unsigned) (length + 1) * sizeof(wchar_t));
10329 
10330   if (tf->text.max_char_size == 1) {
10331     return_val = mbstowcs(wc_value, TextF_Value(tf) + tf->text.prim_pos_left,
10332 			  length);
10333     if (return_val < 0) length = 0;
10334   } else {
10335     (void)memcpy((void*)wc_value,
10336 		 (void*)(TextF_WcValue(tf) + tf->text.prim_pos_left),
10337 		 length * sizeof(wchar_t));
10338   }
10339   wc_value[length] = (wchar_t)0L;
10340   _XmAppUnlock(app);
10341   return (wc_value);
10342 }
10343 
10344 
10345 Boolean
10346 XmTextFieldRemove(Widget w)
10347 {
10348   Boolean ret_val;
10349   _XmWidgetToAppContext(w);
10350 
10351   _XmAppLock(app);
10352   ret_val = TextFieldRemove(w, NULL);
10353   _XmAppUnlock(app);
10354 
10355   return ret_val;
10356 }
10357 
10358 Boolean
10359 XmTextFieldCopy(Widget w,
10360 		Time clip_time)
10361 {
10362   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10363   _XmWidgetToAppContext(w);
10364 
10365   _XmAppLock(app);
10366   /* using the clipboard facilities, copy the selected
10367      text to the clipboard */
10368   if (tf->text.prim_pos_left != tf->text.prim_pos_right)
10369   {
10370     _XmAppUnlock(app);
10371     return XmeClipboardSource(w, XmCOPY, clip_time);
10372   }
10373 
10374   _XmAppUnlock(app);
10375   return False;
10376 }
10377 
10378 Boolean
10379 XmTextFieldCopyLink(Widget w,
10380 		    Time clip_time)
10381 {
10382   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10383   Boolean ret_val;
10384   _XmWidgetToAppContext(w);
10385 
10386   _XmAppLock(app);
10387   if (tf->text.prim_pos_left != tf->text.prim_pos_right)
10388   {
10389     ret_val = XmeClipboardSource(w, XmLINK, clip_time);
10390     _XmAppUnlock(app);
10391     return ret_val;
10392   }
10393 
10394   _XmAppUnlock(app);
10395   return False;
10396 }
10397 
10398 Boolean
10399 XmTextFieldCut(Widget w,
10400 	       Time clip_time)
10401 {
10402   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10403   Boolean ret_val;
10404   _XmWidgetToAppContext(w);
10405 
10406   _XmAppLock(app);
10407 
10408   if (TextF_Editable(tf) == False)
10409   {
10410     _XmAppUnlock(app);
10411     return False;
10412   }
10413 
10414   if (tf->text.prim_pos_left != tf->text.prim_pos_right)
10415   {
10416     ret_val = XmeClipboardSource(w, XmMOVE, clip_time);
10417     _XmAppUnlock(app);
10418     return ret_val;
10419   }
10420 
10421   _XmAppUnlock(app);
10422   return False;
10423 
10424 }
10425 
10426 void
10427 XmTextFieldClearSelection(Widget w,
10428 			  Time sel_time)
10429 {
10430   _XmWidgetToAppContext(w);
10431 
10432   _XmAppLock(app);
10433   _XmTextFieldDeselectSelection(w, False, sel_time);
10434   _XmAppUnlock(app);
10435 }
10436 
10437 void
10438 XmTextFieldSetSelection(Widget w,
10439 			XmTextPosition first,
10440 			XmTextPosition last,
10441 			Time sel_time)
10442 {
10443   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10444   _XmWidgetToAppContext(w);
10445 
10446   _XmAppLock(app);
10447   TextFieldResetIC(w);
10448   tf->text.take_primary = True;
10449   _XmTextFieldStartSelection(tf, first, last, sel_time);
10450   tf->text.pending_off = False;
10451   SetCursorPosition(tf, NULL, last, True, True, False, DontCare);
10452   _XmAppUnlock(app);
10453 }
10454 
10455 /* ARGSUSED */
10456 XmTextPosition
10457 XmTextFieldXYToPos(Widget w,
10458 #if NeedWidePrototypes
10459 		   int x,
10460 		   int y)
10461 #else
10462                    Position x,
10463                    Position y)
10464 #endif /* NeedWidePrototypes */
10465 {
10466   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10467   XmTextPosition ret_val;
10468   _XmWidgetToAppContext(w);
10469 
10470   _XmAppLock(app);
10471   ret_val = GetPosFromX(tf, x);
10472   _XmAppUnlock(app);
10473   return (ret_val);
10474 }
10475 
10476 Boolean
10477 XmTextFieldPosToXY(Widget w,
10478 		   XmTextPosition position,
10479 		   Position *x,
10480 		   Position *y)
10481 {
10482   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10483   Boolean ret_val;
10484   _XmWidgetToAppContext(w);
10485 
10486   _XmAppLock(app);
10487   ret_val = GetXYFromPos(tf, position, x, y);
10488   _XmAppUnlock(app);
10489   return (ret_val);
10490 }
10491 
10492 
10493 /*
10494  * Force the given position to be displayed.  If position is out of bounds,
10495  * then don't force any position to be displayed.
10496  */
10497 void
10498 XmTextFieldShowPosition(Widget w,
10499 			XmTextPosition position)
10500 {
10501   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10502   _XmWidgetToAppContext(w);
10503 
10504   _XmAppLock(app);
10505   if ( (position < 0) || (position > tf->text.string_length) ) {
10506 	_XmAppUnlock(app);
10507 	return;
10508   }
10509 
10510   AdjustText(tf, position, True);
10511   _XmAppUnlock(app);
10512 }
10513 
10514 /* ARGSUSED */
10515 void
10516 XmTextFieldSetHighlight(Widget w,
10517 			XmTextPosition left,
10518 			XmTextPosition right,
10519 			XmHighlightMode mode)
10520 {
10521   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10522   _XmWidgetToAppContext(w);
10523 
10524   _XmAppLock(app);
10525   doSetHighlight(w, left, right, mode);
10526   tf->text.programmatic_highlights = True;
10527   _XmAppUnlock(app);
10528 }
10529 
10530 static Boolean
10531 TrimHighlights(XmTextFieldWidget tf, int *low, int *high)
10532 {
10533  	/*
10534  	** We have a situation in which the programmer has called
10535  	** XmTextFieldSetHighlight and the user is now interacting with the
10536  	** text, which has the possible effect of mis-inserting and doing all
10537  	** sorts of nasty stuff, mostly because this widget assumes that such
10538  	** settings are ephemeral and last only as long as user interaction.
10539  	** As programmer-defined highlights are assumed to be reasonable only
10540  	** for e.g. non-editable text areas, reset them.
10541  	*/
10542 
10543 	Boolean changed = False;
10544  	Boolean justChanged = False;
10545  	_XmHighlightRec *l = tf->text.highlight.list;
10546  	int i;
10547 
10548  	for (i=0; i < tf->text.highlight.number; i++)
10549  	{
10550  		/* iterate through list, resetting spurious back to normal;
10551  		** unfortunately, we can have has_primary even when there is
10552  		** no primary selection anymore, so check pending-deleteness
10553  		*/
10554  		if (justChanged)
10555  			*high = l[i].position;
10556  		if (((XmHIGHLIGHT_SECONDARY_SELECTED == l[i].mode) && !tf->text.has_secondary)
10557  		  ||((XmHIGHLIGHT_SELECTED == l[i].mode) && !NeedsPendingDelete(tf)))
10558  			{
10559  			l[i].mode = XmHIGHLIGHT_NORMAL;
10560  			if (!changed)
10561  				*low = l[i].position;
10562  			changed = True;
10563  			justChanged = True;
10564  			}
10565  		else
10566  			justChanged = False;
10567  	}
10568  	if (justChanged)
10569  		*high = tf->text.string_length;
10570 
10571  	if (changed)
10572  	{
10573   	  int j;
10574  	  /* coalescing blocks; reduce number only */
10575  	  i = 1;
10576  	  while (i < tf->text.highlight.number) {
10577  	    if (l[i].mode == l[i-1].mode) {
10578  	      tf->text.highlight.number--;
10579  	      for (j=i; j<tf->text.highlight.number; j++)
10580  		l[j] = l[j+1];
10581  	    } else i++;
10582  	  }
10583  	}
10584 
10585  	return changed;
10586 }
10587 
10588 /* ARGSUSED */
10589 static void
10590 doSetHighlight(Widget w, XmTextPosition left, XmTextPosition right,
10591 			XmHighlightMode mode)
10592 {
10593   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10594 
10595   /* If right position is out-bound, change it to the last position. */
10596   if (right > tf->text.string_length)
10597     right = tf->text.string_length;
10598 
10599   /* If left is out-bound, don't do anything. */
10600   if (left >= right || right <= 0) {
10601      return;
10602   }
10603 
10604   if (left < 0) left = 0;
10605 
10606   TextFieldSetHighlight(tf, left, right, mode);
10607 
10608   RedisplayText(tf, left, right);
10609 }
10610 
10611 int
10612 XmTextFieldGetBaseline(Widget w)
10613 {
10614   XmTextFieldWidget tf = (XmTextFieldWidget) w;
10615   Dimension margin_top;
10616   int ret_val;
10617   _XmWidgetToAppContext(w);
10618 
10619   _XmAppLock(app);
10620   margin_top = tf->text.margin_top +
10621     tf->primitive.shadow_thickness +
10622       tf->primitive.highlight_thickness;
10623 
10624   ret_val = (int) margin_top + (int) TextF_FontAscent(tf);
10625   _XmAppUnlock(app);
10626 
10627   return(ret_val);
10628 }
10629 /*
10630  * Function:
10631  *    XmCreateTextField()
10632  *    XmVaCreateTextField()
10633  *    XmVaCreateManagedTextField()
10634  *
10635  *  Description:
10636  *      Basic creation routines for the motif TextField Widget Class.
10637  */
10638 
10639 Widget
10640 XmCreateTextField(Widget parent,
10641 		  char *name,
10642 		  ArgList arglist,
10643 		  Cardinal argcount)
10644 {
10645   return (XtCreateWidget(name, xmTextFieldWidgetClass,
10646 			 parent, arglist, argcount));
10647 }
10648 
10649 Widget
10650 XmVaCreateTextField(
10651         Widget parent,
10652         char *name,
10653         ...)
10654 {
10655     register Widget w;
10656     va_list var;
10657     int count;
10658 
10659     Va_start(var,name);
10660     count = XmeCountVaListSimple(var);
10661     va_end(var);
10662 
10663 
10664     Va_start(var, name);
10665     w = XmeVLCreateWidget(name,
10666                          xmTextFieldWidgetClass,
10667                          parent, False,
10668                          var, count);
10669     va_end(var);
10670     return w;
10671 
10672 }
10673 
10674 Widget
10675 XmVaCreateManagedTextField(
10676         Widget parent,
10677         char *name,
10678         ...)
10679 {
10680     Widget w = NULL;
10681     va_list var;
10682     int count;
10683 
10684     Va_start(var, name);
10685     count = XmeCountVaListSimple(var);
10686     va_end(var);
10687 
10688     Va_start(var, name);
10689     w = XmeVLCreateWidget(name,
10690                          xmTextFieldWidgetClass,
10691                          parent, True,
10692                          var, count);
10693     va_end(var);
10694     return w;
10695 
10696 }
10697