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