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