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