#include <X11/Xos.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(SVR4) && defined(i386) && !defined(_XOPEN_SOURCE)
# define _XOPEN_SOURCE
# include <math.h>
# undef _XOPEN_SOURCE
#else
# include <math.h>
#endif
#include <X11/Xfuncs.h>
#include "XKBuiPriv.h"
#include "XKBfileInt.h"
#include <X11/extensions/XKBfile.h>
#ifndef M_PI
# define M_PI 3.141592653589793238462
#endif
static XkbUI_ViewOptsRec dfltOpts = {
XkbUI_AllViewOptsMask ,
1 ,
0 ,
XkbUI_KeyNames ,
0 ,
{
0 ,
0 ,
640 ,
480
},
10, 10,
None
};
XkbUI_ViewPtr
XkbUI_SimpleInit(Display *dpy,Window win,int width,int height)
{
XkbDescPtr xkb;
if ((!dpy)||(win==None)||(width<1)||(height<1))
return NULL;
xkb= XkbGetKeyboard(dpy,XkbGBN_AllComponentsMask,XkbUseCoreKbd);
if (!xkb)
return NULL;
return XkbUI_Init(dpy,win,width,height,xkb,NULL);
}
static void
_XkbUI_AllocateColors(XkbUI_ViewPtr view)
{
register int i;
Display * dpy;
XColor sdef,xdef;
XkbDescPtr xkb;
dpy= view->dpy;
xkb= view->xkb;
if (view->opts.cmap==None)
view->opts.cmap= DefaultColormap(dpy,DefaultScreen(dpy));
for (i=0;i<xkb->geom->num_colors;i++) {
char *spec;
Bool found;
spec= xkb->geom->colors[i].spec;
found= False;
if (XAllocNamedColor(view->dpy,view->opts.cmap,spec,&sdef,&xdef)) {
xkb->geom->colors[i].pixel= sdef.pixel;
#ifdef DEBUG
fprintf(stderr,"got pixel %d for \"%s\"\n",sdef.pixel,spec);
#endif
found= True;
}
if ((!found)&&(XkbLookupCanonicalRGBColor(spec,&sdef))) {
char buf[20];
sprintf(buf,"#%02x%02x%02x",(sdef.red>>8)&0xff,
(sdef.green>>8)&0xff,
(sdef.blue>>8)&&0xff);
if (XAllocNamedColor(view->dpy,view->opts.cmap,buf,&sdef,&xdef)) {
xkb->geom->colors[i].pixel= sdef.pixel;
#ifdef DEBUG
fprintf(stderr,"got pixel %d for \"%s\"\n",sdef.pixel,spec);
#endif
found= True;
}
}
if (!found) {
xkb->geom->colors[i].pixel= view->opts.fg;
fprintf(stderr,"Couldn't allocate color \"%s\"\n",spec);
}
}
return;
}
XkbUI_ViewPtr
XkbUI_Init( Display * dpy,
Window win,
int width,
int height,
XkbDescPtr xkb,
XkbUI_ViewOptsPtr opts)
{
XGCValues xgcv;
XkbUI_ViewPtr view;
int scrn;
if ((!dpy)||(!xkb)||(!xkb->geom)||(win==None)||(width<1)||(height<1))
return NULL;
view= _XkbTypedCalloc(1,XkbUI_ViewRec);
if (!view)
return NULL;
scrn= DefaultScreen(dpy);
view->dpy= dpy;
view->xkb= xkb;
view->win= win;
view->opts= dfltOpts;
view->opts.fg= WhitePixel(dpy,scrn);
view->opts.bg= BlackPixel(dpy,scrn);
view->opts.viewport.x= 0;
view->opts.viewport.y= 0;
view->opts.viewport.width= width;
view->opts.viewport.height= height;
if ((opts)&&(opts->present)) {
if (opts->present&XkbUI_BackgroundMask)
view->opts.bg= opts->bg;
if (opts->present&XkbUI_ForegroundMask)
view->opts.fg= opts->fg;
if (opts->present&XkbUI_LabelModeMask)
view->opts.label_mode= opts->label_mode;
if (opts->present&XkbUI_ColorModeMask)
view->opts.color_mode= opts->color_mode;
if (opts->present&XkbUI_WidthMask)
view->opts.viewport.width= opts->viewport.width;
if (opts->present&XkbUI_HeightMask)
view->opts.viewport.height= opts->viewport.height;
if (opts->present&XkbUI_XOffsetMask)
view->opts.viewport.x= opts->viewport.x;
if (opts->present&XkbUI_YOffsetMask)
view->opts.viewport.y= opts->viewport.y;
if (opts->present&XkbUI_MarginWidthMask)
view->opts.margin_width= opts->margin_width;
if (opts->present&XkbUI_MarginHeightMask)
view->opts.margin_height= opts->margin_height;
if (opts->present&XkbUI_ColormapMask)
view->opts.cmap= opts->cmap;
}
view->canvas_width= width+(2*view->opts.margin_width);
view->canvas_height= height+(2*view->opts.margin_height);
if (view->opts.viewport.width>view->canvas_width) {
int tmp;
tmp= (view->opts.viewport.width-view->canvas_width)/2;
view->opts.margin_width+= tmp;
}
if (view->opts.viewport.height>view->canvas_height) {
int tmp;
tmp= (view->opts.viewport.height-view->canvas_height)/2;
view->opts.margin_height+= tmp;
}
bzero(view->state,XkbMaxLegalKeyCode+1);
xgcv.foreground= view->opts.fg;
xgcv.background= view->opts.bg;
view->gc= XCreateGC(view->dpy,view->win,GCForeground|GCBackground,&xgcv);
view->xscale= ((double)width)/((double)xkb->geom->width_mm);
view->yscale= ((double)height)/((double)xkb->geom->height_mm);
_XkbUI_AllocateColors(view);
return view;
}
Status
XkbUI_SetViewOpts(XkbUI_ViewPtr view,XkbUI_ViewOptsPtr opts)
{
if ((!view)||(!opts))
return BadValue;
if (opts->present==0)
return Success;
if (opts->present&XkbUI_BackgroundMask)
view->opts.bg= opts->bg;
if (opts->present&XkbUI_ForegroundMask)
view->opts.fg= opts->fg;
if (opts->present&XkbUI_LabelModeMask)
view->opts.label_mode= opts->label_mode;
if (opts->present&XkbUI_ColorModeMask)
view->opts.color_mode= opts->color_mode;
if (opts->present&XkbUI_WidthMask)
view->opts.viewport.width= opts->viewport.width;
if (opts->present&XkbUI_HeightMask)
view->opts.viewport.height= opts->viewport.height;
if (opts->present&XkbUI_XOffsetMask)
view->opts.viewport.x= opts->viewport.x;
if (opts->present&XkbUI_YOffsetMask)
view->opts.viewport.y= opts->viewport.y;
if (opts->present&XkbUI_MarginWidthMask)
view->opts.margin_width= opts->margin_width;
if (opts->present&XkbUI_MarginHeightMask)
view->opts.margin_height= opts->margin_height;
if (opts->present&XkbUI_ColormapMask) {
view->opts.cmap= opts->cmap;
_XkbUI_AllocateColors(view);
}
return Success;
}
Status
XbUI_GetViewOpts(XkbUI_ViewPtr view,XkbUI_ViewOptsPtr opts_rtrn)
{
if ((!view)||(!opts_rtrn))
return BadValue;
*opts_rtrn= view->opts;
return Success;
}
Status
XkbUI_SetCanvasSize(XkbUI_ViewPtr view,int width,int height)
{
if ((!view)||(!view->xkb)||(!view->xkb->geom))
return BadValue;
view->canvas_width= width;
view->canvas_height= height;
view->xscale= ((double)width)/((double)view->xkb->geom->width_mm);
view->yscale= ((double)height)/((double)view->xkb->geom->height_mm);
return Success;
}
Status
XkbUI_GetCanvasSize(XkbUI_ViewPtr view,int *width_rtrn,int *height_rtrn)
{
if (!view)
return BadValue;
if (width_rtrn) *width_rtrn= view->canvas_width;
if (height_rtrn) *height_rtrn= view->canvas_height;
return Success;
}
static void
_RotatePoints( double rangle,
int corner_x,
int corner_y,
int nPts,
XkbUI_PointPtr pts)
{
register int i;
double rr,rx,ry,rt;
for (i=0;i<nPts;i++,pts++) {
rx= pts->x-corner_x; ry= pts->y-corner_y;
rr= hypot(rx,ry);
rt= atan2(ry,rx)+rangle;
rx= rr*cos(rt);
ry= rr*sin(rt);
pts->x= rx+corner_x; pts->y= ry+corner_y;
}
return;
}
static void
_DrawPoints(XkbUI_ViewPtr view,int nPts,XkbUI_PointPtr pts,XPoint *xpts)
{
register int i;
for (i=0;i<nPts;i++) {
if (pts[i].x>=0.0) xpts[i].x= pts[i].x*view->xscale+0.5;
else xpts[i].x= pts[i].x*view->xscale-0.5;
xpts[i].x+= view->opts.viewport.x;
if (pts[i].y>=0.0) xpts[i].y= pts[i].y*view->yscale+0.5;
else xpts[i].x= pts[i].y*view->yscale-0.5;
xpts[i].y+= view->opts.viewport.y;
}
if ((xpts[nPts-1].x!=xpts[0].x)||(xpts[nPts-1].y!=xpts[0].y))
xpts[nPts++]= xpts[0];
XDrawLines(view->dpy,view->win,view->gc,xpts,nPts,CoordModeOrigin);
XFlush(view->dpy);
return;
}
static void
_DrawSolidPoints(XkbUI_ViewPtr view,int nPts,XkbUI_PointPtr pts,XPoint *xpts)
{
register int i;
for (i=0;i<nPts;i++) {
if (pts[i].x>=0.0) xpts[i].x= pts[i].x*view->xscale+0.5;
else xpts[i].x= pts[i].x*view->xscale-0.5;
xpts[i].x+= view->opts.viewport.x;
if (pts[i].y>=0.0) xpts[i].y= pts[i].y*view->yscale+0.5;
else xpts[i].x= pts[i].y*view->yscale-0.5;
xpts[i].y+= view->opts.viewport.y;
}
if ((xpts[nPts-1].x!=xpts[0].x)||(xpts[nPts-1].y!=xpts[0].y))
xpts[nPts++]= xpts[0];
XFillPolygon(view->dpy,view->win,view->gc,xpts,nPts,Nonconvex,
CoordModeOrigin);
XFlush(view->dpy);
return;
}
static void
_DrawShape( XkbUI_ViewPtr view,
double rangle,
int xoff,
int yoff,
int rotx,
int roty,
XkbShapePtr shape,
Bool key)
{
XkbOutlinePtr ol;
register int o;
int maxPts;
XkbUI_PointPtr uipts;
XPoint * xpts;
for (maxPts=4,o=0,ol=shape->outlines;o<shape->num_outlines;o++,ol++) {
if ((shape->num_outlines>1)&&(ol==shape->approx))
continue;
if (ol->num_points>maxPts)
maxPts= ol->num_points;
}
uipts= _XkbTypedCalloc(maxPts,XkbUI_PointRec);
xpts= _XkbTypedCalloc(maxPts+1,XPoint);
XSetForeground(view->dpy,view->gc,view->xkb->geom->label_color->pixel);
for (o=0,ol=shape->outlines;o<shape->num_outlines;o++,ol++) {
XkbPointPtr gpts;
register int p;
if ((shape->num_outlines>1)&&(ol==shape->approx))
continue;
gpts= ol->points;
if (ol->num_points==1) {
uipts[0].x= xoff; uipts[0].y= yoff;
uipts[1].x= xoff+gpts[0].x; uipts[1].y= yoff;
uipts[2].x= xoff+gpts[0].x; uipts[2].y= yoff+gpts[0].y;
uipts[3].x= xoff; uipts[3].y= yoff+gpts[0].y;
p= 4;
}
else if (ol->num_points==2) {
uipts[0].x= xoff+gpts[0].x; uipts[0].y= yoff+gpts[0].y;
uipts[1].x= xoff+gpts[1].x; uipts[1].y= yoff+gpts[0].y;
uipts[2].x= xoff+gpts[1].x; uipts[2].y= yoff+gpts[1].y;
uipts[3].x= xoff+gpts[0].x; uipts[3].y= yoff+gpts[1].y;
p= 4;
}
else {
for (p=0;p<ol->num_points;p++) {
uipts[p].x= xoff+gpts[p].x;
uipts[p].y= yoff+gpts[p].y;
}
p= ol->num_points;
}
if (rangle!=0.0)
_RotatePoints(rangle,rotx,roty,p,uipts);
if (key) {
if (o==0) {
XSetForeground(view->dpy,view->gc,
view->xkb->geom->base_color->pixel);
_DrawSolidPoints(view,p,uipts,xpts);
XSetForeground(view->dpy,view->gc,
view->xkb->geom->label_color->pixel);
}
_DrawPoints(view,p,uipts,xpts);
}
else {
_DrawPoints(view,p,uipts,xpts);
}
}
_XkbFree(uipts);
_XkbFree(xpts);
return;
}
static void
_DrawRect( XkbUI_ViewPtr view,
double rangle,
int x1,
int y1,
int x2,
int y2,
Bool key)
{
XkbUI_PointRec uipts[4];
XPoint xpts[4];
XSetForeground(view->dpy,view->gc,view->xkb->geom->label_color->pixel);
uipts[0].x= x1; uipts[0].y= y1;
uipts[1].x= x2; uipts[1].y= y1;
uipts[2].x= x2; uipts[2].y= y2;
uipts[3].x= x1; uipts[3].y= y2;
if (rangle!=0.0)
_RotatePoints(rangle,0,0,4,uipts);
if (key) {
XSetForeground(view->dpy,view->gc,view->xkb->geom->base_color->pixel);
_DrawSolidPoints(view,4,uipts,xpts);
XSetForeground(view->dpy,view->gc,view->xkb->geom->label_color->pixel);
_DrawPoints(view,4,uipts,xpts);
}
else {
_DrawPoints(view,4,uipts,xpts);
}
return;
}
static void
_DrawDoodad( XkbUI_ViewPtr view,
double rangle,
int xoff,
int yoff,
XkbDoodadPtr doodad)
{
int x;
int y;
XkbShapePtr shape;
Bool solid;
x= doodad->any.left+xoff;
y= doodad->any.top+yoff;
shape= NULL;
solid= False;
switch (doodad->any.type) {
case XkbOutlineDoodad:
shape= XkbShapeDoodadShape(view->xkb->geom,(&doodad->shape));
break;
case XkbSolidDoodad:
shape= XkbShapeDoodadShape(view->xkb->geom,(&doodad->shape));
solid= True;
break;
case XkbTextDoodad:
break;
case XkbIndicatorDoodad:
shape= XkbIndicatorDoodadShape(view->xkb->geom,&doodad->indicator);
solid= True;
break;
case XkbLogoDoodad:
shape= XkbLogoDoodadShape(view->xkb->geom,&doodad->logo);
solid= True;
break;
}
if (shape)
_DrawShape(view,rangle,x,y,x,y,shape,solid);
return;
}
static void
_DrawRow( XkbUI_ViewPtr view,
double rangle,
int xoff,
int yoff,
XkbRowPtr row)
{
register int k,x,y;
XkbKeyPtr key;
x= xoff+row->left; y= yoff+row->top;
for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
XkbShapePtr shape;
shape= XkbKeyShape(view->xkb->geom,key);
if (row->vertical) {
y+= key->gap;
_DrawShape(view,rangle,x,y,xoff,yoff,shape,True);
y+= shape->bounds.y2;
}
else {
x+= key->gap;
_DrawShape(view,rangle,x,y,xoff,yoff,shape,True);
x+= shape->bounds.x2;
}
}
return;
}
static void
_DrawSection(XkbUI_ViewPtr view,XkbSectionPtr section)
{
double rangle;
rangle= ((((double)(section->angle%3600))/3600.0)*(2.0*M_PI));
if (section->doodads) {
XkbDrawablePtr first,draw;
first= XkbGetOrderedDrawables(NULL,section);
if (first) {
for (draw=first;draw!=NULL;draw=draw->next) {
_DrawDoodad(view,rangle,section->left,section->top,draw->u.doodad);
}
XkbFreeOrderedDrawables(first);
}
}
if (section->rows) {
register int r;
XkbRowPtr row;
for (r=0,row=section->rows;r<section->num_rows;r++,row++) {
_DrawRow(view,rangle,section->left,section->top,row);
}
}
return;
}
static void
_DrawAll(XkbUI_ViewPtr view)
{
XkbGeometryPtr geom;
XkbDrawablePtr first,draw;
Bool dfltBorder;
geom= view->xkb->geom;
first= XkbGetOrderedDrawables(geom,NULL);
if (first) {
dfltBorder= True;
for (draw=first;draw!=NULL;draw=draw->next) {
char *name;
if ((draw->type!=XkbDW_Doodad)||
((draw->u.doodad->any.type!=XkbOutlineDoodad)&&
(draw->u.doodad->any.type!=XkbSolidDoodad))) {
continue;
}
name= XkbAtomGetString(view->dpy,draw->u.doodad->any.name);
if ((name!=NULL)&&(_XkbStrCaseCmp(name,"edges")==0)) {
dfltBorder= False;
break;
}
}
if (dfltBorder)
_DrawRect(view,0.0,0,0,geom->width_mm,geom->height_mm,True);
for (draw=first;draw!=NULL;draw=draw->next) {
switch (draw->type) {
case XkbDW_Section:
_DrawSection(view,draw->u.section);
break;
case XkbDW_Doodad:
_DrawDoodad(view,0.0,0,0,draw->u.doodad);
break;
}
}
XkbFreeOrderedDrawables(first);
}
XFlush(view->dpy);
return;
}
static void
_RedrawKey(XkbUI_ViewPtr view,KeyCode kc)
{
return;
}
Bool
XkbUI_SetKeyAppearance(XkbUI_ViewPtr view,KeyCode kc,unsigned int flags)
{
XkbDescPtr xkb;
unsigned old;
if ((!view)||(!view->xkb))
return False;
xkb= view->xkb;
if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
return False;
old= view->state[kc];
view->state[kc]= (flags&(~XkbUI_Obscured));
if (old&XkbUI_Obscured)
view->state[kc]|= XkbUI_Obscured;
else if (old!=view->state[kc])
_RedrawKey(view,kc);
return True;
}
Bool
XkbUI_SetKeyAppearanceByName( XkbUI_ViewPtr view,
XkbKeyNamePtr name,
unsigned int flags)
{
KeyCode kc;
if ((!view)||(!view->xkb)||(!name))
return False;
kc= XkbFindKeycodeByName(view->xkb,name->name,True);
if (!kc)
return False;
return XkbUI_SetKeyAppearance(view,kc,flags);
}
Bool
XkbUI_ResetKeyAppearance( XkbUI_ViewPtr view,
unsigned int mask,
unsigned int values)
{
register int i;
unsigned new_val;
if ((!view)||(!view->xkb))
return False;
if (!mask)
return True;
for (i=view->xkb->min_key_code;i<=view->xkb->max_key_code;i++) {
new_val= (view->state[i]&(~mask));
new_val|= (mask&values);
XkbUI_SetKeyAppearance(view,i,new_val);
}
return True;
}
Bool
XkbUI_DrawRegion(XkbUI_ViewPtr view,XRectangle *viewport)
{
if (!view)
return False;
_DrawAll(view);
return True;
}
Bool
XkbUI_DrawChanged( XkbUI_ViewPtr view,
XRectangle * viewport,
XkbChangesPtr changes,
int num_keys,
XkbKeyNamePtr keys)
{
return False;
}
Bool
XkbUI_Select( XkbUI_ViewPtr view,
XPoint * coord,
unsigned int which,
XkbSectionPtr section)
{
return False;
}