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