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