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