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