Imported Upstream version 1.1.2
[platform/upstream/libXmu.git] / src / WidgetNode.c
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 *
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
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 *
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
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
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
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
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 *
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 }