Use CARD32 instead of Atom, move geom headers in
[platform/upstream/libxkbcommon.git] / src / xkbcomp / geometry.c
1 /************************************************************
2  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4  Permission to use, copy, modify, and distribute this
5  software and its documentation for any purpose and without
6  fee is hereby granted, provided that the above copyright
7  notice appear in all copies and that both that copyright
8  notice and this permission notice appear in supporting
9  documentation, and that the name of Silicon Graphics not be
10  used in advertising or publicity pertaining to distribution
11  of the software without specific prior written permission.
12  Silicon Graphics makes no representation about the suitability
13  of this software for any purpose. It is provided "as is"
14  without any express or implied warranty.
15
16  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25  ********************************************************/
26
27 #include "xkbcomp.h"
28 #include "xkballoc.h"
29 #include "xkbgeom.h"
30 #include "xkbmisc.h"
31 #include "tokens.h"
32 #include "expr.h"
33 #include "vmod.h"
34 #include "misc.h"
35 #include "indicators.h"
36 #include "action.h"
37 #include "keycodes.h"
38 #include "alias.h"
39
40 #define DFLT_FONT       "helvetica"
41 #define DFLT_SLANT      "r"
42 #define DFLT_WEIGHT     "medium"
43 #define DFLT_SET_WIDTH  "normal"
44 #define DFLT_VARIANT    ""
45 #define DFLT_ENCODING   "iso8859-1"
46 #define DFLT_SIZE       120
47
48 typedef struct _PropertyInfo
49 {
50     CommonInfo defs;
51     char *name;
52     char *value;
53 } PropertyInfo;
54
55 #define _GSh_Outlines   (1<<1)
56 #define _GSh_Approx     (1<<2)
57 #define _GSh_Primary    (1<<3)
58 typedef struct _ShapeInfo
59 {
60     CommonInfo defs;
61     CARD32 name;
62     short index;
63     unsigned short nOutlines;
64     unsigned short szOutlines;
65     XkbcOutlinePtr outlines;
66     XkbcOutlinePtr approx;
67     XkbcOutlinePtr primary;
68     int dfltCornerRadius;
69 } ShapeInfo;
70
71 #define shText(s) \
72     ((s) ? XkbcAtomText((s)->name) : "default shape")
73
74 #define _GD_Priority    (1<<0)
75 #define _GD_Top         (1<<1)
76 #define _GD_Left        (1<<2)
77 #define _GD_Angle       (1<<3)
78 #define _GD_Shape       (1<<4)
79 #define _GD_FontVariant (1<<4)  /* CHEATING */
80 #define _GD_Corner      (1<<5)
81 #define _GD_Width       (1<<5)  /* CHEATING */
82 #define _GD_Color       (1<<6)
83 #define _GD_OffColor    (1<<7)
84 #define _GD_Height      (1<<7)  /* CHEATING */
85 #define _GD_Text        (1<<8)
86 #define _GD_Font        (1<<9)
87 #define _GD_FontSlant   (1<<10)
88 #define _GD_FontWeight  (1<<11)
89 #define _GD_FontSetWidth (1<<12)
90 #define _GD_FontSize    (1<<13)
91 #define _GD_FontEncoding (1<<14)
92 #define _GD_FontSpec    (1<<15)
93
94
95 #define _GD_FontParts   (_GD_Font|_GD_FontSlant|_GD_FontWeight|_GD_FontSetWidth|_GD_FontSize|_GD_FontEncoding|_GD_FontVariant)
96
97 typedef struct _DoodadInfo
98 {
99     CommonInfo defs;
100     CARD32 name;
101     unsigned char type;
102     unsigned char priority;
103     short top;
104     short left;
105     short angle;
106     unsigned short corner;
107     unsigned short width;
108     unsigned short height;
109     CARD32 shape;
110     CARD32 color;
111     CARD32 offColor;
112     CARD32 text;
113     CARD32 font;
114     CARD32 fontSlant;
115     CARD32 fontWeight;
116     CARD32 fontSetWidth;
117     CARD32 fontVariant;
118     unsigned short fontSize;
119     CARD32 fontEncoding;
120     CARD32 fontSpec;
121     char *logoName;
122     struct _SectionInfo *section;
123 } DoodadInfo;
124
125 #define Yes             1
126 #define No              0
127 #define Undefined       -1
128
129 #define _GK_Default     (1<<0)
130 #define _GK_Name        (1<<1)
131 #define _GK_Gap         (1<<2)
132 #define _GK_Shape       (1<<3)
133 #define _GK_Color       (1<<4)
134 typedef struct _KeyInfo
135 {
136     CommonInfo defs;
137     char name[8];
138     short gap;
139     short index;
140     CARD32 shape;
141     CARD32 color;
142     struct _RowInfo *row;
143 } KeyInfo;
144 #define keyText(k)      ((k)&&(k)->name[0]?(k)->name:"default")
145
146 #define _GR_Default     (1<<0)
147 #define _GR_Vertical    (1<<1)
148 #define _GR_Top         (1<<2)
149 #define _GR_Left        (1<<3)
150 typedef struct _RowInfo
151 {
152     CommonInfo defs;
153     unsigned short top;
154     unsigned short left;
155     short index;
156     Bool vertical;
157     unsigned short nKeys;
158     KeyInfo *keys;
159     KeyInfo dfltKey;
160     struct _SectionInfo *section;
161 } RowInfo;
162 #define rowText(r) \
163     ((r) ? XkbcAtomText((r)->section->name) : "default")
164
165 #define _GOK_UnknownRow -1
166 typedef struct _OverlayKeyInfo
167 {
168     CommonInfo defs;
169     short sectionRow;
170     short overlayRow;
171     char over[XkbKeyNameLength + 1];
172     char under[XkbKeyNameLength + 1];
173 } OverlayKeyInfo;
174
175 typedef struct _OverlayInfo
176 {
177     CommonInfo defs;
178     CARD32 name;
179     unsigned short nRows;
180     unsigned short nKeys;
181     OverlayKeyInfo *keys;
182 } OverlayInfo;
183 #define oiText(o) \
184     ((o) ? XkbcAtomText((o)->name) : "default")
185
186
187 #define _GS_Default     (1<<0)
188 #define _GS_Name        (1<<1)
189 #define _GS_Top         (1<<2)
190 #define _GS_Left        (1<<3)
191 #define _GS_Width       (1<<4)
192 #define _GS_Height      (1<<5)
193 #define _GS_Angle       (1<<6)
194 #define _GS_Priority    (1<<7)
195 typedef struct _SectionInfo
196 {
197     CommonInfo defs;
198     CARD32 name;
199     unsigned short top;
200     unsigned short left;
201     unsigned short width;
202     unsigned short height;
203     unsigned short angle;
204     unsigned short nRows;
205     unsigned short nDoodads;
206     unsigned short nOverlays;
207     unsigned char priority;
208     unsigned char nextDoodadPriority;
209     RowInfo *rows;
210     DoodadInfo *doodads;
211     RowInfo dfltRow;
212     DoodadInfo *dfltDoodads;
213     OverlayInfo *overlays;
214     struct _GeometryInfo *geometry;
215 } SectionInfo;
216 #define scText(s) \
217     ((s) ? XkbcAtomText((s)->name) : "default")
218
219 typedef struct _GeometryInfo
220 {
221     char *name;
222     unsigned fileID;
223     unsigned merge;
224     int errorCount;
225     unsigned nextPriority;
226     int nProps;
227     int nShapes;
228     int nSections;
229     int nDoodads;
230     PropertyInfo *props;
231     ShapeInfo *shapes;
232     SectionInfo *sections;
233     DoodadInfo *doodads;
234     int widthMM;
235     int heightMM;
236     CARD32 font;
237     CARD32 fontSlant;
238     CARD32 fontWeight;
239     CARD32 fontSetWidth;
240     CARD32 fontVariant;
241     unsigned fontSize;
242     CARD32 fontEncoding;
243     CARD32 fontSpec;
244     CARD32 baseColor;
245     CARD32 labelColor;
246     int dfltCornerRadius;
247     SectionInfo dfltSection;
248     DoodadInfo *dfltDoodads;
249     AliasInfo *aliases;
250 } GeometryInfo;
251
252 static char *
253 ddText(DoodadInfo * di)
254 {
255     static char buf[64];
256
257     if (di == NULL)
258     {
259         strcpy(buf, "default");
260         return buf;
261     }
262     if (di->section)
263     {
264         sprintf(buf, "%s in section %s",
265                 XkbcAtomText(di->name), scText(di->section));
266         return buf;
267     }
268     return XkbcAtomText(di->name);
269 }
270
271 /***====================================================================***/
272
273 static void
274 InitPropertyInfo(PropertyInfo * pi, GeometryInfo * info)
275 {
276     pi->defs.defined = 0;
277     pi->defs.fileID = info->fileID;
278     pi->defs.merge = info->merge;
279     pi->name = pi->value = NULL;
280     return;
281 }
282
283 static void
284 FreeProperties(PropertyInfo * pi, GeometryInfo * info)
285 {
286     PropertyInfo *tmp;
287     PropertyInfo *next;
288
289     if (info->props == pi)
290     {
291         info->props = NULL;
292         info->nProps = 0;
293     }
294     for (tmp = pi; tmp != NULL; tmp = next)
295     {
296         if (tmp->name)
297             uFree(tmp->name);
298         if (tmp->value)
299             uFree(tmp->value);
300         tmp->name = tmp->value = NULL;
301         next = (PropertyInfo *) tmp->defs.next;
302         uFree(tmp);
303     }
304     return;
305 }
306
307 static void
308 InitKeyInfo(KeyInfo * key, RowInfo * row, GeometryInfo * info)
309 {
310
311     if (key != &row->dfltKey)
312     {
313         *key = row->dfltKey;
314         strcpy(key->name, "unknown");
315         key->defs.defined &= ~_GK_Default;
316     }
317     else
318     {
319         bzero(key, sizeof(KeyInfo));
320         strcpy(key->name, "default");
321         key->defs.defined = _GK_Default;
322         key->defs.fileID = info->fileID;
323         key->defs.merge = info->merge;
324         key->defs.next = NULL;
325         key->row = row;
326     }
327     return;
328 }
329
330 static void
331 ClearKeyInfo(KeyInfo * key)
332 {
333     key->defs.defined &= ~_GK_Default;
334     strcpy(key->name, "default");
335     key->gap = 0;
336     key->shape = None;
337     key->color = None;
338     return;
339 }
340
341 static void
342 FreeKeys(KeyInfo * key, RowInfo * row, GeometryInfo * info)
343 {
344     KeyInfo *tmp;
345     KeyInfo *next;
346
347     if (row->keys == key)
348     {
349         row->nKeys = 0;
350         row->keys = NULL;
351     }
352     for (tmp = key; tmp != NULL; tmp = next)
353     {
354         ClearKeyInfo(tmp);
355         next = (KeyInfo *) tmp->defs.next;
356         uFree(tmp);
357     }
358     return;
359 }
360
361 static void
362 InitRowInfo(RowInfo * row, SectionInfo * section, GeometryInfo * info)
363 {
364     if (row != &section->dfltRow)
365     {
366         *row = section->dfltRow;
367         row->defs.defined &= ~_GR_Default;
368     }
369     else
370     {
371         bzero(row, sizeof(RowInfo *));
372         row->defs.defined = _GR_Default;
373         row->defs.fileID = info->fileID;
374         row->defs.merge = info->merge;
375         row->defs.next = NULL;
376         row->section = section;
377         row->nKeys = 0;
378         row->keys = NULL;
379         InitKeyInfo(&row->dfltKey, row, info);
380     }
381     return;
382 }
383
384 static void
385 ClearRowInfo(RowInfo * row, GeometryInfo * info)
386 {
387     row->defs.defined &= ~_GR_Default;
388     row->top = row->left = 0;
389     row->vertical = False;
390     row->nKeys = 0;
391     if (row->keys)
392         FreeKeys(row->keys, row, info);
393     ClearKeyInfo(&row->dfltKey);
394     row->dfltKey.defs.defined |= _GK_Default;
395     return;
396 }
397
398 static void
399 FreeRows(RowInfo * row, SectionInfo * section, GeometryInfo * info)
400 {
401     RowInfo *next;
402     RowInfo *tmp;
403
404     if (row == section->rows)
405     {
406         section->nRows = 0;
407         section->rows = NULL;
408     }
409     for (tmp = row; tmp != NULL; tmp = next)
410     {
411         ClearRowInfo(tmp, info);
412         next = (RowInfo *) tmp->defs.next;
413         uFree(tmp);
414     }
415     return;
416 }
417
418 static DoodadInfo *
419 FindDoodadByType(DoodadInfo * di, unsigned type)
420 {
421     while (di)
422     {
423         if (di->type == type)
424             return di;
425         di = (DoodadInfo *) di->defs.next;
426     }
427     return NULL;
428 }
429
430 static DoodadInfo *
431 FindDoodadByName(DoodadInfo * di, CARD32 name)
432 {
433     while (di)
434     {
435         if (di->name == name)
436             return di;
437         di = (DoodadInfo *) di->defs.next;
438     }
439     return NULL;
440 }
441
442 static void
443 InitDoodadInfo(DoodadInfo * di, unsigned type, SectionInfo * si,
444                GeometryInfo * info)
445 {
446     DoodadInfo *dflt;
447
448     dflt = NULL;
449     if (si && si->dfltDoodads)
450         dflt = FindDoodadByType(si->dfltDoodads, type);
451     if ((dflt == NULL) && (info->dfltDoodads))
452         dflt = FindDoodadByType(info->dfltDoodads, type);
453     if (dflt != NULL)
454     {
455         *di = *dflt;
456         di->defs.next = NULL;
457     }
458     else
459     {
460         bzero(di, sizeof(DoodadInfo));
461         di->defs.fileID = info->fileID;
462         di->type = type;
463     }
464     di->section = si;
465     if (si != NULL)
466     {
467         di->priority = si->nextDoodadPriority++;
468 #if XkbGeomMaxPriority < 255
469         if (si->nextDoodadPriority > XkbGeomMaxPriority)
470             si->nextDoodadPriority = XkbGeomMaxPriority;
471 #endif
472     }
473     else
474     {
475         di->priority = info->nextPriority++;
476         if (info->nextPriority > XkbGeomMaxPriority)
477             info->nextPriority = XkbGeomMaxPriority;
478     }
479     return;
480 }
481
482 static void
483 ClearDoodadInfo(DoodadInfo * di)
484 {
485     CommonInfo defs;
486
487     defs = di->defs;
488     bzero(di, sizeof(DoodadInfo));
489     di->defs = defs;
490     di->defs.defined = 0;
491     return;
492 }
493
494 static void
495 ClearOverlayInfo(OverlayInfo * ol)
496 {
497     if (ol && ol->keys)
498     {
499         ol->keys = (OverlayKeyInfo *) ClearCommonInfo(&ol->keys->defs);
500         ol->nKeys = 0;
501     }
502     return;
503 }
504
505 static void
506 FreeDoodads(DoodadInfo * di, SectionInfo * si, GeometryInfo * info)
507 {
508     DoodadInfo *tmp;
509     DoodadInfo *next;
510
511     if (si)
512     {
513         if (si->doodads == di)
514         {
515             si->doodads = NULL;
516             si->nDoodads = 0;
517         }
518         if (si->dfltDoodads == di)
519             si->dfltDoodads = NULL;
520     }
521     if (info->doodads == di)
522     {
523         info->doodads = NULL;
524         info->nDoodads = 0;
525     }
526     if (info->dfltDoodads == di)
527         info->dfltDoodads = NULL;
528     for (tmp = di; tmp != NULL; tmp = next)
529     {
530         next = (DoodadInfo *) tmp->defs.next;
531         ClearDoodadInfo(tmp);
532         uFree(tmp);
533     }
534     return;
535 }
536
537 static void
538 InitSectionInfo(SectionInfo * si, GeometryInfo * info)
539 {
540     if (si != &info->dfltSection)
541     {
542         *si = info->dfltSection;
543         si->defs.defined &= ~_GS_Default;
544         si->name = XkbcInternAtom("unknown", False);
545         si->priority = info->nextPriority++;
546         if (info->nextPriority > XkbGeomMaxPriority)
547             info->nextPriority = XkbGeomMaxPriority;
548     }
549     else
550     {
551         bzero(si, sizeof(SectionInfo));
552         si->defs.fileID = info->fileID;
553         si->defs.merge = info->merge;
554         si->defs.next = NULL;
555         si->geometry = info;
556         si->name = XkbcInternAtom("default", False);
557         InitRowInfo(&si->dfltRow, si, info);
558     }
559     return;
560 }
561
562 static void
563 DupSectionInfo(SectionInfo * into, SectionInfo * from, GeometryInfo * info)
564 {
565     CommonInfo defs;
566
567     defs = into->defs;
568     *into = *from;
569     into->defs.fileID = defs.fileID;
570     into->defs.merge = defs.merge;
571     into->defs.next = NULL;
572     into->dfltRow.defs.fileID = defs.fileID;
573     into->dfltRow.defs.merge = defs.merge;
574     into->dfltRow.defs.next = NULL;
575     into->dfltRow.section = into;
576     into->dfltRow.dfltKey.defs.fileID = defs.fileID;
577     into->dfltRow.dfltKey.defs.merge = defs.merge;
578     into->dfltRow.dfltKey.defs.next = NULL;
579     into->dfltRow.dfltKey.row = &into->dfltRow;
580     return;
581 }
582
583 static void
584 ClearSectionInfo(SectionInfo * si, GeometryInfo * info)
585 {
586
587     si->defs.defined &= ~_GS_Default;
588     si->name = XkbcInternAtom("default", False);
589     si->top = si->left = 0;
590     si->width = si->height = 0;
591     si->angle = 0;
592     if (si->rows)
593     {
594         FreeRows(si->rows, si, info);
595         si->rows = NULL;
596     }
597     ClearRowInfo(&si->dfltRow, info);
598     if (si->doodads)
599     {
600         FreeDoodads(si->doodads, si, info);
601         si->doodads = NULL;
602     }
603     si->dfltRow.defs.defined = _GR_Default;
604     return;
605 }
606
607 static void
608 FreeSections(SectionInfo * si, GeometryInfo * info)
609 {
610     SectionInfo *tmp;
611     SectionInfo *next;
612
613     if (si == info->sections)
614     {
615         info->nSections = 0;
616         info->sections = NULL;
617     }
618     for (tmp = si; tmp != NULL; tmp = next)
619     {
620         ClearSectionInfo(tmp, info);
621         next = (SectionInfo *) tmp->defs.next;
622         uFree(tmp);
623     }
624     return;
625 }
626
627 static void
628 FreeShapes(ShapeInfo * si, GeometryInfo * info)
629 {
630     ShapeInfo *tmp;
631     ShapeInfo *next;
632
633     if (si == info->shapes)
634     {
635         info->nShapes = 0;
636         info->shapes = NULL;
637     }
638     for (tmp = si; tmp != NULL; tmp = next)
639     {
640         if (tmp->outlines)
641         {
642             register int i;
643             for (i = 0; i < tmp->nOutlines; i++)
644             {
645                 if (tmp->outlines[i].points != NULL)
646                 {
647                     uFree(tmp->outlines[i].points);
648                     tmp->outlines[i].num_points = 0;
649                     tmp->outlines[i].points = NULL;
650                 }
651             }
652             uFree(tmp->outlines);
653             tmp->szOutlines = 0;
654             tmp->nOutlines = 0;
655             tmp->outlines = NULL;
656             tmp->primary = tmp->approx = NULL;
657         }
658         next = (ShapeInfo *) tmp->defs.next;
659         uFree(tmp);
660     }
661     return;
662 }
663
664 /***====================================================================***/
665
666 static void
667 InitGeometryInfo(GeometryInfo * info, unsigned fileID, unsigned merge)
668 {
669     bzero(info, sizeof(GeometryInfo));
670     info->fileID = fileID;
671     info->merge = merge;
672     InitSectionInfo(&info->dfltSection, info);
673     info->dfltSection.defs.defined = _GS_Default;
674     return;
675 }
676
677 static void
678 ClearGeometryInfo(GeometryInfo * info)
679 {
680     if (info->name)
681         uFree(info->name);
682     info->name = NULL;
683     if (info->props)
684         FreeProperties(info->props, info);
685     if (info->shapes)
686         FreeShapes(info->shapes, info);
687     if (info->sections)
688         FreeSections(info->sections, info);
689     info->widthMM = 0;
690     info->heightMM = 0;
691     info->dfltCornerRadius = 0;
692     ClearSectionInfo(&info->dfltSection, info);
693     info->dfltSection.defs.defined = _GS_Default;
694     if (info->aliases)
695         ClearAliases(&info->aliases);
696     return;
697 }
698
699 /***====================================================================***/
700
701 static PropertyInfo *
702 NextProperty(GeometryInfo * info)
703 {
704     PropertyInfo *pi;
705
706     pi = uTypedAlloc(PropertyInfo);
707     if (pi)
708     {
709         bzero((char *) pi, sizeof(PropertyInfo));
710         info->props = (PropertyInfo *) AddCommonInfo(&info->props->defs,
711                                                      (CommonInfo *) pi);
712         info->nProps++;
713     }
714     return pi;
715 }
716
717 static PropertyInfo *
718 FindProperty(GeometryInfo * info, char *name)
719 {
720     PropertyInfo *old;
721
722     if (!name)
723         return NULL;
724     for (old = info->props; old != NULL;
725          old = (PropertyInfo *) old->defs.next)
726     {
727         if ((old->name) && (uStringEqual(name, old->name)))
728             return old;
729     }
730     return NULL;
731 }
732
733 static Bool
734 AddProperty(GeometryInfo * info, PropertyInfo * new)
735 {
736     PropertyInfo *old;
737
738     if ((!new) || (!new->value) || (!new->name))
739         return False;
740     old = FindProperty(info, new->name);
741     if (old != NULL)
742     {
743         if ((new->defs.merge == MergeReplace)
744             || (new->defs.merge == MergeOverride))
745         {
746             if (((old->defs.fileID == new->defs.fileID)
747                  && (warningLevel > 0)) || (warningLevel > 9))
748             {
749                 WARN("Multiple definitions for the \"%s\" property\n",
750                       new->name);
751                 ACTION("Ignoring \"%s\", using \"%s\"\n", old->value,
752                         new->value);
753             }
754             if (old->value)
755                 uFree(old->value);
756             old->value = _XkbDupString(new->value);
757             return True;
758         }
759         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
760             || (warningLevel > 9))
761         {
762             WARN("Multiple definitions for \"%s\" property\n", new->name);
763             ACTION("Using \"%s\", ignoring \"%s\" \n", old->value,
764                     new->value);
765         }
766         return True;
767     }
768     old = new;
769     if ((new = NextProperty(info)) == NULL)
770         return False;
771     new->defs.next = NULL;
772     new->name = _XkbDupString(old->name);
773     new->value = _XkbDupString(old->value);
774     return True;
775 }
776
777 /***====================================================================***/
778
779 static ShapeInfo *
780 NextShape(GeometryInfo * info)
781 {
782     ShapeInfo *si;
783
784     si = uTypedAlloc(ShapeInfo);
785     if (si)
786     {
787         bzero((char *) si, sizeof(ShapeInfo));
788         info->shapes = (ShapeInfo *) AddCommonInfo(&info->shapes->defs,
789                                                    (CommonInfo *) si);
790         info->nShapes++;
791         si->dfltCornerRadius = info->dfltCornerRadius;
792     }
793     return si;
794 }
795
796 static ShapeInfo *
797 FindShape(GeometryInfo * info, CARD32 name, const char *type, const char *which)
798 {
799     ShapeInfo *old;
800
801     for (old = info->shapes; old != NULL; old = (ShapeInfo *) old->defs.next)
802     {
803         if (name == old->name)
804             return old;
805     }
806     if (type != NULL)
807     {
808         old = info->shapes;
809         WARN("Unknown shape \"%s\" for %s %s\n",
810               XkbcAtomText(name), type, which);
811         if (old)
812         {
813             ACTION("Using default shape %s instead\n", shText(old));
814             return old;
815         }
816         ACTION("No default shape; definition ignored\n");
817         return NULL;
818     }
819     return NULL;
820 }
821
822 static Bool
823 AddShape(GeometryInfo * info, ShapeInfo * new)
824 {
825     ShapeInfo *old;
826
827     old = FindShape(info, new->name, NULL, NULL);
828     if (old != NULL)
829     {
830         if ((new->defs.merge == MergeReplace)
831             || (new->defs.merge == MergeOverride))
832         {
833             ShapeInfo *next = (ShapeInfo *) old->defs.next;
834             if (((old->defs.fileID == new->defs.fileID)
835                  && (warningLevel > 0)) || (warningLevel > 9))
836             {
837                 WARN("Duplicate shape name \"%s\"\n", shText(old));
838                 ACTION("Using last definition\n");
839             }
840             *old = *new;
841             old->defs.next = &next->defs;
842             return True;
843         }
844         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
845             || (warningLevel > 9))
846         {
847             WARN("Multiple shapes named \"%s\"\n", shText(old));
848             ACTION("Using first definition\n");
849         }
850         return True;
851     }
852     old = new;
853     if ((new = NextShape(info)) == NULL)
854         return False;
855     *new = *old;
856     new->defs.next = NULL;
857     old->szOutlines = old->nOutlines = 0;
858     old->outlines = NULL;
859     old->approx = NULL;
860     old->primary = NULL;
861     return True;
862 }
863
864 /***====================================================================***/
865
866 static void
867 ReplaceDoodad(DoodadInfo * into, DoodadInfo * from)
868 {
869     CommonInfo *next;
870
871     next = into->defs.next;
872     ClearDoodadInfo(into);
873     *into = *from;
874     into->defs.next = next;
875     next = from->defs.next;
876     ClearDoodadInfo(from);
877     from->defs.next = next;
878     return;
879 }
880
881 static DoodadInfo *
882 NextDfltDoodad(SectionInfo * si, GeometryInfo * info)
883 {
884     DoodadInfo *di;
885
886     di = uTypedCalloc(1, DoodadInfo);
887     if (!di)
888         return NULL;
889     if (si)
890     {
891         si->dfltDoodads =
892             (DoodadInfo *) AddCommonInfo(&si->dfltDoodads->defs,
893                                          (CommonInfo *) di);
894     }
895     else
896     {
897         info->dfltDoodads =
898             (DoodadInfo *) AddCommonInfo(&info->dfltDoodads->defs,
899                                          (CommonInfo *) di);
900     }
901     return di;
902 }
903
904 static DoodadInfo *
905 NextDoodad(SectionInfo * si, GeometryInfo * info)
906 {
907     DoodadInfo *di;
908
909     di = uTypedCalloc(1, DoodadInfo);
910     if (di)
911     {
912         if (si)
913         {
914             si->doodads = (DoodadInfo *) AddCommonInfo(&si->doodads->defs,
915                                                        (CommonInfo *) di);
916             si->nDoodads++;
917         }
918         else
919         {
920             info->doodads =
921                 (DoodadInfo *) AddCommonInfo(&info->doodads->defs,
922                                              (CommonInfo *) di);
923             info->nDoodads++;
924         }
925     }
926     return di;
927 }
928
929 static Bool
930 AddDoodad(SectionInfo * si, GeometryInfo * info, DoodadInfo * new)
931 {
932     DoodadInfo *old;
933
934     old = FindDoodadByName((si ? si->doodads : info->doodads), new->name);
935     if (old != NULL)
936     {
937         if ((new->defs.merge == MergeReplace)
938             || (new->defs.merge == MergeOverride))
939         {
940             if (((old->defs.fileID == new->defs.fileID)
941                  && (warningLevel > 0)) || (warningLevel > 9))
942             {
943                 WARN("Multiple doodads named \"%s\"\n",
944                       XkbcAtomText(old->name));
945                 ACTION("Using last definition\n");
946             }
947             ReplaceDoodad(old, new);
948             old->section = si;
949             return True;
950         }
951         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
952             || (warningLevel > 9))
953         {
954             WARN("Multiple doodads named \"%s\"\n",
955                   XkbcAtomText(old->name));
956             ACTION("Using first definition\n");
957         }
958         return True;
959     }
960     old = new;
961     if ((new = NextDoodad(si, info)) == NULL)
962         return False;
963     ReplaceDoodad(new, old);
964     new->section = si;
965     new->defs.next = NULL;
966     return True;
967 }
968
969 static DoodadInfo *
970 FindDfltDoodadByTypeName(char *name, SectionInfo * si, GeometryInfo * info)
971 {
972     DoodadInfo *dflt = NULL;
973     unsigned type;
974
975     if (uStrCaseCmp(name, "outline") == 0)
976         type = XkbOutlineDoodad;
977     else if (uStrCaseCmp(name, "solid") == 0)
978         type = XkbSolidDoodad;
979     else if (uStrCaseCmp(name, "text") == 0)
980         type = XkbTextDoodad;
981     else if (uStrCaseCmp(name, "indicator") == 0)
982         type = XkbIndicatorDoodad;
983     else if (uStrCaseCmp(name, "logo") == 0)
984         type = XkbLogoDoodad;
985     else
986         return NULL;
987     if ((si) && (si->dfltDoodads))
988         dflt = FindDoodadByType(si->dfltDoodads, type);
989     if ((!dflt) && (info->dfltDoodads))
990         dflt = FindDoodadByType(info->dfltDoodads, type);
991     if (dflt == NULL)
992     {
993         dflt = NextDfltDoodad(si, info);
994         if (dflt != NULL)
995         {
996             dflt->name = None;
997             dflt->type = type;
998         }
999     }
1000     return dflt;
1001 }
1002
1003 /***====================================================================***/
1004
1005 static Bool
1006 AddOverlay(SectionInfo * si, GeometryInfo * info, OverlayInfo * new)
1007 {
1008     OverlayInfo *old;
1009
1010     for (old = si->overlays; old != NULL;
1011          old = (OverlayInfo *) old->defs.next)
1012     {
1013         if (old->name == new->name)
1014             break;
1015     }
1016     if (old != NULL)
1017     {
1018         if ((new->defs.merge == MergeReplace)
1019             || (new->defs.merge == MergeOverride))
1020         {
1021             if (((old->defs.fileID == new->defs.fileID)
1022                  && (warningLevel > 0)) || (warningLevel > 9))
1023             {
1024                 WARN
1025                     ("Multiple overlays named \"%s\" for section \"%s\"\n",
1026                      XkbcAtomText(old->name), XkbcAtomText(si->name));
1027                 ACTION("Using last definition\n");
1028             }
1029             ClearOverlayInfo(old);
1030             old->nKeys = new->nKeys;
1031             old->keys = new->keys;
1032             new->nKeys = 0;
1033             new->keys = NULL;
1034             return True;
1035         }
1036         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
1037             || (warningLevel > 9))
1038         {
1039             WARN("Multiple doodads named \"%s\" in section \"%s\"\n",
1040                   XkbcAtomText(old->name), XkbcAtomText(si->name));
1041             ACTION("Using first definition\n");
1042         }
1043         return True;
1044     }
1045     old = new;
1046     new = uTypedCalloc(1, OverlayInfo);
1047     if (!new)
1048     {
1049         if (warningLevel > 0)
1050         {
1051             WSGO("Couldn't allocate a new OverlayInfo\n");
1052             ACTION
1053                 ("Overlay \"%s\" in section \"%s\" will be incomplete\n",
1054                  XkbcAtomText(old->name), XkbcAtomText(si->name));
1055         }
1056         return False;
1057     }
1058     *new = *old;
1059     old->nKeys = 0;
1060     old->keys = NULL;
1061     si->overlays = (OverlayInfo *) AddCommonInfo(&si->overlays->defs,
1062                                                  (CommonInfo *) new);
1063     si->nOverlays++;
1064     return True;
1065 }
1066
1067 /***====================================================================***/
1068
1069 static SectionInfo *
1070 NextSection(GeometryInfo * info)
1071 {
1072     SectionInfo *si;
1073
1074     si = uTypedAlloc(SectionInfo);
1075     if (si)
1076     {
1077         *si = info->dfltSection;
1078         si->defs.defined &= ~_GS_Default;
1079         si->defs.next = NULL;
1080         si->nRows = 0;
1081         si->rows = NULL;
1082         info->sections =
1083             (SectionInfo *) AddCommonInfo(&info->sections->defs,
1084                                           (CommonInfo *) si);
1085         info->nSections++;
1086     }
1087     return si;
1088 }
1089
1090 static SectionInfo *
1091 FindMatchingSection(GeometryInfo * info, SectionInfo * new)
1092 {
1093     SectionInfo *old;
1094
1095     for (old = info->sections; old != NULL;
1096          old = (SectionInfo *) old->defs.next)
1097     {
1098         if (new->name == old->name)
1099             return old;
1100     }
1101     return NULL;
1102 }
1103
1104 static Bool
1105 AddSection(GeometryInfo * info, SectionInfo * new)
1106 {
1107     SectionInfo *old;
1108
1109     old = FindMatchingSection(info, new);
1110     if (old != NULL)
1111     {
1112 #ifdef NOTDEF
1113         if ((new->defs.merge == MergeReplace)
1114             || (new->defs.merge == MergeOverride))
1115         {
1116             SectionInfo *next = (SectionInfo *) old->defs.next;
1117             if (((old->defs.fileID == new->defs.fileID)
1118                  && (warningLevel > 0)) || (warningLevel > 9))
1119             {
1120                 WARN("Duplicate shape name \"%s\"\n", shText(old));
1121                 ACTION("Using last definition\n");
1122             }
1123             *old = *new;
1124             old->defs.next = &next->defs;
1125             return True;
1126         }
1127         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
1128             || (warningLevel > 9))
1129         {
1130             WARN("Multiple shapes named \"%s\"\n", shText(old));
1131             ACTION("Using first definition\n");
1132         }
1133         return True;
1134 #else
1135         WARN("Don't know how to merge sections yet\n");
1136 #endif
1137     }
1138     old = new;
1139     if ((new = NextSection(info)) == NULL)
1140         return False;
1141     *new = *old;
1142     new->defs.next = NULL;
1143     old->nRows = old->nDoodads = old->nOverlays = 0;
1144     old->rows = NULL;
1145     old->doodads = NULL;
1146     old->overlays = NULL;
1147     if (new->doodads)
1148     {
1149         DoodadInfo *di;
1150         for (di = new->doodads; di; di = (DoodadInfo *) di->defs.next)
1151         {
1152             di->section = new;
1153         }
1154     }
1155     return True;
1156 }
1157
1158 /***====================================================================***/
1159
1160 static RowInfo *
1161 NextRow(SectionInfo * si)
1162 {
1163     RowInfo *row;
1164
1165     row = uTypedAlloc(RowInfo);
1166     if (row)
1167     {
1168         *row = si->dfltRow;
1169         row->defs.defined &= ~_GR_Default;
1170         row->defs.next = NULL;
1171         row->nKeys = 0;
1172         row->keys = NULL;
1173         si->rows =
1174             (RowInfo *) AddCommonInfo(&si->rows->defs, (CommonInfo *) row);
1175         row->index = si->nRows++;
1176     }
1177     return row;
1178 }
1179
1180 static Bool
1181 AddRow(SectionInfo * si, RowInfo * new)
1182 {
1183     RowInfo *old;
1184
1185     old = new;
1186     if ((new = NextRow(si)) == NULL)
1187         return False;
1188     *new = *old;
1189     new->defs.next = NULL;
1190     old->nKeys = 0;
1191     old->keys = NULL;
1192     return True;
1193 }
1194
1195 /***====================================================================***/
1196
1197 static KeyInfo *
1198 NextKey(RowInfo * row)
1199 {
1200     KeyInfo *key;
1201
1202     key = uTypedAlloc(KeyInfo);
1203     if (key)
1204     {
1205         *key = row->dfltKey;
1206         key->defs.defined &= ~_GK_Default;
1207         key->defs.next = NULL;
1208         key->index = row->nKeys++;
1209     }
1210     return key;
1211 }
1212
1213 static Bool
1214 AddKey(RowInfo * row, KeyInfo * new)
1215 {
1216     KeyInfo *old;
1217
1218     old = new;
1219     if ((new = NextKey(row)) == NULL)
1220         return False;
1221     *new = *old;
1222     new->defs.next = NULL;
1223     row->keys =
1224         (KeyInfo *) AddCommonInfo(&row->keys->defs, (CommonInfo *) new);
1225     return True;
1226 }
1227
1228 /***====================================================================***/
1229
1230 static void
1231 MergeIncludedGeometry(GeometryInfo * into, GeometryInfo * from,
1232                       unsigned merge)
1233 {
1234     Bool clobber;
1235
1236     if (from->errorCount > 0)
1237     {
1238         into->errorCount += from->errorCount;
1239         return;
1240     }
1241     clobber = (merge == MergeOverride) || (merge == MergeReplace);
1242     if (into->name == NULL)
1243     {
1244         into->name = from->name;
1245         from->name = NULL;
1246     }
1247     if ((into->widthMM == 0) || ((from->widthMM != 0) && clobber))
1248         into->widthMM = from->widthMM;
1249     if ((into->heightMM == 0) || ((from->heightMM != 0) && clobber))
1250         into->heightMM = from->heightMM;
1251     if ((into->font == None) || ((from->font != None) && clobber))
1252         into->font = from->font;
1253     if ((into->fontSlant == None) || ((from->fontSlant != None) && clobber))
1254         into->fontSlant = from->fontSlant;
1255     if ((into->fontWeight == None) || ((from->fontWeight != None) && clobber))
1256         into->fontWeight = from->fontWeight;
1257     if ((into->fontSetWidth == None)
1258         || ((from->fontSetWidth != None) && clobber))
1259         into->fontSetWidth = from->fontSetWidth;
1260     if ((into->fontVariant == None)
1261         || ((from->fontVariant != None) && clobber))
1262         into->fontVariant = from->fontVariant;
1263     if ((into->fontSize == 0) || ((from->fontSize != 0) && clobber))
1264         into->fontSize = from->fontSize;
1265     if ((into->fontEncoding == None)
1266         || ((from->fontEncoding != None) && clobber))
1267         into->fontEncoding = from->fontEncoding;
1268     if ((into->fontSpec == None) || ((from->fontSpec != None) && clobber))
1269         into->fontSpec = from->fontSpec;
1270     if ((into->baseColor == None) || ((from->baseColor != None) && clobber))
1271         into->baseColor = from->baseColor;
1272     if ((into->labelColor == None) || ((from->labelColor != None) && clobber))
1273         into->labelColor = from->labelColor;
1274     into->nextPriority = from->nextPriority;
1275     if (from->props != NULL)
1276     {
1277         PropertyInfo *pi;
1278         for (pi = from->props; pi; pi = (PropertyInfo *) pi->defs.next)
1279         {
1280             if (!AddProperty(into, pi))
1281                 into->errorCount++;
1282         }
1283     }
1284     if (from->shapes != NULL)
1285     {
1286         ShapeInfo *si;
1287
1288         for (si = from->shapes; si; si = (ShapeInfo *) si->defs.next)
1289         {
1290             if (!AddShape(into, si))
1291                 into->errorCount++;
1292         }
1293     }
1294     if (from->sections != NULL)
1295     {
1296         SectionInfo *si;
1297
1298         for (si = from->sections; si; si = (SectionInfo *) si->defs.next)
1299         {
1300             if (!AddSection(into, si))
1301                 into->errorCount++;
1302         }
1303     }
1304     if (from->doodads != NULL)
1305     {
1306         DoodadInfo *di;
1307
1308         for (di = from->doodads; di; di = (DoodadInfo *) di->defs.next)
1309         {
1310             if (!AddDoodad(NULL, into, di))
1311                 into->errorCount++;
1312         }
1313     }
1314     if (!MergeAliases(&into->aliases, &from->aliases, merge))
1315         into->errorCount++;
1316     return;
1317 }
1318
1319 typedef void (*FileHandler) (XkbFile * /* file */ ,
1320                              XkbcDescPtr /* xkb */ ,
1321                              unsigned /* merge */ ,
1322                              GeometryInfo *     /* info */
1323     );
1324
1325 static Bool
1326 HandleIncludeGeometry(IncludeStmt * stmt, XkbcDescPtr xkb, GeometryInfo * info,
1327                       FileHandler hndlr)
1328 {
1329     unsigned newMerge;
1330     XkbFile *rtrn;
1331     GeometryInfo included;
1332     Bool haveSelf;
1333
1334     haveSelf = False;
1335     if ((stmt->file == NULL) && (stmt->map == NULL))
1336     {
1337         haveSelf = True;
1338         included = *info;
1339         bzero(info, sizeof(GeometryInfo));
1340     }
1341     else if (ProcessIncludeFile(stmt, XkmGeometryIndex, &rtrn, &newMerge))
1342     {
1343         InitGeometryInfo(&included, rtrn->id, newMerge);
1344         included.nextPriority = info->nextPriority;
1345         included.dfltCornerRadius = info->dfltCornerRadius;
1346         DupSectionInfo(&included.dfltSection, &info->dfltSection, info);
1347         (*hndlr) (rtrn, xkb, MergeOverride, &included);
1348         if (stmt->stmt != NULL)
1349         {
1350             if (included.name != NULL)
1351                 uFree(included.name);
1352             included.name = stmt->stmt;
1353             stmt->stmt = NULL;
1354         }
1355     }
1356     else
1357     {
1358         info->errorCount += 10;
1359         return False;
1360     }
1361     if ((stmt->next != NULL) && (included.errorCount < 1))
1362     {
1363         IncludeStmt *next;
1364         unsigned op;
1365         GeometryInfo next_incl;
1366
1367         for (next = stmt->next; next != NULL; next = next->next)
1368         {
1369             if ((next->file == NULL) && (next->map == NULL))
1370             {
1371                 haveSelf = True;
1372                 MergeIncludedGeometry(&included, info, next->merge);
1373                 ClearGeometryInfo(info);
1374             }
1375             else if (ProcessIncludeFile(next, XkmGeometryIndex, &rtrn, &op))
1376             {
1377                 InitGeometryInfo(&next_incl, rtrn->id, op);
1378                 next_incl.nextPriority = included.nextPriority;
1379                 next_incl.dfltCornerRadius = included.dfltCornerRadius;
1380                 DupSectionInfo(&next_incl.dfltSection,
1381                                &included.dfltSection, &included);
1382                 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
1383                 MergeIncludedGeometry(&included, &next_incl, op);
1384                 ClearGeometryInfo(&next_incl);
1385             }
1386             else
1387             {
1388                 info->errorCount += 10;
1389                 return False;
1390             }
1391         }
1392     }
1393     if (haveSelf)
1394         *info = included;
1395     else
1396     {
1397         MergeIncludedGeometry(info, &included, newMerge);
1398         ClearGeometryInfo(&included);
1399     }
1400     return (info->errorCount == 0);
1401 }
1402
1403 static int
1404 SetShapeField(ShapeInfo * si,
1405               char *field,
1406               ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1407 {
1408     ExprResult tmp;
1409
1410     if ((uStrCaseCmp(field, "radius") == 0)
1411         || (uStrCaseCmp(field, "corner") == 0)
1412         || (uStrCaseCmp(field, "cornerradius") == 0))
1413     {
1414         if (arrayNdx != NULL)
1415         {
1416             info->errorCount++;
1417             return ReportNotArray("key shape", field, shText(si));
1418         }
1419         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1420         {
1421             info->errorCount++;
1422             return ReportBadType("key shape", field, shText(si), "number");
1423         }
1424         if (si)
1425             si->dfltCornerRadius = tmp.ival;
1426         else
1427             info->dfltCornerRadius = tmp.ival;
1428         return True;
1429     }
1430     info->errorCount++;
1431     return ReportBadField("key shape", field, shText(si));
1432 }
1433
1434 static int
1435 SetShapeDoodadField(DoodadInfo * di,
1436                     char *field,
1437                     ExprDef * arrayNdx,
1438                     ExprDef * value, SectionInfo * si, GeometryInfo * info)
1439 {
1440     ExprResult tmp;
1441     const char *typeName;
1442
1443     typeName =
1444         (di->type == XkbSolidDoodad ? "solid doodad" : "outline doodad");
1445     if ((!uStrCaseCmp(field, "corner"))
1446         || (!uStrCaseCmp(field, "cornerradius")))
1447     {
1448         if (arrayNdx != NULL)
1449         {
1450             info->errorCount++;
1451             return ReportNotArray(typeName, field, ddText(di));
1452         }
1453         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1454         {
1455             info->errorCount++;
1456             return ReportBadType(typeName, field, ddText(di), "number");
1457         }
1458         di->defs.defined |= _GD_Corner;
1459         di->corner = tmp.ival;
1460         return True;
1461     }
1462     else if (uStrCaseCmp(field, "angle") == 0)
1463     {
1464         if (arrayNdx != NULL)
1465         {
1466             info->errorCount++;
1467             return ReportNotArray(typeName, field, ddText(di));
1468         }
1469         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1470         {
1471             info->errorCount++;
1472             return ReportBadType(typeName, field, ddText(di), "number");
1473         }
1474         di->defs.defined |= _GD_Angle;
1475         di->angle = tmp.ival;
1476         return True;
1477     }
1478     else if (uStrCaseCmp(field, "shape") == 0)
1479     {
1480         if (arrayNdx != NULL)
1481         {
1482             info->errorCount++;
1483             return ReportNotArray(typeName, field, ddText(di));
1484         }
1485         if (!ExprResolveString(value, &tmp, NULL, NULL))
1486         {
1487             info->errorCount++;
1488             return ReportBadType(typeName, field, ddText(di), "string");
1489         }
1490         di->shape = XkbcInternAtom(tmp.str, False);
1491         di->defs.defined |= _GD_Shape;
1492         return True;
1493     }
1494     return ReportBadField(typeName, field, ddText(di));
1495 }
1496
1497 #define FIELD_STRING    0
1498 #define FIELD_SHORT     1
1499 #define FIELD_USHORT    2
1500
1501 static int
1502 SetTextDoodadField(DoodadInfo * di,
1503                    char *field,
1504                    ExprDef * arrayNdx,
1505                    ExprDef * value, SectionInfo * si, GeometryInfo * info)
1506 {
1507     ExprResult tmp;
1508     unsigned def;
1509     unsigned type;
1510     char *typeName = "text doodad";
1511     union
1512     {
1513         CARD32 *str;
1514         short *ival;
1515         unsigned short *uval;
1516     } pField;
1517
1518     if (uStrCaseCmp(field, "angle") == 0)
1519     {
1520         if (arrayNdx != NULL)
1521         {
1522             info->errorCount++;
1523             return ReportNotArray(typeName, field, ddText(di));
1524         }
1525         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1526         {
1527             info->errorCount++;
1528             return ReportBadType(typeName, field, ddText(di), "number");
1529         }
1530         di->defs.defined |= _GD_Angle;
1531         di->angle = tmp.ival;
1532         return True;
1533     }
1534     if (uStrCaseCmp(field, "width") == 0)
1535     {
1536         type = FIELD_USHORT;
1537         pField.uval = &di->width;
1538         def = _GD_Width;
1539     }
1540     else if (uStrCaseCmp(field, "height") == 0)
1541     {
1542         type = FIELD_USHORT;
1543         pField.uval = &di->height;
1544         def = _GD_Height;
1545     }
1546     else if (uStrCaseCmp(field, "text") == 0)
1547     {
1548         type = FIELD_STRING;
1549         pField.str = &di->text;
1550         def = _GD_Text;
1551     }
1552     else if (uStrCaseCmp(field, "font") == 0)
1553     {
1554         type = FIELD_STRING;
1555         pField.str = &di->font;
1556         def = _GD_Font;
1557     }
1558     else if ((uStrCaseCmp(field, "fontslant") == 0) ||
1559              (uStrCaseCmp(field, "slant") == 0))
1560     {
1561         type = FIELD_STRING;
1562         pField.str = &di->fontSlant;
1563         def = _GD_FontSlant;
1564     }
1565     else if ((uStrCaseCmp(field, "fontweight") == 0) ||
1566              (uStrCaseCmp(field, "weight") == 0))
1567     {
1568         type = FIELD_STRING;
1569         pField.str = &di->fontWeight;
1570         def = _GD_FontWeight;
1571     }
1572     else if ((uStrCaseCmp(field, "fontwidth") == 0) ||
1573              (uStrCaseCmp(field, "setwidth") == 0))
1574     {
1575         type = FIELD_STRING;
1576         pField.str = &di->fontSetWidth;
1577         def = _GD_FontSetWidth;
1578     }
1579     else if ((uStrCaseCmp(field, "fontvariant") == 0) ||
1580              (uStrCaseCmp(field, "variant") == 0))
1581     {
1582         type = FIELD_STRING;
1583         pField.str = &di->fontVariant;
1584         def = _GD_FontVariant;
1585     }
1586     else if ((uStrCaseCmp(field, "fontencoding") == 0) ||
1587              (uStrCaseCmp(field, "encoding") == 0))
1588     {
1589         type = FIELD_STRING;
1590         pField.str = &di->fontEncoding;
1591         def = _GD_FontEncoding;
1592     }
1593     else if ((uStrCaseCmp(field, "xfont") == 0) ||
1594              (uStrCaseCmp(field, "xfontname") == 0))
1595     {
1596         type = FIELD_STRING;
1597         pField.str = &di->fontSpec;
1598         def = _GD_FontSpec;
1599     }
1600     else if (uStrCaseCmp(field, "fontsize") == 0)
1601     {
1602         type = FIELD_USHORT;
1603         pField.uval = &di->fontSize;
1604         def = _GD_FontSize;
1605     }
1606     else
1607     {
1608         return ReportBadField(typeName, field, ddText(di));
1609     }
1610     if (arrayNdx != NULL)
1611     {
1612         info->errorCount++;
1613         return ReportNotArray(typeName, field, ddText(di));
1614     }
1615     if (type == FIELD_STRING)
1616     {
1617         if (!ExprResolveString(value, &tmp, NULL, NULL))
1618         {
1619             info->errorCount++;
1620             return ReportBadType(typeName, field, ddText(di), "string");
1621         }
1622         di->defs.defined |= def;
1623         *pField.str = XkbcInternAtom(tmp.str, False);
1624     }
1625     else
1626     {
1627         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1628         {
1629             info->errorCount++;
1630             return ReportBadType(typeName, field, ddText(di), "number");
1631         }
1632         if ((type == FIELD_USHORT) && (tmp.ival < 0))
1633         {
1634             info->errorCount++;
1635             return
1636                 ReportBadType(typeName, field, ddText(di), "unsigned");
1637         }
1638         di->defs.defined |= def;
1639         if (type == FIELD_USHORT)
1640             *pField.uval = tmp.uval;
1641         else
1642             *pField.ival = tmp.ival;
1643     }
1644     return True;
1645 }
1646
1647 static int
1648 SetIndicatorDoodadField(DoodadInfo * di,
1649                         char *field,
1650                         ExprDef * arrayNdx,
1651                         ExprDef * value,
1652                         SectionInfo * si, GeometryInfo * info)
1653 {
1654     ExprResult tmp;
1655
1656     if ((uStrCaseCmp(field, "oncolor") == 0)
1657         || (uStrCaseCmp(field, "offcolor") == 0)
1658         || (uStrCaseCmp(field, "shape") == 0))
1659     {
1660         if (arrayNdx != NULL)
1661         {
1662             info->errorCount++;
1663             return ReportNotArray("indicator doodad", field, ddText(di));
1664         }
1665         if (!ExprResolveString(value, &tmp, NULL, NULL))
1666         {
1667             info->errorCount++;
1668             return ReportBadType("indicator doodad", field,
1669                                  ddText(di), "string");
1670         }
1671         if (uStrCaseCmp(field, "oncolor") == 0)
1672         {
1673             di->defs.defined |= _GD_Color;
1674             di->color = XkbcInternAtom(tmp.str, False);
1675         }
1676         else if (uStrCaseCmp(field, "offcolor") == 0)
1677         {
1678             di->defs.defined |= _GD_OffColor;
1679             di->offColor = XkbcInternAtom(tmp.str, False);
1680         }
1681         else if (uStrCaseCmp(field, "shape") == 0)
1682         {
1683             di->defs.defined |= _GD_Shape;
1684             di->shape = XkbcInternAtom(tmp.str, False);
1685         }
1686         return True;
1687     }
1688     return ReportBadField("indicator doodad", field, ddText(di));
1689 }
1690
1691 static int
1692 SetLogoDoodadField(DoodadInfo * di,
1693                    char *field,
1694                    ExprDef * arrayNdx,
1695                    ExprDef * value, SectionInfo * si, GeometryInfo * info)
1696 {
1697     ExprResult tmp;
1698     char *typeName = "logo doodad";
1699
1700     if ((!uStrCaseCmp(field, "corner"))
1701         || (!uStrCaseCmp(field, "cornerradius")))
1702     {
1703         if (arrayNdx != NULL)
1704         {
1705             info->errorCount++;
1706             return ReportNotArray(typeName, field, ddText(di));
1707         }
1708         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1709         {
1710             info->errorCount++;
1711             return ReportBadType(typeName, field, ddText(di), "number");
1712         }
1713         di->defs.defined |= _GD_Corner;
1714         di->corner = tmp.ival;
1715         return True;
1716     }
1717     else if (uStrCaseCmp(field, "angle") == 0)
1718     {
1719         if (arrayNdx != NULL)
1720         {
1721             info->errorCount++;
1722             return ReportNotArray(typeName, field, ddText(di));
1723         }
1724         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1725         {
1726             info->errorCount++;
1727             return ReportBadType(typeName, field, ddText(di), "number");
1728         }
1729         di->defs.defined |= _GD_Angle;
1730         di->angle = tmp.ival;
1731         return True;
1732     }
1733     else if (uStrCaseCmp(field, "shape") == 0)
1734     {
1735         if (arrayNdx != NULL)
1736         {
1737             info->errorCount++;
1738             return ReportNotArray(typeName, field, ddText(di));
1739         }
1740         if (!ExprResolveString(value, &tmp, NULL, NULL))
1741         {
1742             info->errorCount++;
1743             return ReportBadType(typeName, field, ddText(di), "string");
1744         }
1745         di->shape = XkbcInternAtom(tmp.str, False);
1746         di->defs.defined |= _GD_Shape;
1747         return True;
1748     }
1749     else if ((!uStrCaseCmp(field, "logoname"))
1750              || (!uStrCaseCmp(field, "name")))
1751     {
1752         if (arrayNdx != NULL)
1753         {
1754             info->errorCount++;
1755             return ReportNotArray(typeName, field, ddText(di));
1756         }
1757         if (!ExprResolveString(value, &tmp, NULL, NULL))
1758         {
1759             info->errorCount++;
1760             return ReportBadType(typeName, field, ddText(di),
1761                                  "string");
1762         }
1763         di->logoName = _XkbDupString(tmp.str);
1764         return True;
1765     }
1766     return ReportBadField(typeName, field, ddText(di));
1767 }
1768
1769 static int
1770 SetDoodadField(DoodadInfo * di,
1771                char *field,
1772                ExprDef * arrayNdx,
1773                ExprDef * value, SectionInfo * si, GeometryInfo * info)
1774 {
1775     ExprResult tmp;
1776
1777     if (uStrCaseCmp(field, "priority") == 0)
1778     {
1779         if (arrayNdx != NULL)
1780         {
1781             info->errorCount++;
1782             return ReportNotArray("doodad", field, ddText(di));
1783         }
1784         if (!ExprResolveInteger(value, &tmp, NULL, NULL))
1785         {
1786             info->errorCount++;
1787             return ReportBadType("doodad", field, ddText(di), "integer");
1788         }
1789         if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
1790         {
1791             info->errorCount++;
1792             ERROR("Doodad priority %d out of range (must be 0..%d)\n",
1793                    tmp.ival, XkbGeomMaxPriority);
1794             ACTION("Priority for doodad %s not changed", ddText(di));
1795             return False;
1796         }
1797         di->defs.defined |= _GD_Priority;
1798         di->priority = tmp.ival;
1799         return True;
1800     }
1801     else if (uStrCaseCmp(field, "left") == 0)
1802     {
1803         if (arrayNdx != NULL)
1804         {
1805             info->errorCount++;
1806             return ReportNotArray("doodad", field, ddText(di));
1807         }
1808         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1809         {
1810             info->errorCount++;
1811             return ReportBadType("doodad", field, ddText(di), "number");
1812         }
1813         di->defs.defined |= _GD_Left;
1814         di->left = tmp.ival;
1815         return True;
1816     }
1817     else if (uStrCaseCmp(field, "top") == 0)
1818     {
1819         if (arrayNdx != NULL)
1820         {
1821             info->errorCount++;
1822             return ReportNotArray("doodad", field, ddText(di));
1823         }
1824         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1825         {
1826             info->errorCount++;
1827             return ReportBadType("doodad", field, ddText(di), "number");
1828         }
1829         di->defs.defined |= _GD_Top;
1830         di->top = tmp.ival;
1831         return True;
1832     }
1833     else if (uStrCaseCmp(field, "color") == 0)
1834     {
1835         if (arrayNdx != NULL)
1836         {
1837             info->errorCount++;
1838             return ReportNotArray("doodad", field, ddText(di));
1839         }
1840         if (!ExprResolveString(value, &tmp, NULL, NULL))
1841         {
1842             info->errorCount++;
1843             return ReportBadType("doodad", field, ddText(di), "string");
1844         }
1845         di->defs.defined |= _GD_Color;
1846         di->color = XkbcInternAtom(tmp.str, False);
1847         free(tmp.str);
1848         return True;
1849     }
1850     switch (di->type)
1851     {
1852     case XkbOutlineDoodad:
1853     case XkbSolidDoodad:
1854         return SetShapeDoodadField(di, field, arrayNdx, value, si, info);
1855     case XkbTextDoodad:
1856         return SetTextDoodadField(di, field, arrayNdx, value, si, info);
1857     case XkbIndicatorDoodad:
1858         return SetIndicatorDoodadField(di, field, arrayNdx, value, si, info);
1859     case XkbLogoDoodad:
1860         return SetLogoDoodadField(di, field, arrayNdx, value, si, info);
1861     }
1862     WSGO("Unknown doodad type %d in SetDoodadField\n",
1863           (unsigned int) di->type);
1864     ACTION("Definition of %s in %s ignored\n", field, ddText(di));
1865     return False;
1866 }
1867
1868 static int
1869 SetSectionField(SectionInfo * si,
1870                 char *field,
1871                 ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1872 {
1873     unsigned short *pField;
1874     unsigned def;
1875     ExprResult tmp;
1876
1877     pField = NULL;
1878     def = 0;
1879     if (uStrCaseCmp(field, "priority") == 0)
1880     {
1881         if (arrayNdx != NULL)
1882         {
1883             info->errorCount++;
1884             return ReportNotArray("keyboard section", field, scText(si));
1885         }
1886         if (!ExprResolveInteger(value, &tmp, NULL, NULL))
1887         {
1888             info->errorCount++;
1889             ReportBadType("keyboard section", field, scText(si), "integer");
1890             return False;
1891         }
1892         if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
1893         {
1894             info->errorCount++;
1895             ERROR("Section priority %d out of range (must be 0..%d)\n",
1896                    tmp.ival, XkbGeomMaxPriority);
1897             ACTION("Priority for section %s not changed", scText(si));
1898             return False;
1899         }
1900         si->priority = tmp.ival;
1901         si->defs.defined |= _GS_Priority;
1902         return True;
1903     }
1904     else if (uStrCaseCmp(field, "top") == 0)
1905     {
1906         pField = &si->top;
1907         def = _GS_Top;
1908     }
1909     else if (uStrCaseCmp(field, "left") == 0)
1910     {
1911         pField = &si->left;
1912         def = _GS_Left;
1913     }
1914     else if (uStrCaseCmp(field, "width") == 0)
1915     {
1916         pField = &si->width;
1917         def = _GS_Width;
1918     }
1919     else if (uStrCaseCmp(field, "height") == 0)
1920     {
1921         pField = &si->height;
1922         def = _GS_Height;
1923     }
1924     else if (uStrCaseCmp(field, "angle") == 0)
1925     {
1926         pField = &si->angle;
1927         def = _GS_Angle;
1928     }
1929     else
1930     {
1931         info->errorCount++;
1932         return ReportBadField("keyboard section", field, scText(si));
1933     }
1934     if (arrayNdx != NULL)
1935     {
1936         info->errorCount++;
1937         return ReportNotArray("keyboard section", field, scText(si));
1938     }
1939     if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1940     {
1941         info->errorCount++;
1942         ReportBadType("keyboard section", field, scText(si), "number");
1943         return False;
1944     }
1945     si->defs.defined |= def;
1946     *pField = tmp.uval;
1947     return True;
1948 }
1949
1950 static int
1951 SetRowField(RowInfo * row,
1952             char *field,
1953             ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1954 {
1955     ExprResult tmp;
1956
1957     if (uStrCaseCmp(field, "top") == 0)
1958     {
1959         if (arrayNdx != NULL)
1960         {
1961             info->errorCount++;
1962             return ReportNotArray("keyboard row", field, rowText(row));
1963         }
1964         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1965         {
1966             info->errorCount++;
1967             return ReportBadType("keyboard row", field, rowText(row),
1968                                  "number");
1969         }
1970         row->defs.defined |= _GR_Top;
1971         row->top = tmp.uval;
1972     }
1973     else if (uStrCaseCmp(field, "left") == 0)
1974     {
1975         if (arrayNdx != NULL)
1976         {
1977             info->errorCount++;
1978             return ReportNotArray("keyboard row", field, rowText(row));
1979         }
1980         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1981         {
1982             info->errorCount++;
1983             return ReportBadType("keyboard row", field, rowText(row),
1984                                  "number");
1985         }
1986         row->defs.defined |= _GR_Left;
1987         row->left = tmp.uval;
1988     }
1989     else if (uStrCaseCmp(field, "vertical") == 0)
1990     {
1991         if (arrayNdx != NULL)
1992         {
1993             info->errorCount++;
1994             return ReportNotArray("keyboard row", field, rowText(row));
1995         }
1996         if (!ExprResolveBoolean(value, &tmp, NULL, NULL))
1997         {
1998             info->errorCount++;
1999             return ReportBadType("keyboard row", field, rowText(row),
2000                                  "boolean");
2001         }
2002         row->defs.defined |= _GR_Vertical;
2003         row->vertical = tmp.uval;
2004     }
2005     else
2006     {
2007         info->errorCount++;
2008         return ReportBadField("keyboard row", field, rowText(row));
2009     }
2010     return True;
2011 }
2012
2013 static int
2014 SetKeyField(KeyInfo * key,
2015             const char *field,
2016             ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
2017 {
2018     ExprResult tmp;
2019
2020     if (uStrCaseCmp(field, "gap") == 0)
2021     {
2022         if (arrayNdx != NULL)
2023         {
2024             info->errorCount++;
2025             return ReportNotArray("key", field, keyText(key));
2026         }
2027         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
2028         {
2029             info->errorCount++;
2030             return ReportBadType("key", field, keyText(key), "number");
2031         }
2032         key->defs.defined |= _GK_Gap;
2033         key->gap = tmp.ival;
2034     }
2035     else if (uStrCaseCmp(field, "shape") == 0)
2036     {
2037         if (arrayNdx != NULL)
2038         {
2039             info->errorCount++;
2040             return ReportNotArray("key", field, keyText(key));
2041         }
2042         if (!ExprResolveString(value, &tmp, NULL, NULL))
2043         {
2044             info->errorCount++;
2045             return ReportBadType("key", field, keyText(key), "string");
2046         }
2047         key->defs.defined |= _GK_Shape;
2048         key->shape = XkbcInternAtom(tmp.str, False);
2049         free(tmp.str);
2050     }
2051     else if ((uStrCaseCmp(field, "color") == 0) ||
2052              (uStrCaseCmp(field, "keycolor") == 0))
2053     {
2054         if (arrayNdx != NULL)
2055         {
2056             info->errorCount++;
2057             return ReportNotArray("key", field, keyText(key));
2058         }
2059         if (!ExprResolveString(value, &tmp, NULL, NULL))
2060         {
2061             info->errorCount++;
2062             return ReportBadType("key", field, keyText(key), "string");
2063         }
2064         key->defs.defined |= _GK_Color;
2065         key->color = XkbcInternAtom(tmp.str, False);
2066         free(tmp.str);
2067     }
2068     else if ((uStrCaseCmp(field, "name") == 0)
2069              || (uStrCaseCmp(field, "keyname") == 0))
2070     {
2071         if (arrayNdx != NULL)
2072         {
2073             info->errorCount++;
2074             return ReportNotArray("key", field, keyText(key));
2075         }
2076         if (!ExprResolveKeyName(value, &tmp, NULL, NULL))
2077         {
2078             info->errorCount++;
2079             return ReportBadType("key", field, keyText(key), "key name");
2080         }
2081         key->defs.defined |= _GK_Name;
2082         bzero(key->name, XkbKeyNameLength + 1);
2083         strncpy(key->name, tmp.keyName.name, XkbKeyNameLength);
2084     }
2085     else
2086     {
2087         info->errorCount++;
2088         return ReportBadField("key", field, keyText(key));
2089     }
2090     return True;
2091 }
2092
2093 static int
2094 SetGeometryProperty(GeometryInfo * info, char *property, ExprDef * value)
2095 {
2096     PropertyInfo pi;
2097     ExprResult result;
2098     int ret;
2099
2100     InitPropertyInfo(&pi, info);
2101     pi.name = property;
2102     if (!ExprResolveString(value, &result, NULL, NULL))
2103     {
2104         info->errorCount++;
2105         ERROR("Property values must be type string\n");
2106         ACTION("Ignoring illegal definition of \"%s\" property\n", property);
2107         return False;
2108     }
2109     pi.value = result.str;
2110     ret = AddProperty(info, &pi);
2111     free(pi.value);
2112     return ret;
2113 }
2114
2115 static int
2116 HandleGeometryVar(VarDef * stmt, XkbcDescPtr xkb, GeometryInfo * info)
2117 {
2118     ExprResult elem, field, tmp;
2119     ExprDef *ndx;
2120     DoodadInfo *di;
2121     CARD32 *pField = NULL;
2122     int ret;
2123
2124     if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
2125         return 0;               /* internal error, already reported */
2126
2127     if (elem.str) {
2128         if (uStrCaseCmp(elem.str, "shape") == 0)
2129             ret = SetShapeField(NULL, field.str, ndx, stmt->value, info);
2130         else if (uStrCaseCmp(elem.str, "key") == 0)
2131             ret = SetKeyField(&info->dfltSection.dfltRow.dfltKey,
2132                                field.str, ndx, stmt->value, info);
2133         else if (uStrCaseCmp(elem.str, "row") == 0)
2134             ret = SetRowField(&info->dfltSection.dfltRow, field.str, ndx,
2135                                stmt->value, info);
2136         else if (uStrCaseCmp(elem.str, "section") == 0)
2137             ret = SetSectionField(&info->dfltSection, field.str, ndx,
2138                                    stmt->value, info);
2139         else if (uStrCaseCmp(elem.str, "property") == 0)
2140         {
2141             if (ndx != NULL)
2142             {
2143                 info->errorCount++;
2144                 ERROR("The %s geometry property is not an array\n", field.str);
2145                 ACTION("Ignoring illegal property definition\n");
2146                 ret = False;
2147             }
2148             else {
2149                 ret = SetGeometryProperty(info, field.str, stmt->value);
2150             }
2151         }
2152         else if ((di = FindDfltDoodadByTypeName(elem.str, NULL, info)) != NULL)
2153             ret = SetDoodadField(di, field.str, ndx, stmt->value, NULL, info);
2154         else if (uStrCaseCmp(elem.str, "solid") == 0)
2155         {
2156             DoodadInfo *dflt;
2157             dflt = FindDoodadByType(info->dfltDoodads, XkbSolidDoodad);
2158             if (dflt == NULL)
2159                 dflt = NextDfltDoodad(NULL, info);
2160             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2161         }
2162         else if (uStrCaseCmp(elem.str, "outline") == 0)
2163         {
2164             DoodadInfo *dflt;
2165             dflt = FindDoodadByType(info->dfltDoodads, XkbOutlineDoodad);
2166             if (dflt == NULL)
2167                 dflt = NextDfltDoodad(NULL, info);
2168             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2169         }
2170         else if (uStrCaseCmp(elem.str, "text") == 0)
2171         {
2172             DoodadInfo *dflt;
2173             dflt = FindDoodadByType(info->dfltDoodads, XkbTextDoodad);
2174             if (dflt == NULL)
2175                 dflt = NextDfltDoodad(NULL, info);
2176             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2177         }
2178         else if (uStrCaseCmp(elem.str, "indicator") == 0)
2179         {
2180             DoodadInfo *dflt;
2181             dflt = FindDoodadByType(info->dfltDoodads, XkbIndicatorDoodad);
2182             if (dflt == NULL)
2183                 dflt = NextDfltDoodad(NULL, info);
2184             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2185         }
2186         else if (uStrCaseCmp(elem.str, "logo") == 0)
2187         {
2188             DoodadInfo *dflt;
2189             dflt = FindDoodadByType(info->dfltDoodads, XkbLogoDoodad);
2190             if (dflt == NULL)
2191                 dflt = NextDfltDoodad(NULL, info);
2192             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2193         }
2194         else
2195         {
2196             WARN("Assignment to field of unknown element\n");
2197             ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2198             ret = False;
2199         }
2200         free(elem.str);
2201         free(field.str);
2202         return ret;
2203     }
2204
2205     if ((uStrCaseCmp(field.str, "width") == 0) ||
2206         (uStrCaseCmp(field.str, "widthmm") == 0))
2207     {
2208         if (ndx != NULL)
2209         {
2210             info->errorCount++;
2211             ret = ReportNotArray("keyboard", field.str, "geometry");
2212         }
2213         else if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2214         {
2215             info->errorCount++;
2216             ret = ReportBadType("keyboard", field.str, "geometry", "number");
2217         }
2218         else if (tmp.ival < 1)
2219         {
2220             WARN("Keyboard width must be positive\n");
2221             ACTION("Ignoring illegal keyboard width %s\n",
2222                     XkbcGeomFPText(tmp.ival));
2223             ret = True;
2224         }
2225         else {
2226             if (info->widthMM != 0)
2227             {
2228                 WARN("Keyboard width multiply defined\n");
2229                 ACTION("Using last definition (%s),", XkbcGeomFPText(tmp.ival));
2230                 INFO(" ignoring first (%s)\n", XkbcGeomFPText(info->widthMM));
2231             }
2232             info->widthMM = tmp.ival;
2233             ret = True;
2234         }
2235         free(field.str);
2236         return ret;
2237     }
2238     else if ((uStrCaseCmp(field.str, "height") == 0) ||
2239              (uStrCaseCmp(field.str, "heightmm") == 0))
2240     {
2241         if (ndx != NULL)
2242         {
2243             info->errorCount++;
2244             ret = ReportNotArray("keyboard", field.str, "geometry");
2245         }
2246         if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2247         {
2248             info->errorCount++;
2249             ret = ReportBadType("keyboard", field.str, "geometry", "number");
2250         }
2251         if (tmp.ival < 1)
2252         {
2253             WARN("Keyboard height must be positive\n");
2254             ACTION("Ignoring illegal keyboard height %s\n",
2255                     XkbcGeomFPText(tmp.ival));
2256             ret = True;
2257         }
2258         else {
2259             if (info->heightMM != 0)
2260             {
2261                 WARN("Keyboard height multiply defined\n");
2262                 ACTION("Using last definition (%s),", XkbcGeomFPText(tmp.ival));
2263                 INFO(" ignoring first (%s)\n", XkbcGeomFPText(info->heightMM));
2264             }
2265             info->heightMM = tmp.ival;
2266             ret = True;
2267         }
2268         free(field.str);
2269         return ret;
2270     }
2271     else if (uStrCaseCmp(field.str, "fontsize") == 0)
2272     {
2273         if (ndx != NULL)
2274         {
2275             info->errorCount++;
2276             ret = ReportNotArray("keyboard", field.str, "geometry");
2277         }
2278         else if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2279         {
2280             info->errorCount++;
2281             ret = ReportBadType("keyboard", field.str, "geometry", "number");
2282         }
2283         else if ((tmp.ival < 40) || (tmp.ival > 2550))
2284         {
2285             info->errorCount++;
2286             ERROR("Illegal font size %d (must be 4..255)\n", tmp.ival);
2287             ACTION("Ignoring font size in keyboard geometry\n");
2288             ret = False;
2289         }
2290         else {
2291             info->fontSize = tmp.ival;
2292             ret = True;
2293         }
2294         free(field.str);
2295         return ret;
2296     }
2297     else if ((uStrCaseCmp(field.str, "color") == 0) ||
2298              (uStrCaseCmp(field.str, "basecolor") == 0))
2299     {
2300         if (ndx != NULL)
2301         {
2302             info->errorCount++;
2303             ret = ReportNotArray("keyboard", field.str, "geometry");
2304         }
2305         if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2306         {
2307             info->errorCount++;
2308             ret = ReportBadType("keyboard", field.str, "geometry", "string");
2309         }
2310         else {
2311             info->baseColor = XkbcInternAtom(tmp.str, False);
2312             free(tmp.str);
2313             ret = True;
2314         }
2315         free(field.str);
2316         return ret;
2317     }
2318     else if (uStrCaseCmp(field.str, "labelcolor") == 0)
2319     {
2320         if (ndx != NULL)
2321         {
2322             info->errorCount++;
2323             ret = ReportNotArray("keyboard", field.str, "geometry");
2324         }
2325         if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2326         {
2327             info->errorCount++;
2328             ret = ReportBadType("keyboard", field.str, "geometry", "string");
2329         }
2330         else {
2331             info->labelColor = XkbcInternAtom(tmp.str, False);
2332             free(tmp.str);
2333             ret = True;
2334         }
2335         free(field.str);
2336         return ret;
2337     }
2338     else if (uStrCaseCmp(field.str, "font") == 0)
2339     {
2340         pField = &info->font;
2341     }
2342     else if ((uStrCaseCmp(field.str, "fontslant") == 0) ||
2343              (uStrCaseCmp(field.str, "slant") == 0))
2344     {
2345         pField = &info->fontSlant;
2346     }
2347     else if ((uStrCaseCmp(field.str, "fontweight") == 0) ||
2348              (uStrCaseCmp(field.str, "weight") == 0))
2349     {
2350         pField = &info->fontWeight;
2351     }
2352     else if ((uStrCaseCmp(field.str, "fontwidth") == 0) ||
2353              (uStrCaseCmp(field.str, "setwidth") == 0))
2354     {
2355         pField = &info->fontWeight;
2356     }
2357     else if ((uStrCaseCmp(field.str, "fontencoding") == 0) ||
2358              (uStrCaseCmp(field.str, "encoding") == 0))
2359     {
2360         pField = &info->fontEncoding;
2361     }
2362     else if ((uStrCaseCmp(field.str, "xfont") == 0) ||
2363              (uStrCaseCmp(field.str, "xfontname") == 0))
2364     {
2365         pField = &info->fontSpec;
2366     }
2367     else
2368     {
2369         ret = SetGeometryProperty(info, field.str, stmt->value);
2370         free(field.str);
2371         return ret;
2372     }
2373
2374     /* fallthrough for the cases that set pField */
2375     if (ndx != NULL)
2376     {
2377         info->errorCount++;
2378         ret = ReportNotArray("keyboard", field.str, "geometry");
2379     }
2380     else if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2381     {
2382         info->errorCount++;
2383         ret = ReportBadType("keyboard", field.str, "geometry", "string");
2384     }
2385     else {
2386         *pField = XkbcInternAtom(tmp.str, False);
2387         free(tmp.str);
2388     }
2389     free(field.str);
2390     return ret;
2391 }
2392
2393 /***====================================================================***/
2394
2395 static Bool
2396 HandleShapeBody(ShapeDef * def, ShapeInfo * si, unsigned merge,
2397                 GeometryInfo * info)
2398 {
2399     OutlineDef *ol;
2400     int nOut, nPt;
2401     XkbcOutlinePtr outline;
2402     ExprDef *pt;
2403
2404     if (def->nOutlines < 1)
2405     {
2406         WARN("Shape \"%s\" has no outlines\n", shText(si));
2407         ACTION("Definition ignored\n");
2408         return True;
2409     }
2410     si->nOutlines = def->nOutlines;
2411     si->outlines = uTypedCalloc(def->nOutlines, XkbcOutlineRec);
2412     if (!si->outlines)
2413     {
2414         ERROR("Couldn't allocate outlines for \"%s\"\n", shText(si));
2415         ACTION("Definition ignored\n");
2416         info->errorCount++;
2417         return False;
2418     }
2419     for (nOut = 0, ol = def->outlines; ol != NULL;
2420          ol = (OutlineDef *) ol->common.next)
2421     {
2422         if (ol->nPoints < 1)
2423         {
2424             SetShapeField(si, XkbcAtomText(ol->field), NULL, ol->points, info);
2425             continue;
2426         }
2427         outline = NULL;
2428         outline = &si->outlines[nOut++];
2429         outline->num_points = ol->nPoints;
2430         outline->corner_radius = si->dfltCornerRadius;
2431         outline->points = uTypedCalloc(ol->nPoints, XkbcPointRec);
2432         if (!outline->points)
2433         {
2434             ERROR("Can't allocate points for \"%s\"\n", shText(si));
2435             ACTION("Definition ignored\n");
2436             /* XXX leaks */
2437             info->errorCount++;
2438             return False;
2439         }
2440         for (nPt = 0, pt = ol->points; pt != NULL;
2441              pt = (ExprDef *) pt->common.next)
2442         {
2443             outline->points[nPt].x = pt->value.coord.x;
2444             outline->points[nPt].y = pt->value.coord.y;
2445             nPt++;
2446         }
2447         if (ol->field != None)
2448         {
2449             char *str = XkbcAtomText(ol->field);
2450             if ((uStrCaseCmp(str, "approximation") == 0) ||
2451                 (uStrCaseCmp(str, "approx") == 0))
2452             {
2453                 if (si->approx == NULL)
2454                     si->approx = outline;
2455                 else
2456                 {
2457                     WARN("Multiple approximations for \"%s\"\n",
2458                           shText(si));
2459                     ACTION("Treating all but the first as normal outlines\n");
2460                 }
2461             }
2462             else if (uStrCaseCmp(str, "primary") == 0)
2463             {
2464                 if (si->primary == NULL)
2465                     si->primary = outline;
2466                 else
2467                 {
2468                     WARN("Multiple primary outlines for \"%s\"\n",
2469                           shText(si));
2470                     ACTION("Treating all but the first as normal outlines\n");
2471                 }
2472             }
2473             else
2474             {
2475                 WARN("Unknown outline type %s for \"%s\"\n", str,
2476                       shText(si));
2477                 ACTION("Treated as a normal outline\n");
2478             }
2479             free(str);
2480         }
2481     }
2482     if (nOut != si->nOutlines)
2483     {
2484         WSGO("Expected %d outlines, got %d\n",
2485               (unsigned int) si->nOutlines, nOut);
2486         si->nOutlines = nOut;
2487     }
2488     return True;
2489 }
2490
2491 static int
2492 HandleShapeDef(ShapeDef * def, XkbcDescPtr xkb, unsigned merge,
2493                GeometryInfo * info)
2494 {
2495     ShapeInfo si;
2496
2497     if (def->merge != MergeDefault)
2498         merge = def->merge;
2499
2500     bzero(&si, sizeof(ShapeInfo));
2501     si.defs.merge = merge;
2502     si.name = def->name;
2503     si.dfltCornerRadius = info->dfltCornerRadius;
2504     if (!HandleShapeBody(def, &si, merge, info))
2505         return False;
2506     if (!AddShape(info, &si))
2507         return False;
2508     return True;
2509 }
2510
2511 /***====================================================================***/
2512
2513 static int
2514 HandleDoodadDef(DoodadDef * def,
2515                 unsigned merge, SectionInfo * si, GeometryInfo * info)
2516 {
2517     ExprResult elem, field;
2518     ExprDef *ndx;
2519     DoodadInfo new;
2520     VarDef *var;
2521
2522     if (def->common.stmtType == StmtIndicatorMapDef)
2523     {
2524         def->common.stmtType = StmtDoodadDef;
2525         def->type = XkbIndicatorDoodad;
2526     }
2527     InitDoodadInfo(&new, def->type, si, info);
2528     new.name = def->name;
2529     for (var = def->body; var != NULL; var = (VarDef *) var->common.next)
2530     {
2531         if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
2532             return 0;           /* internal error, already reported */
2533         if (elem.str != NULL)
2534         {
2535             WARN("Assignment to field of unknown element in doodad %s\n",
2536                   ddText(&new));
2537             ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2538             free(elem.str);
2539         }
2540         else if (!SetDoodadField(&new, field.str, ndx, var->value, si, info)) {
2541             free(field.str);
2542             return False;
2543         }
2544         free(field.str);
2545     }
2546     if (!AddDoodad(si, info, &new))
2547         return False;
2548     ClearDoodadInfo(&new);
2549     return True;
2550 }
2551
2552 /***====================================================================***/
2553
2554 static int
2555 HandleOverlayDef(OverlayDef * def,
2556                  unsigned merge, SectionInfo * si, GeometryInfo * info)
2557 {
2558     OverlayKeyDef *keyDef;
2559     OverlayKeyInfo *key;
2560     OverlayInfo ol;
2561
2562     if ((def->nKeys < 1) && (warningLevel > 3))
2563     {
2564         WARN("Overlay \"%s\" in section \"%s\" has no keys\n",
2565               XkbcAtomText(def->name), scText(si));
2566         ACTION("Overlay ignored\n");
2567         return True;
2568     }
2569     bzero(&ol, sizeof(OverlayInfo));
2570     ol.name = def->name;
2571     for (keyDef = def->keys; keyDef;
2572          keyDef = (OverlayKeyDef *) keyDef->common.next)
2573     {
2574         key = uTypedCalloc(1, OverlayKeyInfo);
2575         if ((!key) && warningLevel > 0)
2576         {
2577             WSGO("Couldn't allocate OverlayKeyInfo\n");
2578             ACTION("Overlay %s for section %s will be incomplete\n",
2579                     XkbcAtomText(ol.name), scText(si));
2580             return False;
2581         }
2582         strncpy(key->over, keyDef->over, XkbKeyNameLength);
2583         strncpy(key->under, keyDef->under, XkbKeyNameLength);
2584         key->sectionRow = _GOK_UnknownRow;
2585         key->overlayRow = _GOK_UnknownRow;
2586         ol.keys = (OverlayKeyInfo *) AddCommonInfo(&ol.keys->defs,
2587                                                    (CommonInfo *) key);
2588         ol.nKeys++;
2589     }
2590     if (!AddOverlay(si, info, &ol))
2591         return False;
2592     ClearOverlayInfo(&ol);
2593     return True;
2594 }
2595
2596 /***====================================================================***/
2597
2598 static Bool
2599 HandleComplexKey(KeyDef * def, KeyInfo * key, GeometryInfo * info)
2600 {
2601     RowInfo *row;
2602     ExprDef *expr;
2603
2604     row = key->row;
2605     for (expr = def->expr; expr != NULL; expr = (ExprDef *) expr->common.next)
2606     {
2607         if (expr->op == OpAssign)
2608         {
2609             ExprResult elem, f;
2610             ExprDef *ndx;
2611             if (ExprResolveLhs(expr->value.binary.left, &elem, &f, &ndx) == 0)
2612                 return False;   /* internal error, already reported */
2613             if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "key") == 0))
2614             {
2615                 if (!SetKeyField
2616                     (key, f.str, ndx, expr->value.binary.right, info))
2617                     return False;
2618             }
2619             else
2620             {
2621                 ERROR("Illegal element used in a key definition\n");
2622                 ACTION("Assignment to %s.%s ignored\n", elem.str, f.str);
2623                 return False;
2624             }
2625         }
2626         else
2627         {
2628             switch (expr->type)
2629             {
2630             case TypeInt:
2631             case TypeFloat:
2632                 if (!SetKeyField(key, "gap", NULL, expr, info))
2633                     return False;
2634                 break;
2635             case TypeString:
2636                 if (!SetKeyField(key, "shape", NULL, expr, info))
2637                     return False;
2638                 break;
2639             case TypeKeyName:
2640                 if (!SetKeyField(key, "name", NULL, expr, info))
2641                     return False;
2642                 break;
2643             default:
2644                 ERROR("Cannot determine field for unnamed expression\n");
2645                 ACTION("Ignoring key %d in row %d of section %s\n",
2646                         row->nKeys + 1, row->section->nRows + 1,
2647                         rowText(row));
2648                 return False;
2649             }
2650         }
2651     }
2652     return True;
2653 }
2654
2655 static Bool
2656 HandleRowBody(RowDef * def, RowInfo * row, unsigned merge,
2657               GeometryInfo * info)
2658 {
2659     KeyDef *keyDef;
2660
2661     if ((def->nKeys < 1) && (warningLevel > 3))
2662     {
2663         ERROR("Row in section %s has no keys\n", rowText(row));
2664         ACTION("Section ignored\n");
2665         return True;
2666     }
2667     for (keyDef = def->keys; keyDef != NULL;
2668          keyDef = (KeyDef *) keyDef->common.next)
2669     {
2670         if (keyDef->common.stmtType == StmtVarDef)
2671         {
2672             VarDef *var = (VarDef *) keyDef;
2673             ExprResult elem, field;
2674             ExprDef *ndx;
2675             if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
2676                 return 0;       /* internal error, already reported */
2677             if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "row") == 0))
2678             {
2679                 if (!SetRowField(row, field.str, ndx, var->value, info))
2680                     return False;
2681             }
2682             else if (uStrCaseCmp(elem.str, "key") == 0)
2683             {
2684                 if (!SetKeyField
2685                     (&row->dfltKey, field.str, ndx, var->value, info))
2686                     return False;
2687             }
2688             else
2689             {
2690                 WARN("Assignment to field of unknown element in row\n");
2691                 ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2692             }
2693         }
2694         else if (keyDef->common.stmtType == StmtKeyDef)
2695         {
2696             KeyInfo key;
2697             InitKeyInfo(&key, row, info);
2698             if (keyDef->name != NULL)
2699             {
2700                 int len = strlen(keyDef->name);
2701                 if ((len < 1) || (len > XkbKeyNameLength))
2702                 {
2703                     ERROR("Illegal name %s for key in section %s\n",
2704                            keyDef->name, rowText(row));
2705                     ACTION("Section not compiled\n");
2706                     return False;
2707                 }
2708                 bzero(key.name, XkbKeyNameLength + 1);
2709                 strncpy(key.name, keyDef->name, XkbKeyNameLength);
2710                 key.defs.defined |= _GK_Name;
2711             }
2712             else if (!HandleComplexKey(keyDef, &key, info))
2713                 return False;
2714             if (!AddKey(row, &key))
2715                 return False;
2716         }
2717         else
2718         {
2719             WSGO("Unexpected statement (type %d) in row body\n",
2720                   keyDef->common.stmtType);
2721             return False;
2722         }
2723     }
2724     return True;
2725 }
2726
2727 static Bool
2728 HandleSectionBody(SectionDef * def,
2729                   SectionInfo * si, unsigned merge, GeometryInfo * info)
2730 {
2731     RowDef *rowDef;
2732     DoodadInfo *di;
2733
2734     for (rowDef = def->rows; rowDef != NULL;
2735          rowDef = (RowDef *) rowDef->common.next)
2736     {
2737         if (rowDef->common.stmtType == StmtVarDef)
2738         {
2739             VarDef *var = (VarDef *) rowDef;
2740             ExprResult elem, field;
2741             ExprDef *ndx;
2742             if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
2743                 return 0;       /* internal error, already reported */
2744             if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "section") == 0))
2745             {
2746                 if (!SetSectionField(si, field.str, ndx, var->value, info))
2747                 {
2748                     free(field.str);
2749                     return False;
2750                 }
2751             }
2752             else if (uStrCaseCmp(elem.str, "row") == 0)
2753             {
2754                 if (!SetRowField
2755                     (&si->dfltRow, field.str, ndx, var->value, info))
2756                 {
2757                     free(field.str);
2758                     return False;
2759                 }
2760             }
2761             else if (uStrCaseCmp(elem.str, "key") == 0)
2762             {
2763                 if (!SetKeyField(&si->dfltRow.dfltKey, field.str, ndx,
2764                                  var->value, info))
2765                 {
2766                     free(field.str);
2767                     return False;
2768                 }
2769             }
2770             else if ((di =
2771                       FindDfltDoodadByTypeName(elem.str, si, info)) != NULL)
2772             {
2773                 if (!SetDoodadField(di, field.str, ndx, var->value, si, info))
2774                 {
2775                     free(field.str);
2776                     return False;
2777                 }
2778             }
2779             else
2780             {
2781                 WARN("Assignment to field of unknown element in section\n");
2782                 ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2783             }
2784             free(field.str);
2785             free(elem.str);
2786         }
2787         else if (rowDef->common.stmtType == StmtRowDef)
2788         {
2789             RowInfo row;
2790             InitRowInfo(&row, si, info);
2791             if (!HandleRowBody(rowDef, &row, merge, info))
2792                 return False;
2793             if (!AddRow(si, &row))
2794                 return False;
2795 /*          ClearRowInfo(&row,info);*/
2796         }
2797         else if ((rowDef->common.stmtType == StmtDoodadDef) ||
2798                  (rowDef->common.stmtType == StmtIndicatorMapDef))
2799         {
2800             if (!HandleDoodadDef((DoodadDef *) rowDef, merge, si, info))
2801                 return False;
2802         }
2803         else if (rowDef->common.stmtType == StmtOverlayDef)
2804         {
2805             if (!HandleOverlayDef((OverlayDef *) rowDef, merge, si, info))
2806                 return False;
2807         }
2808         else
2809         {
2810             WSGO("Unexpected statement (type %d) in section body\n",
2811                   rowDef->common.stmtType);
2812             return False;
2813         }
2814     }
2815     if (si->nRows != def->nRows)
2816     {
2817         WSGO("Expected %d rows, found %d\n", (unsigned int) def->nRows,
2818               (unsigned int) si->nRows);
2819         ACTION("Definition of section %s might be incorrect\n", scText(si));
2820     }
2821     return True;
2822 }
2823
2824 static int
2825 HandleSectionDef(SectionDef * def,
2826                  XkbcDescPtr xkb, unsigned merge, GeometryInfo * info)
2827 {
2828     SectionInfo si;
2829
2830     if (def->merge != MergeDefault)
2831         merge = def->merge;
2832     InitSectionInfo(&si, info);
2833     si.defs.merge = merge;
2834     si.name = def->name;
2835     if (!HandleSectionBody(def, &si, merge, info))
2836         return False;
2837     if (!AddSection(info, &si))
2838         return False;
2839     return True;
2840 }
2841
2842 /***====================================================================***/
2843
2844 static void
2845 HandleGeometryFile(XkbFile * file,
2846                    XkbcDescPtr xkb, unsigned merge, GeometryInfo * info)
2847 {
2848     ParseCommon *stmt;
2849     char *failWhat;
2850
2851     if (merge == MergeDefault)
2852         merge = MergeAugment;
2853     info->name = _XkbDupString(file->name);
2854     stmt = file->defs;
2855     while (stmt)
2856     {
2857         failWhat = NULL;
2858         switch (stmt->stmtType)
2859         {
2860         case StmtInclude:
2861             if (!HandleIncludeGeometry((IncludeStmt *) stmt, xkb, info,
2862                                        HandleGeometryFile))
2863                 info->errorCount++;
2864             break;
2865         case StmtKeyAliasDef:
2866             if (!HandleAliasDef((KeyAliasDef *) stmt,
2867                                 merge, info->fileID, &info->aliases))
2868             {
2869                 info->errorCount++;
2870             }
2871             break;
2872         case StmtVarDef:
2873             if (!HandleGeometryVar((VarDef *) stmt, xkb, info))
2874                 info->errorCount++;
2875             break;
2876         case StmtShapeDef:
2877             if (!HandleShapeDef((ShapeDef *) stmt, xkb, merge, info))
2878                 info->errorCount++;
2879             break;
2880         case StmtSectionDef:
2881             if (!HandleSectionDef((SectionDef *) stmt, xkb, merge, info))
2882                 info->errorCount++;
2883             break;
2884         case StmtIndicatorMapDef:
2885         case StmtDoodadDef:
2886             if (!HandleDoodadDef((DoodadDef *) stmt, merge, NULL, info))
2887                 info->errorCount++;
2888             break;
2889         case StmtVModDef:
2890             if (!failWhat)
2891                 failWhat = "virtual modfier";
2892         case StmtInterpDef:
2893             if (!failWhat)
2894                 failWhat = "symbol interpretation";
2895         case StmtGroupCompatDef:
2896             if (!failWhat)
2897                 failWhat = "group compatibility map";
2898         case StmtKeycodeDef:
2899             if (!failWhat)
2900                 failWhat = "key name";
2901             ERROR("Interpretation files may not include other types\n");
2902             ACTION("Ignoring %s definition.\n", failWhat);
2903             info->errorCount++;
2904             break;
2905         default:
2906             WSGO("Unexpected statement type %d in HandleGeometryFile\n",
2907                   stmt->stmtType);
2908             break;
2909         }
2910         stmt = stmt->next;
2911         if (info->errorCount > 10)
2912         {
2913 #ifdef NOISY
2914             ERROR("Too many errors\n");
2915 #endif
2916             ACTION("Abandoning geometry file \"%s\"\n", file->topName);
2917             break;
2918         }
2919     }
2920     return;
2921 }
2922
2923 /***====================================================================***/
2924
2925 static Bool
2926 CopyShapeDef(XkbcGeometryPtr geom, ShapeInfo * si)
2927 {
2928     register int i, n;
2929     XkbcShapePtr shape;
2930     XkbcOutlinePtr old_outline, outline;
2931     CARD32 name;
2932
2933     si->index = geom->num_shapes;
2934     name = si->name;
2935     shape = XkbcAddGeomShape(geom, name, si->nOutlines);
2936     if (!shape)
2937     {
2938         WSGO("Couldn't allocate shape in geometry\n");
2939         ACTION("Shape %s not compiled\n", shText(si));
2940         return False;
2941     }
2942     old_outline = si->outlines;
2943     for (i = 0; i < si->nOutlines; i++, old_outline++)
2944     {
2945         outline = XkbcAddGeomOutline(shape, old_outline->num_points);
2946         if (!outline)
2947         {
2948             WSGO("Couldn't allocate outline in shape\n");
2949             ACTION("Shape %s is incomplete\n", shText(si));
2950             return False;
2951         }
2952         n = old_outline->num_points;
2953         memcpy(outline->points, old_outline->points, n * sizeof(XkbcPointRec));
2954         outline->num_points = old_outline->num_points;
2955         outline->corner_radius = old_outline->corner_radius;
2956     }
2957     if (si->approx)
2958     {
2959         n = (si->approx - si->outlines);
2960         shape->approx = &shape->outlines[n];
2961     }
2962     if (si->primary)
2963     {
2964         n = (si->primary - si->outlines);
2965         shape->primary = &shape->outlines[n];
2966     }
2967     XkbcComputeShapeBounds(shape);
2968     return True;
2969 }
2970
2971 static Bool
2972 VerifyDoodadInfo(DoodadInfo * di, GeometryInfo * info)
2973 {
2974     if ((di->defs.defined & (_GD_Top | _GD_Left)) != (_GD_Top | _GD_Left))
2975     {
2976         if (warningLevel < 9)
2977         {
2978             ERROR("No position defined for doodad %s\n",
2979                    ddText(di));
2980             ACTION("Illegal doodad ignored\n");
2981             return False;
2982         }
2983     }
2984     if ((di->defs.defined & _GD_Priority) == 0)
2985     {
2986         /* calculate priority -- should be just above previous doodad/row */
2987     }
2988     switch (di->type)
2989     {
2990     case XkbOutlineDoodad:
2991     case XkbSolidDoodad:
2992         if ((di->defs.defined & _GD_Shape) == 0)
2993         {
2994             ERROR("No shape defined for %s doodad %s\n",
2995                    (di->type == XkbOutlineDoodad ? "outline" : "filled"),
2996                    ddText(di));
2997             ACTION("Incomplete definition ignored\n");
2998             return False;
2999         }
3000         else
3001         {
3002             ShapeInfo *si;
3003             si = FindShape(info, di->shape,
3004                            (di->type ==
3005                             XkbOutlineDoodad ? "outline doodad" :
3006                             "solid doodad"), ddText(di));
3007             if (si)
3008                 di->shape = si->name;
3009             else
3010             {
3011                 ERROR("No legal shape for %s\n", ddText(di));
3012                 ACTION("Incomplete definition ignored\n");
3013                 return False;
3014             }
3015         }
3016         if ((di->defs.defined & _GD_Color) == 0)
3017         {
3018             if (warningLevel > 5)
3019             {
3020                 WARN("No color for doodad %s\n", ddText(di));
3021                 ACTION("Using black\n");
3022             }
3023             di->color = XkbcInternAtom("black", False);
3024         }
3025         break;
3026     case XkbTextDoodad:
3027         if ((di->defs.defined & _GD_Text) == 0)
3028         {
3029             ERROR("No text specified for text doodad %s\n", ddText(di));
3030             ACTION("Illegal doodad definition ignored\n");
3031             return False;
3032         }
3033         if ((di->defs.defined & _GD_Angle) == 0)
3034             di->angle = 0;
3035         if ((di->defs.defined & _GD_Color) == 0)
3036         {
3037             if (warningLevel > 5)
3038             {
3039                 WARN("No color specified for doodad %s\n", ddText(di));
3040                 ACTION("Using black\n");
3041             }
3042             di->color = XkbcInternAtom("black", False);
3043         }
3044         if ((di->defs.defined & _GD_FontSpec) != 0)
3045         {
3046             if ((di->defs.defined & _GD_FontParts) == 0)
3047                 return True;
3048             if (warningLevel < 9)
3049             {
3050                 WARN
3051                     ("Text doodad %s has full and partial font definition\n",
3052                      ddText(di));
3053                 ACTION("Full specification ignored\n");
3054             }
3055             di->defs.defined &= ~_GD_FontSpec;
3056             di->fontSpec = None;
3057         }
3058         if ((di->defs.defined & _GD_Font) == 0)
3059         {
3060             if (warningLevel > 5)
3061             {
3062                 WARN("No font specified for doodad %s\n", ddText(di));
3063                 ACTION("Using \"%s\"\n", DFLT_FONT);
3064             }
3065             di->font = XkbcInternAtom(DFLT_FONT, False);
3066         }
3067         if ((di->defs.defined & _GD_FontSlant) == 0)
3068         {
3069             if (warningLevel > 7)
3070             {
3071                 WARN("No font slant for text doodad %s\n", ddText(di));
3072                 ACTION("Using \"%s\"\n", DFLT_SLANT);
3073             }
3074             di->fontSlant = XkbcInternAtom(DFLT_SLANT, False);
3075         }
3076         if ((di->defs.defined & _GD_FontWeight) == 0)
3077         {
3078             if (warningLevel > 7)
3079             {
3080                 WARN("No font weight for text doodad %s\n", ddText(di));
3081                 ACTION("Using \"%s\"\n", DFLT_WEIGHT);
3082             }
3083             di->fontWeight = XkbcInternAtom(DFLT_WEIGHT, False);
3084         }
3085         if ((di->defs.defined & _GD_FontSetWidth) == 0)
3086         {
3087             if (warningLevel > 9)
3088             {
3089                 WARN("No font set width for text doodad %s\n", ddText(di));
3090                 ACTION("Using \"%s\"\n", DFLT_SET_WIDTH);
3091             }
3092             di->fontSetWidth = XkbcInternAtom(DFLT_SET_WIDTH, False);
3093         }
3094         if ((di->defs.defined & _GD_FontVariant) == 0)
3095         {
3096             if (warningLevel > 9)
3097             {
3098                 WARN("No font variant for text doodad %s\n", ddText(di));
3099                 ACTION("Using \"%s\"\n", DFLT_VARIANT);
3100             }
3101             di->fontVariant = XkbcInternAtom(DFLT_VARIANT, False);
3102         }
3103         if ((di->defs.defined & _GD_FontEncoding) == 0)
3104         {
3105             if (warningLevel > 7)
3106             {
3107                 WARN("No font encoding for doodad %s\n", ddText(di));
3108                 ACTION("Using \"%s\"\n", DFLT_ENCODING);
3109             }
3110             di->fontEncoding = XkbcInternAtom(DFLT_ENCODING, False);
3111         }
3112         if ((di->defs.defined & _GD_FontSize) == 0)
3113         {
3114             if (warningLevel > 7)
3115             {
3116                 WARN("No font size for text doodad %s\n", ddText(di));
3117                 ACTION("Using %s point text\n", XkbcGeomFPText(DFLT_SIZE));
3118             }
3119             di->fontSize = DFLT_SIZE;
3120         }
3121         if ((di->defs.defined & _GD_Height) == 0)
3122         {
3123             unsigned size, nLines;
3124             char *tmp;
3125             size = (di->fontSize * 120) / 100;
3126             size = (size * 254) / 720;  /* convert to mm/10 */
3127             for (nLines = 1, tmp = XkbcAtomText(di->text); *tmp; tmp++)
3128             {
3129                 if (*tmp == '\n')
3130                     nLines++;
3131             }
3132             size *= nLines;
3133             if (warningLevel > 5)
3134             {
3135                 WARN("No height for text doodad %s\n", ddText(di));
3136                 ACTION("Using calculated height %s millimeters\n",
3137                         XkbcGeomFPText(size));
3138             }
3139             di->height = size;
3140         }
3141         if ((di->defs.defined & _GD_Width) == 0)
3142         {
3143             unsigned width, tmp;
3144             char *str;
3145             width = tmp = 0;
3146             for (str = XkbcAtomText(di->text); *str; str++)
3147             {
3148                 if (*str != '\n')
3149                     tmp++;
3150                 else
3151                 {
3152                     if (tmp > width)
3153                         width = tmp;
3154                     tmp = 1;
3155                 }
3156             }
3157             if (width == 0)
3158                 width = tmp;
3159             width *= (di->height * 2) / 3;
3160             if (warningLevel > 5)
3161             {
3162                 WARN("No width for text doodad %s\n", ddText(di));
3163                 ACTION("Using calculated width %s millimeters\n",
3164                         XkbcGeomFPText(width));
3165             }
3166             di->width = width;
3167         }
3168         break;
3169     case XkbIndicatorDoodad:
3170         if ((di->defs.defined & _GD_Shape) == 0)
3171         {
3172             ERROR("No shape defined for indicator doodad %s\n", ddText(di));
3173             ACTION("Incomplete definition ignored\n");
3174             return False;
3175         }
3176         else
3177         {
3178             ShapeInfo *si;
3179             si = FindShape(info, di->shape, "indicator doodad", ddText(di));
3180             if (si)
3181                 di->shape = si->name;
3182             else
3183             {
3184                 ERROR("No legal shape for doodad %s\n", ddText(di));
3185                 ACTION("Incomplete definition ignored\n");
3186                 return False;
3187             }
3188         }
3189         if ((di->defs.defined & _GD_Color) == 0)
3190         {
3191             if (warningLevel > 5)
3192             {
3193                 WARN("No \"on\" color for indicator doodad %s\n",
3194                       ddText(di));
3195                 ACTION("Using green\n");
3196             }
3197             di->color = XkbcInternAtom("green", False);
3198         }
3199         if ((di->defs.defined & _GD_OffColor) == 0)
3200         {
3201             if (warningLevel > 5)
3202             {
3203                 WARN("No \"off\" color for indicator doodad %s\n",
3204                       ddText(di));
3205                 ACTION("Using black\n");
3206             }
3207             di->offColor = XkbcInternAtom("black", False);
3208         }
3209         break;
3210     case XkbLogoDoodad:
3211         if (di->logoName == NULL)
3212         {
3213             ERROR("No logo name defined for logo doodad %s\n", ddText(di));
3214             ACTION("Incomplete definition ignored\n");
3215             return False;
3216         }
3217         if ((di->defs.defined & _GD_Shape) == 0)
3218         {
3219             ERROR("No shape defined for logo doodad %s\n", ddText(di));
3220             ACTION("Incomplete definition ignored\n");
3221             return False;
3222         }
3223         else
3224         {
3225             ShapeInfo *si;
3226             si = FindShape(info, di->shape, "logo doodad",
3227                            ddText(di));
3228             if (si)
3229                 di->shape = si->name;
3230             else
3231             {
3232                 ERROR("No legal shape for %s\n", ddText(di));
3233                 ACTION("Incomplete definition ignored\n");
3234                 return False;
3235             }
3236         }
3237         if ((di->defs.defined & _GD_Color) == 0)
3238         {
3239             if (warningLevel > 5)
3240             {
3241                 WARN("No color for doodad %s\n", ddText(di));
3242                 ACTION("Using black\n");
3243             }
3244             di->color = XkbcInternAtom("black", False);
3245         }
3246         break;
3247     default:
3248         WSGO("Uknown doodad type %d in VerifyDoodad\n",
3249               (unsigned int) di->type);
3250         return False;
3251     }
3252     return True;
3253 }
3254
3255 #define FONT_TEMPLATE   "-*-%s-%s-%s-%s-%s-*-%d-*-*-*-*-%s"
3256
3257 static char *
3258 FontFromParts(CARD32 fontTok,
3259               CARD32 weightTok,
3260               CARD32 slantTok,
3261               CARD32 setWidthTok, CARD32 varTok, int size, CARD32 encodingTok)
3262 {
3263     int totalSize;
3264     char *font, *weight, *slant, *setWidth, *variant, *encoding;
3265     char *rtrn;
3266
3267     font = (fontTok != None ? XkbcAtomText(fontTok) : DFLT_FONT);
3268     weight = (weightTok != None ? XkbcAtomText(weightTok) : DFLT_WEIGHT);
3269     slant = (slantTok != None ? XkbcAtomText(slantTok) : DFLT_SLANT);
3270     setWidth =
3271         (setWidthTok != None ? XkbcAtomText(setWidthTok) : DFLT_SET_WIDTH);
3272     variant = (varTok != None ? XkbcAtomText(varTok) : DFLT_VARIANT);
3273     encoding =
3274         (encodingTok != None ? XkbcAtomText(encodingTok) : DFLT_ENCODING);
3275     if (size == 0)
3276         size = DFLT_SIZE;
3277     totalSize =
3278         strlen(FONT_TEMPLATE) + strlen(font) + strlen(weight) + strlen(slant);
3279     totalSize += strlen(setWidth) + strlen(variant) + strlen(encoding);
3280     rtrn = uCalloc(totalSize, 1);
3281     if (rtrn)
3282         sprintf(rtrn, FONT_TEMPLATE, font, weight, slant, setWidth, variant,
3283                 size, encoding);
3284     return rtrn;
3285 }
3286
3287 static Bool
3288 CopyDoodadDef(XkbcGeometryPtr geom,
3289               XkbcSectionPtr section, DoodadInfo * di, GeometryInfo * info)
3290 {
3291     CARD32 name;
3292     XkbcDoodadPtr doodad;
3293     XkbcColorPtr color;
3294     XkbcShapePtr shape;
3295     ShapeInfo *si;
3296
3297     if (!VerifyDoodadInfo(di, info))
3298         return False;
3299     name = di->name;
3300     doodad = XkbcAddGeomDoodad(geom, section, name);
3301     if (!doodad)
3302     {
3303         WSGO("Couldn't allocate doodad in %s\n",
3304               (section ? "section" : "geometry"));
3305         ACTION("Cannot copy doodad %s\n", ddText(di));
3306         return False;
3307     }
3308     doodad->any.type = di->type;
3309     doodad->any.priority = di->priority;
3310     doodad->any.top = di->top;
3311     doodad->any.left = di->left;
3312     switch (di->type)
3313     {
3314     case XkbOutlineDoodad:
3315     case XkbSolidDoodad:
3316         si = FindShape(info, di->shape, NULL, NULL);
3317         if (!si)
3318             return False;
3319         doodad->shape.angle = di->angle;
3320         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3321                                  geom->num_colors);
3322         shape = &geom->shapes[si->index];
3323         XkbSetShapeDoodadColor(geom, &doodad->shape, color);
3324         XkbSetShapeDoodadShape(geom, &doodad->shape, shape);
3325         break;
3326     case XkbTextDoodad:
3327         doodad->text.angle = di->angle;
3328         doodad->text.width = di->width;
3329         doodad->text.height = di->height;
3330         if (di->fontSpec == None)
3331             doodad->text.font = FontFromParts(di->font, di->fontWeight,
3332                                               di->fontSlant,
3333                                               di->fontSetWidth,
3334                                               di->fontVariant, di->fontSize,
3335                                               di->fontEncoding);
3336         else
3337             doodad->text.font = XkbcAtomGetString(di->fontSpec);
3338         doodad->text.text = XkbcAtomGetString(di->text);
3339         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3340                                  geom->num_colors);
3341         XkbSetTextDoodadColor(geom, &doodad->text, color);
3342         break;
3343     case XkbIndicatorDoodad:
3344         si = FindShape(info, di->shape, NULL, NULL);
3345         if (!si)
3346             return False;
3347         shape = &geom->shapes[si->index];
3348         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3349                                  geom->num_colors);
3350         XkbSetIndicatorDoodadShape(geom, &doodad->indicator, shape);
3351         XkbSetIndicatorDoodadOnColor(geom, &doodad->indicator, color);
3352         color = XkbcAddGeomColor(geom, XkbcAtomText(di->offColor),
3353                                  geom->num_colors);
3354         XkbSetIndicatorDoodadOffColor(geom, &doodad->indicator, color);
3355         break;
3356     case XkbLogoDoodad:
3357         si = FindShape(info, di->shape, NULL, NULL);
3358         if (!si)
3359             return False;
3360         doodad->logo.angle = di->angle;
3361         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3362                                  geom->num_colors);
3363         shape = &geom->shapes[si->index];
3364         XkbSetLogoDoodadColor(geom, &doodad->logo, color);
3365         XkbSetLogoDoodadShape(geom, &doodad->logo, shape);
3366         doodad->logo.logo_name = di->logoName;
3367         di->logoName = NULL;
3368         break;
3369     }
3370     return True;
3371 }
3372
3373 /***====================================================================***/
3374
3375 static Bool
3376 VerifyOverlayInfo(XkbcGeometryPtr geom,
3377                   XkbcSectionPtr section,
3378                   OverlayInfo * oi,
3379                   GeometryInfo * info, short rowMap[256], short rowSize[256])
3380 {
3381     register OverlayKeyInfo *ki, *next;
3382     unsigned long oKey, uKey, sKey;
3383     XkbcRowPtr row;
3384     XkbcKeyPtr key;
3385     int r, k;
3386
3387     /* find out which row each key is in */
3388     for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
3389     {
3390         oKey = KeyNameToLong(ki->over);
3391         uKey = KeyNameToLong(ki->under);
3392         for (r = 0, row = section->rows; (r < section->num_rows) && oKey;
3393              r++, row++)
3394         {
3395             for (k = 0, key = row->keys; (k < row->num_keys) && oKey;
3396                  k++, key++)
3397             {
3398                 sKey = KeyNameToLong(key->name.name);
3399                 if (sKey == oKey)
3400                 {
3401                     if (warningLevel > 0)
3402                     {
3403                         WARN
3404                             ("Key %s in section \"%s\" and overlay \"%s\"\n",
3405                              XkbcKeyNameText(key->name.name),
3406                              XkbcAtomText(section->name),
3407                              XkbcAtomText(oi->name));
3408                         ACTION("Overlay definition ignored\n");
3409                     }
3410                     oKey = 0;
3411                 }
3412                 else if (sKey == uKey)
3413                 {
3414                     ki->sectionRow = r;
3415                     oKey = 0;
3416                 }
3417             }
3418         }
3419         if ((ki->sectionRow == _GOK_UnknownRow) && (warningLevel > 0))
3420         {
3421             WARN
3422                 ("Key %s not in \"%s\", but has an overlay key in \"%s\"\n",
3423                  XkbcKeyNameText(ki->under),
3424                  XkbcAtomText(section->name),
3425                  XkbcAtomText(oi->name));
3426             ACTION("Definition ignored\n");
3427         }
3428     }
3429     /* now prune out keys that aren't in the section */
3430     while ((oi->keys != NULL) && (oi->keys->sectionRow == _GOK_UnknownRow))
3431     {
3432         next = (OverlayKeyInfo *) oi->keys->defs.next;
3433         uFree(oi->keys);
3434         oi->keys = next;
3435         oi->nKeys--;
3436     }
3437     for (ki = oi->keys; (ki != NULL) && (ki->defs.next != NULL); ki = next)
3438     {
3439         next = (OverlayKeyInfo *) ki->defs.next;
3440         if (next->sectionRow == _GOK_UnknownRow)
3441         {
3442             ki->defs.next = next->defs.next;
3443             oi->nKeys--;
3444             uFree(next);
3445             next = (OverlayKeyInfo *) ki->defs.next;
3446         }
3447     }
3448     if (oi->nKeys < 1)
3449     {
3450         ERROR("Overlay \"%s\" for section \"%s\" has no legal keys\n",
3451                XkbcAtomText(oi->name), XkbcAtomText(section->name));
3452         ACTION("Overlay definition ignored\n");
3453         return False;
3454     }
3455     /* now figure out how many rows are defined for the overlay */
3456     bzero(rowSize, sizeof(short) * 256);
3457     for (k = 0; k < 256; k++)
3458     {
3459         rowMap[k] = -1;
3460     }
3461     oi->nRows = 0;
3462     for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
3463     {
3464         if (rowMap[ki->sectionRow] == -1)
3465             rowMap[ki->sectionRow] = oi->nRows++;
3466         ki->overlayRow = rowMap[ki->sectionRow];
3467         rowSize[ki->overlayRow]++;
3468     }
3469     return True;
3470 }
3471
3472 static Bool
3473 CopyOverlayDef(XkbcGeometryPtr geom,
3474                XkbcSectionPtr section, OverlayInfo * oi, GeometryInfo * info)
3475 {
3476     CARD32 name;
3477     XkbcOverlayPtr ol;
3478     XkbcOverlayRowPtr row;
3479     XkbcOverlayKeyPtr key;
3480     OverlayKeyInfo *ki;
3481     short rowMap[256], rowSize[256];
3482     int i;
3483
3484     if (!VerifyOverlayInfo(geom, section, oi, info, rowMap, rowSize))
3485         return False;
3486     name = oi->name;
3487     ol = XkbcAddGeomOverlay(section, name, oi->nRows);
3488     if (!ol)
3489     {
3490         WSGO("Couldn't add overlay \"%s\" to section \"%s\"\n",
3491               XkbcAtomText(name), XkbcAtomText(section->name));
3492         return False;
3493     }
3494     for (i = 0; i < oi->nRows; i++)
3495     {
3496         int tmp, row_under;
3497         for (tmp = 0, row_under = -1;
3498              (tmp < section->num_rows) && (row_under < 0); tmp++)
3499         {
3500             if (rowMap[tmp] == i)
3501                 row_under = tmp;
3502         }
3503         if (!XkbcAddGeomOverlayRow(ol, row_under, rowSize[i]))
3504         {
3505             WSGO
3506                 ("Can't add row %d to overlay \"%s\" of section \"%s\"\n",
3507                  i, XkbcAtomText(name), XkbcAtomText(section->name));
3508             return False;
3509         }
3510     }
3511     for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
3512     {
3513         row = &ol->rows[ki->overlayRow];
3514         key = &row->keys[row->num_keys++];
3515         bzero(key, sizeof(XkbcOverlayKeyRec));
3516         strncpy(key->over.name, ki->over, XkbKeyNameLength);
3517         strncpy(key->under.name, ki->under, XkbKeyNameLength);
3518     }
3519     return True;
3520 }
3521
3522 /***====================================================================***/
3523
3524 static Bool
3525 CopySectionDef(XkbcGeometryPtr geom, SectionInfo * si, GeometryInfo * info)
3526 {
3527     XkbcSectionPtr section;
3528     XkbcRowPtr row;
3529     XkbcKeyPtr key;
3530     KeyInfo *ki;
3531     RowInfo *ri;
3532
3533     section = XkbcAddGeomSection(geom, si->name, si->nRows, si->nDoodads,
3534                                  si->nOverlays);
3535     if (section == NULL)
3536     {
3537         WSGO("Couldn't allocate section in geometry\n");
3538         ACTION("Section %s not compiled\n", scText(si));
3539         return False;
3540     }
3541     section->top = si->top;
3542     section->left = si->left;
3543     section->width = si->width;
3544     section->height = si->height;
3545     section->angle = si->angle;
3546     section->priority = si->priority;
3547     for (ri = si->rows; ri != NULL; ri = (RowInfo *) ri->defs.next)
3548     {
3549         row = XkbcAddGeomRow(section, ri->nKeys);
3550         if (row == NULL)
3551         {
3552             WSGO("Couldn't allocate row in section\n");
3553             ACTION("Section %s is incomplete\n", scText(si));
3554             return False;
3555         }
3556         row->top = ri->top;
3557         row->left = ri->left;
3558         row->vertical = ri->vertical;
3559         for (ki = ri->keys; ki != NULL; ki = (KeyInfo *) ki->defs.next)
3560         {
3561             XkbcColorPtr color;
3562             if ((ki->defs.defined & _GK_Name) == 0)
3563             {
3564                 ERROR("Key %d of row %d in section %s has no name\n",
3565                        (int) ki->index, (int) ri->index, scText(si));
3566                 ACTION("Section %s ignored\n", scText(si));
3567                 return False;
3568             }
3569             key = XkbcAddGeomKey(row);
3570             if (key == NULL)
3571             {
3572                 WSGO("Couldn't allocate key in row\n");
3573                 ACTION("Section %s is incomplete\n", scText(si));
3574                 return False;
3575             }
3576             memcpy(key->name.name, ki->name, XkbKeyNameLength);
3577             key->gap = ki->gap;
3578             if (ki->shape == None)
3579                 key->shape_ndx = 0;
3580             else
3581             {
3582                 ShapeInfo *si;
3583                 si = FindShape(info, ki->shape, "key", keyText(ki));
3584                 if (!si)
3585                     return False;
3586                 key->shape_ndx = si->index;
3587             }
3588             if (ki->color != None)
3589                 color =
3590                     XkbcAddGeomColor(geom, XkbcAtomText(ki->color),
3591                                      geom->num_colors);
3592             else
3593                 color = XkbcAddGeomColor(geom, "white", geom->num_colors);
3594             XkbSetKeyColor(geom, key, color);
3595         }
3596     }
3597     if (si->doodads != NULL)
3598     {
3599         DoodadInfo *di;
3600         for (di = si->doodads; di != NULL; di = (DoodadInfo *) di->defs.next)
3601         {
3602             CopyDoodadDef(geom, section, di, info);
3603         }
3604     }
3605     if (si->overlays != NULL)
3606     {
3607         OverlayInfo *oi;
3608         for (oi = si->overlays; oi != NULL;
3609              oi = (OverlayInfo *) oi->defs.next)
3610         {
3611             CopyOverlayDef(geom, section, oi, info);
3612         }
3613     }
3614     if (XkbcComputeSectionBounds(geom, section))
3615     {
3616         /* 7/6/94 (ef) --  check for negative origin and translate */
3617         if ((si->defs.defined & _GS_Width) == 0)
3618             section->width = section->bounds.x2;
3619         if ((si->defs.defined & _GS_Height) == 0)
3620             section->height = section->bounds.y2;
3621     }
3622     return True;
3623 }
3624
3625 /***====================================================================***/
3626
3627 Bool
3628 CompileGeometry(XkbFile *file, XkbcDescPtr xkb, unsigned merge)
3629 {
3630     GeometryInfo info;
3631
3632     InitGeometryInfo(&info, file->id, merge);
3633     HandleGeometryFile(file, xkb, merge, &info);
3634
3635     if (info.errorCount == 0)
3636     {
3637         XkbcGeometryPtr geom;
3638         XkbcGeometrySizesRec sizes;
3639         bzero(&sizes, sizeof(sizes));
3640         sizes.which = XkbGeomAllMask;
3641         sizes.num_properties = info.nProps;
3642         sizes.num_colors = 8;
3643         sizes.num_shapes = info.nShapes;
3644         sizes.num_sections = info.nSections;
3645         sizes.num_doodads = info.nDoodads;
3646         if (XkbcAllocGeometry(xkb, &sizes) != Success)
3647         {
3648             WSGO("Couldn't allocate GeometryRec\n");
3649             ACTION("Geometry not compiled\n");
3650             return False;
3651         }
3652         geom = xkb->geom;
3653
3654         geom->width_mm = info.widthMM;
3655         geom->height_mm = info.heightMM;
3656         if (info.name != NULL)
3657         {
3658             geom->name = XkbcInternAtom(info.name, False);
3659             if (XkbcAllocNames(xkb, XkbGeometryNameMask, 0, 0) == Success)
3660                 xkb->names->geometry = geom->name;
3661         }
3662         if (info.fontSpec != None)
3663             geom->label_font = XkbcAtomGetString(info.fontSpec);
3664         else
3665             geom->label_font = FontFromParts(info.font, info.fontWeight,
3666                                              info.fontSlant,
3667                                              info.fontSetWidth,
3668                                              info.fontVariant,
3669                                              info.fontSize,
3670                                              info.fontEncoding);
3671         XkbcAddGeomColor(geom, "black", geom->num_colors);
3672         XkbcAddGeomColor(geom, "white", geom->num_colors);
3673
3674         if (info.baseColor == None)
3675             info.baseColor = XkbcInternAtom("white", False);
3676         if (info.labelColor == None)
3677             info.labelColor = XkbcInternAtom("black", False);
3678         geom->base_color =
3679             XkbcAddGeomColor(geom, XkbcAtomText(info.baseColor),
3680                              geom->num_colors);
3681         geom->label_color =
3682             XkbcAddGeomColor(geom, XkbcAtomText(info.labelColor),
3683                              geom->num_colors);
3684
3685         if (info.props)
3686         {
3687             PropertyInfo *pi;
3688             for (pi = info.props; pi != NULL;
3689                  pi = (PropertyInfo *) pi->defs.next)
3690             {
3691                 if (!XkbcAddGeomProperty(geom, pi->name, pi->value))
3692                     return False;
3693             }
3694         }
3695         if (info.shapes)
3696         {
3697             ShapeInfo *si;
3698             for (si = info.shapes; si != NULL;
3699                  si = (ShapeInfo *) si->defs.next)
3700             {
3701                 if (!CopyShapeDef(geom, si))
3702                     return False;
3703             }
3704         }
3705         if (info.sections)
3706         {
3707             SectionInfo *si;
3708             for (si = info.sections; si != NULL;
3709                  si = (SectionInfo *) si->defs.next)
3710             {
3711                 if (!CopySectionDef(geom, si, &info))
3712                     return False;
3713             }
3714         }
3715         if (info.doodads)
3716         {
3717             DoodadInfo *di;
3718             for (di = info.doodads; di != NULL;
3719                  di = (DoodadInfo *) di->defs.next)
3720             {
3721                 if (!CopyDoodadDef(geom, NULL, di, &info))
3722                     return False;
3723             }
3724         }
3725         if (info.aliases)
3726             ApplyAliases(xkb, True, &info.aliases);
3727         ClearGeometryInfo(&info);
3728         return True;
3729     }
3730     return False;
3731 }