geometry.c revision 1d8c7986
1/************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27#include "xkbcomp.h"
28#include "tokens.h"
29#include "expr.h"
30#include "vmod.h"
31#include "misc.h"
32#include "indicators.h"
33#include "action.h"
34#include "keycodes.h"
35#include "alias.h"
36
37#include "X11/extensions/XKBgeom.h"
38
39#define	DFLT_FONT	"helvetica"
40#define	DFLT_SLANT	"r"
41#define	DFLT_WEIGHT	"medium"
42#define	DFLT_SET_WIDTH	"normal"
43#define	DFLT_VARIANT	""
44#define	DFLT_ENCODING	"iso8859-1"
45#define	DFLT_SIZE	120
46
47typedef struct _PropertyInfo
48{
49    CommonInfo defs;
50    char *name;
51    char *value;
52} PropertyInfo;
53
54#define	_GSh_Outlines	(1<<1)
55#define	_GSh_Approx	(1<<2)
56#define	_GSh_Primary	(1<<3)
57typedef struct _ShapeInfo
58{
59    CommonInfo defs;
60    Atom name;
61    short index;
62    unsigned short nOutlines;
63    unsigned short szOutlines;
64    XkbOutlinePtr outlines;
65    XkbOutlinePtr approx;
66    XkbOutlinePtr primary;
67    int dfltCornerRadius;
68} ShapeInfo;
69
70#define	shText(d,s)	\
71		((s)?XkbAtomText((d),(s)->name,XkbMessage):"default shape")
72
73#define	_GD_Priority	(1<<0)
74#define	_GD_Top		(1<<1)
75#define	_GD_Left	(1<<2)
76#define	_GD_Angle	(1<<3)
77#define	_GD_Shape	(1<<4)
78#define	_GD_FontVariant	(1<<4)  /* CHEATING */
79#define	_GD_Corner	(1<<5)
80#define	_GD_Width	(1<<5)  /* CHEATING */
81#define	_GD_Color	(1<<6)
82#define	_GD_OffColor	(1<<7)
83#define	_GD_Height	(1<<7)  /* CHEATING */
84#define	_GD_Text	(1<<8)
85#define	_GD_Font	(1<<9)
86#define	_GD_FontSlant	(1<<10)
87#define	_GD_FontWeight	(1<<11)
88#define	_GD_FontSetWidth (1<<12)
89#define	_GD_FontSize	(1<<13)
90#define	_GD_FontEncoding (1<<14)
91#define	_GD_FontSpec	(1<<15)
92
93
94#define	_GD_FontParts	(_GD_Font|_GD_FontSlant|_GD_FontWeight|_GD_FontSetWidth|_GD_FontSize|_GD_FontEncoding|_GD_FontVariant)
95
96typedef struct _DoodadInfo
97{
98    CommonInfo defs;
99    Atom name;
100    unsigned char type;
101    unsigned char priority;
102    short top;
103    short left;
104    short angle;
105    unsigned short corner;
106    unsigned short width;
107    unsigned short height;
108    Atom shape;
109    Atom color;
110    Atom offColor;
111    Atom text;
112    Atom font;
113    Atom fontSlant;
114    Atom fontWeight;
115    Atom fontSetWidth;
116    Atom fontVariant;
117    unsigned short fontSize;
118    Atom fontEncoding;
119    Atom fontSpec;
120    char *logoName;
121    struct _SectionInfo *section;
122} DoodadInfo;
123
124#define	Yes		1
125#define	No		0
126#define	Undefined	-1
127
128#define	_GK_Default	(1<<0)
129#define	_GK_Name	(1<<1)
130#define	_GK_Gap		(1<<2)
131#define	_GK_Shape	(1<<3)
132#define	_GK_Color	(1<<4)
133typedef struct _KeyInfo
134{
135    CommonInfo defs;
136    char name[8];
137    short gap;
138    short index;
139    Atom shape;
140    Atom color;
141    struct _RowInfo *row;
142} KeyInfo;
143#define	keyText(k)	((k)&&(k)->name[0]?(k)->name:"default")
144
145#define	_GR_Default	(1<<0)
146#define	_GR_Vertical	(1<<1)
147#define	_GR_Top		(1<<2)
148#define	_GR_Left	(1<<3)
149typedef struct _RowInfo
150{
151    CommonInfo defs;
152    unsigned short top;
153    unsigned short left;
154    short index;
155    Bool vertical;
156    unsigned short nKeys;
157    KeyInfo *keys;
158    KeyInfo dfltKey;
159    struct _SectionInfo *section;
160} RowInfo;
161#define	rowText(d,r)	\
162	((r)?XkbAtomText((d),(r)->section->name,XkbMessage):"default")
163
164#define	_GOK_UnknownRow	-1
165typedef struct _OverlayKeyInfo
166{
167    CommonInfo defs;
168    short sectionRow;
169    short overlayRow;
170    char over[XkbKeyNameLength + 1];
171    char under[XkbKeyNameLength + 1];
172} OverlayKeyInfo;
173
174typedef struct _OverlayInfo
175{
176    CommonInfo defs;
177    Atom name;
178    unsigned short nRows;
179    unsigned short nKeys;
180    OverlayKeyInfo *keys;
181} OverlayInfo;
182
183
184#define	_GS_Default	(1<<0)
185#define	_GS_Name	(1<<1)
186#define	_GS_Top		(1<<2)
187#define	_GS_Left	(1<<3)
188#define	_GS_Width	(1<<4)
189#define	_GS_Height	(1<<5)
190#define	_GS_Angle	(1<<6)
191#define	_GS_Priority	(1<<7)
192typedef struct _SectionInfo
193{
194    CommonInfo defs;
195    Atom name;
196    unsigned short top;
197    unsigned short left;
198    unsigned short width;
199    unsigned short height;
200    unsigned short angle;
201    unsigned short nRows;
202    unsigned short nDoodads;
203    unsigned short nOverlays;
204    unsigned char priority;
205    unsigned char nextDoodadPriority;
206    RowInfo *rows;
207    DoodadInfo *doodads;
208    RowInfo dfltRow;
209    DoodadInfo *dfltDoodads;
210    OverlayInfo *overlays;
211    struct _GeometryInfo *geometry;
212} SectionInfo;
213#define	scText(d,s)	((s)?XkbAtomText((d),(s)->name,XkbMessage):"default")
214
215typedef struct _GeometryInfo
216{
217    char *name;
218    Display *dpy;
219    unsigned fileID;
220    unsigned merge;
221    int errorCount;
222    unsigned nextPriority;
223    int nProps;
224    int nShapes;
225    int nSections;
226    int nDoodads;
227    PropertyInfo *props;
228    ShapeInfo *shapes;
229    SectionInfo *sections;
230    DoodadInfo *doodads;
231    int widthMM;
232    int heightMM;
233    Atom font;
234    Atom fontSlant;
235    Atom fontWeight;
236    Atom fontSetWidth;
237    Atom fontVariant;
238    unsigned fontSize;
239    Atom fontEncoding;
240    Atom fontSpec;
241    Atom baseColor;
242    Atom labelColor;
243    int dfltCornerRadius;
244    SectionInfo dfltSection;
245    DoodadInfo *dfltDoodads;
246    AliasInfo *aliases;
247} GeometryInfo;
248
249static char *
250ddText(Display * dpy, DoodadInfo * di)
251{
252    static char buf[64];
253
254    if (di == NULL)
255    {
256        strcpy(buf, "default");
257        return buf;
258    }
259    if (di->section)
260    {
261        sprintf(buf, "%s in section %s",
262                XkbAtomText(dpy, di->name, XkbMessage), scText(dpy,
263                                                               di->section));
264        return buf;
265    }
266    return XkbAtomText(dpy, di->name, XkbMessage);
267}
268
269/***====================================================================***/
270
271static void
272InitPropertyInfo(PropertyInfo * pi, GeometryInfo * info)
273{
274    pi->defs.defined = 0;
275    pi->defs.fileID = info->fileID;
276    pi->defs.merge = info->merge;
277    pi->name = pi->value = NULL;
278    return;
279}
280
281static void
282FreeProperties(PropertyInfo * pi, GeometryInfo * info)
283{
284    PropertyInfo *tmp;
285    PropertyInfo *next;
286
287    if (info->props == pi)
288    {
289        info->props = NULL;
290        info->nProps = 0;
291    }
292    for (tmp = pi; tmp != NULL; tmp = next)
293    {
294        if (tmp->name)
295            uFree(tmp->name);
296        if (tmp->value)
297            uFree(tmp->value);
298        tmp->name = tmp->value = NULL;
299        next = (PropertyInfo *) tmp->defs.next;
300        uFree(tmp);
301    }
302    return;
303}
304
305static void
306InitKeyInfo(KeyInfo * key, RowInfo * row, GeometryInfo * info)
307{
308
309    if (key != &row->dfltKey)
310    {
311        *key = row->dfltKey;
312        strcpy(key->name, "unknown");
313        key->defs.defined &= ~_GK_Default;
314    }
315    else
316    {
317        bzero(key, sizeof(KeyInfo));
318        strcpy(key->name, "default");
319        key->defs.defined = _GK_Default;
320        key->defs.fileID = info->fileID;
321        key->defs.merge = info->merge;
322        key->defs.next = NULL;
323        key->row = row;
324    }
325    return;
326}
327
328static void
329ClearKeyInfo(KeyInfo * key)
330{
331    key->defs.defined &= ~_GK_Default;
332    strcpy(key->name, "default");
333    key->gap = 0;
334    key->shape = None;
335    key->color = None;
336    return;
337}
338
339static void
340FreeKeys(KeyInfo * key, RowInfo * row, GeometryInfo * info)
341{
342    KeyInfo *tmp;
343    KeyInfo *next;
344
345    if (row->keys == key)
346    {
347        row->nKeys = 0;
348        row->keys = NULL;
349    }
350    for (tmp = key; tmp != NULL; tmp = next)
351    {
352        ClearKeyInfo(tmp);
353        next = (KeyInfo *) tmp->defs.next;
354        uFree(tmp);
355    }
356    return;
357}
358
359static void
360InitRowInfo(RowInfo * row, SectionInfo * section, GeometryInfo * info)
361{
362    if (row != &section->dfltRow)
363    {
364        *row = section->dfltRow;
365        row->defs.defined &= ~_GR_Default;
366    }
367    else
368    {
369        bzero(row, sizeof(*row));
370        row->defs.defined = _GR_Default;
371        row->defs.fileID = info->fileID;
372        row->defs.merge = info->merge;
373        row->defs.next = NULL;
374        row->section = section;
375        row->nKeys = 0;
376        row->keys = NULL;
377        InitKeyInfo(&row->dfltKey, row, info);
378    }
379    return;
380}
381
382static void
383ClearRowInfo(RowInfo * row, GeometryInfo * info)
384{
385    row->defs.defined &= ~_GR_Default;
386    row->top = row->left = 0;
387    row->vertical = False;
388    row->nKeys = 0;
389    if (row->keys)
390        FreeKeys(row->keys, row, info);
391    ClearKeyInfo(&row->dfltKey);
392    row->dfltKey.defs.defined |= _GK_Default;
393    return;
394}
395
396static void
397FreeRows(RowInfo * row, SectionInfo * section, GeometryInfo * info)
398{
399    RowInfo *next;
400    RowInfo *tmp;
401
402    if (row == section->rows)
403    {
404        section->nRows = 0;
405        section->rows = NULL;
406    }
407    for (tmp = row; tmp != NULL; tmp = next)
408    {
409        ClearRowInfo(tmp, info);
410        next = (RowInfo *) tmp->defs.next;
411        uFree(tmp);
412    }
413    return;
414}
415
416static DoodadInfo *
417FindDoodadByType(DoodadInfo * di, unsigned type)
418{
419    while (di)
420    {
421        if (di->type == type)
422            return di;
423        di = (DoodadInfo *) di->defs.next;
424    }
425    return NULL;
426}
427
428static DoodadInfo *
429FindDoodadByName(DoodadInfo * di, Atom name)
430{
431    while (di)
432    {
433        if (di->name == name)
434            return di;
435        di = (DoodadInfo *) di->defs.next;
436    }
437    return NULL;
438}
439
440static void
441InitDoodadInfo(DoodadInfo * di, unsigned type, SectionInfo * si,
442               GeometryInfo * info)
443{
444    DoodadInfo *dflt;
445
446    dflt = NULL;
447    if (si && si->dfltDoodads)
448        dflt = FindDoodadByType(si->dfltDoodads, type);
449    if ((dflt == NULL) && (info->dfltDoodads))
450        dflt = FindDoodadByType(info->dfltDoodads, type);
451    if (dflt != NULL)
452    {
453        *di = *dflt;
454        di->defs.next = NULL;
455    }
456    else
457    {
458        bzero(di, sizeof(DoodadInfo));
459        di->defs.fileID = info->fileID;
460        di->type = type;
461    }
462    di->section = si;
463    if (si != NULL)
464    {
465        di->priority = si->nextDoodadPriority++;
466#if XkbGeomMaxPriority < 255
467        if (si->nextDoodadPriority > XkbGeomMaxPriority)
468            si->nextDoodadPriority = XkbGeomMaxPriority;
469#endif
470    }
471    else
472    {
473        di->priority = info->nextPriority++;
474        if (info->nextPriority > XkbGeomMaxPriority)
475            info->nextPriority = XkbGeomMaxPriority;
476    }
477    return;
478}
479
480static void
481ClearDoodadInfo(DoodadInfo * di)
482{
483    CommonInfo defs;
484
485    defs = di->defs;
486    bzero(di, sizeof(DoodadInfo));
487    di->defs = defs;
488    di->defs.defined = 0;
489    return;
490}
491
492static void
493ClearOverlayInfo(OverlayInfo * ol)
494{
495    if (ol && ol->keys)
496    {
497        ol->keys = (OverlayKeyInfo *) ClearCommonInfo(&ol->keys->defs);
498        ol->nKeys = 0;
499    }
500    return;
501}
502
503static void
504FreeDoodads(DoodadInfo * di, SectionInfo * si, GeometryInfo * info)
505{
506    DoodadInfo *tmp;
507    DoodadInfo *next;
508
509    if (si)
510    {
511        if (si->doodads == di)
512        {
513            si->doodads = NULL;
514            si->nDoodads = 0;
515        }
516        if (si->dfltDoodads == di)
517            si->dfltDoodads = NULL;
518    }
519    if (info->doodads == di)
520    {
521        info->doodads = NULL;
522        info->nDoodads = 0;
523    }
524    if (info->dfltDoodads == di)
525        info->dfltDoodads = NULL;
526    for (tmp = di; tmp != NULL; tmp = next)
527    {
528        next = (DoodadInfo *) tmp->defs.next;
529        ClearDoodadInfo(tmp);
530        uFree(tmp);
531    }
532    return;
533}
534
535static void
536InitSectionInfo(SectionInfo * si, GeometryInfo * info)
537{
538    if (si != &info->dfltSection)
539    {
540        *si = info->dfltSection;
541        si->defs.defined &= ~_GS_Default;
542        si->name = XkbInternAtom(info->dpy, "unknown", False);
543        si->priority = info->nextPriority++;
544        if (info->nextPriority > XkbGeomMaxPriority)
545            info->nextPriority = XkbGeomMaxPriority;
546    }
547    else
548    {
549        bzero(si, sizeof(SectionInfo));
550        si->defs.fileID = info->fileID;
551        si->defs.merge = info->merge;
552        si->defs.next = NULL;
553        si->geometry = info;
554        si->name = XkbInternAtom(info->dpy, "default", False);
555        InitRowInfo(&si->dfltRow, si, info);
556    }
557    return;
558}
559
560static void
561DupSectionInfo(SectionInfo * into, SectionInfo * from, GeometryInfo * info)
562{
563    CommonInfo defs;
564
565    defs = into->defs;
566    *into = *from;
567    into->defs.fileID = defs.fileID;
568    into->defs.merge = defs.merge;
569    into->defs.next = NULL;
570    into->dfltRow.defs.fileID = defs.fileID;
571    into->dfltRow.defs.merge = defs.merge;
572    into->dfltRow.defs.next = NULL;
573    into->dfltRow.section = into;
574    into->dfltRow.dfltKey.defs.fileID = defs.fileID;
575    into->dfltRow.dfltKey.defs.merge = defs.merge;
576    into->dfltRow.dfltKey.defs.next = NULL;
577    into->dfltRow.dfltKey.row = &into->dfltRow;
578    return;
579}
580
581static void
582ClearSectionInfo(SectionInfo * si, GeometryInfo * info)
583{
584
585    si->defs.defined &= ~_GS_Default;
586    si->name = XkbInternAtom(info->dpy, "default", False);
587    si->top = si->left = 0;
588    si->width = si->height = 0;
589    si->angle = 0;
590    if (si->rows)
591    {
592        FreeRows(si->rows, si, info);
593        si->rows = NULL;
594    }
595    ClearRowInfo(&si->dfltRow, info);
596    if (si->doodads)
597    {
598        FreeDoodads(si->doodads, si, info);
599        si->doodads = NULL;
600    }
601    si->dfltRow.defs.defined = _GR_Default;
602    return;
603}
604
605static void
606FreeSections(SectionInfo * si, GeometryInfo * info)
607{
608    SectionInfo *tmp;
609    SectionInfo *next;
610
611    if (si == info->sections)
612    {
613        info->nSections = 0;
614        info->sections = NULL;
615    }
616    for (tmp = si; tmp != NULL; tmp = next)
617    {
618        ClearSectionInfo(tmp, info);
619        next = (SectionInfo *) tmp->defs.next;
620        uFree(tmp);
621    }
622    return;
623}
624
625static void
626FreeShapes(ShapeInfo * si, GeometryInfo * info)
627{
628    ShapeInfo *tmp;
629    ShapeInfo *next;
630
631    if (si == info->shapes)
632    {
633        info->nShapes = 0;
634        info->shapes = NULL;
635    }
636    for (tmp = si; tmp != NULL; tmp = next)
637    {
638        if (tmp->outlines)
639        {
640            register int i;
641            for (i = 0; i < tmp->nOutlines; i++)
642            {
643                if (tmp->outlines[i].points != NULL)
644                {
645                    uFree(tmp->outlines[i].points);
646                    tmp->outlines[i].num_points = 0;
647                    tmp->outlines[i].points = NULL;
648                }
649            }
650            uFree(tmp->outlines);
651            tmp->szOutlines = 0;
652            tmp->nOutlines = 0;
653            tmp->outlines = NULL;
654            tmp->primary = tmp->approx = NULL;
655        }
656        next = (ShapeInfo *) tmp->defs.next;
657        uFree(tmp);
658    }
659    return;
660}
661
662/***====================================================================***/
663
664static void
665InitGeometryInfo(GeometryInfo * info, unsigned fileID, unsigned merge)
666{
667    bzero(info, sizeof(GeometryInfo));
668    info->fileID = fileID;
669    info->merge = merge;
670    InitSectionInfo(&info->dfltSection, info);
671    info->dfltSection.defs.defined = _GS_Default;
672    return;
673}
674
675static void
676ClearGeometryInfo(GeometryInfo * info)
677{
678    if (info->name)
679        uFree(info->name);
680    info->name = NULL;
681    if (info->props)
682        FreeProperties(info->props, info);
683    if (info->shapes)
684        FreeShapes(info->shapes, info);
685    if (info->sections)
686        FreeSections(info->sections, info);
687    info->widthMM = 0;
688    info->heightMM = 0;
689    info->dfltCornerRadius = 0;
690    ClearSectionInfo(&info->dfltSection, info);
691    info->dfltSection.defs.defined = _GS_Default;
692    if (info->aliases)
693        ClearAliases(&info->aliases);
694    return;
695}
696
697/***====================================================================***/
698
699static PropertyInfo *
700NextProperty(GeometryInfo * info)
701{
702    PropertyInfo *pi;
703
704    pi = uTypedAlloc(PropertyInfo);
705    if (pi)
706    {
707        bzero((char *) pi, sizeof(PropertyInfo));
708        info->props = (PropertyInfo *) AddCommonInfo(&info->props->defs,
709                                                     (CommonInfo *) pi);
710        info->nProps++;
711    }
712    return pi;
713}
714
715static PropertyInfo *
716FindProperty(GeometryInfo * info, char *name)
717{
718    PropertyInfo *old;
719
720    if (!name)
721        return NULL;
722    for (old = info->props; old != NULL;
723         old = (PropertyInfo *) old->defs.next)
724    {
725        if ((old->name) && (uStringEqual(name, old->name)))
726            return old;
727    }
728    return NULL;
729}
730
731static Bool
732AddProperty(GeometryInfo * info, PropertyInfo * new)
733{
734    PropertyInfo *old;
735
736    if ((!new) || (!new->value) || (!new->name))
737        return False;
738    old = FindProperty(info, new->name);
739    if (old != NULL)
740    {
741        if ((new->defs.merge == MergeReplace)
742            || (new->defs.merge == MergeOverride))
743        {
744            if (((old->defs.fileID == new->defs.fileID)
745                 && (warningLevel > 0)) || (warningLevel > 9))
746            {
747                WARN1("Multiple definitions for the \"%s\" property\n",
748                      new->name);
749                ACTION2("Ignoring \"%s\", using \"%s\"\n", old->value,
750                        new->value);
751            }
752            if (old->value)
753                uFree(old->value);
754            old->value = uStringDup(new->value);
755            return True;
756        }
757        if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
758            || (warningLevel > 9))
759        {
760            WARN1("Multiple definitions for \"%s\" property\n", new->name);
761            ACTION2("Using \"%s\", ignoring \"%s\" \n", old->value,
762                    new->value);
763        }
764        return True;
765    }
766    old = new;
767    if ((new = NextProperty(info)) == NULL)
768        return False;
769    new->defs.next = NULL;
770    new->name = uStringDup(old->name);
771    new->value = uStringDup(old->value);
772    return True;
773}
774
775/***====================================================================***/
776
777static ShapeInfo *
778NextShape(GeometryInfo * info)
779{
780    ShapeInfo *si;
781
782    si = uTypedAlloc(ShapeInfo);
783    if (si)
784    {
785        bzero((char *) si, sizeof(ShapeInfo));
786        info->shapes = (ShapeInfo *) AddCommonInfo(&info->shapes->defs,
787                                                   (CommonInfo *) si);
788        info->nShapes++;
789        si->dfltCornerRadius = info->dfltCornerRadius;
790    }
791    return si;
792}
793
794static ShapeInfo *
795FindShape(GeometryInfo * info, Atom name, const char *type, const char *which)
796{
797    ShapeInfo *old;
798
799    for (old = info->shapes; old != NULL; old = (ShapeInfo *) old->defs.next)
800    {
801        if (name == old->name)
802            return old;
803    }
804    if (type != NULL)
805    {
806        old = info->shapes;
807        WARN3("Unknown shape \"%s\" for %s %s\n",
808              XkbAtomText(info->dpy, name, XkbMessage), type, which);
809        if (old)
810        {
811            ACTION1("Using default shape %s instead\n",
812                    shText(info->dpy, old));
813            return old;
814        }
815        ACTION("No default shape; definition ignored\n");
816        return NULL;
817    }
818    return NULL;
819}
820
821static Bool
822AddShape(GeometryInfo * info, ShapeInfo * new)
823{
824    ShapeInfo *old;
825
826    old = FindShape(info, new->name, NULL, NULL);
827    if (old != NULL)
828    {
829        if ((new->defs.merge == MergeReplace)
830            || (new->defs.merge == MergeOverride))
831        {
832            ShapeInfo *next = (ShapeInfo *) old->defs.next;
833            if (((old->defs.fileID == new->defs.fileID)
834                 && (warningLevel > 0)) || (warningLevel > 9))
835            {
836                WARN1("Duplicate shape name \"%s\"\n",
837                      shText(info->dpy, old));
838                ACTION("Using last definition\n");
839            }
840            *old = *new;
841            old->defs.next = &next->defs;
842            return True;
843        }
844        if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
845            || (warningLevel > 9))
846        {
847            WARN1("Multiple shapes named \"%s\"\n", shText(info->dpy, old));
848            ACTION("Using first definition\n");
849        }
850        return True;
851    }
852    old = new;
853    if ((new = NextShape(info)) == NULL)
854        return False;
855    *new = *old;
856    new->defs.next = NULL;
857    old->szOutlines = old->nOutlines = 0;
858    old->outlines = NULL;
859    old->approx = NULL;
860    old->primary = NULL;
861    return True;
862}
863
864/***====================================================================***/
865
866static void
867ReplaceDoodad(DoodadInfo * into, DoodadInfo * from)
868{
869    CommonInfo *next;
870
871    next = into->defs.next;
872    ClearDoodadInfo(into);
873    *into = *from;
874    into->defs.next = next;
875    next = from->defs.next;
876    ClearDoodadInfo(from);
877    from->defs.next = next;
878    return;
879}
880
881static DoodadInfo *
882NextDfltDoodad(SectionInfo * si, GeometryInfo * info)
883{
884    DoodadInfo *di;
885
886    di = uTypedCalloc(1, DoodadInfo);
887    if (!di)
888        return NULL;
889    if (si)
890    {
891        si->dfltDoodads =
892            (DoodadInfo *) AddCommonInfo(&si->dfltDoodads->defs,
893                                         (CommonInfo *) di);
894    }
895    else
896    {
897        info->dfltDoodads =
898            (DoodadInfo *) AddCommonInfo(&info->dfltDoodads->defs,
899                                         (CommonInfo *) di);
900    }
901    return di;
902}
903
904static DoodadInfo *
905NextDoodad(SectionInfo * si, GeometryInfo * info)
906{
907    DoodadInfo *di;
908
909    di = uTypedCalloc(1, DoodadInfo);
910    if (di)
911    {
912        if (si)
913        {
914            si->doodads = (DoodadInfo *) AddCommonInfo(&si->doodads->defs,
915                                                       (CommonInfo *) di);
916            si->nDoodads++;
917        }
918        else
919        {
920            info->doodads =
921                (DoodadInfo *) AddCommonInfo(&info->doodads->defs,
922                                             (CommonInfo *) di);
923            info->nDoodads++;
924        }
925    }
926    return di;
927}
928
929static Bool
930AddDoodad(SectionInfo * si, GeometryInfo * info, DoodadInfo * new)
931{
932    DoodadInfo *old;
933
934    old = FindDoodadByName((si ? si->doodads : info->doodads), new->name);
935    if (old != NULL)
936    {
937        if ((new->defs.merge == MergeReplace)
938            || (new->defs.merge == MergeOverride))
939        {
940            if (((old->defs.fileID == new->defs.fileID)
941                 && (warningLevel > 0)) || (warningLevel > 9))
942            {
943                WARN1("Multiple doodads named \"%s\"\n",
944                      XkbAtomText(info->dpy, old->name, XkbMessage));
945                ACTION("Using last definition\n");
946            }
947            ReplaceDoodad(old, new);
948            old->section = si;
949            return True;
950        }
951        if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
952            || (warningLevel > 9))
953        {
954            WARN1("Multiple doodads named \"%s\"\n",
955                  XkbAtomText(info->dpy, old->name, XkbMessage));
956            ACTION("Using first definition\n");
957        }
958        return True;
959    }
960    old = new;
961    if ((new = NextDoodad(si, info)) == NULL)
962        return False;
963    ReplaceDoodad(new, old);
964    new->section = si;
965    new->defs.next = NULL;
966    return True;
967}
968
969static DoodadInfo *
970FindDfltDoodadByTypeName(char *name, SectionInfo * si, GeometryInfo * info)
971{
972    DoodadInfo *dflt;
973    unsigned type;
974
975    if (uStrCaseCmp(name, "outline") == 0)
976        type = XkbOutlineDoodad;
977    else if (uStrCaseCmp(name, "solid") == 0)
978        type = XkbSolidDoodad;
979    else if (uStrCaseCmp(name, "text") == 0)
980        type = XkbTextDoodad;
981    else if (uStrCaseCmp(name, "indicator") == 0)
982        type = XkbIndicatorDoodad;
983    else if (uStrCaseCmp(name, "logo") == 0)
984        type = XkbLogoDoodad;
985    else
986        return NULL;
987    if ((si) && (si->dfltDoodads))
988        dflt = FindDoodadByType(si->dfltDoodads, type);
989    else
990        dflt = NULL;
991    if ((!dflt) && (info->dfltDoodads))
992        dflt = FindDoodadByType(info->dfltDoodads, type);
993    if (dflt == NULL)
994    {
995        dflt = NextDfltDoodad(si, info);
996        if (dflt != NULL)
997        {
998            dflt->name = None;
999            dflt->type = type;
1000        }
1001    }
1002    return dflt;
1003}
1004
1005/***====================================================================***/
1006
1007static Bool
1008AddOverlay(SectionInfo * si, GeometryInfo * info, OverlayInfo * new)
1009{
1010    OverlayInfo *old;
1011
1012    for (old = si->overlays; old != NULL;
1013         old = (OverlayInfo *) old->defs.next)
1014    {
1015        if (old->name == new->name)
1016            break;
1017    }
1018    if (old != NULL)
1019    {
1020        if ((new->defs.merge == MergeReplace)
1021            || (new->defs.merge == MergeOverride))
1022        {
1023            if (((old->defs.fileID == new->defs.fileID)
1024                 && (warningLevel > 0)) || (warningLevel > 9))
1025            {
1026                WARN2
1027                    ("Multiple overlays named \"%s\" for section \"%s\"\n",
1028                     XkbAtomText(info->dpy, old->name, XkbMessage),
1029                     XkbAtomText(info->dpy, si->name, XkbMessage));
1030                ACTION("Using last definition\n");
1031            }
1032            ClearOverlayInfo(old);
1033            old->nKeys = new->nKeys;
1034            old->keys = new->keys;
1035            new->nKeys = 0;
1036            new->keys = NULL;
1037            return True;
1038        }
1039        if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
1040            || (warningLevel > 9))
1041        {
1042            WARN2("Multiple doodads named \"%s\" in section \"%s\"\n",
1043                  XkbAtomText(info->dpy, old->name, XkbMessage),
1044                  XkbAtomText(info->dpy, si->name, XkbMessage));
1045            ACTION("Using first definition\n");
1046        }
1047        return True;
1048    }
1049    old = new;
1050    new = uTypedCalloc(1, OverlayInfo);
1051    if (!new)
1052    {
1053        if (warningLevel > 0)
1054        {
1055            WSGO("Couldn't allocate a new OverlayInfo\n");
1056            ACTION2
1057                ("Overlay \"%s\" in section \"%s\" will be incomplete\n",
1058                 XkbAtomText(info->dpy, old->name, XkbMessage),
1059                 XkbAtomText(info->dpy, si->name, XkbMessage));
1060        }
1061        return False;
1062    }
1063    *new = *old;
1064    old->nKeys = 0;
1065    old->keys = NULL;
1066    si->overlays = (OverlayInfo *) AddCommonInfo(&si->overlays->defs,
1067                                                 (CommonInfo *) new);
1068    si->nOverlays++;
1069    return True;
1070}
1071
1072/***====================================================================***/
1073
1074static SectionInfo *
1075NextSection(GeometryInfo * info)
1076{
1077    SectionInfo *si;
1078
1079    si = uTypedAlloc(SectionInfo);
1080    if (si)
1081    {
1082        *si = info->dfltSection;
1083        si->defs.defined &= ~_GS_Default;
1084        si->defs.next = NULL;
1085        si->nRows = 0;
1086        si->rows = NULL;
1087        info->sections =
1088            (SectionInfo *) AddCommonInfo(&info->sections->defs,
1089                                          (CommonInfo *) si);
1090        info->nSections++;
1091    }
1092    return si;
1093}
1094
1095static SectionInfo *
1096FindMatchingSection(GeometryInfo * info, SectionInfo * new)
1097{
1098    SectionInfo *old;
1099
1100    for (old = info->sections; old != NULL;
1101         old = (SectionInfo *) old->defs.next)
1102    {
1103        if (new->name == old->name)
1104            return old;
1105    }
1106    return NULL;
1107}
1108
1109static Bool
1110AddSection(GeometryInfo * info, SectionInfo * new)
1111{
1112    SectionInfo *old;
1113
1114    old = FindMatchingSection(info, new);
1115    if (old != NULL)
1116    {
1117#ifdef NOTDEF
1118        if ((new->defs.merge == MergeReplace)
1119            || (new->defs.merge == MergeOverride))
1120        {
1121            SectionInfo *next = (SectionInfo *) old->defs.next;
1122            if (((old->defs.fileID == new->defs.fileID)
1123                 && (warningLevel > 0)) || (warningLevel > 9))
1124            {
1125                WARN1("Duplicate shape name \"%s\"\n",
1126                      shText(info->dpy, old));
1127                ACTION("Using last definition\n");
1128            }
1129            *old = *new;
1130            old->defs.next = &next->defs;
1131            return True;
1132        }
1133        if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
1134            || (warningLevel > 9))
1135        {
1136            WARN1("Multiple shapes named \"%s\"\n", shText(info->dpy, old));
1137            ACTION("Using first definition\n");
1138        }
1139        return True;
1140#else
1141        WARN("Don't know how to merge sections yet\n");
1142#endif
1143    }
1144    old = new;
1145    if ((new = NextSection(info)) == NULL)
1146        return False;
1147    *new = *old;
1148    new->defs.next = NULL;
1149    old->nRows = old->nDoodads = old->nOverlays = 0;
1150    old->rows = NULL;
1151    old->doodads = NULL;
1152    old->overlays = NULL;
1153    if (new->doodads)
1154    {
1155        DoodadInfo *di;
1156        for (di = new->doodads; di; di = (DoodadInfo *) di->defs.next)
1157        {
1158            di->section = new;
1159        }
1160    }
1161    return True;
1162}
1163
1164/***====================================================================***/
1165
1166static RowInfo *
1167NextRow(SectionInfo * si)
1168{
1169    RowInfo *row;
1170
1171    row = uTypedAlloc(RowInfo);
1172    if (row)
1173    {
1174        *row = si->dfltRow;
1175        row->defs.defined &= ~_GR_Default;
1176        row->defs.next = NULL;
1177        row->nKeys = 0;
1178        row->keys = NULL;
1179        si->rows =
1180            (RowInfo *) AddCommonInfo(&si->rows->defs, (CommonInfo *) row);
1181        row->index = si->nRows++;
1182    }
1183    return row;
1184}
1185
1186static Bool
1187AddRow(SectionInfo * si, RowInfo * new)
1188{
1189    RowInfo *old;
1190
1191    old = new;
1192    if ((new = NextRow(si)) == NULL)
1193        return False;
1194    *new = *old;
1195    new->defs.next = NULL;
1196    old->nKeys = 0;
1197    old->keys = NULL;
1198    return True;
1199}
1200
1201/***====================================================================***/
1202
1203static KeyInfo *
1204NextKey(RowInfo * row)
1205{
1206    KeyInfo *key;
1207
1208    key = uTypedAlloc(KeyInfo);
1209    if (key)
1210    {
1211        *key = row->dfltKey;
1212        key->defs.defined &= ~_GK_Default;
1213        key->defs.next = NULL;
1214        key->index = row->nKeys++;
1215    }
1216    return key;
1217}
1218
1219static Bool
1220AddKey(RowInfo * row, KeyInfo * new)
1221{
1222    KeyInfo *old;
1223
1224    old = new;
1225    if ((new = NextKey(row)) == NULL)
1226        return False;
1227    *new = *old;
1228    new->defs.next = NULL;
1229    row->keys =
1230        (KeyInfo *) AddCommonInfo(&row->keys->defs, (CommonInfo *) new);
1231    return True;
1232}
1233
1234/***====================================================================***/
1235
1236static void
1237MergeIncludedGeometry(GeometryInfo * into, GeometryInfo * from,
1238                      unsigned merge)
1239{
1240    Bool clobber;
1241
1242    if (from->errorCount > 0)
1243    {
1244        into->errorCount += from->errorCount;
1245        return;
1246    }
1247    clobber = (merge == MergeOverride) || (merge == MergeReplace);
1248    if (into->name == NULL)
1249    {
1250        into->name = from->name;
1251        from->name = NULL;
1252    }
1253    if ((into->widthMM == 0) || ((from->widthMM != 0) && clobber))
1254        into->widthMM = from->widthMM;
1255    if ((into->heightMM == 0) || ((from->heightMM != 0) && clobber))
1256        into->heightMM = from->heightMM;
1257    if ((into->font == None) || ((from->font != None) && clobber))
1258        into->font = from->font;
1259    if ((into->fontSlant == None) || ((from->fontSlant != None) && clobber))
1260        into->fontSlant = from->fontSlant;
1261    if ((into->fontWeight == None) || ((from->fontWeight != None) && clobber))
1262        into->fontWeight = from->fontWeight;
1263    if ((into->fontSetWidth == None)
1264        || ((from->fontSetWidth != None) && clobber))
1265        into->fontSetWidth = from->fontSetWidth;
1266    if ((into->fontVariant == None)
1267        || ((from->fontVariant != None) && clobber))
1268        into->fontVariant = from->fontVariant;
1269    if ((into->fontSize == 0) || ((from->fontSize != 0) && clobber))
1270        into->fontSize = from->fontSize;
1271    if ((into->fontEncoding == None)
1272        || ((from->fontEncoding != None) && clobber))
1273        into->fontEncoding = from->fontEncoding;
1274    if ((into->fontSpec == None) || ((from->fontSpec != None) && clobber))
1275        into->fontSpec = from->fontSpec;
1276    if ((into->baseColor == None) || ((from->baseColor != None) && clobber))
1277        into->baseColor = from->baseColor;
1278    if ((into->labelColor == None) || ((from->labelColor != None) && clobber))
1279        into->labelColor = from->labelColor;
1280    into->nextPriority = from->nextPriority;
1281    if (from->props != NULL)
1282    {
1283        PropertyInfo *pi;
1284        for (pi = from->props; pi; pi = (PropertyInfo *) pi->defs.next)
1285        {
1286            if (!AddProperty(into, pi))
1287                into->errorCount++;
1288        }
1289    }
1290    if (from->shapes != NULL)
1291    {
1292        ShapeInfo *si;
1293
1294        for (si = from->shapes; si; si = (ShapeInfo *) si->defs.next)
1295        {
1296            if (!AddShape(into, si))
1297                into->errorCount++;
1298        }
1299    }
1300    if (from->sections != NULL)
1301    {
1302        SectionInfo *si;
1303
1304        for (si = from->sections; si; si = (SectionInfo *) si->defs.next)
1305        {
1306            if (!AddSection(into, si))
1307                into->errorCount++;
1308        }
1309    }
1310    if (from->doodads != NULL)
1311    {
1312        DoodadInfo *di;
1313
1314        for (di = from->doodads; di; di = (DoodadInfo *) di->defs.next)
1315        {
1316            if (!AddDoodad(NULL, into, di))
1317                into->errorCount++;
1318        }
1319    }
1320    if (!MergeAliases(&into->aliases, &from->aliases, merge))
1321        into->errorCount++;
1322    return;
1323}
1324
1325typedef void (*FileHandler) (XkbFile * /* file */ ,
1326                             XkbDescPtr /* xkb */ ,
1327                             unsigned /* merge */ ,
1328                             GeometryInfo *     /* info */
1329    );
1330
1331static Bool
1332HandleIncludeGeometry(IncludeStmt * stmt, XkbDescPtr xkb, GeometryInfo * info,
1333                      FileHandler hndlr)
1334{
1335    unsigned newMerge;
1336    XkbFile *rtrn;
1337    GeometryInfo included;
1338    Bool haveSelf;
1339
1340    haveSelf = False;
1341    if ((stmt->file == NULL) && (stmt->map == NULL))
1342    {
1343        haveSelf = True;
1344        included = *info;
1345        bzero(info, sizeof(GeometryInfo));
1346    }
1347    else if (ProcessIncludeFile(stmt, XkmGeometryIndex, &rtrn, &newMerge))
1348    {
1349        InitGeometryInfo(&included, rtrn->id, newMerge);
1350        included.nextPriority = info->nextPriority;
1351        included.dfltCornerRadius = info->dfltCornerRadius;
1352        DupSectionInfo(&included.dfltSection, &info->dfltSection, info);
1353        (*hndlr) (rtrn, xkb, MergeOverride, &included);
1354        if (stmt->stmt != NULL)
1355        {
1356            if (included.name != NULL)
1357                uFree(included.name);
1358            included.name = stmt->stmt;
1359            stmt->stmt = NULL;
1360        }
1361    }
1362    else
1363    {
1364        info->errorCount += 10;
1365        return False;
1366    }
1367    if ((stmt->next != NULL) && (included.errorCount < 1))
1368    {
1369        IncludeStmt *next;
1370        unsigned op;
1371        GeometryInfo next_incl;
1372
1373        for (next = stmt->next; next != NULL; next = next->next)
1374        {
1375            if ((next->file == NULL) && (next->map == NULL))
1376            {
1377                haveSelf = True;
1378                MergeIncludedGeometry(&included, info, next->merge);
1379                ClearGeometryInfo(info);
1380            }
1381            else if (ProcessIncludeFile(next, XkmGeometryIndex, &rtrn, &op))
1382            {
1383                InitGeometryInfo(&next_incl, rtrn->id, op);
1384                next_incl.nextPriority = included.nextPriority;
1385                next_incl.dfltCornerRadius = included.dfltCornerRadius;
1386                DupSectionInfo(&next_incl.dfltSection,
1387                               &included.dfltSection, &included);
1388                (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
1389                MergeIncludedGeometry(&included, &next_incl, op);
1390                ClearGeometryInfo(&next_incl);
1391            }
1392            else
1393            {
1394                info->errorCount += 10;
1395                return False;
1396            }
1397        }
1398    }
1399    if (haveSelf)
1400        *info = included;
1401    else
1402    {
1403        MergeIncludedGeometry(info, &included, newMerge);
1404        ClearGeometryInfo(&included);
1405    }
1406    return (info->errorCount == 0);
1407}
1408
1409static int
1410SetShapeField(ShapeInfo * si,
1411              char *field,
1412              ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1413{
1414    ExprResult tmp;
1415
1416    if ((uStrCaseCmp(field, "radius") == 0)
1417        || (uStrCaseCmp(field, "corner") == 0)
1418        || (uStrCaseCmp(field, "cornerradius") == 0))
1419    {
1420        if (arrayNdx != NULL)
1421        {
1422            info->errorCount++;
1423            return ReportNotArray("key shape", field, shText(info->dpy, si));
1424        }
1425        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1426        {
1427            info->errorCount++;
1428            return ReportBadType("key shape", field,
1429                                 shText(info->dpy, si), "number");
1430        }
1431        if (si)
1432            si->dfltCornerRadius = tmp.ival;
1433        else
1434            info->dfltCornerRadius = tmp.ival;
1435        return True;
1436    }
1437    info->errorCount++;
1438    return ReportBadField("key shape", field, shText(info->dpy, si));
1439}
1440
1441static int
1442SetShapeDoodadField(DoodadInfo * di,
1443                    char *field,
1444                    ExprDef * arrayNdx,
1445                    ExprDef * value, SectionInfo * si, GeometryInfo * info)
1446{
1447    ExprResult tmp;
1448    const char *typeName;
1449
1450    typeName =
1451        (di->type == XkbSolidDoodad ? "solid doodad" : "outline doodad");
1452    if ((!uStrCaseCmp(field, "corner"))
1453        || (!uStrCaseCmp(field, "cornerradius")))
1454    {
1455        if (arrayNdx != NULL)
1456        {
1457            info->errorCount++;
1458            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1459        }
1460        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1461        {
1462            info->errorCount++;
1463            return ReportBadType(typeName, field, ddText(info->dpy, di),
1464                                 "number");
1465        }
1466        di->defs.defined |= _GD_Corner;
1467        di->corner = tmp.ival;
1468        return True;
1469    }
1470    else if (uStrCaseCmp(field, "angle") == 0)
1471    {
1472        if (arrayNdx != NULL)
1473        {
1474            info->errorCount++;
1475            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1476        }
1477        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1478        {
1479            info->errorCount++;
1480            return ReportBadType(typeName, field, ddText(info->dpy, di),
1481                                 "number");
1482        }
1483        di->defs.defined |= _GD_Angle;
1484        di->angle = tmp.ival;
1485        return True;
1486    }
1487    else if (uStrCaseCmp(field, "shape") == 0)
1488    {
1489        if (arrayNdx != NULL)
1490        {
1491            info->errorCount++;
1492            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1493        }
1494        if (!ExprResolveString(value, &tmp, NULL, NULL))
1495        {
1496            info->errorCount++;
1497            return ReportBadType(typeName, field, ddText(info->dpy, di),
1498                                 "string");
1499        }
1500        di->shape = XkbInternAtom(info->dpy, tmp.str, False);
1501        di->defs.defined |= _GD_Shape;
1502        return True;
1503    }
1504    return ReportBadField(typeName, field, ddText(info->dpy, di));
1505}
1506
1507#define	FIELD_STRING	0
1508#define	FIELD_SHORT	1
1509#define	FIELD_USHORT	2
1510
1511static int
1512SetTextDoodadField(DoodadInfo * di,
1513                   char *field,
1514                   ExprDef * arrayNdx,
1515                   ExprDef * value, SectionInfo * si, GeometryInfo * info)
1516{
1517    ExprResult tmp;
1518    unsigned def;
1519    unsigned type;
1520    char *typeName = "text doodad";
1521    union
1522    {
1523        Atom *str;
1524        short *ival;
1525        unsigned short *uval;
1526    } pField;
1527
1528    if (uStrCaseCmp(field, "angle") == 0)
1529    {
1530        if (arrayNdx != NULL)
1531        {
1532            info->errorCount++;
1533            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1534        }
1535        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1536        {
1537            info->errorCount++;
1538            return ReportBadType(typeName, field, ddText(info->dpy, di),
1539                                 "number");
1540        }
1541        di->defs.defined |= _GD_Angle;
1542        di->angle = tmp.ival;
1543        return True;
1544    }
1545    if (uStrCaseCmp(field, "width") == 0)
1546    {
1547        type = FIELD_USHORT;
1548        pField.uval = &di->width;
1549        def = _GD_Width;
1550    }
1551    else if (uStrCaseCmp(field, "height") == 0)
1552    {
1553        type = FIELD_USHORT;
1554        pField.uval = &di->height;
1555        def = _GD_Height;
1556    }
1557    else if (uStrCaseCmp(field, "text") == 0)
1558    {
1559        type = FIELD_STRING;
1560        pField.str = &di->text;
1561        def = _GD_Text;
1562    }
1563    else if (uStrCaseCmp(field, "font") == 0)
1564    {
1565        type = FIELD_STRING;
1566        pField.str = &di->font;
1567        def = _GD_Font;
1568    }
1569    else if ((uStrCaseCmp(field, "fontslant") == 0) ||
1570             (uStrCaseCmp(field, "slant") == 0))
1571    {
1572        type = FIELD_STRING;
1573        pField.str = &di->fontSlant;
1574        def = _GD_FontSlant;
1575    }
1576    else if ((uStrCaseCmp(field, "fontweight") == 0) ||
1577             (uStrCaseCmp(field, "weight") == 0))
1578    {
1579        type = FIELD_STRING;
1580        pField.str = &di->fontWeight;
1581        def = _GD_FontWeight;
1582    }
1583    else if ((uStrCaseCmp(field, "fontwidth") == 0) ||
1584             (uStrCaseCmp(field, "setwidth") == 0))
1585    {
1586        type = FIELD_STRING;
1587        pField.str = &di->fontSetWidth;
1588        def = _GD_FontSetWidth;
1589    }
1590    else if ((uStrCaseCmp(field, "fontvariant") == 0) ||
1591             (uStrCaseCmp(field, "variant") == 0))
1592    {
1593        type = FIELD_STRING;
1594        pField.str = &di->fontVariant;
1595        def = _GD_FontVariant;
1596    }
1597    else if ((uStrCaseCmp(field, "fontencoding") == 0) ||
1598             (uStrCaseCmp(field, "encoding") == 0))
1599    {
1600        type = FIELD_STRING;
1601        pField.str = &di->fontEncoding;
1602        def = _GD_FontEncoding;
1603    }
1604    else if ((uStrCaseCmp(field, "xfont") == 0) ||
1605             (uStrCaseCmp(field, "xfontname") == 0))
1606    {
1607        type = FIELD_STRING;
1608        pField.str = &di->fontSpec;
1609        def = _GD_FontSpec;
1610    }
1611    else if (uStrCaseCmp(field, "fontsize") == 0)
1612    {
1613        type = FIELD_USHORT;
1614        pField.uval = &di->fontSize;
1615        def = _GD_FontSize;
1616    }
1617    else
1618    {
1619        return ReportBadField(typeName, field, ddText(info->dpy, di));
1620    }
1621    if (arrayNdx != NULL)
1622    {
1623        info->errorCount++;
1624        return ReportNotArray(typeName, field, ddText(info->dpy, di));
1625    }
1626    if (type == FIELD_STRING)
1627    {
1628        if (!ExprResolveString(value, &tmp, NULL, NULL))
1629        {
1630            info->errorCount++;
1631            return ReportBadType(typeName, field, ddText(info->dpy, di),
1632                                 "string");
1633        }
1634        di->defs.defined |= def;
1635        *pField.str = XkbInternAtom(NULL, tmp.str, False);
1636    }
1637    else
1638    {
1639        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1640        {
1641            info->errorCount++;
1642            return ReportBadType(typeName, field, ddText(info->dpy, di),
1643                                 "number");
1644        }
1645        if ((type == FIELD_USHORT) && (tmp.ival < 0))
1646        {
1647            info->errorCount++;
1648            return
1649                ReportBadType(typeName, field, ddText(info->dpy, di),
1650                              "unsigned");
1651        }
1652        di->defs.defined |= def;
1653        if (type == FIELD_USHORT)
1654            *pField.uval = tmp.uval;
1655        else
1656            *pField.ival = tmp.ival;
1657    }
1658    return True;
1659}
1660
1661static int
1662SetIndicatorDoodadField(DoodadInfo * di,
1663                        char *field,
1664                        ExprDef * arrayNdx,
1665                        ExprDef * value,
1666                        SectionInfo * si, GeometryInfo * info)
1667{
1668    ExprResult tmp;
1669
1670    if ((uStrCaseCmp(field, "oncolor") == 0)
1671        || (uStrCaseCmp(field, "offcolor") == 0)
1672        || (uStrCaseCmp(field, "shape") == 0))
1673    {
1674        if (arrayNdx != NULL)
1675        {
1676            info->errorCount++;
1677            return ReportNotArray("indicator doodad", field,
1678                                  ddText(info->dpy, di));
1679        }
1680        if (!ExprResolveString(value, &tmp, NULL, NULL))
1681        {
1682            info->errorCount++;
1683            return ReportBadType("indicator doodad", field,
1684                                 ddText(info->dpy, di), "string");
1685        }
1686        if (uStrCaseCmp(field, "oncolor") == 0)
1687        {
1688            di->defs.defined |= _GD_Color;
1689            di->color = XkbInternAtom(NULL, tmp.str, False);
1690        }
1691        else if (uStrCaseCmp(field, "offcolor") == 0)
1692        {
1693            di->defs.defined |= _GD_OffColor;
1694            di->offColor = XkbInternAtom(NULL, tmp.str, False);
1695        }
1696        else if (uStrCaseCmp(field, "shape") == 0)
1697        {
1698            di->defs.defined |= _GD_Shape;
1699            di->shape = XkbInternAtom(info->dpy, tmp.str, False);
1700        }
1701        return True;
1702    }
1703    return ReportBadField("indicator doodad", field, ddText(info->dpy, di));
1704}
1705
1706static int
1707SetLogoDoodadField(DoodadInfo * di,
1708                   char *field,
1709                   ExprDef * arrayNdx,
1710                   ExprDef * value, SectionInfo * si, GeometryInfo * info)
1711{
1712    ExprResult tmp;
1713    char *typeName = "logo doodad";
1714
1715    if ((!uStrCaseCmp(field, "corner"))
1716        || (!uStrCaseCmp(field, "cornerradius")))
1717    {
1718        if (arrayNdx != NULL)
1719        {
1720            info->errorCount++;
1721            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1722        }
1723        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1724        {
1725            info->errorCount++;
1726            return ReportBadType(typeName, field, ddText(info->dpy, di),
1727                                 "number");
1728        }
1729        di->defs.defined |= _GD_Corner;
1730        di->corner = tmp.ival;
1731        return True;
1732    }
1733    else if (uStrCaseCmp(field, "angle") == 0)
1734    {
1735        if (arrayNdx != NULL)
1736        {
1737            info->errorCount++;
1738            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1739        }
1740        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1741        {
1742            info->errorCount++;
1743            return ReportBadType(typeName, field, ddText(info->dpy, di),
1744                                 "number");
1745        }
1746        di->defs.defined |= _GD_Angle;
1747        di->angle = tmp.ival;
1748        return True;
1749    }
1750    else if (uStrCaseCmp(field, "shape") == 0)
1751    {
1752        if (arrayNdx != NULL)
1753        {
1754            info->errorCount++;
1755            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1756        }
1757        if (!ExprResolveString(value, &tmp, NULL, NULL))
1758        {
1759            info->errorCount++;
1760            return ReportBadType(typeName, field, ddText(info->dpy, di),
1761                                 "string");
1762        }
1763        di->shape = XkbInternAtom(info->dpy, tmp.str, False);
1764        di->defs.defined |= _GD_Shape;
1765        return True;
1766    }
1767    else if ((!uStrCaseCmp(field, "logoname"))
1768             || (!uStrCaseCmp(field, "name")))
1769    {
1770        if (arrayNdx != NULL)
1771        {
1772            info->errorCount++;
1773            return ReportNotArray(typeName, field, ddText(info->dpy, di));
1774        }
1775        if (!ExprResolveString(value, &tmp, NULL, NULL))
1776        {
1777            info->errorCount++;
1778            return ReportBadType(typeName, field, ddText(info->dpy, di),
1779                                 "string");
1780        }
1781        di->logoName = uStringDup(tmp.str);
1782        return True;
1783    }
1784    return ReportBadField(typeName, field, ddText(info->dpy, di));
1785}
1786
1787static int
1788SetDoodadField(DoodadInfo * di,
1789               char *field,
1790               ExprDef * arrayNdx,
1791               ExprDef * value, SectionInfo * si, GeometryInfo * info)
1792{
1793    ExprResult tmp;
1794
1795    if (uStrCaseCmp(field, "priority") == 0)
1796    {
1797        if (arrayNdx != NULL)
1798        {
1799            info->errorCount++;
1800            return ReportNotArray("doodad", field, ddText(info->dpy, di));
1801        }
1802        if (!ExprResolveInteger(value, &tmp, NULL, NULL))
1803        {
1804            info->errorCount++;
1805            return ReportBadType("doodad", field, ddText(info->dpy, di),
1806                                 "integer");
1807        }
1808        if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
1809        {
1810            info->errorCount++;
1811            ERROR2("Doodad priority %d out of range (must be 0..%d)\n",
1812                   tmp.ival, XkbGeomMaxPriority);
1813            ACTION1("Priority for doodad %s not changed",
1814                    ddText(info->dpy, di));
1815            return False;
1816        }
1817        di->defs.defined |= _GD_Priority;
1818        di->priority = tmp.ival;
1819        return True;
1820    }
1821    else if (uStrCaseCmp(field, "left") == 0)
1822    {
1823        if (arrayNdx != NULL)
1824        {
1825            info->errorCount++;
1826            return ReportNotArray("doodad", field, ddText(info->dpy, di));
1827        }
1828        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1829        {
1830            info->errorCount++;
1831            return ReportBadType("doodad", field, ddText(info->dpy, di),
1832                                 "number");
1833        }
1834        di->defs.defined |= _GD_Left;
1835        di->left = tmp.ival;
1836        return True;
1837    }
1838    else if (uStrCaseCmp(field, "top") == 0)
1839    {
1840        if (arrayNdx != NULL)
1841        {
1842            info->errorCount++;
1843            return ReportNotArray("doodad", field, ddText(info->dpy, di));
1844        }
1845        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1846        {
1847            info->errorCount++;
1848            return ReportBadType("doodad", field, ddText(info->dpy, di),
1849                                 "number");
1850        }
1851        di->defs.defined |= _GD_Top;
1852        di->top = tmp.ival;
1853        return True;
1854    }
1855    else if (uStrCaseCmp(field, "color") == 0)
1856    {
1857        if (arrayNdx != NULL)
1858        {
1859            info->errorCount++;
1860            return ReportNotArray("doodad", field, ddText(info->dpy, di));
1861        }
1862        if (!ExprResolveString(value, &tmp, NULL, NULL))
1863        {
1864            info->errorCount++;
1865            return ReportBadType("doodad", field, ddText(info->dpy, di),
1866                                 "string");
1867        }
1868        di->defs.defined |= _GD_Color;
1869        di->color = XkbInternAtom(NULL, tmp.str, False);
1870        return True;
1871    }
1872    switch (di->type)
1873    {
1874    case XkbOutlineDoodad:
1875    case XkbSolidDoodad:
1876        return SetShapeDoodadField(di, field, arrayNdx, value, si, info);
1877    case XkbTextDoodad:
1878        return SetTextDoodadField(di, field, arrayNdx, value, si, info);
1879    case XkbIndicatorDoodad:
1880        return SetIndicatorDoodadField(di, field, arrayNdx, value, si, info);
1881    case XkbLogoDoodad:
1882        return SetLogoDoodadField(di, field, arrayNdx, value, si, info);
1883    }
1884    WSGO1("Unknown doodad type %d in SetDoodadField\n",
1885          (unsigned int) di->type);
1886    ACTION2("Definition of %s in %s ignored\n", field, ddText(info->dpy, di));
1887    return False;
1888}
1889
1890static int
1891SetSectionField(SectionInfo * si,
1892                char *field,
1893                ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1894{
1895    unsigned short *pField;
1896    unsigned def;
1897    ExprResult tmp;
1898
1899    pField = NULL;
1900    def = 0;
1901    if (uStrCaseCmp(field, "priority") == 0)
1902    {
1903        if (arrayNdx != NULL)
1904        {
1905            info->errorCount++;
1906            return ReportNotArray("keyboard section", field,
1907                                  scText(info->dpy, si));
1908        }
1909        if (!ExprResolveInteger(value, &tmp, NULL, NULL))
1910        {
1911            info->errorCount++;
1912            ReportBadType("keyboard section", field,
1913                          scText(info->dpy, si), "integer");
1914            return False;
1915        }
1916        if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
1917        {
1918            info->errorCount++;
1919            ERROR2("Section priority %d out of range (must be 0..%d)\n",
1920                   tmp.ival, XkbGeomMaxPriority);
1921            ACTION1("Priority for section %s not changed",
1922                    scText(info->dpy, si));
1923            return False;
1924        }
1925        si->priority = tmp.ival;
1926        si->defs.defined |= _GS_Priority;
1927        return True;
1928    }
1929    else if (uStrCaseCmp(field, "top") == 0)
1930    {
1931        pField = &si->top;
1932        def = _GS_Top;
1933    }
1934    else if (uStrCaseCmp(field, "left") == 0)
1935    {
1936        pField = &si->left;
1937        def = _GS_Left;
1938    }
1939    else if (uStrCaseCmp(field, "width") == 0)
1940    {
1941        pField = &si->width;
1942        def = _GS_Width;
1943    }
1944    else if (uStrCaseCmp(field, "height") == 0)
1945    {
1946        pField = &si->height;
1947        def = _GS_Height;
1948    }
1949    else if (uStrCaseCmp(field, "angle") == 0)
1950    {
1951        pField = &si->angle;
1952        def = _GS_Angle;
1953    }
1954    else
1955    {
1956        info->errorCount++;
1957        return ReportBadField("keyboard section", field,
1958                              scText(info->dpy, si));
1959    }
1960    if (arrayNdx != NULL)
1961    {
1962        info->errorCount++;
1963        return ReportNotArray("keyboard section", field,
1964                              scText(info->dpy, si));
1965    }
1966    if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1967    {
1968        info->errorCount++;
1969        ReportBadType("keyboard section", field, scText(info->dpy, si),
1970                      "number");
1971        return False;
1972    }
1973    si->defs.defined |= def;
1974    *pField = tmp.uval;
1975    return True;
1976}
1977
1978static int
1979SetRowField(RowInfo * row,
1980            char *field,
1981            ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1982{
1983    ExprResult tmp;
1984
1985    if (uStrCaseCmp(field, "top") == 0)
1986    {
1987        if (arrayNdx != NULL)
1988        {
1989            info->errorCount++;
1990            return ReportNotArray("keyboard row", field,
1991                                  rowText(info->dpy, row));
1992        }
1993        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1994        {
1995            info->errorCount++;
1996            return ReportBadType("keyboard row", field,
1997                                 rowText(info->dpy, row), "number");
1998        }
1999        row->defs.defined |= _GR_Top;
2000        row->top = tmp.uval;
2001    }
2002    else if (uStrCaseCmp(field, "left") == 0)
2003    {
2004        if (arrayNdx != NULL)
2005        {
2006            info->errorCount++;
2007            return ReportNotArray("keyboard row", field,
2008                                  rowText(info->dpy, row));
2009        }
2010        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
2011        {
2012            info->errorCount++;
2013            return ReportBadType("keyboard row", field,
2014                                 rowText(info->dpy, row), "number");
2015        }
2016        row->defs.defined |= _GR_Left;
2017        row->left = tmp.uval;
2018    }
2019    else if (uStrCaseCmp(field, "vertical") == 0)
2020    {
2021        if (arrayNdx != NULL)
2022        {
2023            info->errorCount++;
2024            return ReportNotArray("keyboard row", field,
2025                                  rowText(info->dpy, row));
2026        }
2027        if (!ExprResolveBoolean(value, &tmp, NULL, NULL))
2028        {
2029            info->errorCount++;
2030            return ReportBadType("keyboard row", field,
2031                                 rowText(info->dpy, row), "boolean");
2032        }
2033        row->defs.defined |= _GR_Vertical;
2034        row->vertical = tmp.uval;
2035    }
2036    else
2037    {
2038        info->errorCount++;
2039        return ReportBadField("keyboard row", field, rowText(info->dpy, row));
2040    }
2041    return True;
2042}
2043
2044static int
2045SetKeyField(KeyInfo * key,
2046            const char *field,
2047            ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
2048{
2049    ExprResult tmp;
2050
2051    if (uStrCaseCmp(field, "gap") == 0)
2052    {
2053        if (arrayNdx != NULL)
2054        {
2055            info->errorCount++;
2056            return ReportNotArray("key", field, keyText(key));
2057        }
2058        if (!ExprResolveFloat(value, &tmp, NULL, NULL))
2059        {
2060            info->errorCount++;
2061            return ReportBadType("key", field, keyText(key), "number");
2062        }
2063        key->defs.defined |= _GK_Gap;
2064        key->gap = tmp.ival;
2065    }
2066    else if (uStrCaseCmp(field, "shape") == 0)
2067    {
2068        if (arrayNdx != NULL)
2069        {
2070            info->errorCount++;
2071            return ReportNotArray("key", field, keyText(key));
2072        }
2073        if (!ExprResolveString(value, &tmp, NULL, NULL))
2074        {
2075            info->errorCount++;
2076            return ReportBadType("key", field, keyText(key), "string");
2077        }
2078        key->defs.defined |= _GK_Shape;
2079        key->shape = XkbInternAtom(info->dpy, tmp.str, False);
2080    }
2081    else if ((uStrCaseCmp(field, "color") == 0) ||
2082             (uStrCaseCmp(field, "keycolor") == 0))
2083    {
2084        if (arrayNdx != NULL)
2085        {
2086            info->errorCount++;
2087            return ReportNotArray("key", field, keyText(key));
2088        }
2089        if (!ExprResolveString(value, &tmp, NULL, NULL))
2090        {
2091            info->errorCount++;
2092            return ReportBadType("key", field, keyText(key), "string");
2093        }
2094        key->defs.defined |= _GK_Color;
2095        key->color = XkbInternAtom(NULL, tmp.str, False);
2096    }
2097    else if ((uStrCaseCmp(field, "name") == 0)
2098             || (uStrCaseCmp(field, "keyname") == 0))
2099    {
2100        if (arrayNdx != NULL)
2101        {
2102            info->errorCount++;
2103            return ReportNotArray("key", field, keyText(key));
2104        }
2105        if (!ExprResolveKeyName(value, &tmp, NULL, NULL))
2106        {
2107            info->errorCount++;
2108            return ReportBadType("key", field, keyText(key), "key name");
2109        }
2110        key->defs.defined |= _GK_Name;
2111        bzero(key->name, XkbKeyNameLength + 1);
2112        strncpy(key->name, tmp.keyName.name, XkbKeyNameLength);
2113    }
2114    else
2115    {
2116        info->errorCount++;
2117        return ReportBadField("key", field, keyText(key));
2118    }
2119    return True;
2120}
2121
2122static int
2123SetGeometryProperty(GeometryInfo * info, char *property, ExprDef * value)
2124{
2125    PropertyInfo pi;
2126    ExprResult result;
2127
2128    InitPropertyInfo(&pi, info);
2129    pi.name = property;
2130    if (!ExprResolveString(value, &result, NULL, NULL))
2131    {
2132        info->errorCount++;
2133        ERROR("Property values must be type string\n");
2134        ACTION1("Ignoring illegal definition of \"%s\" property\n", property);
2135        return False;
2136    }
2137    pi.value = result.str;
2138    return AddProperty(info, &pi);
2139}
2140
2141static int
2142HandleGeometryVar(VarDef * stmt, XkbDescPtr xkb, GeometryInfo * info)
2143{
2144    ExprResult elem, field, tmp;
2145    ExprDef *ndx;
2146    DoodadInfo *di;
2147    Atom *pField;
2148
2149    if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
2150        return 0;               /* internal error, already reported */
2151    if (elem.str && (uStrCaseCmp(elem.str, "shape") == 0))
2152        return SetShapeField(NULL, field.str, ndx, stmt->value, info);
2153    if (elem.str && (uStrCaseCmp(elem.str, "key") == 0))
2154        return SetKeyField(&info->dfltSection.dfltRow.dfltKey,
2155                           field.str, ndx, stmt->value, info);
2156    if (elem.str && (uStrCaseCmp(elem.str, "row") == 0))
2157        return SetRowField(&info->dfltSection.dfltRow, field.str, ndx,
2158                           stmt->value, info);
2159    if (elem.str && (uStrCaseCmp(elem.str, "section") == 0))
2160    {
2161        return SetSectionField(&info->dfltSection, field.str, ndx,
2162                               stmt->value, info);
2163    }
2164    if (elem.str && (uStrCaseCmp(elem.str, "property") == 0))
2165    {
2166        if (ndx != NULL)
2167        {
2168            info->errorCount++;
2169            ERROR1("The %s geometry property is not an array\n", field.str);
2170            ACTION("Ignoring illegal property definition\n");
2171            return False;
2172        }
2173        return SetGeometryProperty(info, field.str, stmt->value);
2174    }
2175    if (elem.str
2176        && ((di = FindDfltDoodadByTypeName(elem.str, NULL, info)) != NULL))
2177    {
2178        return SetDoodadField(di, field.str, ndx, stmt->value, NULL, info);
2179    }
2180    if (elem.str && (uStrCaseCmp(elem.str, "solid") == 0))
2181    {
2182        DoodadInfo *dflt;
2183        dflt = FindDoodadByType(info->dfltDoodads, XkbSolidDoodad);
2184        if (dflt == NULL)
2185            dflt = NextDfltDoodad(NULL, info);
2186        return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2187    }
2188    if (elem.str && (uStrCaseCmp(elem.str, "outline") == 0))
2189    {
2190        DoodadInfo *dflt;
2191        dflt = FindDoodadByType(info->dfltDoodads, XkbOutlineDoodad);
2192        if (dflt == NULL)
2193            dflt = NextDfltDoodad(NULL, info);
2194        return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2195    }
2196    if (elem.str && (uStrCaseCmp(elem.str, "text") == 0))
2197    {
2198        DoodadInfo *dflt;
2199        dflt = FindDoodadByType(info->dfltDoodads, XkbTextDoodad);
2200        if (dflt == NULL)
2201            dflt = NextDfltDoodad(NULL, info);
2202        return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2203    }
2204    if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
2205    {
2206        DoodadInfo *dflt;
2207        dflt = FindDoodadByType(info->dfltDoodads, XkbIndicatorDoodad);
2208        if (dflt == NULL)
2209            dflt = NextDfltDoodad(NULL, info);
2210        return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2211    }
2212    if (elem.str && (uStrCaseCmp(elem.str, "logo") == 0))
2213    {
2214        DoodadInfo *dflt;
2215        dflt = FindDoodadByType(info->dfltDoodads, XkbLogoDoodad);
2216        if (dflt == NULL)
2217            dflt = NextDfltDoodad(NULL, info);
2218        return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2219    }
2220    if (elem.str)
2221    {
2222        WARN("Assignment to field of unknown element\n");
2223        ACTION2("No value assigned to %s.%s\n", elem.str, field.str);
2224        return False;
2225    }
2226
2227    if ((uStrCaseCmp(field.str, "width") == 0) ||
2228        (uStrCaseCmp(field.str, "widthmm") == 0))
2229    {
2230        if (ndx != NULL)
2231        {
2232            info->errorCount++;
2233            return ReportNotArray("keyboard", field.str, "geometry");
2234        }
2235        if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2236        {
2237            info->errorCount++;
2238            return ReportBadType("keyboard", field.str, "geometry", "number");
2239        }
2240        if (tmp.ival < 1)
2241        {
2242            WARN("Keyboard width must be positive\n");
2243            ACTION1("Ignoring illegal keyboard width %s\n",
2244                    XkbGeomFPText(tmp.ival, XkbMessage));
2245            return True;
2246        }
2247        if (info->widthMM != 0)
2248        {
2249            WARN("Keyboard width multiply defined\n");
2250            ACTION1("Using last definition (%s),",
2251                    XkbGeomFPText(tmp.ival, XkbMessage));
2252            INFO1(" ignoring first (%s)\n",
2253                  XkbGeomFPText(info->widthMM, XkbMessage));
2254        }
2255        info->widthMM = tmp.ival;
2256        return True;
2257    }
2258    else if ((uStrCaseCmp(field.str, "height") == 0) ||
2259             (uStrCaseCmp(field.str, "heightmm") == 0))
2260    {
2261        if (ndx != NULL)
2262        {
2263            info->errorCount++;
2264            return ReportNotArray("keyboard", field.str, "geometry");
2265        }
2266        if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2267        {
2268            info->errorCount++;
2269            return ReportBadType("keyboard", field.str, "geometry", "number");
2270        }
2271        if (tmp.ival < 1)
2272        {
2273            WARN("Keyboard height must be positive\n");
2274            ACTION1("Ignoring illegal keyboard height %s\n",
2275                    XkbGeomFPText(tmp.ival, XkbMessage));
2276            return True;
2277        }
2278        if (info->heightMM != 0)
2279        {
2280            WARN("Keyboard height multiply defined\n");
2281            ACTION1("Using last definition (%s),",
2282                    XkbGeomFPText(tmp.ival, XkbMessage));
2283            INFO1(" ignoring first (%s)\n",
2284                  XkbGeomFPText(info->heightMM, XkbMessage));
2285        }
2286        info->heightMM = tmp.ival;
2287        return True;
2288    }
2289    else if (uStrCaseCmp(field.str, "font") == 0)
2290    {
2291        pField = &info->font;
2292    }
2293    else if ((uStrCaseCmp(field.str, "fontslant") == 0) ||
2294             (uStrCaseCmp(field.str, "slant") == 0))
2295    {
2296        pField = &info->fontSlant;
2297    }
2298    else if ((uStrCaseCmp(field.str, "fontweight") == 0) ||
2299             (uStrCaseCmp(field.str, "weight") == 0))
2300    {
2301        pField = &info->fontWeight;
2302    }
2303    else if ((uStrCaseCmp(field.str, "fontwidth") == 0) ||
2304             (uStrCaseCmp(field.str, "setwidth") == 0))
2305    {
2306        pField = &info->fontWeight;
2307    }
2308    else if ((uStrCaseCmp(field.str, "fontencoding") == 0) ||
2309             (uStrCaseCmp(field.str, "encoding") == 0))
2310    {
2311        pField = &info->fontEncoding;
2312    }
2313    else if ((uStrCaseCmp(field.str, "xfont") == 0) ||
2314             (uStrCaseCmp(field.str, "xfontname") == 0))
2315    {
2316        pField = &info->fontSpec;
2317    }
2318    else if (uStrCaseCmp(field.str, "fontsize") == 0)
2319    {
2320        if (ndx != NULL)
2321        {
2322            info->errorCount++;
2323            return ReportNotArray("keyboard", field.str, "geometry");
2324        }
2325        if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2326        {
2327            info->errorCount++;
2328            return ReportBadType("keyboard", field.str, "geometry", "number");
2329        }
2330        if ((tmp.ival < 40) || (tmp.ival > 2550))
2331        {
2332            info->errorCount++;
2333            ERROR1("Illegal font size %d (must be 4..255)\n", tmp.ival);
2334            ACTION("Ignoring font size in keyboard geometry\n");
2335            return False;
2336        }
2337        info->fontSize = tmp.ival;
2338        return True;
2339    }
2340    else if ((uStrCaseCmp(field.str, "color") == 0) ||
2341             (uStrCaseCmp(field.str, "basecolor") == 0))
2342    {
2343        if (ndx != NULL)
2344        {
2345            info->errorCount++;
2346            return ReportNotArray("keyboard", field.str, "geometry");
2347        }
2348        if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2349        {
2350            info->errorCount++;
2351            return ReportBadType("keyboard", field.str, "geometry", "string");
2352        }
2353        info->baseColor = XkbInternAtom(NULL, tmp.str, False);
2354        return True;
2355    }
2356    else if (uStrCaseCmp(field.str, "labelcolor") == 0)
2357    {
2358        if (ndx != NULL)
2359        {
2360            info->errorCount++;
2361            return ReportNotArray("keyboard", field.str, "geometry");
2362        }
2363        if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2364        {
2365            info->errorCount++;
2366            return ReportBadType("keyboard", field.str, "geometry", "string");
2367        }
2368        info->labelColor = XkbInternAtom(NULL, tmp.str, False);
2369        return True;
2370    }
2371    else
2372    {
2373        return SetGeometryProperty(info, field.str, stmt->value);
2374    }
2375
2376    if (ndx != NULL)
2377    {
2378        info->errorCount++;
2379        return ReportNotArray("keyboard", field.str, "geometry");
2380    }
2381    if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2382    {
2383        info->errorCount++;
2384        return ReportBadType("keyboard", field.str, "geometry", "string");
2385    }
2386    *pField = XkbInternAtom(NULL, tmp.str, False);
2387    return True;
2388}
2389
2390/***====================================================================***/
2391
2392static Bool
2393HandleShapeBody(ShapeDef * def, ShapeInfo * si, unsigned merge,
2394                GeometryInfo * info)
2395{
2396    OutlineDef *ol;
2397    int nOut, nPt;
2398    XkbOutlinePtr outline;
2399    ExprDef *pt;
2400
2401    if (def->nOutlines < 1)
2402    {
2403        WARN1("Shape \"%s\" has no outlines\n", shText(info->dpy, si));
2404        ACTION("Definition ignored\n");
2405        return True;
2406    }
2407    si->nOutlines = def->nOutlines;
2408    si->outlines = uTypedCalloc(def->nOutlines, XkbOutlineRec);
2409    if (!si->outlines)
2410    {
2411        ERROR1("Couldn't allocate outlines for \"%s\"\n",
2412               shText(info->dpy, si));
2413        ACTION("Definition ignored\n");
2414        info->errorCount++;
2415        return False;
2416    }
2417    for (nOut = 0, ol = def->outlines; ol != NULL;
2418         ol = (OutlineDef *) ol->common.next)
2419    {
2420        if (ol->nPoints < 1)
2421        {
2422            SetShapeField(si, XkbAtomGetString(NULL, ol->field), NULL,
2423                          ol->points, info);
2424            continue;
2425        }
2426        outline = NULL;
2427        outline = &si->outlines[nOut++];
2428        outline->num_points = ol->nPoints;
2429        outline->corner_radius = si->dfltCornerRadius;
2430        outline->points = uTypedCalloc(ol->nPoints, XkbPointRec);
2431        if (!outline->points)
2432        {
2433            ERROR1("Can't allocate points for \"%s\"\n",
2434                   shText(info->dpy, si));
2435            ACTION("Definition ignored\n");
2436            info->errorCount++;
2437            return False;
2438        }
2439        for (nPt = 0, pt = ol->points; pt != NULL;
2440             pt = (ExprDef *) pt->common.next)
2441        {
2442            outline->points[nPt].x = pt->value.coord.x;
2443            outline->points[nPt].y = pt->value.coord.y;
2444            nPt++;
2445        }
2446        if (ol->field != None)
2447        {
2448            char *str = XkbAtomText(NULL, ol->field, XkbMessage);
2449            if ((uStrCaseCmp(str, "approximation") == 0) ||
2450                (uStrCaseCmp(str, "approx") == 0))
2451            {
2452                if (si->approx == NULL)
2453                    si->approx = outline;
2454                else
2455                {
2456                    WARN1("Multiple approximations for \"%s\"\n",
2457                          shText(info->dpy, si));
2458                    ACTION("Treating all but the first as normal outlines\n");
2459                }
2460            }
2461            else if (uStrCaseCmp(str, "primary") == 0)
2462            {
2463                if (si->primary == NULL)
2464                    si->primary = outline;
2465                else
2466                {
2467                    WARN1("Multiple primary outlines for \"%s\"\n",
2468                          shText(info->dpy, si));
2469                    ACTION("Treating all but the first as normal outlines\n");
2470                }
2471            }
2472            else
2473            {
2474                WARN2("Unknown outline type %s for \"%s\"\n", str,
2475                      shText(info->dpy, si));
2476                ACTION("Treated as a normal outline\n");
2477            }
2478        }
2479    }
2480    if (nOut != si->nOutlines)
2481    {
2482        WSGO2("Expected %d outlines, got %d\n",
2483              (unsigned int) si->nOutlines, nOut);
2484        si->nOutlines = nOut;
2485    }
2486    return True;
2487}
2488
2489static int
2490HandleShapeDef(ShapeDef * def, XkbDescPtr xkb, unsigned merge,
2491               GeometryInfo * info)
2492{
2493    ShapeInfo si;
2494
2495    if (def->merge != MergeDefault)
2496        merge = def->merge;
2497
2498    bzero(&si, sizeof(ShapeInfo));
2499    si.defs.merge = merge;
2500    si.name =
2501        XkbInternAtom(info->dpy, XkbAtomGetString(NULL, def->name), False);
2502    si.dfltCornerRadius = info->dfltCornerRadius;
2503    if (!HandleShapeBody(def, &si, merge, info))
2504        return False;
2505    if (!AddShape(info, &si))
2506        return False;
2507    return True;
2508}
2509
2510/***====================================================================***/
2511
2512static int
2513HandleDoodadDef(DoodadDef * def,
2514                unsigned merge, SectionInfo * si, GeometryInfo * info)
2515{
2516    ExprResult elem, field;
2517    ExprDef *ndx;
2518    DoodadInfo new;
2519    VarDef *var;
2520
2521    if (def->common.stmtType == StmtIndicatorMapDef)
2522    {
2523        def->common.stmtType = StmtDoodadDef;
2524        def->type = XkbIndicatorDoodad;
2525    }
2526    InitDoodadInfo(&new, def->type, si, info);
2527    new.name =
2528        XkbInternAtom(info->dpy, XkbAtomGetString(NULL, def->name), False);
2529    for (var = def->body; var != NULL; var = (VarDef *) var->common.next)
2530    {
2531        if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
2532            return 0;           /* internal error, already reported */
2533        if (elem.str != NULL)
2534        {
2535            WARN1("Assignment to field of unknown element in doodad %s\n",
2536                  ddText(info->dpy, &new));
2537            ACTION2("No value assigned to %s.%s\n", elem.str, field.str);
2538        }
2539        else if (!SetDoodadField(&new, field.str, ndx, var->value, si, info))
2540            return False;
2541    }
2542    if (!AddDoodad(si, info, &new))
2543        return False;
2544    ClearDoodadInfo(&new);
2545    return True;
2546}
2547
2548/***====================================================================***/
2549
2550static int
2551HandleOverlayDef(OverlayDef * def,
2552                 unsigned merge, SectionInfo * si, GeometryInfo * info)
2553{
2554    OverlayKeyDef *keyDef;
2555    OverlayKeyInfo *key;
2556    OverlayInfo ol;
2557
2558    if ((def->nKeys < 1) && (warningLevel > 3))
2559    {
2560        WARN2("Overlay \"%s\" in section \"%s\" has no keys\n",
2561              XkbAtomText(NULL, def->name, XkbMessage), scText(info->dpy,
2562                                                               si));
2563        ACTION("Overlay ignored\n");
2564        return True;
2565    }
2566    bzero(&ol, sizeof(OverlayInfo));
2567    ol.name =
2568        XkbInternAtom(info->dpy, XkbAtomGetString(NULL, def->name), False);
2569    for (keyDef = def->keys; keyDef;
2570         keyDef = (OverlayKeyDef *) keyDef->common.next)
2571    {
2572        key = uTypedCalloc(1, OverlayKeyInfo);
2573        if ((!key) && warningLevel > 0)
2574        {
2575            WSGO("Couldn't allocate OverlayKeyInfo\n");
2576            ACTION2("Overlay %s for section %s will be incomplete\n",
2577                    XkbAtomText(info->dpy, ol.name, XkbMessage),
2578                    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 *sinfo;
3615                sinfo = FindShape(info, ki->shape, "key", keyText(ki));
3616                if (!sinfo)
3617                    return False;
3618                key->shape_ndx = sinfo->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