ResConfig.c revision 81d6fa61
1/*
2
3Copyright 1987, 1988, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26/*****************************************************************
27
28(C) COPYRIGHT International Business Machines Corp. 1992,1997
29    All Rights Reserved
30
31Permission is hereby granted, free of charge, to any person obtaining a copy
32of this software and associated documentation files (the "Software"), to deal
33in the Software without restriction, including without limitation the rights
34to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35copies of the Software.
36
37The above copyright notice and this permission notice shall be included in
38all copies or substantial portions of the Software.
39
40THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
43THE IBM CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
44BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
45WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
46IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
47
48Except as contained in this notice, the name of the IBM Corporation shall
49not be used in advertising or otherwise to promote the sale, use or other
50dealings in this Software without prior written authorization from the IBM
51Corporation.
52
53******************************************************************/
54
55#ifdef HAVE_CONFIG_H
56#include <config.h>
57#endif
58#include "Intrinsic.h"
59#include "IntrinsicI.h"
60#include "Core.h"
61#include "CoreP.h"
62#include "ShellP.h"
63#include "StringDefs.h"
64#include "ResConfigP.h"
65#include <X11/Xatom.h>
66#include <stdio.h>
67#include <stdlib.h>
68
69#define MAX_BUFFER 512
70
71static void _search_child(Widget, char *, char *, char *, char *, char, char *);
72static void _set_and_search(Widget, char *, char *, char *, char *, char , char *);
73static int _locate_children(Widget, Widget **);
74
75/*
76 * NAME: _set_resource_values
77 *
78 * FUNCTION:
79 *	This function sets the value on the widget.  It must first determine
80 *	if the last part is a valid resource for that widget.  (eg.
81 *	labelString is a valid resource for label but not for bulletin board)
82 *	It must also add the resource to the application's resource database
83 *	and then query it out using specific resource strings that it builds
84 *	from the widget information.  This ensures that a customizing tool
85 *	on-the-fly paradigm is followed:  an application that is
86 *	instantaneously updated should look the same as one that is restarted
87 *	and uses the .Xdefaults file.
88 *
89 * PARAMETERS:
90 *	w		the widget to match
91 *	resource	the resource string to be matched
92 *	value		the value to be set
93 *	last_part	the last resource part (e.g. *background)
94 *
95 * RETURN VALUES: void
96 *
97 * ERRORS: none
98 */
99static void
100_set_resource_values (
101	Widget w,
102	char *resource,
103	char *value,
104	char *last_part)
105{
106	XrmDatabase 	db = NULL;
107	char		*resource_name = NULL;
108	char		*resource_class = NULL;
109	char		*return_type;
110	XrmValue	return_value;
111	char		*resource_value;
112	Widget		cur = w;
113	char		*temp;
114	XtResourceList	resources_return = NULL;
115	Cardinal 	num_resources_return = 0;
116	Cardinal	res_index;
117	Boolean		found_resource = False;
118	Display		*dpy;
119	XrmDatabase	tmp_db;
120
121	if (!XtIsWidget (w))
122		dpy = XtDisplay (w->core.parent);
123	else
124		dpy = XtDisplay (w);
125	tmp_db = XtDatabase(dpy);
126
127	/*
128	 * get a list of all the valid resources for this widget
129	 */
130	XtGetResourceList (w->core.widget_class,
131		&resources_return, &num_resources_return);
132
133	/*
134	 * try to match the last_part of the resource string with
135	 * a resource in this resource list
136	 */
137	for (res_index=0; res_index<num_resources_return; res_index++) {
138		if ((strcmp (last_part,
139			resources_return[res_index].resource_name) == 0) ||
140		    (strcmp (last_part,
141			resources_return[res_index].resource_class) == 0)) {
142			found_resource = True;
143			break;
144		}
145	}
146
147	/*
148	 * if resource is not a valid resource for this widget
149	 * or the resource name or class are NULL
150	 * then exit this function
151	 */
152	if (!found_resource
153		|| !resources_return[res_index].resource_name
154		|| !resources_return[res_index].resource_class) {
155		XtFree ((char *) resources_return);
156		return;
157	}
158
159	/*
160	 * build the full resource name and class specifications so
161	 * that you can query the resource database
162	 * 	eg: .app.button1.foreground
163	 * 	    .App.XmPushButton.Foreground
164	 */
165	while (cur != NULL) {
166		/*
167		 * create resource name string
168		 */
169		if (resource_name) {
170			XtAsprintf (&temp, ".%s%s", cur->core.name, resource_name);
171			XtFree (resource_name);
172		} else if (!XtIsWidget (cur) || !cur->core.name) {
173			cur = XtParent(cur);
174			continue;
175		} else {
176			XtAsprintf (&temp, ".%s", cur->core.name);
177		}
178		resource_name = temp;
179
180		/*
181		 * create resource class string
182		 */
183		if ((XtIsTopLevelShell (cur)) && (XtParent (cur) == NULL)) {
184			ApplicationShellWidget	top =
185				(ApplicationShellWidget) (cur);
186
187			if (resource_class) {
188				XtAsprintf (&temp, ".%s%s",
189					top->application.class, resource_class);
190			} else {
191				XtAsprintf (&temp, ".%s",
192					top->application.class);
193			}
194		} else {
195			if (resource_class) {
196				XtAsprintf (&temp, ".%s%s",
197					cur->core.widget_class->core_class.class_name,
198					resource_class);
199			} else {
200				XtAsprintf (&temp, ".%s",
201					cur->core.widget_class->core_class.class_name);
202			}
203		}
204		if (resource_class != NULL)
205			XtFree (resource_class);
206		resource_class = temp;
207
208		cur = XtParent(cur);
209	}
210
211	/*
212	 * add the resource name to the end of the resource name string
213	 */
214	XtAsprintf (&temp, "%s.%s", resource_name,
215		resources_return[res_index].resource_name);
216	if (resource_name != NULL)
217		XtFree (resource_name);
218	resource_name = temp;
219
220	/*
221	 * add the resource class to the end of the resource class string
222	 */
223	XtAsprintf (&temp, "%s.%s", resource_class,
224		resources_return[res_index].resource_class);
225	if (resource_class != NULL)
226		XtFree (resource_class);
227	resource_class = temp;
228
229#ifdef DEBUG
230	fprintf (stderr, "resource_name = %s\n", resource_name);
231	fprintf (stderr, "resource_class = %s\n", resource_class);
232#endif
233
234	/*
235	 * put the resource and its value in a resource database and
236	 * then query it back out again using the specific name and
237	 * class resource strings that were built above.  This is
238	 * necessary to maintain a precedence similar to the .Xdefaults
239	 * file
240	 */
241	XrmPutStringResource (&db, resource, value);
242	XrmMergeDatabases (db, &tmp_db);
243	XrmGetResource (tmp_db, resource_name, resource_class,
244		&return_type, &return_value);
245	if (return_type)
246		resource_value = XtNewString (return_value.addr);
247	else
248		resource_value = XtNewString (value);
249
250#ifdef DEBUG
251	fprintf (stderr,
252		"Apply:\n\twidget = %s\n\tlast_part = %s\n\tvalue = %s\n",
253		(w->core.name == NULL) ? "NULL" : w->core.name,
254		resources_return[res_index].resource_name,
255		resource_value);
256#endif
257	/*
258	 * use XtVaSetValues with XtVaTypedArg to convert the value of
259	 * type String the the same type as the resource (last_part).
260	 * Then set the value.
261	 */
262	XtVaSetValues (w,
263		XtVaTypedArg, resources_return[res_index].resource_name,
264		XtRString, resource_value,
265		strlen (resource_value) + 1,
266		NULL);
267
268	XtFree ((char *) resources_return);
269	XtFree (resource_name);
270	XtFree (resource_class);
271	XtFree (resource_value);
272}
273
274/*
275 * NAME: _apply_values_to_children
276 *
277 * FUNCTION:
278 *	Once the resource string matches the value must be applied to
279 *	all children if applicable. (eg. App*Form.background must apply
280 *	background to all children of the Form widget)
281 *
282 * PARAMETERS:
283 *	w		the widget to match
284 *	remainder	the part of the resource string left over
285 *	resource	the resource string to be matched
286 *	value		the value to be set
287 *	last_token	the last * or . before the final resoruce part
288 *	last_part	the last resource part (e.g. *background)
289 *
290 * RETURN VALUES: void
291 *
292 * ERRORS: none
293 */
294static void
295_apply_values_to_children (
296	Widget w,
297	char *remainder,
298	char *resource,
299	char *value,
300	char last_token,
301	char *last_part)
302{
303	int 	i;
304	int	num_children;
305	Widget	*children;
306
307	/*
308	 * Recursively search through the children
309	 */
310	num_children = _locate_children (w, &children);
311
312	for (i=0; i<num_children; i++) {
313
314#ifdef DEBUG
315		if (XtIsWidget (children[i]) && XtIsWidget (w))
316			fprintf (stderr, "searching child %s of parent %s\n",
317				children[i]->core.name, w->core.name);
318		else
319			fprintf (stderr,"searching child (NULL) of parent %s\n",
320				w->core.name);
321		if (!XtIsWidget (children[i]))
322			fprintf (stderr, "children[%d] is NOT a widget\n", i);
323		if (!XtIsWidget (w))
324			fprintf (stderr, "w is NOT a widget\n");
325#endif
326
327		_set_resource_values (children[i], resource, value, last_part);
328		_apply_values_to_children (children[i], remainder,
329				resource, value, last_token, last_part);
330	}
331
332	XtFree ((char *)children);
333}
334
335/*
336 * NAME: _search_child
337 *
338 * FUNCTION:
339 *	descends through each child of the tree
340 *
341 * PARAMETERS:
342 *	w		the widget whose children are to be searched
343 *	indx		index into the resource string
344 *	remainder	the remaining part of the resource string
345 *	resource	the resource string to be matched
346 *	value		the value to be applied
347 *	last_token	the last * or . before the final resoruce part
348 *	last_part	the last resource part (e.g. *background)
349 *
350 * RETURN VALUES: none
351 *
352 * ERRORS: none
353 */
354static void
355_search_child (
356	Widget w,
357	char *indx,
358	char *remainder,
359	char *resource,
360	char *value,
361	char last_token,
362	char *last_part)
363{
364	int 	i;
365	int	num_children;
366	Widget	*children;
367
368	/*
369	 * Recursively search through the children
370	 */
371	num_children = _locate_children (w, &children);
372	for (i=0; i<num_children; i++) {
373		_set_and_search (children[i], indx, remainder, resource,
374			value, last_token, last_part);
375	}
376
377	XtFree ((char *)children);
378}
379
380/*
381 * NAME: _get_part
382 *
383 * FUNCTION:
384 * 	This routine will return the token and following part of the resource
385 * 	when given the current index it will update the index accordingly
386 *
387 * PARAMETERS:
388 *	remainder	the part of the resource string left over
389 *	indx		the index into the resource string
390 *	part		the parsed off part of the resource string
391 *
392 * RETURN VALUES:
393 *	char		the token (* or . or ?) preceding the resource part
394 *	indx		the index into the resource string
395 *	part		the parsed off part of the resource string
396 *
397 * ERRORS: none
398 */
399/* ARGSUSED */
400static char
401_get_part (
402	char *remainder,
403	char **indx,
404	char **part)
405{
406	char	buffer[MAX_BUFFER];
407	char	*buf_ptr;
408	char	token = **indx;
409	int	i = 0;
410
411	/*
412	 * copy the remainder part into the buffer
413	 */
414	buf_ptr = buffer;
415	(*indx)++;			/* get rid of the token		*/
416	while (**indx && (**indx != '.') && (**indx != '*')) {
417		*buf_ptr++ = *(*indx)++;
418		if (++i >= MAX_BUFFER - 1)
419			break;
420	}
421	*buf_ptr = '\0';
422
423	*part = XtNewString (buffer);	/* return a new string to part	*/
424
425	if (strcmp (*indx, "") == 0)
426		*indx = NULL;
427
428	return (token);			/* return the token		*/
429}
430
431/*
432 * NAME: _match_resource_to_widget
433 *
434 * FUNCTION:
435 *	This function matches the resource part to the widget name or class
436 *
437 * PARAMETERS:
438 *	w		the widget to match
439 *	part		the parsed off part of the resource string
440 *
441 * RETURN VALUES:
442 *	Boolean		true if a match occurs
443 *
444 * ERRORS: none
445 */
446static Boolean
447_match_resource_to_widget (
448	Widget w,
449	char *part)
450{
451	/*
452	 * Match any widget at this level if the ? is used
453	 */
454	if (strcmp (part, "?") == 0)
455		return (True);
456
457	/*
458	 * if the object is really a widget then its name can be matched
459	 * otherwise only use its class.  Note that if you try to reference
460	 * a widget name when the object is not a widget, you may get a
461	 * core dump from an invalid pointer reference.
462	 */
463	if (XtIsWidget (w)) {
464		if ((strcmp (w->core.name, part) == 0) ||
465		    (strcmp (w->core.widget_class->core_class.class_name,
466							part) == 0))
467			return (True);
468		else
469			return (False);
470	} else {
471		if ((strcmp (w->core.widget_class->core_class.class_name,
472							part) == 0))
473			return (True);
474		else
475			return (False);
476	}
477}
478
479/*
480 * NAME: _set_and_search
481 *
482 * FUNCTION:
483 * 	The algorithm to search the widget tree and apply a resource string
484 *
485 * PARAMETERS:
486 *	w		the widget to match
487 *	indx		the index into the resource string
488 *	remainder	the part of the resource string left over
489 *	resource	the resource string to be matched
490 *	value		the value to be set
491 *	last_token	the last * or . before the final resoruce part
492 *	last_part	the last resource part (e.g. *background)
493 *
494 * RETURN VALUES: none
495 *
496 * ERRORS: none
497 *
498 * ALGORITHM:
499 * loop (look at all children)
500 * 	if (resource segment and current widget match)
501 *		if '.'
502 *			if at end of resource string
503 *				set values (	.=over all children
504 *						*=this widget only)
505 *			else
506 *				descend the widget tree
507 *				and parse off resource segment
508 *			exit the loop
509 *		if '*'
510 *			if at end of resource string
511 *				set values (	.=over all children
512 *						*=this widget only)
513 *			descend and parse
514 *	else
515 *		if '.'
516 *			continue looping
517 *		if '*'
518 *			descend but don't parse
519 *			continue looping
520 * end loop
521 *
522 * NOTE:  the _set_resource_values routine will not allow a value to be
523 *	set on a resource against the rules of the resource database manager
524 */
525static void
526_set_and_search (
527	Widget w,
528	char *indx,
529	char *remainder,
530	char *resource,
531	char *value,
532	char last_token,
533	char *last_part)
534{
535	char	*part;
536	char	*local_index = indx;
537	char	token;
538
539	/*
540	 * parse off one part, return token and the new index
541	 */
542	token = _get_part (remainder, &local_index, &part);
543
544	if (_match_resource_to_widget (w, part)) {
545		if (token == '.') {
546			if (local_index == NULL) {
547				if (last_token == '.') {
548					_set_resource_values (w, resource,
549						value, last_part);
550				} else if (last_token == '*') {
551					_set_resource_values (w, resource,
552						value, last_part);
553					_apply_values_to_children (w,
554						remainder, resource, value,
555						last_token, last_part);
556				}
557			} else
558				_search_child (w, local_index, remainder,
559					resource, value, last_token, last_part);
560			return;
561		}
562		if (token == '*') {
563			if (local_index == NULL) {
564				if (last_token == '.') {
565					_set_resource_values (w, resource,
566						value, last_part);
567				} else if (last_token == '*') {
568					_set_resource_values (w, resource,
569						value, last_part);
570					_apply_values_to_children ( w,
571						remainder, resource, value,
572						last_token, last_part);
573				}
574			} else
575				_search_child (w, local_index, remainder,
576					resource, value, last_token, last_part);
577		}
578	} else {/* if the widget name and class don't match the part */
579		/* if (token == '.') just continue looping */
580
581		if (token == '*') {
582			_search_child (w, indx, remainder, resource, value,
583				last_token, last_part);
584		}
585	}
586
587	XtFree (part);
588}
589
590/*
591 * NAME: _get_last_part
592 *
593 * FUNCTION:
594 * 	This routine will parse off the last segment of a resource string
595 * 	and its token and return them.  the remainder of resource is also
596 * 	returned.  strcoll is used to guarantee no problems with
597 *	international strings.
598 *
599 * PARAMETERS:
600 *	remainder	the part of the resource string left over
601 *	part		the parsed off part of the resource string
602 *
603 * RETURN VALUES:
604 *	char		the token (* or . or ?) preceding the resource part
605 *	remainder	the part of the resource string left over
606 *	part		the parsed off part of the resource string
607 *
608 * ERRORS: none
609 */
610static char
611_get_last_part (
612	char *remainder,
613	char **part)
614{
615	char	*loose, *tight;
616
617	loose = strrchr (remainder, '*');
618	tight = strrchr (remainder, '.');
619
620	if ((loose == NULL) && (tight == NULL)) {
621		*part = XtNewString (remainder);
622		return ('.');
623	}
624	if ((loose == NULL) || (tight && (strcoll (loose, tight) < 0))) {
625		*tight++ = '\0';	/* shorten the remainder string */
626		*part = XtNewString (tight);
627		return ('.');
628	}
629	if ((tight == NULL) || (loose && (strcoll (tight, loose) < 0))) {
630		*loose++ = '\0';
631		*part = XtNewString (loose);
632		return ('*');
633	}
634	*part = NULL;
635
636	return ('0');	/* error - return 0 */
637}
638
639/*
640 * NAME: _search_widget_tree
641 *
642 * FUNCTION:
643 *	This function tries to match a resource string to the widgets
644 *	it applies to.  The functions it invokes to do this then set
645 *	the value for that resource to each widget.
646 *
647 *	The resource string has to be parsed into the following format:
648 *		resource = App*Form*button1.background
649 *		remainder = *Form*button1
650 *		last_part = background		last_token = .
651 *	As the widget tree is recursively descended, these variables are
652 *	passed.  The remainder is parsed at each level in the widget
653 *	tree as the _set_and_search function attempts to match
654 *	the resource part (eg. part = Form  token = *) to a widget.  When
655 *	the entire resource string has been matched, the _set_resource_values
656 *	functions is called to apply the value to the widget or widgets.
657 *
658 * PARAMETERS:
659 *	w		a widget from whose toplevel shell ancestor
660 *			the search will start
661 *	resource	the resource string to match
662 *	value		the value to apply
663 *
664 * RETURN VALUES: none
665 *
666 * ERRORS: none
667 */
668static void
669_search_widget_tree (
670	Widget w,
671	char *resource,
672	char *value)
673{
674	Widget	parent = w;
675	char	*last_part;
676	char	*remainder = NULL;
677	char	last_token;
678	char	*indx, *copy;
679	char	*loose, *tight;
680	int	loose_len, tight_len;
681
682	/*
683	 * Find the root of the tree given any widget
684	 */
685	while (XtParent(parent) != NULL) {
686		parent = XtParent(parent);
687	}
688#ifdef DEBUG
689	if (XtIsWidget (w) && XtIsWidget (parent))
690		fprintf (stderr, "widget = %s parent = %s\n",
691			w->core.name, parent->core.name);
692	else
693		fprintf (stderr, "widget = NULL parent = NULL\n");
694#endif
695
696	/*
697	 * parse off the Class name that was prepended to this string in
698	 * a customizing tool
699	 */
700	loose = strchr (resource, '*');
701	tight = strchr (resource, '.');
702	if ((loose == NULL) && (tight == NULL))
703		return;
704
705	loose_len = (loose) ? strlen (loose) : 0;
706	tight_len = (tight) ? strlen (tight) : 0;
707
708	if ((loose == NULL) || (tight_len > loose_len))
709		remainder = XtNewString (tight);
710	else if ((tight == NULL) || (loose_len > tight_len))
711		remainder = XtNewString (loose);
712
713	/*
714	 * Parse last segment off of resource string, (eg. background, font,
715	 * etc.)
716	 */
717	last_token = _get_last_part (remainder, &last_part);
718	/*
719	 * this case covers resources of only one level (eg. *background)
720	 */
721	if (remainder[0] == 0) {
722		_set_resource_values (w, resource, value, last_part);
723		if (last_token == '*')
724			_apply_values_to_children (parent, remainder, resource,
725				value, last_token, last_part);
726	/*
727	 * all other resource strings are recursively applied to the widget tree.
728	 * Prepend a '.' to the remainder string if there is no leading token.
729	 */
730	} else {
731		if (remainder[0] != '*' && remainder[0] != '.') {
732			XtAsprintf (&copy, ".%s", remainder);
733			XtFree (remainder);
734			remainder = copy;
735		}
736		indx = remainder;
737		_set_and_search (parent, indx, remainder, resource, value,
738			last_token, last_part);
739	}
740
741	XtFree (remainder);
742	XtFree (last_part);
743}
744
745/*
746 * NAME: _locate_children
747 *
748 * FUNCTION:
749 *	returns a list of all of a widget's children
750 *
751 * PARAMETERS:
752 *	w		the parent to search for its children
753 *	children	the list of children that is created
754 *	normal		flag for normal children
755 *	popup		flag for popup children
756 *
757 * RETURN VALUES:
758 *	int		the number of children
759 *	children	the list of children found
760 *
761 * ERRORS: none
762 */
763static int
764_locate_children (
765	Widget parent,
766	Widget **children)
767{
768	CompositeWidget comp = (CompositeWidget) parent;
769	Cardinal	i;
770	int	num_children = 0;
771	int	current = 0;
772
773	/*
774	 * count the number of children
775	 */
776	if (XtIsWidget (parent))
777		num_children += parent->core.num_popups;
778	if (XtIsComposite (parent))
779		num_children += comp->composite.num_children;
780	if (num_children == 0) {
781		*children = NULL;
782		return (0);
783	}
784
785	*children = (Widget *)
786		XtMalloc ((Cardinal) sizeof(Widget) * num_children);
787
788	if (XtIsComposite (parent)) {
789		for (i=0; i<comp->composite.num_children; i++) {
790			(*children)[current] = comp->composite.children[i];
791			current++;
792		}
793	}
794
795	if (XtIsWidget (parent)) {
796		for (i=0; i<parent->core.num_popups; i++) {
797			(*children)[current] = comp->core.popup_list[i];
798			current++;
799		}
800	}
801
802	return (num_children);
803}
804
805#ifdef DEBUG
806/*
807 * NAME: dump_widget_tree
808 *
809 * FUNCTION:
810 *	recursively printout entire widget tree
811 *
812 * PARAMETERS:
813 *	w		the widget to match
814 *	indent		the amount to indent each line
815 *
816 * RETURN VALUES: void
817 *
818 * ERRORS: none
819 */
820static void
821dump_widget_tree (
822	Widget w,
823	int	indent)
824{
825	int 	i,j;
826	int	num_children;
827	Widget	*children;
828
829	/*
830	 * Recursively search through the children
831	 */
832	num_children = _locate_children (w, &children);
833	indent += 2;
834	for (i=0; i<num_children; i++) {
835		if (children[i] != NULL) {
836			for (j=0; j<indent; j++)
837				fprintf (stderr, " ");
838			if (XtIsWidget (children[i])) {
839				fprintf (stderr, "(%s)\t",children[i]->core.name);
840				fprintf (stderr, "(%s)\n",
841			children[i]->core.widget_class->core_class.class_name);
842			} else {
843				fprintf (stderr, "(NULL)\t");
844				fprintf (stderr, "(%s)\n",
845			children[i]->core.widget_class->core_class.class_name);
846			}
847		}
848		dump_widget_tree (children[i], indent);
849	}
850
851	XtFree ((char *)children);
852}
853#endif
854
855/*
856 * NAME: _XtResourceConfiguationEH
857 *
858 * FUNCTION:
859 *	This function is the event handler for the on-the-fly communication
860 *	with a resource customization tool.  This event handler must be
861 *      registered for the toplevel shell of each app.  This is best done
862 *      in the _XtCreatePopupShell and _XtAppCreateShell functions in Xt's
863 *	Create.c source file.
864 *
865 * 	The property used to communicate with a customizing tool is
866 *	placed on the toplevel shell window of the application.  The
867 *	customizing tool places a property on this window which causes
868 *	this event handler to be invoked via the PropertyNotify event.
869 *	This event handler reads the property and then deletes it from
870 *	the server.  The contents of the property are a resource string
871 *	and value.  The event handler then calls functions to walk the
872 *	applications widget tree, determining which widgets are affected
873 *	by the resource string, and then applying the value with XtSetValues.
874 *
875 * PARAMETERS:
876 *	w		the widget that invoked this event handler
877 *	client_data	not used
878 *	event		the event structure
879 *
880 * RETURN VALUES: none
881 *
882 * ERRORS: none
883 */
884/* ARGSUSED */
885void
886_XtResourceConfigurationEH (
887	Widget w,
888	XtPointer client_data,
889	XEvent *event)
890{
891	Atom		actual_type;
892	int		actual_format;
893	unsigned long	nitems;
894	unsigned long	leftover;
895	char		*data = NULL;
896	unsigned long	resource_len;
897	char		*data_ptr;
898	char		*resource;
899	char		*value;
900#ifdef DEBUG
901	int		indent = 0;
902#endif
903	XtPerDisplay	pd;
904
905#ifdef DEBUG
906	fprintf (stderr, "in _XtResourceConfiguationEH atom = %u\n",(unsigned) event->xproperty.atom);
907	fprintf (stderr, "    window = %x\n", (unsigned) XtWindow (w));
908	if (XtIsWidget (w))
909		fprintf (stderr, "    widget = %zx   name = %s\n", (size_t)w, w->core.name);
910#endif
911
912	pd = _XtGetPerDisplay (XtDisplay (w));
913
914	/*
915	 * The window on which a customizing tool places the property
916	 * is determined at this point.  It should be the applications
917	 * toplevel shell window.
918	 *
919	 * A customizing tool sends a "ping" to the application on
920	 * the RCM_INIT property.  The application answers the ping
921	 * by deleting the property.
922	 */
923	if (event->xproperty.atom == pd->rcm_init) {
924		XDeleteProperty (XtDisplay(w), XtWindow (w), pd->rcm_init);
925
926#ifdef DEBUG
927		if (XtIsWidget (w))
928			fprintf (stderr, "%s\n", w->core.name);
929		else
930			fprintf (stderr, "NULL name\n");
931		dump_widget_tree(w, indent);
932
933		fprintf (stderr, "answer ping\n");
934#endif
935	}
936
937	/*
938	 * This event handler ignores any property notify events that
939	 * are not RCM_INIT or RCM_DATA
940	 */
941	if (event->xproperty.atom != pd->rcm_data)
942		return;
943
944	/*
945	 * Retrieve the data from the property
946	 */
947#ifdef DEBUG
948	fprintf (stderr, "receiving RCM_DATA property\n");
949#endif
950	if (XGetWindowProperty (XtDisplay(w),
951		XtWindow (w),
952		pd->rcm_data, 0L, 8192L,
953		TRUE, XA_STRING,
954		&actual_type, &actual_format, &nitems, &leftover,
955		(unsigned char **)&data ) == Success && actual_type == XA_STRING
956			   && actual_format == 8) {
957	/*
958	 *      data format is:
959	 *
960	 *      resource_length, resource, value
961	 *
962	 *      convert the resource_length to a long, skip over it, put a
963	 *      zero byte at the end of the resource, and pick off the
964	 *      resource and value fields.
965	 */
966		if (data) {
967			char *data_end = data + nitems;
968			char *data_value;
969
970			resource_len = strtoul (data, &data_ptr, 10);
971
972			if (data_ptr != (char *) data) {
973				data_ptr++;
974				data_value = data_ptr + resource_len;
975			} else /* strtoul failed to convert a number */
976				data_ptr = data_value = NULL;
977
978			if (data_value > data_ptr && data_value < data_end) {
979				*data_value++ = '\0';
980
981				resource = XtNewString (data_ptr);
982				value = XtNewString (data_value);
983#ifdef DEBUG
984				fprintf (stderr, "resource_len=%lu\n",
985					 resource_len);
986				fprintf (stderr, "resource = %s\t value = %s\n",
987					 resource, value);
988#endif
989				/*
990				 * descend the application widget tree and
991				 * apply the value to the appropriate widgets
992				 */
993				_search_widget_tree (w, resource, value);
994
995				XtFree (resource);
996				XtFree (value);
997			}
998		}
999	}
1000
1001	if (data)
1002		XFree ((char *)data);
1003}
1004