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