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