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