#ifdef DEBUG
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#endif
#define NEED_EVENTS
#define NEED_REPLIES
#define NEED_MAP_READERS
#include "Xlibint.h"
#include <X11/extensions/XKBgeom.h>
#include <X11/extensions/XKBproto.h>
#include "XKBlibint.h"
#ifndef MINSHORT
#define MINSHORT -32768
#endif
#ifndef MAXSHORT
#define MAXSHORT 32767
#endif
static void
_XkbCheckBounds(XkbBoundsPtr bounds,int x,int y)
{
if (x<bounds->x1) bounds->x1= x;
if (x>bounds->x2) bounds->x2= x;
if (y<bounds->y1) bounds->y1= y;
if (y>bounds->y2) bounds->y2= y;
return;
}
Bool
XkbComputeShapeBounds(XkbShapePtr shape)
{
register int o,p;
XkbOutlinePtr outline;
XkbPointPtr pt;
if ((!shape)||(shape->num_outlines<1))
return False;
shape->bounds.x1= shape->bounds.y1= MAXSHORT;
shape->bounds.x2= shape->bounds.y2= MINSHORT;
for (outline=shape->outlines,o=0;o<shape->num_outlines;o++,outline++) {
for (pt=outline->points,p=0;p<outline->num_points;p++,pt++) {
_XkbCheckBounds(&shape->bounds,pt->x,pt->y);
}
if (outline->num_points<2) {
_XkbCheckBounds(&shape->bounds,0,0);
}
}
return True;
}
Bool
XkbComputeShapeTop(XkbShapePtr shape,XkbBoundsPtr bounds)
{
register int p;
XkbOutlinePtr outline;
XkbPointPtr pt;
if ((!shape)||(shape->num_outlines<1))
return False;
if (shape->approx) outline= shape->approx;
else outline= &shape->outlines[shape->num_outlines-1];
if (outline->num_points<2) {
bounds->x1= bounds->y1= 0;
bounds->x2= bounds->y2= 0;
}
else {
bounds->x1= bounds->y1= MAXSHORT;
bounds->x2= bounds->y2= MINSHORT;
}
for (pt=outline->points,p=0;p<outline->num_points;p++,pt++) {
_XkbCheckBounds(bounds,pt->x,pt->y);
}
return True;
}
Bool
XkbComputeRowBounds(XkbGeometryPtr geom,XkbSectionPtr section,XkbRowPtr row)
{
register int k,pos;
XkbKeyPtr key;
XkbBoundsPtr bounds,sbounds;
if ((!geom)||(!section)||(!row))
return False;
pos= 0;
bounds= &row->bounds;
bzero(bounds,sizeof(XkbBoundsRec));
for (key=row->keys,pos=k=0;k<row->num_keys;k++,key++) {
sbounds= &XkbKeyShape(geom,key)->bounds;
_XkbCheckBounds(bounds,pos,0);
if (!row->vertical) {
if (key->gap!=0) {
pos+= key->gap;
_XkbCheckBounds(bounds,pos,0);
}
_XkbCheckBounds(bounds,pos+sbounds->x1,sbounds->y1);
_XkbCheckBounds(bounds,pos+sbounds->x2,sbounds->y2);
pos+= sbounds->x2;
}
else {
if (key->gap!=0) {
pos+= key->gap;
_XkbCheckBounds(bounds,0,pos);
}
_XkbCheckBounds(bounds,pos+sbounds->x1,sbounds->y1);
_XkbCheckBounds(bounds,pos+sbounds->x2,sbounds->y2);
pos+= sbounds->y2;
}
}
return True;
}
Bool
XkbComputeSectionBounds(XkbGeometryPtr geom,XkbSectionPtr section)
{
register int i;
XkbShapePtr shape;
XkbRowPtr row;
XkbDoodadPtr doodad;
XkbBoundsPtr bounds,rbounds=NULL;
if ((!geom)||(!section))
return False;
bounds= §ion->bounds;
bzero(bounds,sizeof(XkbBoundsRec));
for (i=0,row=section->rows;i<section->num_rows;i++,row++) {
if (!XkbComputeRowBounds(geom,section,row))
return False;
rbounds= &row->bounds;
_XkbCheckBounds(bounds,row->left+rbounds->x1,row->top+rbounds->y1);
_XkbCheckBounds(bounds,row->left+rbounds->x2,row->top+rbounds->y2);
}
for (i=0,doodad=section->doodads;i<section->num_doodads;i++,doodad++) {
static XkbBoundsRec tbounds;
switch (doodad->any.type) {
case XkbOutlineDoodad:
case XkbSolidDoodad:
shape= XkbShapeDoodadShape(geom,&doodad->shape);
rbounds= &shape->bounds;
break;
case XkbTextDoodad:
tbounds.x1= doodad->text.left;
tbounds.y1= doodad->text.top;
tbounds.x2= tbounds.x1+doodad->text.width;
tbounds.y2= tbounds.y1+doodad->text.height;
rbounds= &tbounds;
break;
case XkbIndicatorDoodad:
shape= XkbIndicatorDoodadShape(geom,&doodad->indicator);
rbounds= &shape->bounds;
break;
case XkbLogoDoodad:
shape= XkbLogoDoodadShape(geom,&doodad->logo);
rbounds= &shape->bounds;
break;
default:
tbounds.x1= tbounds.x2= doodad->any.left;
tbounds.y1= tbounds.y2= doodad->any.top;
break;
}
_XkbCheckBounds(bounds,rbounds->x1,rbounds->y1);
_XkbCheckBounds(bounds,rbounds->x2,rbounds->y2);
}
return True;
}
char *
XkbFindOverlayForKey(XkbGeometryPtr geom,XkbSectionPtr wanted,char *under)
{
int s;
XkbSectionPtr section;
if ((geom==NULL)||(under==NULL)||(geom->num_sections<1))
return NULL;
if (wanted)
section= wanted;
else section= geom->sections;
for (s=0;s<geom->num_sections;s++,section++) {
XkbOverlayPtr ol;
int o;
if (section->num_overlays<1)
continue;
for (o=0,ol=section->overlays;o<section->num_overlays;o++,ol++) {
XkbOverlayRowPtr row;
int r;
for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) {
XkbOverlayKeyPtr key;
int k;
for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
if (strncmp(under,key->under.name,XkbKeyNameLength)==0)
return key->over.name;
}
}
}
if (wanted!=NULL)
break;
}
return NULL;
}
static Status
_XkbReadGeomProperties( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
xkbGetGeometryReply * rep)
{
Status rtrn;
if (rep->nProperties<1)
return Success;
if ((rtrn=XkbAllocGeomProps(geom,rep->nProperties))==Success) {
register int i;
register Bool ok;
char *name,*value;
ok= True;
for (i=0;(i<rep->nProperties)&&ok;i++) {
name=NULL;
value=NULL;
ok= _XkbGetReadBufferCountedString(buf,&name)&&ok;
ok= _XkbGetReadBufferCountedString(buf,&value)&&ok;
ok= ok&&(XkbAddGeomProperty(geom,name,value)!=NULL);
if (name)
_XkbFree(name);
if (value)
_XkbFree(value);
}
if (ok) rtrn= Success;
else rtrn= BadLength;
}
return rtrn;
}
static Status
_XkbReadGeomKeyAliases( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
xkbGetGeometryReply * rep)
{
Status rtrn;
if (rep->nKeyAliases<1)
return Success;
if ((rtrn=XkbAllocGeomKeyAliases(geom,rep->nKeyAliases))==Success) {
if (!_XkbCopyFromReadBuffer(buf,(char *)geom->key_aliases,
(rep->nKeyAliases*XkbKeyNameLength*2)))
return BadLength;
geom->num_key_aliases= rep->nKeyAliases;
return Success;
}
else {
_XkbSkipReadBufferData(buf,(rep->nKeyAliases*XkbKeyNameLength*2));
}
return rtrn;
}
static Status
_XkbReadGeomColors( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
xkbGetGeometryReply * rep)
{
Status rtrn;
if (rep->nColors<1)
return Success;
if ((rtrn=XkbAllocGeomColors(geom,rep->nColors))==Success) {
register int i;
char *spec;
for (i=0;i<rep->nColors;i++) {
spec = NULL;
if (!_XkbGetReadBufferCountedString(buf,&spec))
rtrn = BadLength;
else if (XkbAddGeomColor(geom,spec,geom->num_colors)==NULL)
rtrn = BadAlloc;
if (spec)
_XkbFree(spec);
if (rtrn != Success)
return rtrn;
}
return Success;
}
return rtrn;
}
static Status
_XkbReadGeomShapes( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
xkbGetGeometryReply * rep)
{
register int i;
Status rtrn;
if (rep->nShapes<1)
return Success;
if ((rtrn=XkbAllocGeomShapes(geom,rep->nShapes))!=Success)
return rtrn;
for (i=0;i<rep->nShapes;i++) {
xkbShapeWireDesc *shapeWire;
XkbShapePtr shape;
register int o;
shapeWire= (xkbShapeWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbShapeWireDesc));
if (!shapeWire)
return BadLength;
shape= XkbAddGeomShape(geom,shapeWire->name,shapeWire->nOutlines);
if (!shape)
return BadAlloc;
for (o=0;o<shapeWire->nOutlines;o++) {
xkbOutlineWireDesc *olWire;
XkbOutlinePtr ol;
register int p;
XkbPointPtr pt;
olWire= (xkbOutlineWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbOutlineWireDesc));
if (!olWire)
return BadLength;
ol= XkbAddGeomOutline(shape,olWire->nPoints);
if (!ol)
return BadAlloc;
ol->corner_radius= olWire->cornerRadius;
for (p=0,pt=ol->points;p<olWire->nPoints;p++,pt++) {
xkbPointWireDesc * ptWire;
ptWire= (xkbPointWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbPointWireDesc));
if (!ptWire)
return BadLength;
pt->x= ptWire->x;
pt->y= ptWire->y;
}
ol->num_points= olWire->nPoints;
}
if (shapeWire->primaryNdx!=XkbNoShape)
shape->primary= &shape->outlines[shapeWire->primaryNdx];
else shape->primary= NULL;
if (shapeWire->approxNdx!=XkbNoShape)
shape->approx= &shape->outlines[shapeWire->approxNdx];
else shape->approx= NULL;
XkbComputeShapeBounds(shape);
}
return Success;
}
static Status
_XkbReadGeomDoodad( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
XkbSectionPtr section)
{
XkbDoodadPtr doodad;
xkbDoodadWireDesc * doodadWire;
doodadWire= (xkbDoodadWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbDoodadWireDesc));
if (!doodadWire)
return BadLength;
doodad= XkbAddGeomDoodad(geom,section,doodadWire->any.name);
if (!doodad)
return BadAlloc;
doodad->any.type= doodadWire->any.type;
doodad->any.priority= doodadWire->any.priority;
doodad->any.top= doodadWire->any.top;
doodad->any.left= doodadWire->any.left;
doodad->any.angle= doodadWire->any.angle;
switch (doodad->any.type) {
case XkbOutlineDoodad:
case XkbSolidDoodad:
doodad->shape.color_ndx= doodadWire->shape.colorNdx;
doodad->shape.shape_ndx= doodadWire->shape.shapeNdx;
break;
case XkbTextDoodad:
doodad->text.width= doodadWire->text.width;
doodad->text.height= doodadWire->text.height;
doodad->text.color_ndx= doodadWire->text.colorNdx;
if (!_XkbGetReadBufferCountedString(buf,&doodad->text.text))
return BadLength;
if (!_XkbGetReadBufferCountedString(buf,&doodad->text.font))
return BadLength;
break;
case XkbIndicatorDoodad:
doodad->indicator.shape_ndx= doodadWire->indicator.shapeNdx;
doodad->indicator.on_color_ndx= doodadWire->indicator.onColorNdx;
doodad->indicator.off_color_ndx= doodadWire->indicator.offColorNdx;
break;
case XkbLogoDoodad:
doodad->logo.color_ndx= doodadWire->logo.colorNdx;
doodad->logo.shape_ndx= doodadWire->logo.shapeNdx;
if (!_XkbGetReadBufferCountedString(buf,&doodad->logo.logo_name))
return BadLength;
break;
default:
return BadValue;
}
return Success;
}
static Status
_XkbReadGeomOverlay( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
XkbSectionPtr section)
{
XkbOverlayPtr ol;
xkbOverlayWireDesc * olWire;
register int r;
olWire= (xkbOverlayWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbOverlayWireDesc));
if (olWire==NULL)
return BadLength;
ol= XkbAddGeomOverlay(section,olWire->name,olWire->nRows);
if (ol==NULL)
return BadLength;
for (r=0;r<olWire->nRows;r++) {
register int k;
XkbOverlayRowPtr row;
xkbOverlayRowWireDesc * rowWire;
xkbOverlayKeyWireDesc * keyWire;
rowWire= (xkbOverlayRowWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbOverlayRowWireDesc));
if (rowWire==NULL)
return BadLength;
row= XkbAddGeomOverlayRow(ol,rowWire->rowUnder,rowWire->nKeys);
row->row_under= rowWire->rowUnder;
if (!row)
return BadAlloc;
if (rowWire->nKeys<1)
continue;
keyWire= (xkbOverlayKeyWireDesc *)
_XkbGetReadBufferPtr(buf,
SIZEOF(xkbOverlayKeyWireDesc)*rowWire->nKeys);
if (keyWire==NULL)
return BadLength;
for (k=0;k<rowWire->nKeys;k++,keyWire++,row->num_keys++) {
memcpy(row->keys[row->num_keys].over.name,keyWire->over,
XkbKeyNameLength);
memcpy(row->keys[row->num_keys].under.name,keyWire->under,
XkbKeyNameLength);
}
}
return Success;
}
static Status
_XkbReadGeomSections( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
xkbGetGeometryReply * rep)
{
register int s;
XkbSectionPtr section;
xkbSectionWireDesc * sectionWire;
Status rtrn;
if (rep->nSections<1)
return Success;
if ((rtrn=XkbAllocGeomSections(geom,rep->nSections))!=Success)
return rtrn;
for (s=0;s<rep->nSections;s++) {
sectionWire= (xkbSectionWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbSectionWireDesc));
if (!sectionWire)
return BadLength;
section= XkbAddGeomSection(geom,sectionWire->name,sectionWire->nRows,
sectionWire->nDoodads,
sectionWire->nOverlays);
if (!section)
return BadAlloc;
section->top= sectionWire->top;
section->left= sectionWire->left;
section->width= sectionWire->width;
section->height= sectionWire->height;
section->angle= sectionWire->angle;
section->priority= sectionWire->priority;
if (sectionWire->nRows>0) {
register int r;
XkbRowPtr row;
xkbRowWireDesc * rowWire;
for (r=0;r<sectionWire->nRows;r++) {
rowWire= (xkbRowWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbRowWireDesc));
if (!rowWire)
return BadLength;
row= XkbAddGeomRow(section,rowWire->nKeys);
if (!row)
return BadAlloc;
row->top= rowWire->top;
row->left= rowWire->left;
row->vertical= rowWire->vertical;
if (rowWire->nKeys>0) {
register int k;
XkbKeyPtr key;
xkbKeyWireDesc * keyWire;
for (k=0;k<rowWire->nKeys;k++) {
keyWire= (xkbKeyWireDesc *)
_XkbGetReadBufferPtr(buf,SIZEOF(xkbKeyWireDesc));
if (!keyWire)
return BadLength;
key= XkbAddGeomKey(row);
if (!key)
return BadAlloc;
memcpy(key->name.name,keyWire->name,XkbKeyNameLength);
key->gap= keyWire->gap;
key->shape_ndx= keyWire->shapeNdx;
key->color_ndx= keyWire->colorNdx;
}
}
}
}
if (sectionWire->nDoodads>0) {
register int d;
for (d=0;d<sectionWire->nDoodads;d++) {
if ((rtrn=_XkbReadGeomDoodad(buf,geom,section))!=Success)
return rtrn;
}
}
if (sectionWire->nOverlays>0) {
register int o;
for (o=0;o<sectionWire->nOverlays;o++) {
if ((rtrn=_XkbReadGeomOverlay(buf,geom,section))!=Success)
return rtrn;
}
}
}
return Success;
}
static Status
_XkbReadGeomDoodads( XkbReadBufferPtr buf,
XkbGeometryPtr geom,
xkbGetGeometryReply * rep)
{
register int d;
Status rtrn;
if (rep->nDoodads<1)
return Success;
if ((rtrn=XkbAllocGeomDoodads(geom,rep->nDoodads))!=Success)
return rtrn;
for (d=0;d<rep->nDoodads;d++) {
if ((rtrn=_XkbReadGeomDoodad(buf,geom,NULL))!=Success)
return rtrn;
}
return Success;
}
Status
_XkbReadGetGeometryReply( Display * dpy,
xkbGetGeometryReply * rep,
XkbDescPtr xkb,
int * nread_rtrn)
{
XkbGeometryPtr geom;
geom= _XkbTypedCalloc(1,XkbGeometryRec);
if (!geom)
return BadAlloc;
if (xkb->geom)
XkbFreeGeometry(xkb->geom,XkbGeomAllMask,True);
xkb->geom= geom;
geom->name= rep->name;
geom->width_mm= rep->widthMM;
geom->height_mm= rep->heightMM;
if (rep->length) {
XkbReadBufferRec buf;
int left;
if (_XkbInitReadBuffer(dpy,&buf,(int)rep->length*4)) {
Status status= Success;
if (nread_rtrn)
*nread_rtrn= (int)rep->length*4;
if (!_XkbGetReadBufferCountedString(&buf,&geom->label_font))
status= BadLength;
if (status==Success)
status= _XkbReadGeomProperties(&buf,geom,rep);
if (status==Success)
status= _XkbReadGeomColors(&buf,geom,rep);
if (status==Success)
status= _XkbReadGeomShapes(&buf,geom,rep);
if (status==Success)
status= _XkbReadGeomSections(&buf,geom,rep);
if (status==Success)
status= _XkbReadGeomDoodads(&buf,geom,rep);
if (status==Success)
status= _XkbReadGeomKeyAliases(&buf,geom,rep);
left= _XkbFreeReadBuffer(&buf);
if ((status!=Success) || left || buf.error) {
if (status==Success)
status= BadLength;
XkbFreeGeometry(geom,XkbGeomAllMask,True);
xkb->geom= NULL;
return status;
}
geom->base_color= &geom->colors[rep->baseColorNdx];
geom->label_color= &geom->colors[rep->labelColorNdx];
}
else {
XkbFreeGeometry(geom,XkbGeomAllMask,True);
xkb->geom= NULL;
return BadAlloc;
}
}
return Success;
}
Status
XkbGetGeometry(Display *dpy,XkbDescPtr xkb)
{
xkbGetGeometryReq *req;
xkbGetGeometryReply rep;
Status status;
if ( (!xkb) || (dpy->flags & XlibDisplayNoXkb) ||
(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
return BadAccess;
LockDisplay(dpy);
GetReq(kbGetGeometry, req);
req->reqType = dpy->xkb_info->codes->major_opcode;
req->xkbReqType = X_kbGetGeometry;
req->deviceSpec = xkb->device_spec;
req->name= None;
if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
status = BadImplementation;
else if (!rep.found)
status = BadName;
else
status = _XkbReadGetGeometryReply(dpy,&rep,xkb,NULL);
UnlockDisplay(dpy);
SyncHandle();
return status;
}
Status
XkbGetNamedGeometry(Display *dpy,XkbDescPtr xkb,Atom name)
{
xkbGetGeometryReq *req;
xkbGetGeometryReply rep;
Status status;
if ( (name==None) || (dpy->flags & XlibDisplayNoXkb) ||
(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)) )
return BadAccess;
LockDisplay(dpy);
GetReq(kbGetGeometry, req);
req->reqType = dpy->xkb_info->codes->major_opcode;
req->xkbReqType = X_kbGetGeometry;
req->deviceSpec = xkb->device_spec;
req->name= (CARD32)name;
if ((!_XReply(dpy, (xReply *)&rep, 0, xFalse))||(!rep.found))
status = BadImplementation;
else if (!rep.found)
status = BadName;
else
status = _XkbReadGetGeometryReply(dpy,&rep,xkb,NULL);
UnlockDisplay(dpy);
SyncHandle();
return status;
}