1 /*
2  * Motif Tools Library, Version 3.1
3  * $Id: NameToWidget.c,v 1.3 2001/09/19 02:57:18 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: NameToWidget.c,v $
12  * Revision 1.3  2001/09/19 02:57:18  grmcdorman
13  * This change makes the following modifications:
14  *   A new program, printConfig, is provided. This is built by a
15  *   simple rule in the Makefile and not installed. It prints
16  *   significant defines from Xmt.tmpl.
17  *
18  *   XmtP.h is now generated from XmtP.h.in using printConfig. As
19  *   a result, code compiled outside of the Xmt Imakefiles will
20  *   have all of the Xmt.tmpl defines.
21  *
22  *   Source files are modified to use XmtP.h instead of Xmt.h.
23  *
24  *   WorkingBox.c is modified to use the new Progress widget.
25  *   It can be compiled in the old style if WORKINGBOX_USE_SCALE is
26  *   defined at compile time.
27  *
28  *   Because XmtP.h is generated dynamically, it is removed from CVS
29  *   with this check-in.
30  *
31  * Revision 1.2  2001/04/15 15:29:36  grmcdorman
32  *   * XmtCallCallback has two new arguments types: XmtRCallbackUserData, which
33  *     is the XmNuserData value, and XmtRCallbackImmediate, which is a value
34  *     embedded in the list.
35  *
36  *   * Two new functions, XmtCreateQueryListChildren and XmtCreateQueryListChild,
37  *     are provided. They are like the XmtCreate* functions except that they
38  *     return a list of the widgets created (quark and pointer to the widget).
39  *
40  *   * Major enhancements to XmtInputField:
41  *     - The input field now has a cancel() action. This reverts the field's
42  *       value to that prior to the start of editing (i.e. the last commit).
43  *       No default translation is bound to this action, however.
44  *     - There is a callback for the cancel action (XmtNcancelCallback).
45  *     - The input field can be set to cancel, commit, or do nothing on focus
46  *       out. (Previously, it always did a commit). The default is commit.
47  *       (XmtNfocusOutAction)
48  *
49  *   * XmtLayout:
50  *     - It now has a losingFocusCallback (XmNloosingFocusCallback).
51  *     - It, and the layout widgets (XmtLayoutBox/XmtLayoutString), now
52  *       support background pixmaps.
53  *     - It now supports XmNresizePolicy.
54  *     - Strings in the layout parser are converted to XmStrings by
55  *       XtConvertAndStore, so any custom XmString conversion is used
56  *       (as, for example, the Xmt convert, which supports the @[]
57  *       embedded items)
58  *
59  *   * Other:
60  *     - Pixmaps are convered using XtConvertAndStore, again to allow
61  *       custom converters.
62  *
63  * Bug Fixes: (for Solaris 2.5.1/Motif 1.2/Sparc system)
64  *   * XmtInputField did not work properly if the widget had traversalOn
65  *     false.
66  *   * XmtLayout's child geometry manager was called by Xt when
67  *     a shell child was added to the layout; it did not handle
68  *     this case.
69  *   * XmtLayout had an XmtWarningMsg call with a missing argument (line 2029).
70  *   * Widgets automatically created by XmtLayout parsing have been given
71  *     non-blank names. [You may wish to tweak this by adding, for example,
72  *     a leading underscore.]
73  *   * Under some circumstances, XmtNameToWidget could be called during
74  *     widget creation, with 'w->core.num_popups' uninitialized. The
75  *     workaround applied is to ignore the popup list if the 'num_popups'
76  *     value is more than 50 or negative.
77  *
78  * Revision 1.1.1.1  2001/02/10 13:50:08  motiftools
79  * Initial import of Xmt310 to CVS
80  *
81  *
82  */
83 
84 /*
85  * Portions of this file are derived from the Xt source code.
86  * See the file COPYRIGHT for the MIT and Digital copyrights.
87  */
88 
89 #include <Xmt/XmtP.h>
90 #include <Xmt/Util.h>
91 #include <Xmt/AppRes.h>
92 #include <X11/IntrinsicP.h>
93 
94 static XrmQuark selfq = NULLQUARK;
95 static XrmQuark questionq = NULLQUARK;
96 
97 #if NeedFunctionPrototypes
GetParent(Widget w)98 static Widget GetParent(Widget w)
99 #else
100 static Widget GetParent(w)
101 Widget w;
102 #endif
103 {
104     if (w == NULL) return NULL;
105     if (XtParent(w) != NULL) return XtParent(w);
106     else return w;
107 }
108 
109 #if NeedFunctionPrototypes
GetNamedAncestor(Widget ref,char * name)110 static Widget GetNamedAncestor(Widget ref, char *name)
111 #else
112 static Widget GetNamedAncestor(ref, name)
113 Widget ref;
114 char *name;
115 #endif
116 {
117     Widget w;
118     WidgetClass c;
119     XrmQuark q = XrmStringToQuark(name);
120 
121     if (ref == NULL) return NULL;
122 
123     /* see if the supplied name matches any ancestor's names */
124     for(w = XtParent(ref); w != NULL; w = XtParent(w))
125 	if (w->core.xrm_name == q) return w;
126 
127     /*
128      * if not, start checking classes.  Check the class name, and
129      * all the superclass names of each ancestor widget.
130      * This is done with WidgetClass, but should work for objects too.
131      */
132     for(w = XtParent(ref); w != NULL; w = XtParent(w))
133 	for(c = XtClass(w); c != NULL; c = c->core_class.superclass)
134 	    if (c->core_class.xrm_class == q) return w;
135 
136     /* if no name or class matches, return NULL */
137     return NULL;
138 }
139 
140 #if NeedFunctionPrototypes
GetChild(Widget w,XrmName q)141 static Widget GetChild(Widget w, XrmName q)
142 #else
143 static Widget GetChild(w, q)
144 Widget w;
145 XrmName q;
146 #endif
147 {
148     CompositeWidget parent = (CompositeWidget) w;
149     int i;
150 
151     /*
152      * Check the names of all normal children.
153      * Check the names of all popup children.
154      * Check the class names of all normal children.
155      * Check the class names of all popup children.
156      * Note that we don't check superclass names.
157      */
158 
159     if (w == NULL) return NULL;
160 
161     /* normal children names */
162     if (XtIsComposite(w)) {
163 	for(i = 0; i < parent->composite.num_children; i++)
164 	    if (parent->composite.children[i]->core.xrm_name == q)
165 		return parent->composite.children[i];
166     }
167 
168     /* popup children names */
169     /* try to handle unintialized 'num_popups' */
170     if (w->core.num_popups < 50 && w->core.num_popups > 0)
171       for(i = 0; i < w->core.num_popups; i++)
172 	if (w->core.popup_list[i]->core.xrm_name == q)
173 	    return w->core.popup_list[i];
174 
175     /* normal children classes */
176     if (XtIsComposite(w)) {
177 	for(i = 0; i < parent->composite.num_children; i++)
178 	    if (XtClass(parent->composite.children[i])->core_class.xrm_class
179 		== q)
180 		return parent->composite.children[i];
181     }
182 
183     /* popup children classes */
184     /* try to handle unintialized 'num_popups' */
185     if (w->core.num_popups < 50 && w->core.num_popups > 0)
186       for(i = 0; i < w->core.num_popups; i++)
187 	if (XtClass(w->core.popup_list[i])->core_class.xrm_class == q)
188 	    return w->core.popup_list[i];
189 
190     /* no child matches */
191     return NULL;
192 }
193 
194 
195 #if NeedFunctionPrototypes
ParseWidgetModifiers(Widget w,StringConst * name)196 static Widget ParseWidgetModifiers(Widget w, StringConst *name)
197 #else
198 static Widget ParseWidgetModifiers(w, name)
199 Widget w;
200 StringConst *name;
201 #endif
202 {
203     if (*name == NULL || **name == '\0')
204 	return w;  /* no recursion */
205     else if (**name == '.') {
206 	/*
207 	 * ignore '.' if there are following modifiers, or
208 	 * return w if no modifiers follow it.
209 	 */
210 	*name += 1;
211 	return ParseWidgetModifiers(w, name);
212     }
213     else if (**name == '~') {
214 	*name += 1;
215 	return XmtGetShell(ParseWidgetModifiers(w, name));
216     }
217     else if (**name == '^') {
218 	if (*(*name+1) != '{') {
219 	    *name += 1;
220 	    return GetParent(ParseWidgetModifiers(w, name));
221 	}
222     	else {
223 	    char ancestor[100];
224 	    int i = 0;
225 	    *name += 2;
226 	    while (**name && **name != '}') {
227 		ancestor[i++] = **name;
228 		*name += 1;
229 	    }
230 	    ancestor[i] = '\0';
231 	    if (**name == '}') *name += 1;
232 	    return GetNamedAncestor(ParseWidgetModifiers(w, name),
233 				    ancestor);
234 	}
235     }
236     else /* there are no more modifiers, so don't recurse */
237 	return w;
238 }
239 
240 
241 /*
242  * The following 5 procedures are code modified from the internals
243  * of the function XtNameToWidget.  This code appears in the file
244  * Intrinsic.c in the MIT Xt distribution, with the following RCS info:
245  * $XConsortium: Intrinsic.c,v 1.171 91/07/16 18:30:20 converse Exp $
246  */
247 #if NeedFunctionPrototypes
248 static Widget NameListToWidget(register Widget root,
249 			       XrmNameList names, XrmBindingList bindings,
250 			       int num_quarks, int in_depth, int *out_depth,
251 			       int *found_depth);
252 #else
253 static Widget NameListToWidget();
254 #endif
255 
256 typedef Widget (*NameMatchProc)();
257 
258 #if NeedFunctionPrototypes
MatchExactChildren(XrmNameList names,XrmBindingList bindings,int num_quarks,register WidgetList children,register int num,int in_depth,int * out_depth,int * found_depth)259 static Widget MatchExactChildren(XrmNameList names, XrmBindingList bindings,
260 				 int num_quarks, register WidgetList children,
261 				 register int num, int in_depth,
262 				 int *out_depth, int *found_depth)
263 #else
264 static Widget MatchExactChildren(names, bindings, num_quarks, children, num,
265 				 in_depth, out_depth, found_depth)
266 XrmNameList names;
267 XrmBindingList bindings;
268 int num_quarks;
269 register WidgetList children;
270 register int num;
271 int in_depth;
272 int *out_depth;
273 int *found_depth;
274 #endif
275 {
276     register Cardinal   i;
277     register XrmName    name = *names;
278     Widget w, result = NULL;
279     int d, min = 10000;
280 
281     /* check the names of children.  '?' always matches -- djf */
282     for (i = 0; i < num; i++) {
283 	if ((name == children[i]->core.xrm_name) ||
284 	    (name == questionq)) /* djf */ {
285 	    w = NameListToWidget(children[i], &names[1], &bindings[1],
286 				 num_quarks-1,
287 				 in_depth+1, &d, found_depth);
288 	    if (w != NULL && d < min) {result = w; min = d;}
289 	}
290     }
291 
292     *out_depth = min;
293     return result;
294 }
295 
296 #if NeedFunctionPrototypes
MatchExactClass(XrmNameList names,XrmBindingList bindings,int num_quarks,register WidgetList children,register int num,int in_depth,int * out_depth,int * found_depth)297 static Widget MatchExactClass(XrmNameList names, XrmBindingList bindings,
298 			      int num_quarks, register WidgetList children,
299 			      register int num, int in_depth, int *out_depth,
300 			      int *found_depth)
301 #else
302 static Widget MatchExactClass(names, bindings, num_quarks, children, num,
303 			      in_depth, out_depth, found_depth)
304 XrmNameList names;
305 XrmBindingList bindings;
306 int num_quarks;
307 register WidgetList children;
308 register int num;
309 int in_depth;
310 int *out_depth;
311 int *found_depth;
312 #endif
313 {
314     register Cardinal   i;
315     register XrmName    name = *names;
316     Widget w, result = NULL;
317     int d, min = 10000;
318 
319     /* like the above, but check classes  -- djf */
320     for (i = 0; i < num; i++) {
321 	if (name == XtClass(children[i])->core_class.xrm_class) {
322 	    w = NameListToWidget(children[i], &names[1], &bindings[1],
323 				 num_quarks-1,
324 				 in_depth+1, &d, found_depth);
325 	    if (w != NULL && d < min) {result = w; min = d;}
326 	}
327     }
328 
329     *out_depth = min;
330     return result;
331 }
332 
333 
334 #if NeedFunctionPrototypes
MatchWildChildren(XrmNameList names,XrmBindingList bindings,int num_quarks,register WidgetList children,register int num,int in_depth,int * out_depth,int * found_depth)335 static Widget MatchWildChildren(XrmNameList names, XrmBindingList bindings,
336 				int num_quarks,	register WidgetList children,
337 				register int num, int in_depth,
338 				int *out_depth, int *found_depth)
339 #else
340 static Widget MatchWildChildren(names, bindings, num_quarks, children, num,
341 				in_depth, out_depth, found_depth)
342 XrmNameList names;
343 XrmBindingList bindings;
344 int num_quarks;
345 register WidgetList children;
346 register int num;
347 int in_depth;
348 int *out_depth;
349 int *found_depth;
350 #endif
351 {
352     register Cardinal   i;
353     Widget w, result = NULL;
354     int d, min = 10000;
355 
356     for (i = 0; i < num; i++) {
357 	w = NameListToWidget(children[i], names, bindings, num_quarks,
358 		in_depth+1, &d, found_depth);
359 	if (w != NULL && d < min) {result = w; min = d;}
360     }
361     *out_depth = min;
362     return result;
363 }
364 
365 #if NeedFunctionPrototypes
SearchChildren(Widget root,XrmNameList names,XrmBindingList bindings,int num_quarks,NameMatchProc matchproc,int in_depth,int * out_depth,int * found_depth)366 static Widget SearchChildren(Widget root,
367 			     XrmNameList names, XrmBindingList bindings,
368 			     int num_quarks, NameMatchProc matchproc,
369 			     int in_depth, int *out_depth, int *found_depth)
370 #else
371 static Widget SearchChildren(root, names, bindings, num_quarks, matchproc,
372 			     in_depth, out_depth, found_depth)
373 Widget root;
374 XrmNameList names;
375 XrmBindingList bindings;
376 int num_quarks;
377 NameMatchProc matchproc;
378 int in_depth;
379 int *out_depth;
380 int *found_depth;
381 #endif
382 {
383     Widget w1, w2;
384     int d1, d2;
385 
386     if (XtIsComposite(root)) {
387 	w1 = (*matchproc)(names, bindings, num_quarks,
388 		((CompositeWidget) root)->composite.children,
389 		((CompositeWidget) root)->composite.num_children,
390 		in_depth, &d1, found_depth);
391     }
392     else {
393 	d1 = 10000;
394 	w1 = NULL;
395     }
396     w2 = (*matchproc)(names, bindings, num_quarks, root->core.popup_list,
397 	    root->core.num_popups < 50 && root->core.num_popups > 0 ? root->core.num_popups : 0,
398 	    in_depth, &d2, found_depth);
399     *out_depth = (d1 < d2 ? d1 : d2);
400     return (d1 < d2 ? w1 : w2);
401 }
402 
403 #if NeedFunctionPrototypes
NameListToWidget(register Widget root,XrmNameList names,XrmBindingList bindings,int num_quarks,int in_depth,int * out_depth,int * found_depth)404 static Widget NameListToWidget(register Widget root,
405 			       XrmNameList names, XrmBindingList bindings,
406 			       int num_quarks, int in_depth,
407 			       int *out_depth, int *found_depth)
408 #else
409 static Widget NameListToWidget(root, names, bindings, num_quarks, in_depth,
410 			       out_depth, found_depth)
411 register Widget root;
412 XrmNameList names;
413 XrmBindingList bindings;
414 int num_quarks;
415 int in_depth;
416 int *out_depth;
417 int *found_depth;
418 #endif
419 {
420     Widget w1, w2;
421     int d1, d2;
422 
423     if (in_depth >= *found_depth) {
424 	*out_depth = 10000;
425 	return NULL;
426     }
427 
428     if (num_quarks == 0) {
429 	*out_depth = *found_depth = in_depth;
430 	return root;
431     }
432 
433     if (! XtIsWidget(root)) {
434 	*out_depth = 10000;
435 	return NULL;
436     }
437 
438     if (*bindings == XrmBindTightly) {
439 	w1 =  SearchChildren(root, names, bindings, num_quarks,
440 			     MatchExactChildren,
441 			     in_depth, out_depth, found_depth);
442 	/* if no names match, look for a class name that matches -- djf */
443 	if (w1 == NULL) {
444 	    w1 = SearchChildren(root, names, bindings, num_quarks,
445 				MatchExactClass,
446 				in_depth, out_depth, found_depth);
447 	}
448 
449 	if (w1 != NULL)
450 	    return w1;
451     }
452     else {  /* XrmBindLoosely */
453 	w1 = SearchChildren(root, names, bindings, num_quarks,
454 			    MatchExactChildren,
455 			    in_depth, &d1, found_depth);
456 	if (w1 == NULL) { /* if no names match exactly, check classes -- djf */
457 	    w1 = SearchChildren(root, names, bindings, num_quarks,
458 				MatchExactClass,
459 				in_depth, &d1, found_depth);
460 	}
461 	w2 = SearchChildren(root, names, bindings, num_quarks,
462 			    MatchWildChildren,
463 			    in_depth, &d2, found_depth);
464 	*out_depth = (d1 < d2 ? d1 : d2);
465 	return (d1 < d2 ? w1 : w2);
466     }
467     /* NOTREACHED */
468     return NULL;  /* but return something anyway to keep gcc -Wall quiet */
469 } /* NameListToWidget */
470 
471 
472 /* modified X Consortium code ends here. */
473 
474 #if NeedFunctionPrototypes
XmtNameToWidget(Widget ref,StringConst name)475 Widget XmtNameToWidget(Widget ref, StringConst name)
476 #else
477 Widget XmtNameToWidget(ref, name)
478 Widget ref;
479 StringConst name;
480 #endif
481 {
482     StringConst newname;
483     Boolean modifiers = False;
484     XrmQuark quark_array[50];
485     XrmBinding binding_array[50];
486     XrmQuarkList quarks;
487     XrmBindingList bindings;
488     int numquarks;
489     Widget w;
490     int depth = 0;
491     int found = 10000;
492 
493     /* initialize quarks used by lots of functions */
494     if (selfq == NULLQUARK) selfq = XrmStringToQuark("self");
495     if (questionq == NULLQUARK)	questionq = XrmStringToQuark("?");
496 
497     newname = name;
498     /* if the name begins with a modifier, go parse them */
499     if ((name[0] == '.') || (name[0] == '^') || (name[0] == '~')) {
500 	modifiers = True;
501 	ref = ParseWidgetModifiers(ref, &newname);
502     }
503 
504     /*
505      * if no name, or nothing following the modifiers,
506      * then just return the reference widget.  This is
507      * so names like "^^" work.
508      */
509     if (!newname || !*newname) return ref;
510 
511     /* quarkify the name and count the quarks */
512     quarks = quark_array;
513     bindings = binding_array;
514     XrmStringToBindingQuarkList(newname, bindings, quarks);
515     for(numquarks = 0; quarks[numquarks] != NULLQUARK; numquarks++);
516 
517     if (!modifiers) {
518 	/* if the name begins with '*', it is relative to the root. */
519 	if (name[0]== '*')
520 	    ref = XmtGetApplicationShell(ref);
521 	else {
522 	    /*
523 	     * if first quark is 'self', skip it.
524 	     * if first quark is a sibling of ref, ref = parent
525 	     * otherwise if first quark doesn't name a child, maybe it
526 	     * names a root widget.  If it doesn't name any known root,
527 	     * it is an error.
528 	     */
529 	    if (quarks[0] == selfq) {
530 		quarks++;
531 		bindings++;
532 		numquarks--;
533 	    }
534 	    else if (GetChild(XtParent(ref), quarks[0]))
535 		ref = XtParent(ref);
536 	    else if (!GetChild(ref, quarks[0])) {
537 		ref = XmtLookupApplicationShell(quarks[0]);
538 		if (!ref) return NULL;
539 		quarks++;
540 		bindings++;
541 		numquarks--;
542 	    }
543 	}
544     }
545 
546     w =  NameListToWidget(ref, quarks, bindings, numquarks,
547 			  0, &depth, &found);
548     return w;
549 }
550 
551