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