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