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