1 /*
2 
3 Copyright 1989, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in 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  */
46 static char *binsearch(char*, char*, int, int,
47 		       int (*__compar)(_Xconst void*, _Xconst void*));
48 static int compare_resource_entries(_Xconst void *a,  _Xconst void *b);
49 static XmuWidgetNode *find_resource(XmuWidgetNode*, char*, Bool);
50 static void mark_resource_owner(XmuWidgetNode*);
51 /*
52  * Implementation
53  */
54 static char *
binsearch(char * key,char * base,int nelems,int elemsize,int compar (_Xconst void *,_Xconst void *))55 binsearch(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 
85 static int
compare_resource_entries(register _Xconst void * a,register _Xconst void * b)86 compare_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 
94 static XmuWidgetNode *
find_resource(XmuWidgetNode * node,char * name,Bool cons)95 find_resource(XmuWidgetNode *node, 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 
118 static void
mark_resource_owner(register XmuWidgetNode * node)119 mark_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 
142 void
XmuWnInitializeNodes(XmuWidgetNode * nodearray,int nnodes)143 XmuWnInitializeNodes(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 
209 void
XmuWnFetchResources(XmuWidgetNode * node,Widget toplevel,XmuWidgetNode * topnode)210 XmuWnFetchResources(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 geting 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 
277 int
XmuWnCountOwnedResources(XmuWidgetNode * node,XmuWidgetNode * ownernode,Bool cons)278 XmuWnCountOwnedResources(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 
291 XmuWidgetNode *
XmuWnNameToNode(XmuWidgetNode * nodelist,int nnodes,_Xconst char * name)292 XmuWnNameToNode(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