1/*
2
3Copyright 1989, 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 * Author:  Jim Fulton, MIT X Consortium
29 */
30
31
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36#include <stdio.h>
37#include <stdlib.h>
38#include <X11/Xos.h>
39#include <X11/IntrinsicP.h>
40#include <X11/Xmu/CharSet.h>
41#include <X11/Xmu/WidgetNode.h>
42
43/*
44 * Prototypes
45 */
46static char *binsearch(char*, char*, int, int,
47		       int (*__compar)(_Xconst void*, _Xconst void*));
48static int compare_resource_entries(_Xconst void *a,  _Xconst void *b);
49static XmuWidgetNode *find_resource(XmuWidgetNode*, _Xconst char*, Bool);
50static void mark_resource_owner(XmuWidgetNode*);
51/*
52 * Implementation
53 */
54static char *
55binsearch(char *key, char *base, int nelems, int elemsize,
56	  int compar(_Xconst void*, _Xconst void*))
57     /*
58      * key		- template of object to find
59      * base		- beginning of array
60      * nelems		- number of elements in array
61      * elemsize	- sizeof an element
62      * compar		- qsort-style compare function
63      */
64{
65    int lower = 0, upper = nelems - 1;
66
67    while (lower <= upper) {
68	int middle = (lower + upper) / 2;
69	char *p = base + middle * elemsize;
70	int res = (*compar) (p, key);
71
72	if (res < 0) {
73	    lower = middle + 1;
74	} else if (res == 0) {
75	    return p;
76	} else {
77	    upper = middle - 1;
78	}
79    }
80
81    return NULL;
82}
83
84
85static int
86compare_resource_entries(register _Xconst void *a,
87			 register _Xconst void *b)
88{
89    return strcmp (((_Xconst XtResource *)a)->resource_name,
90		   ((_Xconst XtResource *)b)->resource_name);
91}
92
93
94static XmuWidgetNode *
95find_resource(XmuWidgetNode *node, _Xconst char *name, Bool cons)
96{
97    register XmuWidgetNode *sup;
98    XtResource res;
99
100#define reslist ((char *) (cons ? sup->constraints : sup->resources))
101#define nreslist (int) (cons ? sup->nconstraints : sup->nresources)
102
103    res.resource_name = name;
104    for (sup = node->superclass;
105	 sup && (XtResourceList) binsearch ((char *) &res,
106					    reslist, nreslist,
107					    sizeof(XtResource),
108					    compare_resource_entries);
109	 node = sup, sup = sup->superclass) ;
110
111#undef reslist
112#undef nreslist
113
114    return node;
115}
116
117
118static void
119mark_resource_owner(register XmuWidgetNode *node)
120{
121    register Cardinal i;
122    XtResourceList childres;
123
124    childres = node->resources;
125    for (i = 0; i < node->nresources; i++, childres++) {
126	node->resourcewn[i] = find_resource (node, childres->resource_name,
127					     False);
128    }
129
130    childres = node->constraints;
131    for (i = 0; i < node->nconstraints; i++, childres++) {
132	node->constraintwn[i] = find_resource (node, childres->resource_name,
133						True);
134    }
135}
136
137
138/*
139 * 			       Public Interfaces
140 */
141
142void
143XmuWnInitializeNodes(XmuWidgetNode *nodearray, int nnodes)
144{
145    int i;
146    XmuWidgetNode *wn;
147
148    /*
149     * Assume that the node array is in alphabetic order, so we need to
150     * search backwards to make sure that the children are listed forward.
151     */
152    for (i = nnodes - 1, wn = nodearray + (nnodes - 1); i >= 0; i--, wn--) {
153	WidgetClass superclass = XmuWnSuperclass(wn);
154	int j;
155	XmuWidgetNode *swn;
156	int lablen = strlen (wn->label);
157	int namelen = strlen (XmuWnClassname(wn));
158
159	wn->lowered_label = XtMalloc (lablen + namelen + 2);
160#if 0
161	/* XtMalloc exits if failed */
162	if (!wn->lowered_label) {
163	    fprintf (stderr,
164		     "%s:  unable to allocate %d bytes for widget name\n",
165		     "XmuWnInitializeNodes", lablen + namelen + 2);
166	    exit (1);
167	}
168#endif
169	wn->lowered_classname = wn->lowered_label + (lablen + 1);
170	XmuCopyISOLatin1Lowered (wn->lowered_label, wn->label);
171	XmuCopyISOLatin1Lowered (wn->lowered_classname, XmuWnClassname(wn));
172	wn->superclass = NULL;
173	wn->have_resources = False;
174	wn->resources = NULL;
175	wn->resourcewn = NULL;
176	wn->nresources = 0;
177	wn->constraints = NULL;
178	wn->constraintwn = NULL;
179	wn->nconstraints = 0;
180	wn->data = (XtPointer) NULL;
181
182	/*
183	 * walk up the superclass chain
184	 */
185	while (superclass) {
186	    for (j = 0, swn = nodearray; j < nnodes; j++, swn++) {
187		if (superclass == XmuWnClass(swn)) {
188		    wn->superclass = swn;
189		    goto done;		/* stupid C language */
190	        }
191	    }
192	    /*
193	     * Hmm, we have a hidden superclass (such as in core in R4); just
194	     * ignore it and keep on walking
195	     */
196	    superclass = superclass->core_class.superclass;
197	}
198      done:
199	if (wn->superclass) {
200	    wn->siblings = wn->superclass->children;
201	    wn->superclass->children = wn;
202	}
203    }
204
205    return;
206}
207
208
209void
210XmuWnFetchResources(XmuWidgetNode *node, Widget toplevel,
211		    XmuWidgetNode *topnode)
212{
213    Widget dummy;
214    XmuWidgetNode *wn;
215
216    if (node->have_resources) return;
217
218    dummy = XtCreateWidget (node->label, XmuWnClass(node), toplevel,
219			    NULL, 0);
220    if (dummy) XtDestroyWidget (dummy);
221
222
223    /*
224     * walk up tree getting resources; since we've instantiated the widget,
225     * we know that all of our superclasses have been initialized
226     */
227    for (wn = node; wn && !wn->have_resources; wn = wn->superclass) {
228	XtGetResourceList (XmuWnClass(wn), &wn->resources, &wn->nresources);
229	if (wn->resources) {
230	    qsort ((char *) wn->resources, wn->nresources,
231		   sizeof(XtResource), compare_resource_entries);
232	}
233	wn->resourcewn = (XmuWidgetNode **) XtCalloc (wn->nresources,
234						  sizeof (XmuWidgetNode *));
235	if (!wn->resourcewn) {
236	    fprintf (stderr,
237		     "%s:  unable to calloc %d %ld byte widget node ptrs\n",
238		     "XmuWnFetchResources", wn->nresources,
239		     (unsigned long)sizeof (XmuWidgetNode *));
240	    exit (1);
241	}
242
243	XtGetConstraintResourceList (XmuWnClass(wn), &wn->constraints,
244				     &wn->nconstraints);
245	if (wn->constraints) {
246	    qsort ((char *) wn->constraints, wn->nconstraints,
247		   sizeof(XtResource), compare_resource_entries);
248	}
249	wn->constraintwn = (XmuWidgetNode **)
250	  XtCalloc (wn->nconstraints, sizeof (XmuWidgetNode *));
251	if (!wn->constraintwn) {
252	    fprintf (stderr,
253		     "%s:  unable to calloc %d %ld byte widget node ptrs\n",
254		     "XmuWnFetchResources", wn->nconstraints,
255		     (unsigned long)sizeof (XmuWidgetNode *));
256	    exit (1);
257	}
258
259	wn->have_resources = True;
260	if (wn == topnode) break;
261    }
262
263
264    /*
265     * Walk up tree removing all resources that appear in superclass; we can
266     * mash the resource list in place since it was copied out of widget.
267     */
268    for (wn = node; wn; wn = wn->superclass) {
269	mark_resource_owner (wn);
270	if (wn == topnode) break;
271    }
272
273    return;
274}
275
276
277int
278XmuWnCountOwnedResources(XmuWidgetNode *node, XmuWidgetNode *ownernode,
279			 Bool cons)
280{
281    register int i;
282    XmuWidgetNode **wn = (cons ? node->constraintwn : node->resourcewn);
283    int nmatches = 0;
284
285    for (i = (cons ? node->nconstraints : node->nresources); i > 0; i--, wn++)
286      if (*wn == ownernode) nmatches++;
287    return nmatches;
288}
289
290
291XmuWidgetNode *
292XmuWnNameToNode(XmuWidgetNode *nodelist, int nnodes, _Xconst char *name)
293{
294    int i;
295    XmuWidgetNode *wn;
296    char tmp[1024];
297
298    XmuNCopyISOLatin1Lowered(tmp, name, sizeof(tmp));
299    for (i = 0, wn = nodelist; i < nnodes; i++, wn++) {
300	if (strcmp (tmp, wn->lowered_label) == 0 ||
301	    strcmp (tmp, wn->lowered_classname) == 0) {
302	  return wn;
303	}
304    }
305    return NULL;
306}
307