#include "xkbcomp.h"
#include "tokens.h"
#include "expr.h"
#include "vmod.h"
#include "misc.h"
#include "indicators.h"
#include "action.h"
#include "keycodes.h"
#include "alias.h"
#include "X11/extensions/XKBgeom.h"
#define DFLT_FONT "helvetica"
#define DFLT_SLANT "r"
#define DFLT_WEIGHT "medium"
#define DFLT_SET_WIDTH "normal"
#define DFLT_VARIANT ""
#define DFLT_ENCODING "iso8859-1"
#define DFLT_SIZE 120
typedef struct _PropertyInfo {
CommonInfo defs;
char * name;
char * value;
} PropertyInfo;
#define _GSh_Outlines (1<<1)
#define _GSh_Approx (1<<2)
#define _GSh_Primary (1<<3)
typedef struct _ShapeInfo {
CommonInfo defs;
Atom name;
short index;
unsigned short nOutlines;
unsigned short szOutlines;
XkbOutlinePtr outlines;
XkbOutlinePtr approx;
XkbOutlinePtr primary;
int dfltCornerRadius;
} ShapeInfo;
#define shText(d,s) \
((s)?XkbAtomText((d),(s)->name,XkbMessage):"default shape")
#define _GD_Priority (1<<0)
#define _GD_Top (1<<1)
#define _GD_Left (1<<2)
#define _GD_Angle (1<<3)
#define _GD_Shape (1<<4)
#define _GD_FontVariant (1<<4)
#define _GD_Corner (1<<5)
#define _GD_Width (1<<5)
#define _GD_Color (1<<6)
#define _GD_OffColor (1<<7)
#define _GD_Height (1<<7)
#define _GD_Text (1<<8)
#define _GD_Font (1<<9)
#define _GD_FontSlant (1<<10)
#define _GD_FontWeight (1<<11)
#define _GD_FontSetWidth (1<<12)
#define _GD_FontSize (1<<13)
#define _GD_FontEncoding (1<<14)
#define _GD_FontSpec (1<<15)
#define _GD_FontParts (_GD_Font|_GD_FontSlant|_GD_FontWeight|_GD_FontSetWidth|_GD_FontSize|_GD_FontEncoding|_GD_FontVariant)
typedef struct _DoodadInfo {
CommonInfo defs;
Atom name;
unsigned char type;
unsigned char priority;
short top;
short left;
short angle;
unsigned short corner;
unsigned short width;
unsigned short height;
Atom shape;
Atom color;
Atom offColor;
Atom text;
Atom font;
Atom fontSlant;
Atom fontWeight;
Atom fontSetWidth;
Atom fontVariant;
unsigned short fontSize;
Atom fontEncoding;
Atom fontSpec;
char * logoName;
struct _SectionInfo *section;
} DoodadInfo;
#define Yes 1
#define No 0
#define Undefined -1
#define _GK_Default (1<<0)
#define _GK_Name (1<<1)
#define _GK_Gap (1<<2)
#define _GK_Shape (1<<3)
#define _GK_Color (1<<4)
typedef struct _KeyInfo {
CommonInfo defs;
char name[8];
short gap;
short index;
Atom shape;
Atom color;
struct _RowInfo * row;
} KeyInfo;
#define keyText(k) ((k)&&(k)->name[0]?(k)->name:"default")
#define _GR_Default (1<<0)
#define _GR_Vertical (1<<1)
#define _GR_Top (1<<2)
#define _GR_Left (1<<3)
typedef struct _RowInfo {
CommonInfo defs;
unsigned short top;
unsigned short left;
short index;
Bool vertical;
unsigned short nKeys;
KeyInfo * keys;
KeyInfo dfltKey;
struct _SectionInfo *section;
} RowInfo;
#define rowText(d,r) \
((r)?XkbAtomText((d),(r)->section->name,XkbMessage):"default")
#define _GOK_UnknownRow -1
typedef struct _OverlayKeyInfo {
CommonInfo defs;
short sectionRow;
short overlayRow;
char over[XkbKeyNameLength+1];
char under[XkbKeyNameLength+1];
} OverlayKeyInfo;
typedef struct _OverlayInfo {
CommonInfo defs;
Atom name;
unsigned short nRows;
unsigned short nKeys;
OverlayKeyInfo *keys;
} OverlayInfo;
#define oiText(d,o) ((o)?XkbAtomText((d),(o)->name,XkbMessage):"default")
#define _GS_Default (1<<0)
#define _GS_Name (1<<1)
#define _GS_Top (1<<2)
#define _GS_Left (1<<3)
#define _GS_Width (1<<4)
#define _GS_Height (1<<5)
#define _GS_Angle (1<<6)
#define _GS_Priority (1<<7)
typedef struct _SectionInfo {
CommonInfo defs;
Atom name;
unsigned short top;
unsigned short left;
unsigned short width;
unsigned short height;
unsigned short angle;
unsigned short nRows;
unsigned short nDoodads;
unsigned short nOverlays;
unsigned char priority;
unsigned char nextDoodadPriority;
RowInfo * rows;
DoodadInfo * doodads;
RowInfo dfltRow;
DoodadInfo * dfltDoodads;
OverlayInfo * overlays;
struct _GeometryInfo *geometry;
} SectionInfo;
#define scText(d,s) ((s)?XkbAtomText((d),(s)->name,XkbMessage):"default")
typedef struct _GeometryInfo {
char * name;
Display * dpy;
unsigned fileID;
unsigned merge;
int errorCount;
unsigned nextPriority;
int nProps;
int nShapes;
int nSections;
int nDoodads;
PropertyInfo * props;
ShapeInfo * shapes;
SectionInfo * sections;
DoodadInfo * doodads;
int widthMM;
int heightMM;
Atom font;
Atom fontSlant;
Atom fontWeight;
Atom fontSetWidth;
Atom fontVariant;
unsigned fontSize;
Atom fontEncoding;
Atom fontSpec;
Atom baseColor;
Atom labelColor;
int dfltCornerRadius;
SectionInfo dfltSection;
DoodadInfo * dfltDoodads;
AliasInfo * aliases;
} GeometryInfo;
static char *
ddText(Display *dpy,DoodadInfo *di)
{
static char buf[64];
if (di==NULL) {
strcpy(buf,"default");
return buf;
}
if (di->section) {
sprintf(buf,"%s in section %s",XkbAtomText(dpy,di->name,XkbMessage),
scText(dpy,di->section));
return buf;
}
return XkbAtomText(dpy,di->name,XkbMessage);
}
static void
InitPropertyInfo(PropertyInfo *pi,GeometryInfo *info)
{
pi->defs.defined= 0;
pi->defs.fileID= info->fileID;
pi->defs.merge= info->merge;
pi->name= pi->value= NULL;
return;
}
static void
FreeProperties(PropertyInfo *pi,GeometryInfo *info)
{
PropertyInfo * tmp;
PropertyInfo * next;
if (info->props==pi) {
info->props= NULL;
info->nProps= 0;
}
for (tmp=pi;tmp!=NULL;tmp=next) {
if (tmp->name)
uFree(tmp->name);
if (tmp->value)
uFree(tmp->value);
tmp->name= tmp->value=NULL;
next= (PropertyInfo *)tmp->defs.next;
uFree(tmp);
}
return;
}
static void
InitKeyInfo(KeyInfo *key,RowInfo *row,GeometryInfo *info)
{
if (key!=&row->dfltKey) {
*key= row->dfltKey;
strcpy(key->name,"unknown");
key->defs.defined&= ~_GK_Default;
}
else {
bzero(key,sizeof(KeyInfo));
strcpy(key->name,"default");
key->defs.defined= _GK_Default;
key->defs.fileID= info->fileID;
key->defs.merge= info->merge;
key->defs.next= NULL;
key->row= row;
}
return;
}
static void
ClearKeyInfo(KeyInfo *key)
{
key->defs.defined&= ~_GK_Default;
strcpy(key->name,"default");
key->gap= 0;
key->shape= None;
key->color= None;
return;
}
static void
FreeKeys(KeyInfo *key,RowInfo *row,GeometryInfo *info)
{
KeyInfo * tmp;
KeyInfo * next;
if (row->keys==key) {
row->nKeys= 0;
row->keys= NULL;
}
for (tmp=key;tmp!=NULL;tmp=next) {
ClearKeyInfo(tmp);
next= (KeyInfo *)tmp->defs.next;
uFree(tmp);
}
return;
}
static void
InitRowInfo(RowInfo *row,SectionInfo *section,GeometryInfo *info)
{
if (row!= §ion->dfltRow) {
*row= section->dfltRow;
row->defs.defined&= ~_GR_Default;
}
else {
bzero(row,sizeof(RowInfo *));
row->defs.defined= _GR_Default;
row->defs.fileID= info->fileID;
row->defs.merge= info->merge;
row->defs.next= NULL;
row->section= section;
row->nKeys= 0;
row->keys= NULL;
InitKeyInfo(&row->dfltKey,row,info);
}
return;
}
static void
ClearRowInfo(RowInfo *row,GeometryInfo *info)
{
row->defs.defined&= ~_GR_Default;
row->top= row->left= 0;
row->vertical= False;
row->nKeys= 0;
if (row->keys)
FreeKeys(row->keys,row,info);
ClearKeyInfo(&row->dfltKey);
row->dfltKey.defs.defined|= _GK_Default;
return;
}
static void
FreeRows(RowInfo *row,SectionInfo *section,GeometryInfo *info)
{
RowInfo * next;
RowInfo * tmp;
if (row==section->rows) {
section->nRows= 0;
section->rows= NULL;
}
for (tmp=row;tmp!=NULL;tmp=next) {
ClearRowInfo(tmp,info);
next= (RowInfo *)tmp->defs.next;
uFree(tmp);
}
return;
}
static DoodadInfo *
FindDoodadByType(DoodadInfo *di,unsigned type)
{
while (di) {
if (di->type==type)
return di;
di= (DoodadInfo *)di->defs.next;
}
return NULL;
}
static DoodadInfo *
FindDoodadByName(DoodadInfo *di,Atom name)
{
while (di) {
if (di->name==name)
return di;
di= (DoodadInfo *)di->defs.next;
}
return NULL;
}
static void
InitDoodadInfo(DoodadInfo *di,unsigned type,SectionInfo *si,GeometryInfo *info)
{
DoodadInfo * dflt;
dflt= NULL;
if (si && si->dfltDoodads)
dflt= FindDoodadByType(si->dfltDoodads,type);
if ((dflt==NULL)&&(info->dfltDoodads))
dflt= FindDoodadByType(info->dfltDoodads,type);
if (dflt!=NULL) {
*di= *dflt;
di->defs.next= NULL;
}
else {
bzero(di,sizeof(DoodadInfo));
di->defs.fileID= info->fileID;
di->type= type;
}
di->section= si;
if (si!=NULL) {
di->priority= si->nextDoodadPriority++;
#if XkbGeomMaxPriority < 255
if (si->nextDoodadPriority>XkbGeomMaxPriority)
si->nextDoodadPriority= XkbGeomMaxPriority;
#endif
}
else {
di->priority= info->nextPriority++;
if (info->nextPriority>XkbGeomMaxPriority)
info->nextPriority= XkbGeomMaxPriority;
}
return;
}
static void
ClearDoodadInfo(DoodadInfo *di)
{
CommonInfo defs;
defs= di->defs;
bzero(di,sizeof(DoodadInfo));
di->defs= defs;
di->defs.defined= 0;
return;
}
static void
ClearOverlayInfo(OverlayInfo *ol)
{
if (ol && ol->keys) {
ol->keys= (OverlayKeyInfo *)ClearCommonInfo(&ol->keys->defs);
ol->nKeys= 0;
}
return;
}
static void
FreeDoodads(DoodadInfo *di,SectionInfo *si,GeometryInfo *info)
{
DoodadInfo * tmp;
DoodadInfo * next;
if (si) {
if (si->doodads==di) {
si->doodads= NULL;
si->nDoodads= 0;
}
if (si->dfltDoodads==di)
si->dfltDoodads= NULL;
}
if (info->doodads==di) {
info->doodads= NULL;
info->nDoodads= 0;
}
if (info->dfltDoodads==di)
info->dfltDoodads= NULL;
for (tmp=di;tmp!=NULL;tmp=next) {
next= (DoodadInfo *)tmp->defs.next;
ClearDoodadInfo(tmp);
uFree(tmp);
}
return;
}
static void
InitSectionInfo(SectionInfo *si,GeometryInfo *info)
{
if (si!=&info->dfltSection) {
*si= info->dfltSection;
si->defs.defined&= ~_GS_Default;
si->name= XkbInternAtom(info->dpy,"unknown",False);
si->priority= info->nextPriority++;
if (info->nextPriority>XkbGeomMaxPriority)
info->nextPriority= XkbGeomMaxPriority;
}
else {
bzero(si,sizeof(SectionInfo));
si->defs.fileID= info->fileID;
si->defs.merge= info->merge;
si->defs.next= NULL;
si->geometry= info;
si->name= XkbInternAtom(info->dpy,"default",False);
InitRowInfo(&si->dfltRow,si,info);
}
return;
}
static void
DupSectionInfo(SectionInfo *into,SectionInfo *from,GeometryInfo *info)
{
CommonInfo defs;
defs= into->defs;
*into= *from;
into->defs.fileID= defs.fileID;
into->defs.merge= defs.merge;
into->defs.next= NULL;
into->dfltRow.defs.fileID= defs.fileID;
into->dfltRow.defs.merge= defs.merge;
into->dfltRow.defs.next= NULL;
into->dfltRow.section= into;
into->dfltRow.dfltKey.defs.fileID= defs.fileID;
into->dfltRow.dfltKey.defs.merge= defs.merge;
into->dfltRow.dfltKey.defs.next= NULL;
into->dfltRow.dfltKey.row= &into->dfltRow;
return;
}
static void
ClearSectionInfo(SectionInfo *si,GeometryInfo *info)
{
si->defs.defined&= ~_GS_Default;
si->name= XkbInternAtom(info->dpy,"default",False);
si->top= si->left= 0;
si->width= si->height= 0;
si->angle= 0;
if (si->rows) {
FreeRows(si->rows,si,info);
si->rows= NULL;
}
ClearRowInfo(&si->dfltRow,info);
if (si->doodads) {
FreeDoodads(si->doodads,si,info);
si->doodads= NULL;
}
si->dfltRow.defs.defined= _GR_Default;
return;
}
static void
FreeSections(SectionInfo *si,GeometryInfo *info)
{
SectionInfo * tmp;
SectionInfo * next;
if (si==info->sections) {
info->nSections= 0;
info->sections= NULL;
}
for (tmp=si;tmp!=NULL;tmp=next) {
ClearSectionInfo(tmp,info);
next= (SectionInfo *)tmp->defs.next;
uFree(tmp);
}
return;
}
static void
FreeShapes(ShapeInfo *si,GeometryInfo *info)
{
ShapeInfo * tmp;
ShapeInfo * next;
if (si==info->shapes) {
info->nShapes= 0;
info->shapes= NULL;
}
for (tmp=si;tmp!=NULL;tmp=next) {
if (tmp->outlines) {
register int i;
for (i=0;i<tmp->nOutlines;i++) {
if (tmp->outlines[i].points!=NULL) {
uFree(tmp->outlines[i].points);
tmp->outlines[i].num_points= 0;
tmp->outlines[i].points= NULL;
}
}
uFree(tmp->outlines);
tmp->szOutlines= 0;
tmp->nOutlines= 0;
tmp->outlines= NULL;
tmp->primary= tmp->approx=NULL;
}
next= (ShapeInfo *)tmp->defs.next;
uFree(tmp);
}
return;
}
static void
InitGeometryInfo(GeometryInfo *info,unsigned fileID,unsigned merge)
{
bzero(info,sizeof(GeometryInfo));
info->fileID= fileID;
info->merge= merge;
InitSectionInfo(&info->dfltSection,info);
info->dfltSection.defs.defined= _GS_Default;
return;
}
static void
ClearGeometryInfo(GeometryInfo *info)
{
if (info->name)
uFree(info->name);
info->name= NULL;
if (info->props)
FreeProperties(info->props,info);
if (info->shapes)
FreeShapes(info->shapes,info);
if (info->sections)
FreeSections(info->sections,info);
info->widthMM= 0;
info->heightMM= 0;
info->dfltCornerRadius= 0;
ClearSectionInfo(&info->dfltSection,info);
info->dfltSection.defs.defined= _GS_Default;
if (info->aliases)
ClearAliases(&info->aliases);
return;
}
static PropertyInfo *
NextProperty(GeometryInfo *info)
{
PropertyInfo * pi;
pi= uTypedAlloc(PropertyInfo);
if (pi) {
bzero((char *)pi,sizeof(PropertyInfo));
info->props= (PropertyInfo *)AddCommonInfo(&info->props->defs,
(CommonInfo *)pi);
info->nProps++;
}
return pi;
}
static PropertyInfo *
FindProperty(GeometryInfo *info,char *name)
{
PropertyInfo * old;
if (!name)
return NULL;
for (old= info->props;old!=NULL;old=(PropertyInfo *)old->defs.next) {
if ((old->name)&&(uStringEqual(name,old->name)))
return old;
}
return NULL;
}
static Bool
AddProperty(GeometryInfo *info,PropertyInfo *new)
{
PropertyInfo * old;
if ((!new)||(!new->value)||(!new->name))
return False;
old= FindProperty(info,new->name);
if (old!=NULL) {
if ((new->defs.merge==MergeReplace)||(new->defs.merge==MergeOverride)) {
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Multiple definitions for the \"%s\" property\n",
new->name);
ACTION2("Ignoring \"%s\", using \"%s\"\n",old->value,
new->value);
}
if (old->value)
uFree(old->value);
old->value= uStringDup(new->value);
return True;
}
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Multiple definitions for \"%s\" property\n",new->name);
ACTION2("Using \"%s\", ignoring \"%s\" \n",old->value,new->value);
}
return True;
}
old= new;
if ((new= NextProperty(info))==NULL)
return False;
new->defs.next= NULL;
new->name= uStringDup(old->name);
new->value= uStringDup(old->value);
return True;
}
static ShapeInfo *
NextShape(GeometryInfo *info)
{
ShapeInfo * si;
si= uTypedAlloc(ShapeInfo);
if (si) {
bzero((char *)si,sizeof(ShapeInfo));
info->shapes= (ShapeInfo *)AddCommonInfo(&info->shapes->defs,
(CommonInfo *)si);
info->nShapes++;
si->dfltCornerRadius= info->dfltCornerRadius;
}
return si;
}
static ShapeInfo *
FindShape(GeometryInfo *info,Atom name,char *type,char *which)
{
ShapeInfo * old;
for (old= info->shapes;old!=NULL;old=(ShapeInfo *)old->defs.next) {
if (name==old->name)
return old;
}
if (type!=NULL) {
old= info->shapes;
WARN3("Unknown shape \"%s\" for %s %s\n",
XkbAtomText(info->dpy,name,XkbMessage),type,which);
if (old) {
ACTION1("Using default shape %s instead\n",shText(info->dpy,old));
return old;
}
ACTION("No default shape; definition ignored\n");
return NULL;
}
return NULL;
}
static Bool
AddShape(GeometryInfo *info,ShapeInfo *new)
{
ShapeInfo * old;
old= FindShape(info,new->name,NULL,NULL);
if (old!=NULL) {
if ((new->defs.merge==MergeReplace)||(new->defs.merge==MergeOverride)) {
ShapeInfo *next= (ShapeInfo *)old->defs.next;
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Duplicate shape name \"%s\"\n",shText(info->dpy,old));
ACTION("Using last definition\n");
}
*old= *new;
old->defs.next= &next->defs;
return True;
}
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Multiple shapes named \"%s\"\n",shText(info->dpy,old));
ACTION("Using first definition\n");
}
return True;
}
old= new;
if ((new= NextShape(info))==NULL)
return False;
*new= *old;
new->defs.next= NULL;
old->szOutlines= old->nOutlines= 0;
old->outlines= NULL;
old->approx= NULL;
old->primary= NULL;
return True;
}
static void
ReplaceDoodad(DoodadInfo *into,DoodadInfo *from)
{
CommonInfo * next;
next= into->defs.next;
ClearDoodadInfo(into);
*into= *from;
into->defs.next= next;
next= from->defs.next;
ClearDoodadInfo(from);
from->defs.next= next;
return;
}
static DoodadInfo *
NextDfltDoodad(SectionInfo *si,GeometryInfo *info)
{
DoodadInfo * di;
di= uTypedCalloc(1,DoodadInfo);
if (!di)
return NULL;
if (si) {
si->dfltDoodads= (DoodadInfo *)AddCommonInfo(&si->dfltDoodads->defs,
(CommonInfo *)di);
}
else {
info->dfltDoodads= (DoodadInfo *)AddCommonInfo(&info->dfltDoodads->defs,
(CommonInfo *)di);
}
return di;
}
static DoodadInfo *
NextDoodad(SectionInfo *si,GeometryInfo *info)
{
DoodadInfo * di;
di= uTypedCalloc(1,DoodadInfo);
if (di) {
if (si) {
si->doodads= (DoodadInfo *)AddCommonInfo(&si->doodads->defs,
(CommonInfo *)di);
si->nDoodads++;
}
else {
info->doodads= (DoodadInfo *)AddCommonInfo(&info->doodads->defs,
(CommonInfo *)di);
info->nDoodads++;
}
}
return di;
}
static Bool
AddDoodad(SectionInfo *si,GeometryInfo *info,DoodadInfo *new)
{
DoodadInfo * old;
old= FindDoodadByName((si?si->doodads:info->doodads),new->name);
if (old!=NULL) {
if ((new->defs.merge==MergeReplace)||(new->defs.merge==MergeOverride)) {
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Multiple doodads named \"%s\"\n",
XkbAtomText(info->dpy,old->name,XkbMessage));
ACTION("Using last definition\n");
}
ReplaceDoodad(old,new);
old->section= si;
return True;
}
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Multiple doodads named \"%s\"\n",
XkbAtomText(info->dpy,old->name,XkbMessage));
ACTION("Using first definition\n");
}
return True;
}
old= new;
if ((new= NextDoodad(si,info))==NULL)
return False;
ReplaceDoodad(new,old);
new->section= si;
new->defs.next= NULL;
return True;
}
static DoodadInfo *
FindDfltDoodadByTypeName(char *name,SectionInfo *si,GeometryInfo *info)
{
DoodadInfo * dflt;
unsigned type;
if (uStrCaseCmp(name,"outline")==0) type= XkbOutlineDoodad;
else if (uStrCaseCmp(name,"solid")==0) type= XkbSolidDoodad;
else if (uStrCaseCmp(name,"text")==0) type= XkbTextDoodad;
else if (uStrCaseCmp(name,"indicator")==0) type= XkbIndicatorDoodad;
else if (uStrCaseCmp(name,"logo")==0) type= XkbLogoDoodad;
else return NULL;
if ((si)&&(si->dfltDoodads))
dflt= FindDoodadByType(si->dfltDoodads,type);
else dflt= NULL;
if ((!dflt)&&(info->dfltDoodads))
dflt= FindDoodadByType(info->dfltDoodads,type);
if (dflt==NULL) {
dflt= NextDfltDoodad(si,info);
if (dflt!=NULL) {
dflt->name= None;
dflt->type= type;
}
}
return dflt;
}
static Bool
AddOverlay(SectionInfo *si,GeometryInfo *info,OverlayInfo *new)
{
OverlayInfo * old;
for (old=si->overlays;old!=NULL;old=(OverlayInfo *)old->defs.next) {
if (old->name==new->name)
break;
}
if (old!=NULL) {
if ((new->defs.merge==MergeReplace)||(new->defs.merge==MergeOverride)) {
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN2("Multiple overlays named \"%s\" for section \"%s\"\n",
XkbAtomText(info->dpy,old->name,XkbMessage),
XkbAtomText(info->dpy,si->name,XkbMessage));
ACTION("Using last definition\n");
}
ClearOverlayInfo(old);
old->nKeys= new->nKeys;
old->keys= new->keys;
new->nKeys= 0;
new->keys= NULL;
return True;
}
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN2("Multiple doodads named \"%s\" in section \"%s\"\n",
XkbAtomText(info->dpy,old->name,XkbMessage),
XkbAtomText(info->dpy,si->name,XkbMessage));
ACTION("Using first definition\n");
}
return True;
}
old= new;
new= uTypedCalloc(1,OverlayInfo);
if (!new) {
if (warningLevel>0) {
WSGO("Couldn't allocate a new OverlayInfo\n");
ACTION2("Overlay \"%s\" in section \"%s\" will be incomplete\n",
XkbAtomText(info->dpy,old->name,XkbMessage),
XkbAtomText(info->dpy,si->name,XkbMessage));
}
return False;
}
*new= *old;
old->nKeys= 0;
old->keys= NULL;
si->overlays= (OverlayInfo *)AddCommonInfo(&si->overlays->defs,
(CommonInfo *)new);
si->nOverlays++;
return True;
}
static SectionInfo *
NextSection(GeometryInfo *info)
{
SectionInfo * si;
si= uTypedAlloc(SectionInfo);
if (si) {
*si= info->dfltSection;
si->defs.defined&= ~_GS_Default;
si->defs.next= NULL;
si->nRows= 0;
si->rows= NULL;
info->sections= (SectionInfo *)AddCommonInfo(&info->sections->defs,
(CommonInfo *)si);
info->nSections++;
}
return si;
}
static SectionInfo *
FindMatchingSection(GeometryInfo *info,SectionInfo *new)
{
SectionInfo * old;
for (old=info->sections;old!=NULL;old=(SectionInfo *)old->defs.next) {
if (new->name==old->name)
return old;
}
return NULL;
}
static Bool
AddSection(GeometryInfo *info,SectionInfo *new)
{
SectionInfo * old;
old= FindMatchingSection(info,new);
if (old!=NULL) {
#ifdef NOTDEF
if ((new->defs.merge==MergeReplace)||(new->defs.merge==MergeOverride)) {
SectionInfo *next= (SectionInfo *)old->defs.next;
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Duplicate shape name \"%s\"\n",shText(info->dpy,old));
ACTION("Using last definition\n");
}
*old= *new;
old->defs.next= &next->defs;
return True;
}
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Multiple shapes named \"%s\"\n",shText(info->dpy,old));
ACTION("Using first definition\n");
}
return True;
#else
WARN("Don't know how to merge sections yet\n");
#endif
}
old= new;
if ((new= NextSection(info))==NULL)
return False;
*new= *old;
new->defs.next= NULL;
old->nRows= old->nDoodads= old->nOverlays= 0;
old->rows= NULL;
old->doodads= NULL;
old->overlays= NULL;
if (new->doodads) {
DoodadInfo *di;
for (di=new->doodads;di;di=(DoodadInfo *)di->defs.next) {
di->section= new;
}
}
return True;
}
static RowInfo *
NextRow(SectionInfo *si)
{
RowInfo * row;
row= uTypedAlloc(RowInfo);
if (row) {
*row= si->dfltRow;
row->defs.defined&= ~_GR_Default;
row->defs.next= NULL;
row->nKeys= 0;
row->keys= NULL;
si->rows= (RowInfo *)AddCommonInfo(&si->rows->defs,(CommonInfo *)row);
row->index= si->nRows++;
}
return row;
}
static Bool
AddRow(SectionInfo *si,RowInfo *new)
{
RowInfo * old;
old= new;
if ((new= NextRow(si))==NULL)
return False;
*new= *old;
new->defs.next= NULL;
old->nKeys= 0;
old->keys= NULL;
return True;
}
static KeyInfo *
NextKey(RowInfo *row)
{
KeyInfo * key;
key= uTypedAlloc(KeyInfo);
if (key) {
*key= row->dfltKey;
key->defs.defined&= ~_GK_Default;
key->defs.next= NULL;
key->index= row->nKeys++;
}
return key;
}
static Bool
AddKey(RowInfo *row,KeyInfo *new)
{
KeyInfo * old;
old= new;
if ((new= NextKey(row))==NULL)
return False;
*new= *old;
new->defs.next= NULL;
row->keys= (KeyInfo *)AddCommonInfo(&row->keys->defs,(CommonInfo *)new);
return True;
}
static void
MergeIncludedGeometry(GeometryInfo *into,GeometryInfo *from,unsigned merge)
{
Bool clobber;
if (from->errorCount>0) {
into->errorCount+= from->errorCount;
return;
}
clobber= (merge==MergeOverride)||(merge==MergeReplace);
if (into->name==NULL) {
into->name= from->name;
from->name= NULL;
}
if ((into->widthMM==0)||((from->widthMM!=0)&&clobber))
into->widthMM= from->widthMM;
if ((into->heightMM==0)||((from->heightMM!=0)&&clobber))
into->heightMM= from->heightMM;
if ((into->font==None)||((from->font!=None)&&clobber))
into->font= from->font;
if ((into->fontSlant==None)||((from->fontSlant!=None)&&clobber))
into->fontSlant= from->fontSlant;
if ((into->fontWeight==None)||((from->fontWeight!=None)&&clobber))
into->fontWeight= from->fontWeight;
if ((into->fontSetWidth==None)||((from->fontSetWidth!=None)&&clobber))
into->fontSetWidth= from->fontSetWidth;
if ((into->fontVariant==None)||((from->fontVariant!=None)&&clobber))
into->fontVariant= from->fontVariant;
if ((into->fontSize==0)||((from->fontSize!=0)&&clobber))
into->fontSize= from->fontSize;
if ((into->fontEncoding==None)||((from->fontEncoding!=None)&&clobber))
into->fontEncoding= from->fontEncoding;
if ((into->fontSpec==None)||((from->fontSpec!=None)&&clobber))
into->fontSpec= from->fontSpec;
if ((into->baseColor==None)||((from->baseColor!=None)&&clobber))
into->baseColor= from->baseColor;
if ((into->labelColor==None)||((from->labelColor!=None)&&clobber))
into->labelColor= from->labelColor;
into->nextPriority= from->nextPriority;
if (from->props!=NULL) {
PropertyInfo *pi;
for (pi=from->props;pi;pi=(PropertyInfo *)pi->defs.next) {
if (!AddProperty(into,pi))
into->errorCount++;
}
}
if (from->shapes!=NULL) {
ShapeInfo * si;
for (si=from->shapes;si;si=(ShapeInfo *)si->defs.next) {
if (!AddShape(into,si))
into->errorCount++;
}
}
if (from->sections!=NULL) {
SectionInfo * si;
for (si=from->sections;si;si=(SectionInfo *)si->defs.next) {
if (!AddSection(into,si))
into->errorCount++;
}
}
if (from->doodads!=NULL) {
DoodadInfo * di;
for (di=from->doodads;di;di=(DoodadInfo *)di->defs.next) {
if (!AddDoodad(NULL,into,di))
into->errorCount++;
}
}
if (!MergeAliases(&into->aliases,&from->aliases,merge))
into->errorCount++;
return;
}
typedef void (*FileHandler)(
XkbFile * ,
XkbDescPtr ,
unsigned ,
GeometryInfo *
);
static Bool
HandleIncludeGeometry(IncludeStmt *stmt,XkbDescPtr xkb,GeometryInfo *info,
FileHandler hndlr)
{
unsigned newMerge;
XkbFile * rtrn;
GeometryInfo included;
Bool haveSelf;
haveSelf= False;
if ((stmt->file==NULL)&&(stmt->map==NULL)) {
haveSelf= True;
included= *info;
bzero(info,sizeof(GeometryInfo));
}
else if (ProcessIncludeFile(stmt,XkmGeometryIndex,&rtrn,&newMerge)) {
InitGeometryInfo(&included,rtrn->id,newMerge);
included.nextPriority= info->nextPriority;
included.dfltCornerRadius= info->dfltCornerRadius;
DupSectionInfo(&included.dfltSection,&info->dfltSection,info);
(*hndlr)(rtrn,xkb,MergeOverride,&included);
if (stmt->stmt!=NULL) {
if (included.name!=NULL)
uFree(included.name);
included.name= stmt->stmt;
stmt->stmt= NULL;
}
}
else {
info->errorCount+= 10;
return False;
}
if ((stmt->next!=NULL)&&(included.errorCount<1)) {
IncludeStmt * next;
unsigned op;
GeometryInfo next_incl;
for (next=stmt->next;next!=NULL;next=next->next) {
if ((next->file==NULL)&&(next->map==NULL)) {
haveSelf= True;
MergeIncludedGeometry(&included,info,next->merge);
ClearGeometryInfo(info);
}
else if (ProcessIncludeFile(next,XkmGeometryIndex,&rtrn,&op)) {
InitGeometryInfo(&next_incl,rtrn->id,op);
next_incl.nextPriority= included.nextPriority;
next_incl.dfltCornerRadius= included.dfltCornerRadius;
DupSectionInfo(&next_incl.dfltSection,&included.dfltSection,
&included);
(*hndlr)(rtrn,xkb,MergeOverride,&next_incl);
MergeIncludedGeometry(&included,&next_incl,op);
ClearGeometryInfo(&next_incl);
}
else {
info->errorCount+= 10;
return False;
}
}
}
if (haveSelf)
*info= included;
else {
MergeIncludedGeometry(info,&included,newMerge);
ClearGeometryInfo(&included);
}
return (info->errorCount==0);
}
static int
SetShapeField( ShapeInfo * si,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
GeometryInfo * info)
{
ExprResult tmp;
if ((uStrCaseCmp(field,"radius")==0)||(uStrCaseCmp(field,"corner")==0)||
(uStrCaseCmp(field,"cornerradius")==0)) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("key shape",field,shText(info->dpy,si));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("key shape",field,
shText(info->dpy,si),"number");
}
if (si)
si->dfltCornerRadius= tmp.ival;
else info->dfltCornerRadius= tmp.ival;
return True;
}
info->errorCount++;
return ReportBadField("key shape",field,shText(info->dpy,si));
}
static int
SetShapeDoodadField( DoodadInfo * di,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
SectionInfo * si,
GeometryInfo * info)
{
ExprResult tmp;
char * typeName;
typeName= (di->type==XkbSolidDoodad?"solid doodad":"outline doodad");
if ((!uStrCaseCmp(field,"corner"))||(!uStrCaseCmp(field,"cornerradius"))) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"number");
}
di->defs.defined|= _GD_Corner;
di->corner= tmp.ival;
return True;
}
else if (uStrCaseCmp(field,"angle")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"number");
}
di->defs.defined|= _GD_Angle;
di->angle= tmp.ival;
return True;
}
else if (uStrCaseCmp(field,"shape")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"string");
}
di->shape= XkbInternAtom(info->dpy,tmp.str,False);
di->defs.defined|= _GD_Shape;
return True;
}
return ReportBadField(typeName,field,ddText(info->dpy,di));
}
#define FIELD_STRING 0
#define FIELD_SHORT 1
#define FIELD_USHORT 2
static int
SetTextDoodadField( DoodadInfo * di,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
SectionInfo * si,
GeometryInfo * info)
{
ExprResult tmp;
unsigned def;
unsigned type;
char * typeName= "text doodad";
union {
Atom * str;
short * ival;
unsigned short * uval;
} pField;
if (uStrCaseCmp(field,"angle")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"number");
}
di->defs.defined|= _GD_Angle;
di->angle= tmp.ival;
return True;
}
if (uStrCaseCmp(field,"width")==0) {
type= FIELD_USHORT;
pField.uval= &di->width;
def= _GD_Width;
}
else if (uStrCaseCmp(field,"height")==0) {
type= FIELD_USHORT;
pField.uval= &di->height;
def= _GD_Height;
}
else if (uStrCaseCmp(field,"text")==0) {
type= FIELD_STRING;
pField.str= &di->text;
def= _GD_Text;
}
else if (uStrCaseCmp(field,"font")==0) {
type= FIELD_STRING;
pField.str= &di->font;
def= _GD_Font;
}
else if ((uStrCaseCmp(field,"fontslant")==0)||
(uStrCaseCmp(field,"slant")==0)) {
type= FIELD_STRING;
pField.str= &di->fontSlant;
def= _GD_FontSlant;
}
else if ((uStrCaseCmp(field,"fontweight")==0)||
(uStrCaseCmp(field,"weight")==0)) {
type= FIELD_STRING;
pField.str= &di->fontWeight;
def= _GD_FontWeight;
}
else if ((uStrCaseCmp(field,"fontwidth")==0)||
(uStrCaseCmp(field,"setwidth")==0)) {
type= FIELD_STRING;
pField.str= &di->fontSetWidth;
def= _GD_FontSetWidth;
}
else if ((uStrCaseCmp(field,"fontvariant")==0)||
(uStrCaseCmp(field,"variant")==0)) {
type= FIELD_STRING;
pField.str= &di->fontVariant;
def= _GD_FontVariant;
}
else if ((uStrCaseCmp(field,"fontencoding")==0)||
(uStrCaseCmp(field,"encoding")==0)) {
type= FIELD_STRING;
pField.str= &di->fontEncoding;
def= _GD_FontEncoding;
}
else if ((uStrCaseCmp(field,"xfont")==0)||
(uStrCaseCmp(field,"xfontname")==0)) {
type= FIELD_STRING;
pField.str= &di->fontSpec;
def= _GD_FontSpec;
}
else if (uStrCaseCmp(field,"fontsize")==0) {
type= FIELD_USHORT;
pField.uval= &di->fontSize;
def= _GD_FontSize;
}
else {
return ReportBadField(typeName,field,ddText(info->dpy,di));
}
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (type==FIELD_STRING) {
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),
"string");
}
di->defs.defined|= def;
*pField.str= XkbInternAtom(NULL,tmp.str,False);
}
else {
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"number");
}
if ((type==FIELD_USHORT)&&(tmp.ival<0)) {
info->errorCount++;
return
ReportBadType(typeName,field,ddText(info->dpy,di),"unsigned");
}
di->defs.defined|= def;
if (type==FIELD_USHORT)
*pField.uval= tmp.uval;
else *pField.ival= tmp.ival;
}
return True;
}
static int
SetIndicatorDoodadField( DoodadInfo * di,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
SectionInfo * si,
GeometryInfo * info)
{
ExprResult tmp;
if ((uStrCaseCmp(field,"oncolor")==0)||(uStrCaseCmp(field,"offcolor")==0)
||(uStrCaseCmp(field,"shape")==0)) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("indicator doodad",field,
ddText(info->dpy,di));
}
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("indicator doodad",field,ddText(info->dpy,di),
"string");
}
if (uStrCaseCmp(field,"oncolor")==0) {
di->defs.defined|= _GD_Color;
di->color= XkbInternAtom(NULL,tmp.str,False);
}
else if (uStrCaseCmp(field,"offcolor")==0) {
di->defs.defined|= _GD_OffColor;
di->offColor= XkbInternAtom(NULL,tmp.str,False);
}
else if (uStrCaseCmp(field,"shape")==0) {
di->defs.defined|= _GD_Shape;
di->shape= XkbInternAtom(info->dpy,tmp.str,False);
}
return True;
}
return ReportBadField("indicator doodad",field,ddText(info->dpy,di));
}
static int
SetLogoDoodadField( DoodadInfo * di,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
SectionInfo * si,
GeometryInfo * info)
{
ExprResult tmp;
char * typeName= "logo doodad";
if ((!uStrCaseCmp(field,"corner"))||(!uStrCaseCmp(field,"cornerradius"))) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"number");
}
di->defs.defined|= _GD_Corner;
di->corner= tmp.ival;
return True;
}
else if (uStrCaseCmp(field,"angle")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"number");
}
di->defs.defined|= _GD_Angle;
di->angle= tmp.ival;
return True;
}
else if (uStrCaseCmp(field,"shape")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"string");
}
di->shape= XkbInternAtom(info->dpy,tmp.str,False);
di->defs.defined|= _GD_Shape;
return True;
}
else if ((!uStrCaseCmp(field,"logoname"))||(!uStrCaseCmp(field,"name"))) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray(typeName,field,ddText(info->dpy,di));
}
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType(typeName,field,ddText(info->dpy,di),"string");
}
di->logoName= uStringDup(tmp.str);
return True;
}
return ReportBadField(typeName,field,ddText(info->dpy,di));
}
static int
SetDoodadField( DoodadInfo * di,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
SectionInfo * si,
GeometryInfo * info)
{
ExprResult tmp;
if (uStrCaseCmp(field,"priority")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("doodad",field,ddText(info->dpy,di));
}
if (!ExprResolveInteger(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("doodad",field,ddText(info->dpy,di),"integer");
}
if ((tmp.ival<0)||(tmp.ival>XkbGeomMaxPriority)) {
info->errorCount++;
ERROR2("Doodad priority %d out of range (must be 0..%d)\n",
tmp.ival,XkbGeomMaxPriority);
ACTION1("Priority for doodad %s not changed",ddText(info->dpy,di));
return False;
}
di->defs.defined|= _GD_Priority;
di->priority= tmp.ival;
return True;
}
else if (uStrCaseCmp(field,"left")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("doodad",field,ddText(info->dpy,di));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("doodad",field,ddText(info->dpy,di),"number");
}
di->defs.defined|= _GD_Left;
di->left= tmp.ival;
return True;
}
else if (uStrCaseCmp(field,"top")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("doodad",field,ddText(info->dpy,di));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("doodad",field,ddText(info->dpy,di),"number");
}
di->defs.defined|= _GD_Top;
di->top= tmp.ival;
return True;
}
else if (uStrCaseCmp(field,"color")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("doodad",field,ddText(info->dpy,di));
}
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("doodad",field,ddText(info->dpy,di),"string");
}
di->defs.defined|= _GD_Color;
di->color= XkbInternAtom(NULL,tmp.str,False);
return True;
}
switch (di->type) {
case XkbOutlineDoodad:
case XkbSolidDoodad:
return SetShapeDoodadField(di,field,arrayNdx,value,si,info);
case XkbTextDoodad:
return SetTextDoodadField(di,field,arrayNdx,value,si,info);
case XkbIndicatorDoodad:
return SetIndicatorDoodadField(di,field,arrayNdx,value,si,info);
case XkbLogoDoodad:
return SetLogoDoodadField(di,field,arrayNdx,value,si,info);
}
WSGO1("Unknown doodad type %d in SetDoodadField\n",(unsigned int)di->type);
ACTION2("Definition of %s in %s ignored\n",field,ddText(info->dpy,di));
return False;
}
static int
SetSectionField( SectionInfo * si,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
GeometryInfo * info)
{
unsigned short * pField;
unsigned def;
ExprResult tmp;
pField= NULL;
def= 0;
if (uStrCaseCmp(field,"priority")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard section",field,scText(info->dpy,si));
}
if (!ExprResolveInteger(value,&tmp,NULL,NULL)) {
info->errorCount++;
ReportBadType("keyboard section",field,scText(info->dpy,si),
"integer");
return False;
}
if ((tmp.ival<0)||(tmp.ival>XkbGeomMaxPriority)) {
info->errorCount++;
ERROR2("Section priority %d out of range (must be 0..%d)\n",
tmp.ival,XkbGeomMaxPriority);
ACTION1("Priority for section %s not changed",scText(info->dpy,si));
return False;
}
si->priority= tmp.ival;
si->defs.defined|= _GS_Priority;
return True;
}
else if (uStrCaseCmp(field,"top")==0) {
pField= &si->top;
def= _GS_Top;
}
else if (uStrCaseCmp(field,"left")==0) {
pField= &si->left;
def= _GS_Left;
}
else if (uStrCaseCmp(field,"width")==0) {
pField= &si->width;
def= _GS_Width;
}
else if (uStrCaseCmp(field,"height")==0) {
pField= &si->height;
def= _GS_Height;
}
else if (uStrCaseCmp(field,"angle")==0) {
pField= &si->angle;
def= _GS_Angle;
}
else {
info->errorCount++;
return ReportBadField("keyboard section",field,scText(info->dpy,si));
}
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard section",field,scText(info->dpy,si));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
ReportBadType("keyboard section",field,scText(info->dpy,si),"number");
return False;
}
si->defs.defined|= def;
*pField= tmp.uval;
return True;
}
static int
SetRowField( RowInfo * row,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
GeometryInfo * info)
{
ExprResult tmp;
if (uStrCaseCmp(field,"top")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard row",field,rowText(info->dpy,row));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard row",field,rowText(info->dpy,row),
"number");
}
row->defs.defined|= _GR_Top;
row->top= tmp.uval;
}
else if (uStrCaseCmp(field,"left")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard row",field,rowText(info->dpy,row));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard row",field,rowText(info->dpy,row),
"number");
}
row->defs.defined|= _GR_Left;
row->left= tmp.uval;
}
else if (uStrCaseCmp(field,"vertical")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard row",field,rowText(info->dpy,row));
}
if (!ExprResolveBoolean(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard row",field,rowText(info->dpy,row),
"boolean");
}
row->defs.defined|= _GR_Vertical;
row->vertical= tmp.uval;
}
else {
info->errorCount++;
return ReportBadField("keyboard row",field,rowText(info->dpy,row));
}
return True;
}
static int
SetKeyField( KeyInfo *key,
char *field,
ExprDef *arrayNdx,
ExprDef *value,
GeometryInfo *info)
{
ExprResult tmp;
if (uStrCaseCmp(field,"gap")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("key",field,keyText(key));
}
if (!ExprResolveFloat(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("key",field,keyText(key),"number");
}
key->defs.defined|= _GK_Gap;
key->gap= tmp.ival;
}
else if (uStrCaseCmp(field,"shape")==0) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("key",field,keyText(key));
}
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("key",field,keyText(key),"string");
}
key->defs.defined|= _GK_Shape;
key->shape= XkbInternAtom(info->dpy,tmp.str,False);
}
else if ((uStrCaseCmp(field,"color")==0)||
(uStrCaseCmp(field,"keycolor")==0)) {
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("key",field,keyText(key));
}
if (!ExprResolveString(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("key",field,keyText(key),"string");
}
key->defs.defined|= _GK_Color;
key->color= XkbInternAtom(NULL,tmp.str,False);
}
else if ((uStrCaseCmp(field,"name")==0)||(uStrCaseCmp(field,"keyname")==0)){
if (arrayNdx!=NULL) {
info->errorCount++;
return ReportNotArray("key",field,keyText(key));
}
if (!ExprResolveKeyName(value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("key",field,keyText(key),"key name");
}
key->defs.defined|= _GK_Name;
bzero(key->name,XkbKeyNameLength+1);
strncpy(key->name,tmp.keyName.name,XkbKeyNameLength);
}
else {
info->errorCount++;
return ReportBadField("key",field,keyText(key));
}
return True;
}
static int
SetGeometryProperty(GeometryInfo *info,char *property,ExprDef *value)
{
PropertyInfo pi;
ExprResult result;
InitPropertyInfo(&pi,info);
pi.name= property;
if (!ExprResolveString(value,&result,NULL,NULL)) {
info->errorCount++;
ERROR("Property values must be type string\n");
ACTION1("Ignoring illegal definition of \"%s\" property\n",property);
return False;
}
pi.value= result.str;
return AddProperty(info,&pi);
}
static int
HandleGeometryVar(VarDef *stmt,XkbDescPtr xkb,GeometryInfo *info)
{
ExprResult elem,field,tmp;
ExprDef * ndx;
DoodadInfo * di;
Atom * pField;
if (ExprResolveLhs(stmt->name,&elem,&field,&ndx)==0)
return 0;
if (elem.str&&(uStrCaseCmp(elem.str,"shape")==0))
return SetShapeField(NULL,field.str,ndx,stmt->value,info);
if (elem.str&&(uStrCaseCmp(elem.str,"key")==0))
return SetKeyField(&info->dfltSection.dfltRow.dfltKey,
field.str,ndx,stmt->value,info);
if (elem.str&&(uStrCaseCmp(elem.str,"row")==0))
return SetRowField(&info->dfltSection.dfltRow,field.str,ndx,
stmt->value,info);
if (elem.str&&(uStrCaseCmp(elem.str,"section")==0)) {
return SetSectionField(&info->dfltSection,field.str,ndx,stmt->value,
info);
}
if (elem.str&&(uStrCaseCmp(elem.str,"property")==0)) {
if (ndx!=NULL) {
info->errorCount++;
ERROR1("The %s geometry property is not an array\n",field.str);
ACTION("Ignoring illegal property definition\n");
return False;
}
return SetGeometryProperty(info,field.str,stmt->value);
}
if (elem.str&&((di=FindDfltDoodadByTypeName(elem.str,NULL,info))!=NULL)) {
return SetDoodadField(di,field.str,ndx,stmt->value,NULL,info);
}
if (elem.str&&(uStrCaseCmp(elem.str,"solid")==0)) {
DoodadInfo *dflt;
dflt= FindDoodadByType(info->dfltDoodads,XkbSolidDoodad);
if (dflt==NULL)
dflt= NextDfltDoodad(NULL,info);
return SetDoodadField(dflt,field.str,ndx,stmt->value,NULL,info);
}
if (elem.str&&(uStrCaseCmp(elem.str,"outline")==0)) {
DoodadInfo *dflt;
dflt= FindDoodadByType(info->dfltDoodads,XkbOutlineDoodad);
if (dflt==NULL)
dflt= NextDfltDoodad(NULL,info);
return SetDoodadField(dflt,field.str,ndx,stmt->value,NULL,info);
}
if (elem.str&&(uStrCaseCmp(elem.str,"text")==0)) {
DoodadInfo *dflt;
dflt= FindDoodadByType(info->dfltDoodads,XkbTextDoodad);
if (dflt==NULL)
dflt= NextDfltDoodad(NULL,info);
return SetDoodadField(dflt,field.str,ndx,stmt->value,NULL,info);
}
if (elem.str&&(uStrCaseCmp(elem.str,"indicator")==0)) {
DoodadInfo *dflt;
dflt= FindDoodadByType(info->dfltDoodads,XkbIndicatorDoodad);
if (dflt==NULL)
dflt= NextDfltDoodad(NULL,info);
return SetDoodadField(dflt,field.str,ndx,stmt->value,NULL,info);
}
if (elem.str&&(uStrCaseCmp(elem.str,"logo")==0)) {
DoodadInfo *dflt;
dflt= FindDoodadByType(info->dfltDoodads,XkbLogoDoodad);
if (dflt==NULL)
dflt= NextDfltDoodad(NULL,info);
return SetDoodadField(dflt,field.str,ndx,stmt->value,NULL,info);
}
if (elem.str) {
WARN("Assignment to field of unknown element\n");
ACTION2("No value assigned to %s.%s\n",elem.str,field.str);
return False;
}
if ((uStrCaseCmp(field.str,"width")==0)||
(uStrCaseCmp(field.str,"widthmm")==0)) {
if (ndx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard",field.str,"geometry");
}
if (!ExprResolveFloat(stmt->value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard",field.str,"geometry","number");
}
if (tmp.ival<1) {
WARN("Keyboard width must be positive\n");
ACTION1("Ignoring illegal keyboard width %s\n",
XkbGeomFPText(tmp.ival,XkbMessage));
return True;
}
if (info->widthMM!=0) {
WARN("Keyboard width multiply defined\n");
ACTION1("Using last definition (%s),",
XkbGeomFPText(tmp.ival,XkbMessage));
INFO1(" ignoring first (%s)\n",
XkbGeomFPText(info->widthMM,XkbMessage));
}
info->widthMM= tmp.ival;
return True;
}
else if ((uStrCaseCmp(field.str,"height")==0)||
(uStrCaseCmp(field.str,"heightmm")==0)) {
if (ndx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard",field.str,"geometry");
}
if (!ExprResolveFloat(stmt->value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard",field.str,"geometry","number");
}
if (tmp.ival<1) {
WARN("Keyboard height must be positive\n");
ACTION1("Ignoring illegal keyboard height %s\n",
XkbGeomFPText(tmp.ival,XkbMessage));
return True;
}
if (info->heightMM!=0) {
WARN("Keyboard height multiply defined\n");
ACTION1("Using last definition (%s),",
XkbGeomFPText(tmp.ival,XkbMessage));
INFO1(" ignoring first (%s)\n",
XkbGeomFPText(info->heightMM,XkbMessage));
}
info->heightMM= tmp.ival;
return True;
}
else if (uStrCaseCmp(field.str,"font")==0) {
pField= &info->font;
}
else if ((uStrCaseCmp(field.str,"fontslant")==0)||
(uStrCaseCmp(field.str,"slant")==0)) {
pField= &info->fontSlant;
}
else if ((uStrCaseCmp(field.str,"fontweight")==0)||
(uStrCaseCmp(field.str,"weight")==0)) {
pField= &info->fontWeight;
}
else if ((uStrCaseCmp(field.str,"fontwidth")==0)||
(uStrCaseCmp(field.str,"setwidth")==0)) {
pField= &info->fontWeight;
}
else if ((uStrCaseCmp(field.str,"fontencoding")==0)||
(uStrCaseCmp(field.str,"encoding")==0)) {
pField= &info->fontEncoding;
}
else if ((uStrCaseCmp(field.str,"xfont")==0)||
(uStrCaseCmp(field.str,"xfontname")==0)) {
pField= &info->fontSpec;
}
else if (uStrCaseCmp(field.str,"fontsize")==0) {
if (ndx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard",field.str,"geometry");
}
if (!ExprResolveFloat(stmt->value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard",field.str,"geometry","number");
}
if ((tmp.ival<40)||(tmp.ival>2550)) {
info->errorCount++;
ERROR1("Illegal font size %d (must be 4..255)\n",tmp.ival);
ACTION("Ignoring font size in keyboard geometry\n");
return False;
}
info->fontSize= tmp.ival;
return True;
}
else if ((uStrCaseCmp(field.str,"color")==0)||
(uStrCaseCmp(field.str,"basecolor")==0)){
if (ndx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard",field.str,"geometry");
}
if (!ExprResolveString(stmt->value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard",field.str,"geometry","string");
}
info->baseColor= XkbInternAtom(NULL,tmp.str,False);
return True;
}
else if (uStrCaseCmp(field.str,"labelcolor")==0){
if (ndx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard",field.str,"geometry");
}
if (!ExprResolveString(stmt->value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard",field.str,"geometry","string");
}
info->labelColor= XkbInternAtom(NULL,tmp.str,False);
return True;
}
else {
return SetGeometryProperty(info,field.str,stmt->value);
}
if (ndx!=NULL) {
info->errorCount++;
return ReportNotArray("keyboard",field.str,"geometry");
}
if (!ExprResolveString(stmt->value,&tmp,NULL,NULL)) {
info->errorCount++;
return ReportBadType("keyboard",field.str,"geometry","string");
}
*pField= XkbInternAtom(NULL,tmp.str,False);
return True;
}
static Bool
HandleShapeBody(ShapeDef *def,ShapeInfo *si,unsigned merge,GeometryInfo *info)
{
OutlineDef * ol;
int nOut,nPt;
XkbOutlinePtr outline;
ExprDef * pt;
if (def->nOutlines<1) {
WARN1("Shape \"%s\" has no outlines\n",shText(info->dpy,si));
ACTION("Definition ignored\n");
return True;
}
si->nOutlines= def->nOutlines;
si->outlines= uTypedCalloc(def->nOutlines,XkbOutlineRec);
if (!si->outlines) {
ERROR1("Couldn't allocate outlines for \"%s\"\n",shText(info->dpy,si));
ACTION("Definition ignored\n");
info->errorCount++;
return False;
}
for (nOut=0,ol=def->outlines;ol!=NULL;ol=(OutlineDef *)ol->common.next) {
if (ol->nPoints<1) {
SetShapeField(si,XkbAtomGetString(NULL,ol->field),NULL,
ol->points,info);
continue;
}
outline= NULL;
outline= &si->outlines[nOut++];
outline->num_points= ol->nPoints;
outline->corner_radius= si->dfltCornerRadius;
outline->points= uTypedCalloc(ol->nPoints,XkbPointRec);
if (!outline->points) {
ERROR1("Can't allocate points for \"%s\"\n",shText(info->dpy,si));
ACTION("Definition ignored\n");
info->errorCount++;
return False;
}
for (nPt=0,pt=ol->points;pt!=NULL;pt=(ExprDef *)pt->common.next) {
outline->points[nPt].x= pt->value.coord.x;
outline->points[nPt].y= pt->value.coord.y;
nPt++;
}
if (ol->field!=None) {
char *str= XkbAtomText(NULL,ol->field,XkbMessage);
if ((uStrCaseCmp(str,"approximation")==0)||
(uStrCaseCmp(str,"approx")==0)) {
if (si->approx==NULL)
si->approx= outline;
else {
WARN1("Multiple approximations for \"%s\"\n",
shText(info->dpy,si));
ACTION("Treating all but the first as normal outlines\n");
}
}
else if (uStrCaseCmp(str,"primary")==0) {
if (si->primary==NULL)
si->primary= outline;
else {
WARN1("Multiple primary outlines for \"%s\"\n",
shText(info->dpy,si));
ACTION("Treating all but the first as normal outlines\n");
}
}
else {
WARN2("Unknown outline type %s for \"%s\"\n",str,
shText(info->dpy,si));
ACTION("Treated as a normal outline\n");
}
}
}
if (nOut!=si->nOutlines) {
WSGO2("Expected %d outlines, got %d\n",(unsigned int)si->nOutlines,
nOut);
si->nOutlines= nOut;
}
return True;
}
static int
HandleShapeDef(ShapeDef *def,XkbDescPtr xkb,unsigned merge,GeometryInfo *info)
{
ShapeInfo si;
if (def->merge!=MergeDefault)
merge= def->merge;
bzero(&si,sizeof(ShapeInfo));
si.defs.merge= merge;
si.name= XkbInternAtom(info->dpy,XkbAtomGetString(NULL,def->name),False);
si.dfltCornerRadius= info->dfltCornerRadius;
if (!HandleShapeBody(def,&si,merge,info))
return False;
if (!AddShape(info,&si))
return False;
return True;
}
static int
HandleDoodadDef( DoodadDef *def,
unsigned merge,
SectionInfo *si,
GeometryInfo *info)
{
ExprResult elem,field;
ExprDef * ndx;
DoodadInfo new;
VarDef * var;
if (def->common.stmtType==StmtIndicatorMapDef) {
def->common.stmtType= StmtDoodadDef;
def->type= XkbIndicatorDoodad;
}
InitDoodadInfo(&new,def->type,si,info);
new.name= XkbInternAtom(info->dpy,XkbAtomGetString(NULL,def->name),False);
for (var=def->body;var!=NULL;var= (VarDef *)var->common.next) {
if (ExprResolveLhs(var->name,&elem,&field,&ndx)==0)
return 0;
if (elem.str!=NULL) {
WARN1("Assignment to field of unknown element in doodad %s\n",
ddText(info->dpy,&new));
ACTION2("No value assigned to %s.%s\n",elem.str,field.str);
}
else if (!SetDoodadField(&new,field.str,ndx,var->value,si,info))
return False;
}
if (!AddDoodad(si,info,&new))
return False;
ClearDoodadInfo(&new);
return True;
}
static int
HandleOverlayDef( OverlayDef * def,
unsigned merge,
SectionInfo * si,
GeometryInfo * info)
{
OverlayKeyDef * keyDef;
OverlayKeyInfo *key;
OverlayInfo ol;
if ((def->nKeys<1)&&(warningLevel>3)) {
WARN2("Overlay \"%s\" in section \"%s\" has no keys\n",
XkbAtomText(NULL,def->name,XkbMessage),
scText(info->dpy,si));
ACTION("Overlay ignored\n");
return True;
}
bzero(&ol,sizeof(OverlayInfo));
ol.name= XkbInternAtom(info->dpy,XkbAtomGetString(NULL,def->name),False);
for (keyDef= def->keys;keyDef;keyDef=(OverlayKeyDef *)keyDef->common.next) {
key= uTypedCalloc(1,OverlayKeyInfo);
if ((!key)&&warningLevel>0) {
WSGO("Couldn't allocate OverlayKeyInfo\n");
ACTION2("Overlay %s for section %s will be incomplete\n",
oiText(info->dpy,&ol),
scText(info->dpy,si));
return False;
}
strncpy(key->over,keyDef->over,XkbKeyNameLength);
strncpy(key->under,keyDef->under,XkbKeyNameLength);
key->sectionRow= _GOK_UnknownRow;
key->overlayRow= _GOK_UnknownRow;
ol.keys= (OverlayKeyInfo *)AddCommonInfo(&ol.keys->defs,
(CommonInfo *)key);
ol.nKeys++;
}
if (!AddOverlay(si,info,&ol))
return False;
ClearOverlayInfo(&ol);
return True;
}
static Bool
HandleComplexKey(KeyDef *def,KeyInfo *key,GeometryInfo *info)
{
RowInfo * row;
ExprDef * expr;
row= key->row;
for (expr=def->expr;expr!=NULL;expr=(ExprDef *)expr->common.next) {
if (expr->op==OpAssign) {
ExprResult elem,f;
ExprDef *ndx;
if (ExprResolveLhs(expr->value.binary.left,&elem,&f,&ndx)==0)
return False;
if ((elem.str==NULL)||(uStrCaseCmp(elem.str,"key")==0)) {
if (!SetKeyField(key,f.str,ndx,expr->value.binary.right,info))
return False;
}
else {
ERROR("Illegal element used in a key definition\n");
ACTION2("Assignment to %s.%s ignored\n",elem.str,f.str);
return False;
}
}
else {
switch (expr->type) {
case TypeInt: case TypeFloat:
if (!SetKeyField(key,"gap",NULL,expr,info))
return False;
break;
case TypeString:
if (!SetKeyField(key,"shape",NULL,expr,info))
return False;
break;
case TypeKeyName:
if (!SetKeyField(key,"name",NULL,expr,info))
return False;
break;
default:
ERROR("Cannot determine field for unnamed expression\n");
ACTION3("Ignoring key %d in row %d of section %s\n",
row->nKeys+1,row->section->nRows+1,
rowText(info->dpy,row));
return False;
}
}
}
return True;
}
static Bool
HandleRowBody(RowDef *def,RowInfo *row,unsigned merge,GeometryInfo *info)
{
KeyDef * keyDef;
if ((def->nKeys<1)&&(warningLevel>3)) {
ERROR1("Row in section %s has no keys\n",rowText(info->dpy,row));
ACTION("Section ignored\n");
return True;
}
for (keyDef= def->keys; keyDef!=NULL;keyDef=(KeyDef *)keyDef->common.next) {
if (keyDef->common.stmtType==StmtVarDef) {
VarDef *var= (VarDef *)keyDef;
ExprResult elem,field;
ExprDef *ndx;
if (ExprResolveLhs(var->name,&elem,&field,&ndx)==0)
return 0;
if ((elem.str==NULL)||(uStrCaseCmp(elem.str,"row")==0)) {
if (!SetRowField(row,field.str,ndx,var->value,info))
return False;
}
else if (uStrCaseCmp(elem.str,"key")==0) {
if (!SetKeyField(&row->dfltKey,field.str,ndx,var->value,info))
return False;
}
else {
WARN("Assignment to field of unknown element in row\n");
ACTION2("No value assigned to %s.%s\n",elem.str,field.str);
}
}
else if (keyDef->common.stmtType==StmtKeyDef) {
KeyInfo key;
InitKeyInfo(&key,row,info);
if (keyDef->name!=NULL) {
int len= strlen(keyDef->name);
if ((len<1)||(len>XkbKeyNameLength)) {
ERROR2("Illegal name %s for key in section %s\n",
keyDef->name,
rowText(info->dpy,row));
ACTION("Section not compiled\n");
return False;
}
bzero(key.name,XkbKeyNameLength+1);
strncpy(key.name,keyDef->name,XkbKeyNameLength);
key.defs.defined|= _GK_Name;
}
else if (!HandleComplexKey(keyDef,&key,info))
return False;
if (!AddKey(row,&key))
return False;
}
else {
WSGO1("Unexpected statement (type %d) in row body\n",
keyDef->common.stmtType);
return False;
}
}
return True;
}
static Bool
HandleSectionBody( SectionDef * def,
SectionInfo * si,
unsigned merge,
GeometryInfo * info)
{
RowDef * rowDef;
DoodadInfo * di;
for (rowDef= def->rows;rowDef!=NULL;rowDef=(RowDef *)rowDef->common.next) {
if (rowDef->common.stmtType==StmtVarDef) {
VarDef *var= (VarDef *)rowDef;
ExprResult elem,field;
ExprDef *ndx;
if (ExprResolveLhs(var->name,&elem,&field,&ndx)==0)
return 0;
if ((elem.str==NULL)||(uStrCaseCmp(elem.str,"section")==0)) {
if (!SetSectionField(si,field.str,ndx,var->value,info))
return False;
}
else if (uStrCaseCmp(elem.str,"row")==0) {
if (!SetRowField(&si->dfltRow,field.str,ndx,var->value,info))
return False;
}
else if (uStrCaseCmp(elem.str,"key")==0) {
if(!SetKeyField(&si->dfltRow.dfltKey,field.str,ndx,
var->value,info))
return False;
}
else if ((di=FindDfltDoodadByTypeName(elem.str,si,info))!=NULL) {
if (!SetDoodadField(di,field.str,ndx,var->value,si,info))
return False;
}
else {
WARN("Assignment to field of unknown element in section\n");
ACTION2("No value assigned to %s.%s\n",elem.str,field.str);
}
}
else if (rowDef->common.stmtType==StmtRowDef) {
RowInfo row;
InitRowInfo(&row,si,info);
if (!HandleRowBody(rowDef,&row,merge,info))
return False;
if (!AddRow(si,&row))
return False;
}
else if ((rowDef->common.stmtType==StmtDoodadDef)||
(rowDef->common.stmtType==StmtIndicatorMapDef)) {
if (!HandleDoodadDef((DoodadDef *)rowDef,merge,si,info))
return False;
}
else if (rowDef->common.stmtType==StmtOverlayDef) {
if (!HandleOverlayDef((OverlayDef *)rowDef,merge,si,info))
return False;
}
else {
WSGO1("Unexpected statement (type %d) in section body\n",
rowDef->common.stmtType);
return False;
}
}
if (si->nRows!=def->nRows) {
WSGO2("Expected %d rows, found %d\n",(unsigned int)def->nRows,
(unsigned int)si->nRows);
ACTION1("Definition of section %s might be incorrect\n",
scText(info->dpy,si));
}
return True;
}
static int
HandleSectionDef( SectionDef * def,
XkbDescPtr xkb,
unsigned merge,
GeometryInfo * info)
{
SectionInfo si;
char * str;
if (def->merge!=MergeDefault)
merge= def->merge;
InitSectionInfo(&si,info);
si.defs.merge= merge;
str= XkbAtomGetString(NULL,def->name);
if ((str==NULL)||(strlen(str)<1)) {
ERROR("Section defined without a name\n");
ACTION("Definition ignored\n");
return False;
}
si.name= XkbInternAtom(info->dpy,XkbAtomGetString(NULL,def->name),False);
if (!HandleSectionBody(def,&si,merge,info))
return False;
if (!AddSection(info,&si))
return False;
return True;
}
static void
HandleGeometryFile( XkbFile * file,
XkbDescPtr xkb,
unsigned merge,
GeometryInfo * info)
{
ParseCommon * stmt;
char * failWhat;
if (merge==MergeDefault)
merge= MergeAugment;
info->name= uStringDup(file->name);
stmt= file->defs;
while (stmt) {
failWhat= NULL;
switch (stmt->stmtType) {
case StmtInclude:
if (!HandleIncludeGeometry((IncludeStmt *)stmt,xkb,info,
HandleGeometryFile))
info->errorCount++;
break;
case StmtKeyAliasDef:
if (!HandleAliasDef((KeyAliasDef *)stmt,
merge,info->fileID,&info->aliases)) {
info->errorCount++;
}
break;
case StmtVarDef:
if (!HandleGeometryVar((VarDef *)stmt,xkb,info))
info->errorCount++;
break;
case StmtShapeDef:
if (!HandleShapeDef((ShapeDef *)stmt,xkb,merge,info))
info->errorCount++;
break;
case StmtSectionDef:
if (!HandleSectionDef((SectionDef *)stmt,xkb,merge,info))
info->errorCount++;
break;
case StmtIndicatorMapDef:
case StmtDoodadDef:
if (!HandleDoodadDef((DoodadDef *)stmt,merge,NULL,info))
info->errorCount++;
break;
case StmtVModDef:
if (!failWhat) failWhat= "virtual modfier";
case StmtInterpDef:
if (!failWhat) failWhat= "symbol interpretation";
case StmtGroupCompatDef:
if (!failWhat) failWhat= "group compatibility map";
case StmtKeycodeDef:
if (!failWhat) failWhat= "key name";
ERROR("Interpretation files may not include other types\n");
ACTION1("Ignoring %s definition.\n",failWhat);
info->errorCount++;
break;
default:
WSGO1("Unexpected statement type %d in HandleGeometryFile\n",
stmt->stmtType);
break;
}
stmt= stmt->next;
if (info->errorCount>10) {
#ifdef NOISY
ERROR("Too many errors\n");
#endif
ACTION1("Abandoning geometry file \"%s\"\n",file->topName);
break;
}
}
return;
}
static Bool
CopyShapeDef(Display *dpy,XkbGeometryPtr geom,ShapeInfo *si)
{
register int i,n;
XkbShapePtr shape;
XkbOutlinePtr old_outline,outline;
Atom name;
si->index= geom->num_shapes;
name= XkbInternAtom(dpy,XkbAtomGetString(NULL,si->name),False);
shape= XkbAddGeomShape(geom,name,si->nOutlines);
if (!shape) {
WSGO("Couldn't allocate shape in geometry\n");
ACTION1("Shape %s not compiled\n",shText(dpy,si));
return False;
}
old_outline= si->outlines;
for (i=0;i<si->nOutlines;i++,old_outline++) {
outline= XkbAddGeomOutline(shape,old_outline->num_points);
if (!outline) {
WSGO("Couldn't allocate outline in shape\n");
ACTION1("Shape %s is incomplete\n",shText(dpy,si));
return False;
}
n= old_outline->num_points;
memcpy(outline->points,old_outline->points,n*sizeof(XkbPointRec));
outline->num_points= old_outline->num_points;
outline->corner_radius= old_outline->corner_radius;
}
if (si->approx) {
n= (si->approx-si->outlines);
shape->approx= &shape->outlines[n];
}
if (si->primary) {
n= (si->primary-si->outlines);
shape->primary= &shape->outlines[n];
}
XkbComputeShapeBounds(shape);
return True;
}
static Bool
VerifyDoodadInfo(DoodadInfo *di,GeometryInfo *info)
{
if ((di->defs.defined&(_GD_Top|_GD_Left))!=(_GD_Top|_GD_Left)) {
if (warningLevel<9) {
ERROR1("No position defined for doodad %s\n",ddText(info->dpy,di));
ACTION("Illegal doodad ignored\n");
return False;
}
}
if ((di->defs.defined & _GD_Priority) == 0) {
}
switch (di->type) {
case XkbOutlineDoodad:
case XkbSolidDoodad:
if ((di->defs.defined&_GD_Shape)==0) {
ERROR2("No shape defined for %s doodad %s\n",
(di->type==XkbOutlineDoodad?"outline":"filled"),
ddText(info->dpy,di));
ACTION("Incomplete definition ignored\n");
return False;
}
else {
ShapeInfo *si;
si= FindShape(info,di->shape, (di->type==XkbOutlineDoodad?
"outline doodad":
"solid doodad"),
ddText(info->dpy,di));
if (si)
di->shape= si->name;
else {
ERROR1("No legal shape for %s\n",ddText(info->dpy,di));
ACTION("Incomplete definition ignored\n");
return False;
}
}
if ((di->defs.defined&_GD_Color)==0) {
if (warningLevel>5) {
WARN1("No color for doodad %s\n",ddText(info->dpy,di));
ACTION("Using black\n");
}
di->color= XkbInternAtom(NULL,"black",False);
}
break;
case XkbTextDoodad:
if ((di->defs.defined&_GD_Text)==0) {
ERROR1("No text specified for text doodad %s\n",
ddText(info->dpy,di));
ACTION("Illegal doodad definition ignored\n");
return False;
}
if ((di->defs.defined&_GD_Angle)==0)
di->angle= 0;
if ((di->defs.defined&_GD_Color)==0) {
if (warningLevel>5) {
WARN1("No color specified for doodad %s\n",
ddText(info->dpy,di));
ACTION("Using black\n");
}
di->color= XkbInternAtom(NULL,"black",False);
}
if ((di->defs.defined&_GD_FontSpec)!=0) {
if ((di->defs.defined&_GD_FontParts)==0)
return True;
if (warningLevel<9) {
WARN1("Text doodad %s has full and partial font definition\n",
ddText(info->dpy,di));
ACTION("Full specification ignored\n");
}
di->defs.defined&= ~_GD_FontSpec;
di->fontSpec= None;
}
if ((di->defs.defined&_GD_Font)==0) {
if (warningLevel>5) {
WARN1("No font specified for doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using \"%s\"\n",DFLT_FONT);
}
di->font= XkbInternAtom(NULL,DFLT_FONT,False);
}
if ((di->defs.defined&_GD_FontSlant)==0) {
if (warningLevel>7) {
WARN1("No font slant for text doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using \"%s\"\n",DFLT_SLANT);
}
di->fontSlant= XkbInternAtom(NULL,DFLT_SLANT,False);
}
if ((di->defs.defined&_GD_FontWeight)==0) {
if (warningLevel>7) {
WARN1("No font weight for text doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using \"%s\"\n",DFLT_WEIGHT);
}
di->fontWeight= XkbInternAtom(NULL,DFLT_WEIGHT,False);
}
if ((di->defs.defined&_GD_FontSetWidth)==0) {
if (warningLevel>9) {
WARN1("No font set width for text doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using \"%s\"\n",DFLT_SET_WIDTH);
}
di->fontSetWidth= XkbInternAtom(NULL,DFLT_SET_WIDTH,False);
}
if ((di->defs.defined&_GD_FontVariant)==0) {
if (warningLevel>9) {
WARN1("No font variant for text doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using \"%s\"\n",DFLT_VARIANT);
}
di->fontVariant= XkbInternAtom(NULL,DFLT_VARIANT,False);
}
if ((di->defs.defined&_GD_FontEncoding)==0) {
if (warningLevel>7) {
WARN1("No font encoding for doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using \"%s\"\n",DFLT_ENCODING);
}
di->fontEncoding= XkbInternAtom(NULL,DFLT_ENCODING,False);
}
if ((di->defs.defined&_GD_FontSize)==0) {
if (warningLevel>7) {
WARN1("No font size for text doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using %s point text\n",
XkbGeomFPText(DFLT_SIZE,XkbMessage));
}
di->fontSize= DFLT_SIZE;
}
if ((di->defs.defined&_GD_Height)==0) {
unsigned size,nLines;
char *tmp;
size= (di->fontSize*120)/100;
size= (size*254)/720;
for (nLines=1,tmp=XkbAtomGetString(NULL,di->text);*tmp;tmp++) {
if (*tmp=='\n') nLines++;
}
size*= nLines;
if (warningLevel>5) {
WARN1("No height for text doodad %s\n",
ddText(info->dpy,di));
ACTION1("Using calculated height %s millimeters\n",
XkbGeomFPText(size,XkbMessage));
}
di->height= size;
}
if ((di->defs.defined&_GD_Width)==0) {
unsigned width,tmp;
char *str;
width= tmp= 0;
for (str=XkbAtomGetString(NULL,di->text);*str;str++) {
if (*str!='\n')
tmp++;
else {
if (tmp>width)
width= tmp;
tmp= 1;
}
}
if (width==0)
width= tmp;
width*= (di->height*2)/3;
if (warningLevel>5) {
WARN1("No width for text doodad %s\n",ddText(info->dpy,di));
ACTION1("Using calculated width %s millimeters\n",
XkbGeomFPText(width,XkbMessage));
}
di->width= width;
}
break;
case XkbIndicatorDoodad:
if ((di->defs.defined&_GD_Shape)==0) {
ERROR1("No shape defined for indicator doodad %s\n",
ddText(info->dpy,di));
ACTION("Incomplete definition ignored\n");
return False;
}
else {
ShapeInfo *si;
si= FindShape(info,di->shape,"indicator doodad",
ddText(info->dpy,di));
if (si)
di->shape= si->name;
else {
ERROR1("No legal shape for doodad %s\n",
ddText(info->dpy,di));
ACTION("Incomplete definition ignored\n");
return False;
}
}
if ((di->defs.defined&_GD_Color)==0) {
if (warningLevel>5) {
WARN1("No \"on\" color for indicator doodad %s\n",
ddText(info->dpy,di));
ACTION("Using green\n");
}
di->color= XkbInternAtom(NULL,"green",False);
}
if ((di->defs.defined&_GD_OffColor)==0) {
if (warningLevel>5) {
WARN1("No \"off\" color for indicator doodad %s\n",
ddText(info->dpy,di));
ACTION("Using black\n");
}
di->offColor= XkbInternAtom(NULL,"black",False);
}
break;
case XkbLogoDoodad:
if (di->logoName==NULL) {
ERROR1("No logo name defined for logo doodad %s\n",
ddText(info->dpy,di));
ACTION("Incomplete definition ignored\n");
return False;
}
if ((di->defs.defined&_GD_Shape)==0) {
ERROR1("No shape defined for logo doodad %s\n",
ddText(info->dpy,di));
ACTION("Incomplete definition ignored\n");
return False;
}
else {
ShapeInfo *si;
si= FindShape(info,di->shape,"logo doodad",
ddText(info->dpy,di));
if (si)
di->shape= si->name;
else {
ERROR1("No legal shape for %s\n",ddText(info->dpy,di));
ACTION("Incomplete definition ignored\n");
return False;
}
}
if ((di->defs.defined&_GD_Color)==0) {
if (warningLevel>5) {
WARN1("No color for doodad %s\n",ddText(info->dpy,di));
ACTION("Using black\n");
}
di->color= XkbInternAtom(NULL,"black",False);
}
break;
default:
WSGO1("Uknown doodad type %d in VerifyDoodad\n",(unsigned int)di->type);
return False;
}
return True;
}
#define FONT_TEMPLATE "-*-%s-%s-%s-%s-%s-*-%d-*-*-*-*-%s"
static char *
FontFromParts( Atom fontTok,
Atom weightTok,
Atom slantTok,
Atom setWidthTok,
Atom varTok,
int size,
Atom encodingTok)
{
int totalSize;
char *font,*weight,*slant,*setWidth,*variant,*encoding;
char * rtrn;
font= (fontTok!=None?XkbAtomGetString(NULL,fontTok):DFLT_FONT);
weight= (weightTok!=None?XkbAtomGetString(NULL,weightTok):DFLT_WEIGHT);
slant= (slantTok!=None?XkbAtomGetString(NULL,slantTok):DFLT_SLANT);
setWidth= (setWidthTok!=None?XkbAtomGetString(NULL,setWidthTok):
DFLT_SET_WIDTH);
variant= (varTok!=None?XkbAtomGetString(NULL,varTok):DFLT_VARIANT);
encoding= (encodingTok!=None?XkbAtomGetString(NULL,encodingTok):
DFLT_ENCODING);
if (size==0)
size= DFLT_SIZE;
totalSize= strlen(FONT_TEMPLATE)+strlen(font)+strlen(weight)+strlen(slant);
totalSize+= strlen(setWidth)+strlen(variant)+strlen(encoding);
rtrn= uCalloc(totalSize,1);
if (rtrn) {
sprintf(rtrn,FONT_TEMPLATE,font,weight,slant,setWidth,variant,
size,encoding);
}
return rtrn;
}
static Bool
CopyDoodadDef( XkbGeometryPtr geom,
XkbSectionPtr section,
DoodadInfo * di,
GeometryInfo * info)
{
Atom name;
XkbDoodadPtr doodad;
XkbColorPtr color;
XkbShapePtr shape;
ShapeInfo * si;
if (!VerifyDoodadInfo(di,info))
return False;
name= XkbInternAtom(NULL,XkbAtomGetString(NULL,di->name),False);
doodad= XkbAddGeomDoodad(geom,section,name);
if (!doodad) {
WSGO1("Couldn't allocate doodad in %s\n",
(section?"section":"geometry"));
ACTION1("Cannot copy doodad %s\n",ddText(info->dpy,di));
return False;
}
doodad->any.type= di->type;
doodad->any.priority= di->priority;
doodad->any.top= di->top;
doodad->any.left= di->left;
switch (di->type) {
case XkbOutlineDoodad:
case XkbSolidDoodad:
si= FindShape(info,di->shape,NULL,NULL);
if (!si)
return False;
doodad->shape.angle= di->angle;
color= XkbAddGeomColor(geom,XkbAtomGetString(NULL,di->color),geom->num_colors);
shape= &geom->shapes[si->index];
XkbSetShapeDoodadColor(geom,&doodad->shape,color);
XkbSetShapeDoodadShape(geom,&doodad->shape,shape);
break;
case XkbTextDoodad:
doodad->text.angle= di->angle;
doodad->text.width= di->width;
doodad->text.height= di->height;
if (di->fontSpec==None)
doodad->text.font= FontFromParts(di->font,di->fontWeight,
di->fontSlant,di->fontSetWidth,
di->fontVariant,
di->fontSize,di->fontEncoding);
else doodad->text.font= XkbAtomGetString(NULL,di->fontSpec);
doodad->text.text= XkbAtomGetString(NULL,di->text);
color= XkbAddGeomColor(geom,XkbAtomGetString(NULL,di->color),geom->num_colors);
XkbSetTextDoodadColor(geom,&doodad->text,color);
break;
case XkbIndicatorDoodad:
si= FindShape(info,di->shape,NULL,NULL);
if (!si)
return False;
shape= &geom->shapes[si->index];
color= XkbAddGeomColor(geom,XkbAtomGetString(NULL,di->color),geom->num_colors);
XkbSetIndicatorDoodadShape(geom,&doodad->indicator,shape);
XkbSetIndicatorDoodadOnColor(geom,&doodad->indicator,color);
color= XkbAddGeomColor(geom,XkbAtomGetString(NULL,di->offColor),geom->num_colors);
XkbSetIndicatorDoodadOffColor(geom,&doodad->indicator,color);
break;
case XkbLogoDoodad:
si= FindShape(info,di->shape,NULL,NULL);
if (!si)
return False;
doodad->logo.angle= di->angle;
color= XkbAddGeomColor(geom,XkbAtomGetString(NULL,di->color),geom->num_colors);
shape= &geom->shapes[si->index];
XkbSetLogoDoodadColor(geom,&doodad->logo,color);
XkbSetLogoDoodadShape(geom,&doodad->logo,shape);
doodad->logo.logo_name= di->logoName;
di->logoName= NULL;
break;
}
return True;
}
static Bool
VerifyOverlayInfo( XkbGeometryPtr geom,
XkbSectionPtr section,
OverlayInfo * oi,
GeometryInfo * info,
short rowMap[256],
short rowSize[256])
{
register OverlayKeyInfo * ki,*next;
unsigned long oKey,uKey,sKey;
XkbRowPtr row;
XkbKeyPtr key;
int r,k;
for (ki=oi->keys;ki!=NULL;ki=(OverlayKeyInfo *)ki->defs.next) {
oKey= KeyNameToLong(ki->over);
uKey= KeyNameToLong(ki->under);
for (r=0,row=section->rows;(r<section->num_rows)&&oKey;r++,row++) {
for (k=0,key=row->keys;(k<row->num_keys)&&oKey;k++,key++) {
sKey= KeyNameToLong(key->name.name);
if (sKey==oKey) {
if (warningLevel>0) {
WARN3("Key %s in section \"%s\" and overlay \"%s\"\n",
XkbKeyNameText(key->name.name,XkbMessage),
XkbAtomText(info->dpy,section->name,XkbMessage),
XkbAtomText(info->dpy,oi->name,XkbMessage));
ACTION("Overlay definition ignored\n");
}
oKey= 0;
}
else if (sKey==uKey) {
ki->sectionRow= r;
oKey= 0;
}
}
}
if ((ki->sectionRow==_GOK_UnknownRow)&&(warningLevel>0)) {
WARN3("Key %s not in \"%s\", but has an overlay key in \"%s\"\n",
XkbKeyNameText(ki->under,XkbMessage),
XkbAtomText(info->dpy,section->name,XkbMessage),
XkbAtomText(info->dpy,oi->name,XkbMessage));
ACTION("Definition ignored\n");
}
}
while ((oi->keys!=NULL)&&(oi->keys->sectionRow==_GOK_UnknownRow)) {
next= (OverlayKeyInfo *)oi->keys->defs.next;
uFree(oi->keys);
oi->keys= next;
oi->nKeys--;
}
for (ki=oi->keys;(ki!=NULL)&&(ki->defs.next!=NULL);ki=next) {
next= (OverlayKeyInfo *)ki->defs.next;
if (next->sectionRow==_GOK_UnknownRow) {
ki->defs.next= next->defs.next;
oi->nKeys--;
uFree(next);
next= (OverlayKeyInfo *)ki->defs.next;
}
}
if (oi->nKeys<1) {
ERROR2("Overlay \"%s\" for section \"%s\" has no legal keys\n",
XkbAtomText(info->dpy,oi->name,XkbMessage),
XkbAtomText(info->dpy,section->name,XkbMessage));
ACTION("Overlay definition ignored\n");
return False;
}
bzero(rowSize,sizeof(short)*256);
for (k=0;k<256;k++) {
rowMap[k]= -1;
}
oi->nRows= 0;
for (ki=oi->keys;ki!=NULL;ki=(OverlayKeyInfo *)ki->defs.next) {
if (rowMap[ki->sectionRow]==-1)
rowMap[ki->sectionRow]= oi->nRows++;
ki->overlayRow= rowMap[ki->sectionRow];
rowSize[ki->overlayRow]++;
}
return True;
}
static Bool
CopyOverlayDef( XkbGeometryPtr geom,
XkbSectionPtr section,
OverlayInfo * oi,
GeometryInfo * info)
{
Atom name;
XkbOverlayPtr ol;
XkbOverlayRowPtr row;
XkbOverlayKeyPtr key;
OverlayKeyInfo * ki;
short rowMap[256],rowSize[256];
int i;
if (!VerifyOverlayInfo(geom,section,oi,info,rowMap,rowSize))
return False;
name= XkbInternAtom(NULL,XkbAtomGetString(NULL,oi->name),False);
ol= XkbAddGeomOverlay(section,name,oi->nRows);
if (!ol) {
WSGO2("Couldn't add overlay \"%s\" to section \"%s\"\n",
XkbAtomText(info->dpy,name,XkbMessage),
XkbAtomText(info->dpy,section->name,XkbMessage));
return False;
}
for (i=0;i<oi->nRows;i++) {
int tmp,row_under;
for (tmp=0,row_under=-1;(tmp<section->num_rows)&&(row_under<0);tmp++) {
if (rowMap[tmp]==i)
row_under= tmp;
}
if (!XkbAddGeomOverlayRow(ol,row_under,rowSize[i])) {
WSGO3("Can't add row %d to overlay \"%s\" of section \"%s\"\n",
i,XkbAtomText(info->dpy,name,XkbMessage),
XkbAtomText(info->dpy,section->name,XkbMessage));
return False;
}
}
for (ki=oi->keys;ki!=NULL;ki=(OverlayKeyInfo *)ki->defs.next) {
row= &ol->rows[ki->overlayRow];
key= &row->keys[row->num_keys++];
bzero(key,sizeof(XkbOverlayKeyRec));
strncpy(key->over.name,ki->over,XkbKeyNameLength);
strncpy(key->under.name,ki->under,XkbKeyNameLength);
}
return True;
}
static Bool
CopySectionDef(XkbGeometryPtr geom,SectionInfo *si,GeometryInfo *info)
{
XkbSectionPtr section;
XkbRowPtr row;
XkbKeyPtr key;
KeyInfo * ki;
RowInfo * ri;
Atom name;
name= XkbInternAtom(NULL,XkbAtomGetString(NULL,si->name),False);
section= XkbAddGeomSection(geom,name,si->nRows,si->nDoodads,si->nOverlays);
if (section==NULL) {
WSGO("Couldn't allocate section in geometry\n");
ACTION1("Section %s not compiled\n",scText(info->dpy,si));
return False;
}
section->top= si->top;
section->left= si->left;
section->width= si->width;
section->height= si->height;
section->angle= si->angle;
section->priority= si->priority;
for (ri=si->rows;ri!=NULL;ri=(RowInfo *)ri->defs.next) {
row= XkbAddGeomRow(section,ri->nKeys);
if (row==NULL) {
WSGO("Couldn't allocate row in section\n");
ACTION1("Section %s is incomplete\n",scText(info->dpy,si));
return False;
}
row->top= ri->top;
row->left= ri->left;
row->vertical= ri->vertical;
for (ki=ri->keys;ki!=NULL;ki=(KeyInfo *)ki->defs.next) {
XkbColorPtr color;
if ((ki->defs.defined&_GK_Name)==0) {
ERROR3("Key %d of row %d in section %s has no name\n",
(int)ki->index,(int)ri->index,
scText(info->dpy,si));
ACTION1("Section %s ignored\n",scText(info->dpy,si));
return False;
}
key= XkbAddGeomKey(row);
if (key==NULL) {
WSGO("Couldn't allocate key in row\n");
ACTION1("Section %s is incomplete\n",scText(info->dpy,si));
return False;
}
memcpy(key->name.name,ki->name,XkbKeyNameLength);
key->gap= ki->gap;
if (ki->shape==None)
key->shape_ndx= 0;
else {
ShapeInfo *si;
si= FindShape(info,ki->shape,"key",keyText(ki));
if (!si)
return False;
key->shape_ndx= si->index;
}
if (ki->color!=None)
color= XkbAddGeomColor(geom,XkbAtomGetString(NULL,ki->color),geom->num_colors);
else color= XkbAddGeomColor(geom,"white",geom->num_colors);
XkbSetKeyColor(geom,key,color);
}
}
if (si->doodads!=NULL) {
DoodadInfo *di;
for (di=si->doodads;di!=NULL;di=(DoodadInfo *)di->defs.next) {
CopyDoodadDef(geom,section,di,info);
}
}
if (si->overlays!=NULL) {
OverlayInfo *oi;
for (oi=si->overlays;oi!=NULL;oi=(OverlayInfo *)oi->defs.next) {
CopyOverlayDef(geom,section,oi,info);
}
}
if (XkbComputeSectionBounds(geom,section)) {
if ((si->defs.defined&_GS_Width)==0)
section->width= section->bounds.x2;
if ((si->defs.defined&_GS_Height)==0)
section->height= section->bounds.y2;
}
return True;
}
Bool
CompileGeometry(XkbFile *file,XkbFileInfo *result,unsigned merge)
{
GeometryInfo info;
XkbDescPtr xkb;
xkb= result->xkb;
InitGeometryInfo(&info,file->id,merge);
info.dpy= xkb->dpy;
HandleGeometryFile(file,xkb,merge,&info);
if (info.errorCount==0) {
XkbGeometryPtr geom;
XkbGeometrySizesRec sizes;
bzero(&sizes,sizeof(sizes));
sizes.which= XkbGeomAllMask;
sizes.num_properties= info.nProps;
sizes.num_colors= 8;
sizes.num_shapes= info.nShapes;
sizes.num_sections= info.nSections;
sizes.num_doodads= info.nDoodads;
if (XkbAllocGeometry(xkb,&sizes)!=Success) {
WSGO("Couldn't allocate GeometryRec\n");
ACTION("Geometry not compiled\n");
return False;
}
geom= xkb->geom;
geom->width_mm= info.widthMM;
geom->height_mm= info.heightMM;
if (info.name!=NULL) {
geom->name= XkbInternAtom(xkb->dpy,info.name,False);
if (XkbAllocNames(xkb,XkbGeometryNameMask,0,0)==Success)
xkb->names->geometry= geom->name;
}
if (info.fontSpec!=None)
geom->label_font= uStringDup(XkbAtomGetString(NULL,info.fontSpec));
else geom->label_font= FontFromParts(info.font,info.fontWeight,
info.fontSlant,info.fontSetWidth,
info.fontVariant,
info.fontSize,info.fontEncoding);
XkbAddGeomColor(geom,"black",geom->num_colors);
XkbAddGeomColor(geom,"white",geom->num_colors);
if (info.baseColor==None)
info.baseColor= XkbInternAtom(NULL,"white",False);
if (info.labelColor==None)
info.labelColor= XkbInternAtom(NULL,"black",False);
geom->base_color=
XkbAddGeomColor(geom,XkbAtomGetString(NULL,info.baseColor),geom->num_colors);
geom->label_color=
XkbAddGeomColor(geom,XkbAtomGetString(NULL,info.labelColor),geom->num_colors);
if (info.props) {
PropertyInfo *pi;
for (pi= info.props;pi!=NULL;pi=(PropertyInfo *)pi->defs.next) {
if (!XkbAddGeomProperty(geom,pi->name,pi->value))
return False;
}
}
if (info.shapes) {
ShapeInfo *si;
for (si= info.shapes;si!=NULL;si=(ShapeInfo *)si->defs.next) {
if (!CopyShapeDef(xkb->dpy,geom,si))
return False;
}
}
if (info.sections) {
SectionInfo *si;
for (si= info.sections;si!=NULL;si=(SectionInfo *)si->defs.next) {
if (!CopySectionDef(geom,si,&info))
return False;
}
}
if (info.doodads) {
DoodadInfo *di;
for (di= info.doodads;di!=NULL;di=(DoodadInfo *)di->defs.next) {
if (!CopyDoodadDef(geom,NULL,di,&info))
return False;
}
}
if (info.aliases)
ApplyAliases(xkb,True,&info.aliases);
ClearGeometryInfo(&info);
return True;
}
return False;
}