1 /*
2  * Motif Tools Library, Version 3.1
3  * $Id: InputField.c,v 1.3 2001/07/20 23:07:49 grmcdorman Exp $
4  *
5  * Written by David Flanagan.
6  * Copyright (c) 1992-2001 by David Flanagan.
7  * All Rights Reserved.  See the file COPYRIGHT for details.
8  * This is open source software.  See the file LICENSE for details.
9  * There is no warranty for this software.  See NO_WARRANTY for details.
10  *
11  * $Log: InputField.c,v $
12  * Revision 1.3  2001/07/20 23:07:49  grmcdorman
13  * This change provides two optional Motif/NuTCracker bug workarounds.
14  * Defines in Xmt.tmpl (normally commented out) turn them on.
15  *
16  * Revision 1.2  2001/04/15 15:29:36  grmcdorman
17  *   * XmtCallCallback has two new arguments types: XmtRCallbackUserData, which
18  *     is the XmNuserData value, and XmtRCallbackImmediate, which is a value
19  *     embedded in the list.
20  *
21  *   * Two new functions, XmtCreateQueryListChildren and XmtCreateQueryListChild,
22  *     are provided. They are like the XmtCreate* functions except that they
23  *     return a list of the widgets created (quark and pointer to the widget).
24  *
25  *   * Major enhancements to XmtInputField:
26  *     - The input field now has a cancel() action. This reverts the field's
27  *       value to that prior to the start of editing (i.e. the last commit).
28  *       No default translation is bound to this action, however.
29  *     - There is a callback for the cancel action (XmtNcancelCallback).
30  *     - The input field can be set to cancel, commit, or do nothing on focus
31  *       out. (Previously, it always did a commit). The default is commit.
32  *       (XmtNfocusOutAction)
33  *
34  *   * XmtLayout:
35  *     - It now has a losingFocusCallback (XmNloosingFocusCallback).
36  *     - It, and the layout widgets (XmtLayoutBox/XmtLayoutString), now
37  *       support background pixmaps.
38  *     - It now supports XmNresizePolicy.
39  *     - Strings in the layout parser are converted to XmStrings by
40  *       XtConvertAndStore, so any custom XmString conversion is used
41  *       (as, for example, the Xmt convert, which supports the @[]
42  *       embedded items)
43  *
44  *   * Other:
45  *     - Pixmaps are convered using XtConvertAndStore, again to allow
46  *       custom converters.
47  *
48  * Bug Fixes: (for Solaris 2.5.1/Motif 1.2/Sparc system)
49  *   * XmtInputField did not work properly if the widget had traversalOn
50  *     false.
51  *   * XmtLayout's child geometry manager was called by Xt when
52  *     a shell child was added to the layout; it did not handle
53  *     this case.
54  *   * XmtLayout had an XmtWarningMsg call with a missing argument (line 2029).
55  *   * Widgets automatically created by XmtLayout parsing have been given
56  *     non-blank names. [You may wish to tweak this by adding, for example,
57  *     a leading underscore.]
58  *   * Under some circumstances, XmtNameToWidget could be called during
59  *     widget creation, with 'w->core.num_popups' uninitialized. The
60  *     workaround applied is to ignore the popup list if the 'num_popups'
61  *     value is more than 50 or negative.
62  *
63  * Revision 1.1.1.1  2001/02/10 13:44:32  motiftools
64  * Initial import of Xmt310 to CVS
65  *
66  *
67  */
68 
69 #include <stdio.h>
70 #include <ctype.h>
71 #include <string.h>
72 #include <Xmt/XmtP.h>
73 #include <Xmt/InputFieldP.h>
74 #include <Xmt/WidgetType.h>
75 #include <Xmt/Layout.h> /* for XmtNlayoutSensitive resource */
76 #include <Xmt/QuarksP.h>
77 
78 #ifdef DISABLE_INPUTFIELD_DRAGDROP
79 #include <Xm/DragDrop.h>
80 #endif
81 
82 #ifndef X_NOT_STDC_ENV
83 #include <stdlib.h>
84 #else
85 extern int atoi();
86 extern double atof();
87 #endif
88 
89 /*
90  * I don't know how MAXINT is getting defined on most platforms, (I
91  * don't know where <values.h> is included), but it isn't defined in
92  * Linux.  It might be better to include <limits.h> and switch to
93  * INT_MAX, since this is the POSIX way to do it.  But then I'd have
94  * to take care of non-POSIX platforms as a special case.  So this fix
95  * is easier.  Platforms with 64-bit integers that don't define MAXINT
96  * will just have to live with this 32-bit definition.  This won't be
97  * a problem for its use in this file.
98  */
99 #ifndef MAXINT
100 #define MAXINT 0x7FFFFFFF
101 #endif
102 
103 #define offset(field) XtOffsetOf(XmtInputFieldRec, input_field.field)
104 
105 static XtResource resources[] = {
106 {XmtNinput, XmtCInput, XtRString,
107      sizeof(String), offset(input),
108      XtRString, (XtPointer)NULL},
109 {XmtNpattern, XmtCPattern, XtRString,
110      sizeof(String), offset(pattern),
111      XtRString, (XtPointer)NULL},
112 {XmtNmatchAll, XmtCMatchAll, XtRBoolean,
113      sizeof(Boolean), offset(match_all),
114      XtRImmediate, (XtPointer)True},
115 {XmtNoverstrike, XmtCOverstrike, XtRBoolean,
116      sizeof(Boolean), offset(overstrike),
117      XtRBoolean, (XtPointer) False},
118 {XmtNbufferSymbolName, XmtCBufferSymbolName, XtRString,
119      sizeof(String), offset(buffer_symbol_name),
120      XtRString, (XtPointer)NULL},
121 {XmtNtargetSymbolName, XmtCTargetSymbolName, XtRString,
122      sizeof(String), offset(target_symbol_name),
123      XtRString, (XtPointer)NULL},
124 {XmtNautoInsert, XmtCAutoInsert, XtRBoolean,
125      sizeof(Boolean), offset(auto_insert),
126      XtRImmediate, (XtPointer)True},
127 {XmtNautoDelete, XmtCAutoDelete, XtRBoolean,
128      sizeof(Boolean), offset(auto_delete),
129      XtRImmediate, (XtPointer)True},
130 {XmtNbeepOnError, XmtCBeepOnError, XtRBoolean,
131      sizeof(Boolean), offset(beep_on_error),
132      XtRImmediate, (XtPointer) True},
133 {XmtNreplaceOnError, XmtCReplaceOnError, XtRBoolean,
134      sizeof(Boolean), offset(replace_on_error),
135      XtRImmediate, (XtPointer) True},
136 {XmtNhighlightOnError, XmtCHighlightOnError, XtRBoolean,
137      sizeof(Boolean), offset(highlight_on_error),
138      XtRImmediate, (XtPointer) False},
139 {XmtNerrorString, XmtCErrorString, XtRString,
140      sizeof(String), offset(error_string),
141      XtRString, (XtPointer) NULL},
142 {XmtNerrorForeground, XmtCErrorForeground, XtRPixel,
143      sizeof(String), offset(error_foreground),
144      XtRImmediate, (XtPointer) -1},  /* XXX could be a valid Pixel value */
145 {XmtNerrorBackground, XmtCErrorBackground, XtRPixel,
146      sizeof(String), offset(error_background),
147      XtRImmediate, (XtPointer) -1},  /* XXX could be a valid Pixel value */
148 {XmtNinputCallback, XtCCallback, XtRCallback,
149      sizeof(XtCallbackList), offset(input_callback),
150      XtRCallback, (XtPointer) NULL},
151 {XmtNverifyCallback, XtCCallback, XtRCallback,
152      sizeof(XtCallbackList), offset(verify_callback),
153      XtRCallback, (XtPointer) NULL},
154 {XmtNerrorCallback, XtCCallback, XtRCallback,
155      sizeof(XtCallbackList), offset(error_callback),
156      XtRCallback, (XtPointer) NULL},
157 {XmtNcancelCallback, XtCCallback, XtRCallback,
158      sizeof(XtCallbackList), offset(cancel_callback),
159      XtRCallback, (XtPointer) NULL},
160 {XmtNfocusOutAction, XmtCFocusOutAction, XmtRXmtInputFieldActions,
161      sizeof(int), offset(focus_out_action),
162      XtRImmediate, (XtPointer) XmtINPUT_COMMIT},
163 /*
164  * override navigationType here so arrow-key traversal will work
165  */
166 {XmNnavigationType, XmCNavigationType, XmRNavigationType,
167      sizeof(unsigned char),
168      XtOffsetOf(XmtInputFieldRec, primitive.navigation_type),
169      XtRImmediate, (XtPointer) XmNONE},
170 };
171 #undef offset
172 
173 /* widget methods */
174 #if NeedFunctionPrototypes
175 static void ClassInitialize(void);
176 static void Initialize(Widget, Widget, ArgList, Cardinal *);
177 static void Destroy(Widget);
178 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
179 #else
180 static void ClassInitialize();
181 static void Initialize();
182 static void Destroy();
183 static Boolean SetValues();
184 #endif
185 
186 /* action procedure */
187 #if NeedFunctionPrototypes
188 static void Overstrike(Widget, XEvent *, String *, Cardinal *);
189 static void Cancel(Widget, XEvent *, String *, Cardinal *);
190 static void GrabFocus(Widget, XEvent *, String *, Cardinal *);
191 #else
192 static void Overstrike();
193 static void Cancel();
194 static void GrabFocus();
195 #endif
196 
197 static XtActionsRec actions[] = {
198   {"overstrike", Overstrike},
199   {"cancel", Cancel},
200   {"grab-focus", GrabFocus},    /* same as XmText action */
201 };
202 
203 #if XmVersion > 1001
204 static XmPrimitiveClassExtRec primClassExtRec = {
205     NULL,
206     NULLQUARK,
207     XmPrimitiveClassExtVersion,
208     sizeof(XmPrimitiveClassExtRec),
209     XmInheritBaselineProc,                  /* widget_baseline */
210     XmInheritDisplayRectProc,               /* widget_display_rect */
211 /*    (XmWidgetMarginsProc) _XtInherit */
212     _XmTextMarginsProc  /* this isn't inherited properly */
213 };
214 #endif
215 
216 #define Superclass (&xmTextClassRec)
217 
218 externaldef(xmtinputfieldclassrec)
219 XmtInputFieldClassRec xmtInputFieldClassRec = {
220   { /* core_class fields */
221     /* superclass         */    (WidgetClass) Superclass,
222     /* class_name         */    "XmtInputField",
223     /* widget_size        */    sizeof(XmtInputFieldRec),
224     /* class_initialize   */    ClassInitialize,
225     /* class_part_init    */    NULL,
226     /* class_inited       */    FALSE,
227     /* initialize         */    Initialize,
228     /* initialize_hook    */    NULL,
229     /* realize            */    XtInheritRealize,
230     /* actions            */    actions,
231     /* num_actions        */    XtNumber(actions),
232     /* resources          */    resources,
233     /* num_resources      */    XtNumber(resources),
234     /* xrm_class          */    NULLQUARK,
235     /* compress_motion    */    TRUE,
236     /* compress_exposure  */    XtExposeCompressMaximal,
237     /* compress_enterleave*/    TRUE,
238     /* visible_interest   */    FALSE,
239     /* destroy            */    Destroy,
240     /* resize             */    XtInheritResize,
241     /* expose             */    XtInheritExpose,
242     /* set_values         */    SetValues,
243     /* set_values_hook    */    NULL,
244     /* set_values_almost  */    XtInheritSetValuesAlmost,
245     /* get_values_hook    */    NULL,
246     /* accept_focus       */    XtInheritAcceptFocus,
247     /* version            */    XtVersion,
248     /* callback_private   */    NULL,
249     /* tm_table           */    XtInheritTranslations,
250     /* query_geometry     */    XtInheritQueryGeometry,
251     /* display_accelerator*/    XtInheritDisplayAccelerator,
252     /* extension	  */	NULL,
253   },
254    {				/* primitive_class fields 	*/
255       XmInheritBorderHighlight, /* Primitive border_highlight   */
256       XmInheritBorderUnhighlight,/* Primitive border_unhighlight */
257       NULL,	                /* translations                 */
258       NULL,         		/* arm_and_activate           	*/
259       NULL,  	    	        /* get resources 	        */
260       0, 	                /* num get_resources            */
261 #if XmVersion <= 1001
262       NULL,         		/* extension                    */
263 #else
264       (XtPointer)&primClassExtRec,/* extension                    */
265 #endif
266    },
267    {				/* text class fields */
268       NULL,             	/* extension         */
269    },
270    { /* XmtInputField      */
271      /* superclassGrabFocus*/    NULL,
272      /* extension	   */    NULL
273    }
274 };
275 
276 externaldef(xmtinputfieldwidgetclass)
277 WidgetClass xmtInputFieldWidgetClass = (WidgetClass)&xmtInputFieldClassRec;
278 
279 #if XmVersion != 1002
280 #define SetString XmTextSetString
281 #else
282 #if NeedFunctionPrototypes
SetString(Widget w,String s)283 static void SetString(Widget w, String s)
284 #else
285 static void SetString(w, s)
286 Widget w;
287 String s;
288 #endif
289 {
290     Boolean hack;
291     XmtInputFieldWidget iw = (XmtInputFieldWidget) w;
292 
293     if (s && s[0]) XmTextSetString(w,s);
294     else {
295 	hack = iw->text.auto_show_cursor_position;
296 	iw->text.auto_show_cursor_position = False;
297 	XmTextSetString(w,s);
298 	iw->text.auto_show_cursor_position = hack;
299     }
300 }
301 #endif
302 
303 
304 /* ARGSUSED */
305 #if NeedFunctionPrototypes
HandleOverstrike(Widget text,XtPointer tag,XtPointer call_data)306 static void HandleOverstrike(Widget text, XtPointer tag, XtPointer call_data)
307 #else
308 static void HandleOverstrike(text, tag, call_data)
309 Widget text;
310 XtPointer tag;
311 XtPointer call_data;
312 #endif
313 {
314     XmtInputFieldWidget iw = (XmtInputFieldWidget) text;
315     XmTextVerifyCallbackStruct *data = (XmTextVerifyCallbackStruct*) call_data;
316 
317     /* if this is not a user keystroke, don't check it */
318     if (!data->event) return;
319 
320     /* if this is a deletion, do nothing */
321     /* Different versions of Motif indicate deletions in different ways,
322      * so check several fields */
323     if ((data->text->length == 0) ||
324 	(data->text->ptr == NULL) || (data->text->ptr[0] == '\0')) return;
325 
326     /*
327      * turn an insertion into a replace.
328      * HandlePattern() also does this for us, in case it is called
329      * after this callback and changes increase the insertion length
330      */
331     data->endPos = data->startPos+data->text->length;
332 
333     /*
334      * We can't have overstrike on and the text XmNmaxLength set, because the
335      * text won't allow us to type a character when we're at maxLength, because
336      * it assumes we'll be inserting it.  So when overstrike is on, we
337      * don't set maxLength, and instead check the length here.
338      */
339     if (data->endPos > iw->input_field.max_length)
340 	data->doit = False;
341 }
342 
343 /* ARGSUSED */
344 #if NeedFunctionPrototype
MoveCursorTimerProc(XtPointer data,XtIntervalId * id)345 static void MoveCursorTimerProc(XtPointer data, XtIntervalId *id)
346 #else
347 static void MoveCursorTimerProc(data, id)
348 XtPointer data;
349 XtIntervalId *id;
350 #endif
351 {
352     XmtInputFieldWidget iw = (XmtInputFieldWidget)data;
353 
354     if (iw->input_field.pattern_skip != 0) {
355 	XmTextSetInsertionPosition((Widget)iw,
356 				   XmTextGetInsertionPosition((Widget)iw) +
357 				   iw->input_field.pattern_skip);
358 	iw->input_field.pattern_skip = 0;
359     }
360 }
361 
362 /* ARGSUSED */
363 #if NeedFunctionPrototypes
isoctal(int c)364 static int isoctal(int c)
365 #else
366 static int isoctal(c)
367 int c;
368 #endif
369 {
370 
371     return (int)(strchr ("01234567", c));
372 }
373 
374 /* ARGSUSED */
375 #if NeedFunctionPrototypes
ishex(int c)376 static int ishex(int c)
377 #else
378 static int ishex(c)
379 int c;
380 #endif
381 {
382     return (int)(strchr ("0123456789abcdefABCDEF", c));
383 }
384 
385 /* ARGSUSED */
386 #if NeedFunctionPrototypes
HandlePattern(Widget text,XtPointer tag,XtPointer call_data)387 static void HandlePattern(Widget text, XtPointer tag, XtPointer call_data)
388 #else
389 static void HandlePattern(text, tag, call_data)
390 Widget text;
391 XtPointer tag;
392 XtPointer call_data;
393 #endif
394 {
395     XmtInputFieldWidget iw = (XmtInputFieldWidget) text;
396     XmTextVerifyCallbackStruct *data = (XmTextVerifyCallbackStruct*) call_data;
397     int i, j, pos, last;
398     char *c;
399 
400     /* if this is not a user keystroke, don't check it */
401     if (!data->event) return;
402 
403     last = XmTextGetLastPosition(text);
404 
405     /* if it is a deletion, only allow it at the end.
406      * Also, if autoDelete adjust startPos to point to a non-constant char
407      */
408     /* Different versions of Motif indicate deletions in different ways,
409      * so check several fields */
410     if ((data->text->length == 0) ||
411 	(data->text->ptr == NULL) || (data->text->ptr[0] == '\0')) {
412 	if (data->endPos != last) {
413 	    data->doit = False;
414 #ifdef BACKSPACEBUG
415 	    data->text->ptr = NULL;
416 #endif
417 	    return;
418 	}
419 	if (iw->input_field.auto_delete)
420 	    for(c = &iw->input_field.pattern[data->startPos];
421 		data->startPos > 0;
422 		data->startPos--, c--) {
423 		if (((*c >= 'a')&&(*c <= 'd')) ||
424 		    ((*c >= 'A')&&(*c <= 'C')) ||
425 		    (*c == 'h') ||
426 		    (*c == 'o'))
427 		    break;
428 	    }
429 	return;
430     }
431 
432     /* otherwise it is an insertion, or if in overstrike mode, a replace.
433      * if not in overstrike mode, only allow it at the end.
434      * Also, if it would put us past the end of the pattern, reject
435      */
436     if ((!iw->input_field.overstrike) && (data->startPos != last)) {
437 	data->doit = False;
438 	return;
439     }
440 
441     if (data->startPos + data->text->length >
442 	iw->input_field.pattern_length) {
443 	data->doit = False;
444 	return;
445     }
446 
447     iw->input_field.pattern_skip = 0;  /* # of const. chars inserted */
448 
449     /* test each character of the insertion */
450     for(i=0, pos=data->startPos;
451 	i < data->text->length;
452 	i++, pos++) {
453 	c = &data->text->ptr[i];
454 	switch(iw->input_field.pattern[pos]) {
455 	case 'A':
456 	    *c = toupper(*c);
457 	case 'a':
458 	    if (!isalpha(*c)) data->doit = False;
459 	    break;
460 	case 'B':
461 	    *c = toupper(*c);
462 	case 'b':
463 	    if (!isalpha(*c) && !isdigit(*c)) data->doit = False;
464 	    break;
465 	case 'C':
466 	    *c = toupper(*c);
467 	case 'c':
468 	    break;
469 	case 'd':
470 	    if (!isdigit(*c)) data->doit = False;
471 	    break;
472         case 'o':
473 	  if (!isoctal(*c)) data->doit = False;
474 	  break;
475         case 'h':
476 	  if (!ishex(*c)) data->doit = False;
477           break;
478 	default:
479 	    /*
480 	     * it is a constant character.  If *c matches, accept it.
481 	     * Otherwise, if autoInsert, insert it, otherwise reject.
482 	     */
483 	    if (*c == iw->input_field.pattern[pos]) break;
484 	    if (!iw->input_field.auto_insert) {
485 		data->doit = False;
486 		break;
487 	    }
488 	    data->text->length++;
489 	    data->text->ptr = XtRealloc(data->text->ptr,
490 					data->text->length);
491 	    for(j=data->text->length-1; j > i; j--)
492 		data->text->ptr[j] = data->text->ptr[j-1];
493 	    data->text->ptr[i] = iw->input_field.pattern[pos];
494 	    iw->input_field.pattern_skip++;
495 	    break;
496 	}
497 	if (data->doit == False) return;
498     }
499 
500     if (iw->input_field.pattern_skip)
501 	XtAppAddTimeOut(XtWidgetToApplicationContext(text),
502 			0, MoveCursorTimerProc, (XtPointer)iw);
503 
504     /* if we are overstriking and this is a replace, we've got to
505      * increase the deleted characters by the # of inserted constant chars
506      * The right thing will happen whether HandleOverstrike is called
507      * first or this procedure is called first.
508      */
509     if (iw->input_field.overstrike)
510 	data->endPos = data->startPos + data->text->length;
511 }
512 
513 /* ARGSUSED */
514 #if NeedFunctionPrototypes
ValueChanged(Widget text,XtPointer tag,XtPointer data)515 static void ValueChanged(Widget text, XtPointer tag, XtPointer data)
516 #else
517 static void ValueChanged(text, tag, data)
518 Widget text;
519 XtPointer tag;
520 XtPointer data;
521 #endif
522 {
523     XmtInputFieldWidget iw = (XmtInputFieldWidget) text;
524 
525     /* remember that the value has changed */
526     iw->input_field.input_changed = True;
527 
528     /* and remove ourselves for efficiency */
529     XtRemoveCallback(text, XmNvalueChangedCallback, ValueChanged, NULL);
530 }
531 
532 #if NeedFunctionPrototypes
RestoreOldValue(XmtInputFieldWidget iw)533 static void RestoreOldValue(XmtInputFieldWidget iw)
534 #else
535 static void RestoreOldValue(iw)
536 XmtInputFieldWidget iw;
537 #endif
538 {
539     SetString((Widget)iw, iw->input_field.input);
540     XmTextSetInsertionPosition((Widget)iw, XmTextGetLastPosition((Widget)iw));
541     iw->input_field.input_changed = False;
542     XtAddCallback((Widget)iw, XmNvalueChangedCallback, ValueChanged, NULL);
543 }
544 
545 /* ARGSUSED */
546 #if NeedFunctionPrototypes
UndoError(Widget text,XtPointer tag,XtPointer data)547 static void UndoError(Widget text, XtPointer tag, XtPointer data)
548 #else
549 static void UndoError(text, tag, data)
550 Widget text;
551 XtPointer tag;
552 XtPointer data;
553 #endif
554 {
555     XmtInputFieldWidget iw = (XmtInputFieldWidget) text;
556 
557     /*
558      * if not handling an error, don't do anything.
559      * This should never happen.
560      */
561     if (!iw->input_field.error_state) return;
562 
563     /* remove this callback everywhere it was registered */
564     XtRemoveCallback(text, XmNvalueChangedCallback, UndoError, NULL);
565     XtRemoveCallback(text, XmNfocusCallback, UndoError, NULL);
566     XtRemoveCallback(text, XmNactivateCallback, UndoError, NULL);
567 
568     /* if we are currently displaying an error string, change it, either
569      * to the last value, or back to the bad value
570      */
571     if (iw->input_field.error_string) {
572 	if (iw->input_field.replace_on_error) {
573 	    RestoreOldValue(iw);
574 	}
575        	else {
576 	    SetString(text, iw->input_field.error_value);
577 	    XmTextSetInsertionPosition(text, XmTextGetLastPosition(text));
578 	    XtFree(iw->input_field.error_value);
579 	}
580     }
581     else if (iw->input_field.highlight_on_error) {
582 	/* if a color specified, and color display, restore old color */
583 	if (((iw->input_field.error_background != (Pixel)-1) ||
584 	     (iw->input_field.error_foreground != (Pixel)-1)) &&
585 	    (iw->core.depth > 1)) {
586 	    Arg al[2];
587 	    int ac = 0;
588 	    if (iw->input_field.error_background != (Pixel)-1) {
589 		XtSetArg(al[ac],XmNbackground,iw->input_field.background);
590 		ac++;
591 	    }
592 	    if (iw->input_field.error_foreground != (Pixel)-1) {
593 		XtSetArg(al[ac],XmNforeground,iw->input_field.foreground);
594 		ac++;
595 	    }
596 	    XtSetValues(text, al, ac);
597 	}
598 	else {  /* remove the underlining */
599 	    XmTextSetHighlight(text, 0,XmTextGetLastPosition(text),
600 			       XmHIGHLIGHT_NORMAL);
601 	}
602 	/* if replaceOnError, restore old string */
603 	if (iw->input_field.replace_on_error)
604 	    RestoreOldValue(iw);
605     }
606 
607     iw->input_field.error_state = False;
608 }
609 
610 #if NeedFunctionPrototypes
HandleError(XmtInputFieldWidget iw,String value)611 static void HandleError(XmtInputFieldWidget iw, String value)
612 #else
613 static void HandleError(iw, value)
614 XmtInputFieldWidget iw;
615 String value;
616 #endif
617 {
618     XmtInputFieldCallbackStruct error;
619 
620     /*
621      * if we're already handling an error, don't do anything.
622      */
623     if (iw->input_field.error_state) return;
624 
625     /*
626      * call the error callback to give app programmer the chance to handle
627      * the error.  If requested, abort further error handling
628      */
629     error.input = value;
630     error.okay = False;
631     XtCallCallbackList((Widget)iw, iw->input_field.error_callback,
632 		       (XtPointer) &error);
633     if (error.okay == True) return;
634 
635     /* beep if requested */
636     if (iw->input_field.beep_on_error)
637 	XBell(XtDisplay(iw), 0);
638 
639     if (iw->input_field.error_string) {
640 	/*
641 	 * We'll display the error string, but first, we've got to save a
642 	 * copy of the current bad string, unless we're going to replace that
643 	 * string with the current value resource.
644 	 * See UndoError() above.
645 	 */
646 	if (!iw->input_field.replace_on_error)
647 	    iw->input_field.error_value =
648 		XmTextGetString((Widget)iw);
649 	SetString((Widget)iw, iw->input_field.error_string);
650 	XmTextSetInsertionPosition((Widget)iw,
651 				   XmTextGetLastPosition((Widget)iw));
652     }
653     else if (iw->input_field.highlight_on_error) {
654 	/* use color if a color is specified, and if a color display */
655 	if (((iw->input_field.error_background != (Pixel)-1) ||
656 	     (iw->input_field.error_foreground != (Pixel)-1)) &&
657 	    (iw->core.depth > 1)) {
658 	    Arg al[2];
659 	    int ac = 0;
660 	    if (iw->input_field.error_background != (Pixel)-1) {
661 		iw->input_field.background = iw->core.background_pixel;
662 		XtSetArg(al[ac],XmNbackground,
663 			 iw->input_field.error_background);
664 		ac++;
665 	    }
666 	    if (iw->input_field.error_foreground != (Pixel)-1) {
667 		iw->input_field.foreground = iw->primitive.foreground;
668 		XtSetArg(al[ac],XmNforeground,
669 			 iw->input_field.error_foreground);
670 		ac++;
671 	    }
672 	    XtSetValues((Widget)iw, al, ac);
673 	}
674 	else {  /* just underline the text */
675 	    XmTextSetHighlight((Widget)iw, 0,XmTextGetLastPosition((Widget)iw),
676 			       XmHIGHLIGHT_SECONDARY_SELECTED);
677 	}
678     }
679     else if (iw->input_field.replace_on_error) {
680 	/*
681 	 * if no error string or highlighting, restore old value now.
682 	 * otherwise, we restore it in UndoError() above.
683 	 */
684 	RestoreOldValue(iw);
685     }
686 
687     /*
688      * add callbacks to undo the effects of this error handling
689      * on focus in or any keypress.  Note that if the error handling is
690      * just replace_on_error, there is nothing to undo.
691      * Set the error_state flag.
692      */
693     if (iw->input_field.error_string || iw->input_field.highlight_on_error) {
694 	XtAddCallback((Widget)iw, XmNvalueChangedCallback, UndoError, NULL);
695 	XtAddCallback((Widget)iw, XmNfocusCallback, UndoError, NULL);
696 	XtAddCallback((Widget)iw, XmNactivateCallback, UndoError, NULL);
697 	iw->input_field.error_state = True;
698 
699     }
700 }
701 
702 #if NeedFunctionPrototypes
SetValueOnSymbols(XmtInputFieldWidget iw,StringConst value,Boolean check)703 static Boolean SetValueOnSymbols(XmtInputFieldWidget iw, StringConst value,
704 				 Boolean check)
705 #else
706 static Boolean SetValueOnSymbols(iw, value, check)
707 XmtInputFieldWidget iw;
708 StringConst value;
709 Boolean check;
710 #endif
711 {
712     Boolean status = True;
713 
714     /*
715      * set the buffer and target symbols from the value resource.
716      * This will cause the buffer symbol callback to be invoked, so we
717      * set a flag which will make that callback a no-op.
718      * If check is true, then we don't set the buffer symbol if
719      * the target symbol conversion failed.
720      */
721     if (value == NULL) value = "";
722     if (iw->input_field.target_symbol)
723 	status = XmtSymbolSetTypedValue((Widget) iw,
724 					iw->input_field.target_symbol,
725 					XtRString, (XtArgVal) value,
726 					strlen(value)+1);
727 
728     if ((!check || status) && iw->input_field.buffer_symbol) {
729 	iw->input_field.ignore_symbol_notify = True;
730 	XmtSymbolSetValue(iw->input_field.buffer_symbol, (XtArgVal)value);
731 	iw->input_field.ignore_symbol_notify = False;
732     }
733 
734     return status;
735 }
736 
737 #if NeedFunctionPrototypes
SetValueFromSymbol(XmtInputFieldWidget iw)738 static void SetValueFromSymbol(XmtInputFieldWidget iw)
739 #else
740 static void SetValueFromSymbol(iw)
741 XmtInputFieldWidget iw;
742 #endif
743 {
744     String symbol_value;
745 
746     /*
747      * set the value resource from the buffer_symbol
748      */
749     if (iw->input_field.buffer_symbol) {
750 	XmtSymbolGetValue(iw->input_field.buffer_symbol,
751 			  (XtArgVal *) &symbol_value);
752         if (iw->input_field.input) XtFree(iw->input_field.input);
753 	iw->input_field.input = XtNewString(symbol_value);
754     }
755 }
756 
757 /* ARGSUSED */
758 #if NeedFunctionPrototypes
SymbolValueChanged(XmtSymbol s,XtPointer tag,XtArgVal value)759 static void SymbolValueChanged(XmtSymbol s, XtPointer tag, XtArgVal value)
760 #else
761 static void SymbolValueChanged(s, tag, value)
762 XmtSymbol s;
763 XtPointer tag;
764 XtArgVal value;
765 #endif
766 {
767     XmtInputFieldWidget iw = (XmtInputFieldWidget)tag;
768 
769     /*
770      * the notify callback invoked when the value in the buffer symbol
771      * changes underneath us.  Update the value resource, the display,
772      * and the target symbol.  If this procedure is called as a side
773      * effect fo SetValueOnSymbols(), then we do nothing.
774      */
775     if (iw->input_field.ignore_symbol_notify) return;
776 
777     /* set the value resource, and the text widget displayed value */
778     SetValueFromSymbol(iw);
779     SetString((Widget)iw, iw->input_field.input);
780 
781     /* set the target symbol value */
782     if (iw->input_field.target_symbol)
783 	XmtSymbolSetTypedValue((Widget) iw, iw->input_field.target_symbol,
784 			       XtRString, (XtArgVal) iw->input_field.input,
785 			       strlen(iw->input_field.input)+1);
786 }
787 
788 
789 /* ARGSUSED */
790 #if NeedFunctionPrototypes
Activate(Widget text,XtPointer tag,XtPointer data)791 static void Activate(Widget text, XtPointer tag, XtPointer data)
792 #else
793 static void Activate(text, tag, data)
794 Widget text;
795 XtPointer tag;
796 XtPointer data;
797 #endif
798 {
799     XmtInputFieldWidget iw = (XmtInputFieldWidget) text;
800     XmtInputFieldCallbackStruct verify;
801     String input;
802     int input_length;
803     Boolean status;
804 
805     /* if we're handling an error, don't activate */
806     if (iw->input_field.error_state) return;
807 
808     /* if nothing has changed since the last time, don't do anything */
809     if (!iw->input_field.input_changed) return;
810 
811     /* get the current input */
812     input = XmTextGetString(text);
813     input_length = strlen(input);
814 
815     /* check that input matches all of the pattern error if not */
816     if (iw->input_field.pattern && iw->input_field.match_all &&
817 	(input_length != iw->input_field.pattern_length))
818 	goto error;
819 
820     /* call the verify callback; error if it fails.
821      * The programmer may replace input, but should not free or realloc it.
822      * Programmer owns any string used to replace the input.
823      */
824     verify.input = input;
825     verify.okay = True;
826     XtCallCallbackList((Widget)iw, iw->input_field.verify_callback,
827 		       (XtPointer)&verify);
828     if (verify.okay == False) goto error;
829     if (verify.input != input) {
830 	XtFree(input);
831 	input = XtNewString(verify.input);
832 	input_length = strlen(input);
833 	SetString(text, input);
834 	XmTextSetInsertionPosition(text, XmTextGetLastPosition(text));
835     }
836 
837     /* put the new input into buffer, and target, if specified */
838     status = SetValueOnSymbols(iw, input, True);
839 
840     if (status == False) goto error;
841 
842     /* re-register the value changed callback */
843     iw->input_field.input_changed = False;
844     XtAddCallback(text, XmNvalueChangedCallback, ValueChanged, NULL);
845 
846     /* update the input resource */
847     XtFree(iw->input_field.input);
848     iw->input_field.input = input;
849 
850     /* invoke the input field input callback */
851     XtCallCallbackList((Widget)iw, iw->input_field.input_callback,
852 		       input);
853     return;
854 
855  error:
856     HandleError(iw, input);
857     XtFree(input);
858 }
859 
860 
861 /* ARGSUSED */
862 #if NeedFunctionPrototypes
handleFocusOut(Widget text,XtPointer tag,XtPointer data)863 static void handleFocusOut(Widget text, XtPointer tag, XtPointer data)
864 #else
865 static void handleFocusOut(text, tag, data)
866 Widget text;
867 XtPointer tag;
868 XtPointer data;
869 #endif
870 {
871     XmtInputFieldWidget iw = (XmtInputFieldWidget) text;
872 
873     /*
874      * Turn off traversal if applicable.
875      */
876     if (iw->input_field.notTraversable) {
877         XtVaSetValues(text, XmNtraversalOn, False, NULL);
878     }
879 
880     switch (iw->input_field.focus_out_action) {
881      default:   /* default is Activate */
882      case XmtINPUT_COMMIT:
883 	Activate(text, tag, data);
884 	break;
885      case XmtINPUT_CANCEL:
886 	Cancel(text, NULL, NULL, 0);
887 	break;
888      case XmtINPUT_NONE:
889 	break;
890     }
891 }
892 
893 
894 #if NeedFunctionPrototypes
BindBufferSymbol(XmtInputFieldWidget iw)895 static void BindBufferSymbol(XmtInputFieldWidget iw)
896 #else
897 static void BindBufferSymbol(iw)
898 XmtInputFieldWidget iw;
899 #endif
900 {
901     if (iw->input_field.buffer_symbol_name) {
902 	iw->input_field.buffer_symbol =
903 	    XmtLookupSymbol(iw->input_field.buffer_symbol_name);
904 	if (iw->input_field.buffer_symbol) {
905 	    if (strcmp(XmtSymbolType(iw->input_field.buffer_symbol),
906 		       XmtRBuffer) != 0) {
907 		XmtWarningMsg("XmtInputField", "symbolType",
908 			      "%s: buffer symbol '%s' has wrong type;\n\tshould be XmtRBuffer.",
909 			      XtName((Widget)iw),
910 			      iw->input_field.buffer_symbol_name);
911 		iw->input_field.buffer_symbol = NULL;
912 	    }
913 	    else {
914 		/* a defined symbol of the right type */
915 		XmtSymbolAddCallback(iw->input_field.buffer_symbol,
916 				     SymbolValueChanged, (XtPointer)iw);
917 	    }
918 	}
919 	else {
920 	    XmtWarningMsg("XmtInputField", "badBSymbol",
921 			  "%s: buffer symbol '%s' is undefined.",
922 			  XtName((Widget)iw),
923 			  iw->input_field.buffer_symbol_name);
924 	}
925     }
926     else
927 	iw->input_field.buffer_symbol = NULL;
928 }
929 
930 #if NeedFunctionPrototypes
ReleaseBufferSymbol(XmtInputFieldWidget iw)931 static void ReleaseBufferSymbol(XmtInputFieldWidget iw)
932 #else
933 static void ReleaseBufferSymbol(iw)
934 XmtInputFieldWidget iw;
935 #endif
936 {
937     if (iw->input_field.buffer_symbol) {
938 	XmtSymbolRemoveCallback(iw->input_field.buffer_symbol,
939 				SymbolValueChanged, (XtPointer)iw);
940 	iw->input_field.buffer_symbol = NULL;
941     }
942 }
943 
944 #if NeedFunctionPrototypes
BindTargetSymbol(XmtInputFieldWidget iw)945 static void BindTargetSymbol(XmtInputFieldWidget iw)
946 #else
947 static void BindTargetSymbol(iw)
948 XmtInputFieldWidget iw;
949 #endif
950 {
951     if (iw->input_field.target_symbol_name) {
952 	iw->input_field.target_symbol =
953 	    XmtLookupSymbol(iw->input_field.target_symbol_name);
954 	if (!iw->input_field.target_symbol)
955 	    XmtWarningMsg("XmtInputField", "badTSymbol",
956 			  "%s: target symbol '%s' is undefined.",
957 			  XtName((Widget)iw),
958 			  iw->input_field.target_symbol_name);
959     }
960     else
961 	iw->input_field.target_symbol = NULL;
962 }
963 
964 #if NeedFunctionPrototypes
ReleaseTargetSymbol(XmtInputFieldWidget iw)965 static void ReleaseTargetSymbol(XmtInputFieldWidget iw)
966 #else
967 static void ReleaseTargetSymbol(iw)
968 XmtInputFieldWidget iw;
969 #endif
970 {
971     if (iw->input_field.target_symbol)
972 	iw->input_field.target_symbol = NULL;
973 }
974 
975 /* ARGSUSED */
976 #if NeedFunctionPrototypes
Overstrike(Widget w,XEvent * e,String * args,Cardinal * num)977 static void Overstrike(Widget w, XEvent * e, String *args, Cardinal *num)
978 #else
979 static void Overstrike(w, e, args, num)
980 Widget w;
981 XEvent *e;
982 String *args;
983 Cardinal *num;
984 #endif
985 {
986     XmtInputFieldWidget iw = (XmtInputFieldWidget)w;
987     Boolean overstrike;
988 
989     if (*num == 1) {
990 	if (args[0][1] == 'n') /* "On" */
991 	    overstrike = True;
992 	else
993 	    overstrike = False;
994     }
995     else
996 	overstrike = !iw->input_field.overstrike;
997 
998     XtVaSetValues(w, XmtNoverstrike, overstrike, NULL);
999 }
1000 
1001 
1002 /*
1003  * About to do a grab-focus(). If the text widget is not traversable but is
1004  * editable, turn on traversal (until focus is lost).
1005  */
1006 /* ARGSUSED */
1007 #if NeedFunctionPrototypes
GrabFocus(Widget text,XEvent * e,String * args,Cardinal * num)1008 static void GrabFocus(Widget text, XEvent * e, String *args, Cardinal *num)
1009 #else
1010 static void GrabFocus(text, e, args, num)
1011 Widget text;
1012 XEvent *e;
1013 String *args;
1014 Cardinal *num;
1015 #endif
1016 {
1017     XmtInputFieldWidget iw = (XmtInputFieldWidget) text;
1018 
1019     /*
1020      * If the widget is not traversable, make it so for the duration
1021      * (until focus out).
1022      */
1023     if (iw->input_field.notTraversable && iw->text.editable) {
1024         XtVaSetValues(text, XmNtraversalOn, True, NULL);
1025         iw->input_field.notTraversable = 1; /* changed by SetValues */
1026     }
1027     /*
1028      * Invoke our superclass' grab-focus.
1029      */
1030     if (xmtInputFieldClassRec.input_field_class.superclassGrabFocus != NULL)
1031       xmtInputFieldClassRec.input_field_class.superclassGrabFocus(text, e, args, num);
1032 }
1033 
1034 /* ARGSUSED */
1035 #if NeedFunctionPrototypes
Cancel(Widget w,XEvent * e,String * args,Cardinal * num)1036 static void Cancel(Widget w, XEvent * e, String *args, Cardinal *num)
1037 #else
1038 static void Cancel(w, e, args, num)
1039 Widget w;
1040 XEvent *e;
1041 String *args;
1042 Cardinal *num;
1043 #endif
1044 {
1045     XmtInputFieldWidget iw = (XmtInputFieldWidget)w;
1046     XmtInputFieldCallbackStruct cancel;
1047     char * input;
1048 
1049     /* if we're handling an error, don't activate */
1050     if (iw->input_field.error_state) return;
1051 
1052     /* if nothing has changed since the last time, don't do anything */
1053     if (!iw->input_field.input_changed) return;
1054 
1055     input = XmTextGetString(w);
1056 
1057     cancel.input = input;
1058     cancel.okay = False;
1059     XtCallCallbackList((Widget)iw, iw->input_field.cancel_callback,
1060 		       (XtPointer) &cancel);
1061     XtFree(input);
1062     if (cancel.okay == True) return;
1063 
1064     RestoreOldValue(iw);
1065 }
1066 
1067 
1068 #if NeedFunctionPrototypes
ClassInitialize(void)1069 static void ClassInitialize(void)
1070 #else
1071 static void ClassInitialize()
1072 #endif
1073 {
1074     static String names[] = {
1075 	  "CANCEL",
1076 	  "COMMIT",
1077 	  "Cancel",
1078 	  "Commit",
1079 	  "NONE",
1080 	  "None",
1081 	  "cancel",
1082 	  "commit",
1083 	  "none"
1084     };
1085     static int values[] = {
1086 	  XmtINPUT_CANCEL,
1087 	  XmtINPUT_COMMIT,
1088 	  XmtINPUT_CANCEL,
1089 	  XmtINPUT_COMMIT,
1090 	  XmtINPUT_NONE,
1091 	  XmtINPUT_NONE,
1092 	  XmtINPUT_CANCEL,
1093 	  XmtINPUT_COMMIT,
1094 	  XmtINPUT_NONE
1095     };
1096     static String prefixes[] = { "Xmt", "INPUT_", "Input_", "input_", NULL };
1097 
1098     XtActionList      list;
1099     Cardinal          count;
1100     int               i;
1101 
1102     XmtRegisterStringListConverter();
1103     XmtRegisterEnumConverter(XmtRXmtInputFieldActions, names, values,
1104 			     XtNumber(names), prefixes);
1105 
1106     /*
1107      * Find GrabFocus in parent.
1108      */
1109     XtGetActionList((WidgetClass) Superclass,
1110                     &list, &count);
1111     for (i = 0; i < count; i++) {
1112         if (strcmp(list[i].string, "grab-focus") == 0) {
1113             xmtInputFieldClassRec.input_field_class.superclassGrabFocus = list[i].proc;
1114         }
1115     }
1116 
1117 }
1118 
1119 
1120 /* ARGSUSED */
1121 #if NeedFunctionPrototypes
Initialize(Widget request,Widget init,ArgList arglist,Cardinal * num_args)1122 static void Initialize(Widget request, Widget init,
1123 		       ArgList arglist, Cardinal *num_args)
1124 #else
1125 static void Initialize(request, init, arglist, num_args)
1126 Widget request;
1127 Widget init;
1128 ArgList arglist;
1129 Cardinal *num_args;
1130 #endif
1131 {
1132     XmtInputFieldWidget iw = (XmtInputFieldWidget) init;
1133 #ifdef DISABLE_INPUTFIELD_DRAGDROP
1134     Arg args[1];
1135     int n;
1136 #endif
1137 
1138     /*
1139      * copy the symbol names, and bind the symbols, if defined
1140      */
1141     if (iw->input_field.buffer_symbol_name)
1142 	iw->input_field.buffer_symbol_name =
1143 	    XtNewString(iw->input_field.buffer_symbol_name);
1144     BindBufferSymbol(iw);
1145     if (iw->input_field.target_symbol_name)
1146 	iw->input_field.target_symbol_name =
1147 	    XtNewString(iw->input_field.target_symbol_name);
1148     BindTargetSymbol(iw);
1149 
1150     /*
1151      * figure out the initial value.
1152      * if value is specified, copy it.
1153      * also, store it in buffer and target if those are specified.
1154      * otherwise, buffer contains the initial value, and we make
1155      * a copy of it for the value resource.  In this case target is not set.
1156      */
1157     if (iw->input_field.input) {
1158 	iw->input_field.input = XtNewString(iw->input_field.input);
1159 	(void)SetValueOnSymbols(iw, iw->input_field.input, False);
1160     }
1161     else if (iw->input_field.buffer_symbol)
1162 	SetValueFromSymbol(iw);
1163 
1164 
1165     /* if there is a pattern, get its length */
1166     if (iw->input_field.pattern)
1167 	iw->input_field.pattern_length = strlen(iw->input_field.pattern);
1168     else
1169 	iw->input_field.pattern_length = 0;
1170 
1171     /*
1172      * figure out the maximum length of the input string.  This value can
1173      * come from 3 sources:
1174      *   the XmNmaxLength resource
1175      *   the length of the pattern resource
1176      *   the size of the buffer.
1177      */
1178     if (iw->text.max_length != MAXINT)
1179 	iw->input_field.max_length = iw->text.max_length;
1180     else if (iw->input_field.pattern)
1181 	iw->input_field.max_length = iw->input_field.pattern_length;
1182     else if (iw->input_field.buffer_symbol)
1183 	iw->input_field.max_length =
1184 	    XmtSymbolSize(iw->input_field.buffer_symbol);
1185     else
1186 	iw->input_field.max_length = MAXINT;
1187 
1188     XmTextSetMaxLength(init, iw->input_field.overstrike?MAXINT:
1189 		       iw->input_field.max_length);
1190 
1191     /*
1192      * if we're insensitve, set layoutSensitive, in case we're a child
1193      * of a layout and have a caption
1194      */
1195     if (!iw->core.sensitive || !iw->core.ancestor_sensitive)
1196 	XtVaSetValues(init, XmtNlayoutSensitive, False, NULL);
1197 
1198     /* set initial value, if any */
1199     if (iw->input_field.input)
1200 	SetString(init, iw->input_field.input);
1201 
1202     XtAddCallback(init, XmNactivateCallback, Activate, NULL);
1203     XtAddCallback(init, XmNlosingFocusCallback, handleFocusOut, NULL);
1204     XtAddCallback(init, XmNvalueChangedCallback, ValueChanged, NULL);
1205 
1206     /* if we're in overstrike mode, add the callback */
1207     if (iw->input_field.overstrike)
1208 	XtAddCallback(init, XmNmodifyVerifyCallback, HandleOverstrike, NULL);
1209 
1210     /* if there's a pattern, add the callbacks to handle it */
1211     if (iw->input_field.pattern) {
1212 	XtAddCallback(init, XmNmodifyVerifyCallback, HandlePattern, NULL);
1213     }
1214 
1215     /*
1216      * initialize private fields that need it
1217      */
1218     iw->input_field.input_changed = False;
1219     iw->input_field.pattern_skip = 0;
1220     iw->input_field.error_state = False;
1221     iw->input_field.ignore_symbol_notify = False;
1222     iw->input_field.notTraversable = !iw->primitive.traversal_on;
1223 
1224 #ifdef NUTCRACKER_BUG_WORKAROUND
1225     iw->input_field.sensitive_background = iw->core.background_pixel;
1226 #endif
1227 
1228 #ifdef DISABLE_INPUTFIELD_DRAGDROP
1229     n = 0;
1230     XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_INACTIVE); n++;
1231     XmDropSiteUpdate((Widget) iw, args, n);
1232 #endif
1233 }
1234 
1235 
1236 #if NeedFunctionPrototypes
Destroy(Widget w)1237 static void Destroy(Widget w)
1238 #else
1239 static void Destroy(w)
1240 Widget w;
1241 #endif
1242 {
1243     XmtInputFieldWidget iw = (XmtInputFieldWidget) w;
1244 
1245     XtFree(iw->input_field.input);
1246     XtFree(iw->input_field.pattern);
1247 
1248     /* release the symbols, if bound, and free the symbol names */
1249     if (iw->input_field.buffer_symbol_name) {
1250 	ReleaseBufferSymbol(iw);
1251 	XtFree(iw->input_field.buffer_symbol_name);
1252     }
1253     if (iw->input_field.target_symbol_name) {
1254 	ReleaseTargetSymbol(iw);
1255 	XtFree(iw->input_field.target_symbol_name);
1256     }
1257 }
1258 
1259 /* ARGSUSED */
1260 #if NeedFunctionPrototypes
SetValues(Widget current,Widget request,Widget set,ArgList arglist,Cardinal * num_args)1261 static Boolean SetValues(Widget current, Widget request, Widget set,
1262 			 ArgList arglist, Cardinal *num_args)
1263 #else
1264 static Boolean SetValues(current, request, set, arglist, num_args)
1265 Widget current;
1266 Widget request;
1267 Widget set;
1268 ArgList arglist;
1269 Cardinal *num_args;
1270 #endif
1271 {
1272     XmtInputFieldWidget cw = (XmtInputFieldWidget) current;
1273     XmtInputFieldWidget rw = (XmtInputFieldWidget) request;
1274     XmtInputFieldWidget sw = (XmtInputFieldWidget) set;
1275 
1276 #define Current(field) (cw->input_field.field)
1277 #define Request(field) (rw->input_field.field)
1278 #define Set(field) (sw->input_field.field)
1279 #define Changed(field) (rw->input_field.field != cw->input_field.field)
1280 
1281     /*
1282      * handle changes to the buffer or target symbol names
1283      */
1284     if (Changed(buffer_symbol_name)) {
1285 	/* XXX do something with the new value in the symbol? */
1286 	if (Current(buffer_symbol_name)) {
1287 	    XtFree(Current(buffer_symbol_name));
1288 	    ReleaseBufferSymbol(cw);
1289 	}
1290 	if (Set(buffer_symbol_name)) {
1291 	    Set(buffer_symbol_name) = XtNewString(Set(buffer_symbol_name));
1292 	    BindBufferSymbol(sw);
1293 	}
1294     }
1295     if (Changed(target_symbol_name)) {
1296 	if (Current(target_symbol_name)) {
1297 	    XtFree(Current(target_symbol_name));
1298 	    ReleaseTargetSymbol(cw);
1299 	}
1300 	if (Set(target_symbol_name)) {
1301 	    Set(target_symbol_name) = XtNewString(Set(target_symbol_name));
1302 	    BindTargetSymbol(sw);
1303 	}
1304     }
1305 
1306     /*
1307      * if the value resource changes, copy the new value, set it on the
1308      * text widget, and copy it to the buffer, and target, if any.  Note
1309      * that we do not call the verifyCallback, nor do we handle errors.
1310      * Note that changing value updates the buffer, but changing the buffer
1311      * does not change the value.
1312      */
1313     if (Changed(input)) {
1314 	XtFree(Current(input));
1315 	if (Set(input))
1316 	    Set(input) = XtNewString(Set(input));
1317 	SetString(set, Set(input));
1318 	(void)SetValueOnSymbols(sw, Set(input), False);
1319     }
1320 
1321     if (Changed(overstrike)) {
1322 	if (Set(overstrike))
1323 	    XtAddCallback(set, XmNmodifyVerifyCallback,
1324 			  HandleOverstrike, NULL);
1325 	else
1326 	    XtRemoveCallback(set, XmNmodifyVerifyCallback,
1327 			     HandleOverstrike, NULL);
1328     }
1329 
1330     /* if pattern changed, free old, copy new, and adjust callbacks */
1331     if (Changed(pattern)) {
1332 	/* if the old pattern was NULL, add the callbacks, else free */
1333 	if (Current(pattern) == NULL) {
1334 	    XtAddCallback(set, XmNmodifyVerifyCallback, HandlePattern, NULL);
1335 	}
1336 	else
1337 	    XtFree(Current(pattern));
1338 
1339 	/* if the new pattern is NULL, remove the callbacks, else copy */
1340 	if (Set(pattern) == NULL) {
1341 	    XtRemoveCallback(set, XmNmodifyVerifyCallback,HandlePattern, NULL);
1342 	}
1343 	else
1344 	    Set(pattern) = XtNewString(Set(pattern));
1345 
1346 	/* get the new size of the pattern */
1347 	if (Set(pattern))
1348 	    Set(pattern_length) = strlen(Set(pattern));
1349 	else
1350 	    Set(pattern_length) = 0;
1351     }
1352 
1353     /*
1354      * update max_length from pattern or buffer size
1355      */
1356     if (sw->text.max_length != Current(max_length))
1357 	Set(max_length) = sw->text.max_length;
1358     else if (Changed(pattern))
1359 	Set(max_length) = Set(pattern_length);
1360     else if (Changed(buffer_symbol) && Set(buffer_symbol))
1361 	Set(max_length) = XmtSymbolSize(Set(buffer_symbol));
1362     /*
1363      * if max_length  or overstrike changed,
1364      * update the internal widget
1365      */
1366     if (Changed(max_length) || Changed(overstrike))
1367 	XmTextSetMaxLength(set, Set(overstrike)?MAXINT:Set(max_length));
1368 #ifdef NUTCRACKER_BUG_WORKAROUND
1369 
1370 
1371     /* If the background changed, save it - but only if we're not already in
1372      * SetValues.
1373      */
1374     if (sw->core.background_pixel != cw->core.background_pixel &&
1375         !sw->text.in_setvalues) {
1376         sw->input_field.sensitive_background = sw->core.background_pixel;
1377     }
1378 #endif
1379 
1380     /*
1381      * if sensitivity changes, set the layoutSensitive resource, in case
1382      * we're a child of XmtLayout, and have a caption.
1383      */
1384     if ((sw->core.sensitive != cw->core.sensitive) ||
1385 	(sw->core.ancestor_sensitive != cw->core.ancestor_sensitive)) {
1386 	XtVaSetValues(set, XmtNlayoutSensitive,
1387 		      sw->core.sensitive && sw->core.ancestor_sensitive, NULL);
1388     }
1389 
1390 
1391     /*
1392      * Get new traversalOn state.
1393      */
1394     Set(notTraversable) = !sw->primitive.traversal_on;
1395 
1396 #ifdef NUTCRACKER_BUG_WORKAROUND
1397     if (sw->core.sensitive && sw->core.ancestor_sensitive) {
1398         if (sw->core.background_pixel != sw->input_field.sensitive_background) {
1399             XtVaSetValues((Widget) sw, XmNbackground, sw->input_field.sensitive_background, NULL);
1400         }
1401     } else {
1402         /* Save the *old* background pixel, not the new. WINTIF munches that too. */
1403         sw->input_field.sensitive_background = cw->core.background_pixel;
1404     }
1405 #endif
1406 
1407     /* never need to redraw */
1408     return False;
1409 
1410 #undef Current
1411 #undef Request
1412 #undef Set
1413 #undef Changed
1414 }
1415 
1416 #if NeedFunctionPrototypes
XmtCreateInputField(Widget parent,StringConst name,ArgList args,Cardinal n)1417 Widget XmtCreateInputField(Widget parent, StringConst name,
1418 			   ArgList args, Cardinal n)
1419 #else
1420 Widget XmtCreateInputField(parent, name, args, n)
1421 Widget parent;
1422 StringConst name;
1423 ArgList args;
1424 Cardinal n;
1425 #endif
1426 {
1427     return XtCreateWidget((String)name, xmtInputFieldWidgetClass,
1428 			  parent, args, n);
1429 }
1430 
1431 /*
1432  * returns a string that must not be modified or freed by the caller
1433  */
1434 #if NeedFunctionPrototypes
XmtInputFieldGetString(Widget w)1435 String XmtInputFieldGetString(Widget w)
1436 #else
1437 String XmtInputFieldGetString(w)
1438 Widget w;
1439 #endif
1440 {
1441     XmtInputFieldWidget iw = (XmtInputFieldWidget) w;
1442 
1443     XmtAssertWidgetClass(w, xmtInputFieldWidgetClass,"XmtInputFieldGetString");
1444     return iw->input_field.input;
1445 }
1446 
1447 #if NeedFunctionPrototypes
XmtInputFieldSetString(Widget w,StringConst s)1448 void XmtInputFieldSetString(Widget w, StringConst s)
1449 #else
1450 void XmtInputFieldSetString(w, s)
1451 Widget w;
1452 StringConst s;
1453 #endif
1454 {
1455     XmtInputFieldWidget iw = (XmtInputFieldWidget) w;
1456 
1457     XmtAssertWidgetClass(w, xmtInputFieldWidgetClass,"XmtInputFieldSetString");
1458     if (iw->input_field.input)
1459 	XtFree(iw->input_field.input);
1460     if (s)
1461 	iw->input_field.input = XtNewString(s);
1462     else
1463 	iw->input_field.input = NULL;
1464     SetString((Widget)iw, (String)s);
1465     (void) SetValueOnSymbols(iw, s, False);
1466 }
1467 
1468 
1469 /* ARGSUSED */
1470 #if NeedFunctionPrototypes
setvalue(Widget w,XtPointer address,XrmQuark type,Cardinal size)1471 static void setvalue(Widget w, XtPointer address, XrmQuark type, Cardinal size)
1472 #else
1473 static void setvalue(w, address, type, size)
1474 Widget w;
1475 XtPointer address;
1476 XrmQuark type;
1477 Cardinal size;
1478 #endif
1479 {
1480     char buf[100];
1481 
1482     if (type == XmtQString)
1483 	XmtInputFieldSetString(w, *(String *)address);
1484     else if (type == XmtQBuffer)
1485 	XmtInputFieldSetString(w, (char *)address);
1486     else if ((type == XmtQShort) || (type == XmtQPosition)) {
1487 	(void)sprintf(buf, "%d", *(short *)address);
1488 	XmtInputFieldSetString(w, buf);
1489     }
1490     else if (type == XmtQDimension) {
1491 	(void)sprintf(buf, "%u", *(unsigned short *)address);
1492 	XmtInputFieldSetString(w, buf);
1493     }
1494     else if (type == XmtQInt) {
1495 	(void)sprintf(buf, "%d", *(int *)address);
1496 	XmtInputFieldSetString(w, buf);
1497     }
1498     else if (type == XmtQCardinal) {
1499 	(void)sprintf(buf, "%u", *(unsigned int *)address);
1500 	XmtInputFieldSetString(w, buf);
1501     }
1502     else if (type == XmtQFloat) {
1503 	(void)sprintf(buf, "%g", *(float *)address);
1504 	XmtInputFieldSetString(w, buf);
1505     }
1506     else if (type == XmtQDouble) {
1507 	(void)sprintf(buf, "%g", *(double *)address);
1508 	XmtInputFieldSetString(w, buf);
1509     }
1510     else
1511 	XmtWarningMsg("XmtInputField", "setvalue",
1512 		      "Type mismatch:\n\tCan't set value from resource of type '%s'.  String or Buffer expected.",
1513 		   XrmQuarkToString(type));
1514 }
1515 
1516 #if NeedFunctionPrototypes
getvalue(Widget w,XtPointer address,XrmQuark type,Cardinal size)1517 static void getvalue(Widget w, XtPointer address, XrmQuark type, Cardinal size)
1518 #else
1519 static void getvalue(w, address, type, size)
1520 Widget w;
1521 XtPointer address;
1522 XrmQuark type;
1523 Cardinal size;
1524 #endif
1525 {
1526     String s = XmtInputFieldGetString(w);
1527 
1528     if (type == XmtQString)
1529 	*(String *)address = s;
1530     else if (type == XmtQBuffer) {
1531 	int len = strlen(s);
1532 
1533 	strncpy(address, s, size-1);
1534 	((char *)address)[size-1] = '\0';
1535 	if (len >= size)
1536 	    XmtWarningMsg("XmtInputField", "trunc",
1537 			  "The input value is %d characters long\n\tand does not fit into a buffer %d characters long.\n\tThe trailing characters have been truncated.",
1538 			  len+1, size);
1539     }
1540     /* XXX
1541      * unsigned values should be handled better here.
1542      * the XmtInputField should also probably have resources to
1543      * set that will automatically verify that the value is valid.
1544      */
1545     else if ((type == XmtQShort) || (type == XmtQPosition) ||
1546 	     (type == XmtQDimension))
1547 	*(short *)address = atoi(s);
1548     else if ((type == XmtQInt) || (type == XmtQCardinal))
1549 	*(int *)address = atoi(s);
1550     else if (type == XmtQFloat)
1551 	*(float *)address = atof(s);
1552     else if (type == XmtQDouble)
1553 	*(double *)address = atof(s);
1554     else
1555 	XmtWarningMsg("XmtInputField", "getvalue",
1556 		      "Type mismatch:\n\tCan't set input value on a resource of type '%s'.  String or Buffer expected.",
1557 		      XrmQuarkToString(type));
1558 }
1559 
1560 
1561 static XmtWidgetType inputfield_widget = {
1562     "XmtInputField",
1563     (WidgetClass) &xmtInputFieldClassRec,
1564     NULL,
1565     setvalue,
1566     getvalue,
1567 };
1568 
1569 #if NeedFunctionPrototypes
XmtRegisterInputField(void)1570 void XmtRegisterInputField(void)
1571 #else
1572 void XmtRegisterInputField()
1573 #endif
1574 {
1575     _XmtInitQuarks();
1576     XmtRegisterWidgetTypes(&inputfield_widget, 1);
1577 }
1578 
1579