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