1/* $XConsortium: XKBui.c /main/2 1995/12/07 21:18:19 kaleb $ */ 2/************************************************************ 3 Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc. 4 5 Permission to use, copy, modify, and distribute this 6 software and its documentation for any purpose and without 7 fee is hereby granted, provided that the above copyright 8 notice appear in all copies and that both that copyright 9 notice and this permission notice appear in supporting 10 documentation, and that the name of Silicon Graphics not be 11 used in advertising or publicity pertaining to distribution 12 of the software without specific prior written permission. 13 Silicon Graphics makes no representation about the suitability 14 of this software for any purpose. It is provided "as is" 15 without any express or implied warranty. 16 17 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 18 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 19 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 20 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 21 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 22 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 23 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 24 THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 26 ********************************************************/ 27/* $XFree86: xc/lib/xkbui/XKBui.c,v 3.6 1999/06/20 07:14:08 dawes Exp $ */ 28 29#include <X11/Xos.h> 30#include <stdio.h> 31#include <stdlib.h> 32 33#if defined(SVR4) && defined(i386) && !defined(_XOPEN_SOURCE) 34# define _XOPEN_SOURCE 35# include <math.h> 36# undef _XOPEN_SOURCE 37#else 38# include <math.h> 39#endif /* _XOPEN_SOURCE */ 40 41#include <X11/Xfuncs.h> 42#include "XKBuiPriv.h" 43#include <X11/extensions/XKBfile.h> 44 45#ifndef M_PI 46# define M_PI 3.141592653589793238462 47#endif 48 49static XkbUI_ViewOptsRec dfltOpts = { 50 XkbUI_AllViewOptsMask /* present */, 51 1 /* fg */, 52 0 /* bg */, 53 XkbUI_KeyNames /* label_mode */, 54 0 /* color_mode */, 55 { 56 0 /* viewport.x */, 57 0 /* viewport.y */, 58 640 /* viewport.width */, 59 480 /* viewport.height */ 60 }, 61 10, 10, /* margin_width, margin_height */ 62 None 63}; 64 65XkbUI_ViewPtr 66XkbUI_SimpleInit(Display *dpy,Window win,int width,int height) 67{ 68XkbDescPtr xkb; 69 70 if ((!dpy)||(win==None)||(width<1)||(height<1)) 71 return NULL; 72 xkb= XkbGetKeyboard(dpy,XkbGBN_AllComponentsMask,XkbUseCoreKbd); 73 if (!xkb) 74 return NULL; 75 return XkbUI_Init(dpy,win,width,height,xkb,NULL); 76} 77 78static void 79_XkbUI_AllocateColors(XkbUI_ViewPtr view) 80{ 81register int i; 82Display * dpy; 83XColor sdef,xdef; 84XkbDescPtr xkb; 85 86 dpy= view->dpy; 87 xkb= view->xkb; 88 if (view->opts.cmap==None) 89 view->opts.cmap= DefaultColormap(dpy,DefaultScreen(dpy)); 90 for (i=0;i<xkb->geom->num_colors;i++) { 91 char *spec; 92 Bool found; 93 94 spec= xkb->geom->colors[i].spec; 95 found= False; 96 if (XAllocNamedColor(view->dpy,view->opts.cmap,spec,&sdef,&xdef)) { 97 xkb->geom->colors[i].pixel= sdef.pixel; 98#ifdef DEBUG 99 fprintf(stderr,"got pixel %lu for \"%s\"\n",sdef.pixel,spec); 100#endif 101 found= True; 102 } 103 if ((!found)&&(XkbLookupCanonicalRGBColor(spec,&sdef))) { 104 char buf[20]; 105 sprintf(buf,"#%02x%02x%02x",(sdef.red>>8)&0xff, 106 (sdef.green>>8)&0xff, 107 (sdef.blue>>8)&0xff); 108 if (XAllocNamedColor(view->dpy,view->opts.cmap,buf,&sdef,&xdef)) { 109 xkb->geom->colors[i].pixel= sdef.pixel; 110#ifdef DEBUG 111 fprintf(stderr,"got pixel %lu for \"%s\"\n",sdef.pixel,spec); 112#endif 113 found= True; 114 } 115 } 116 if (!found) { 117 xkb->geom->colors[i].pixel= view->opts.fg; 118 fprintf(stderr,"Couldn't allocate color \"%s\"\n",spec); 119 } 120 } 121 return; 122} 123 124XkbUI_ViewPtr 125XkbUI_Init( Display * dpy, 126 Window win, 127 int width, 128 int height, 129 XkbDescPtr xkb, 130 XkbUI_ViewOptsPtr opts) 131{ 132XGCValues xgcv; 133XkbUI_ViewPtr view; 134int scrn; 135 136 if ((!dpy)||(!xkb)||(!xkb->geom)||(win==None)||(width<1)||(height<1)) 137 return NULL; 138 view= _XkbTypedCalloc(1,XkbUI_ViewRec); 139 if (!view) 140 return NULL; 141 scrn= DefaultScreen(dpy); 142 view->dpy= dpy; 143 view->xkb= xkb; 144 view->win= win; 145 view->opts= dfltOpts; 146 view->opts.fg= WhitePixel(dpy,scrn); 147 view->opts.bg= BlackPixel(dpy,scrn); 148 view->opts.viewport.x= 0; 149 view->opts.viewport.y= 0; 150 view->opts.viewport.width= width; 151 view->opts.viewport.height= height; 152 if ((opts)&&(opts->present)) { 153 if (opts->present&XkbUI_BackgroundMask) 154 view->opts.bg= opts->bg; 155 if (opts->present&XkbUI_ForegroundMask) 156 view->opts.fg= opts->fg; 157 if (opts->present&XkbUI_LabelModeMask) 158 view->opts.label_mode= opts->label_mode; 159 if (opts->present&XkbUI_ColorModeMask) 160 view->opts.color_mode= opts->color_mode; 161 if (opts->present&XkbUI_WidthMask) 162 view->opts.viewport.width= opts->viewport.width; 163 if (opts->present&XkbUI_HeightMask) 164 view->opts.viewport.height= opts->viewport.height; 165 if (opts->present&XkbUI_XOffsetMask) 166 view->opts.viewport.x= opts->viewport.x; 167 if (opts->present&XkbUI_YOffsetMask) 168 view->opts.viewport.y= opts->viewport.y; 169 if (opts->present&XkbUI_MarginWidthMask) 170 view->opts.margin_width= opts->margin_width; 171 if (opts->present&XkbUI_MarginHeightMask) 172 view->opts.margin_height= opts->margin_height; 173 if (opts->present&XkbUI_ColormapMask) 174 view->opts.cmap= opts->cmap; 175 } 176 view->canvas_width= width+(2*view->opts.margin_width); 177 view->canvas_height= height+(2*view->opts.margin_height); 178 if (view->opts.viewport.width>view->canvas_width) { 179 int tmp; 180 tmp= (view->opts.viewport.width-view->canvas_width)/2; 181 view->opts.margin_width+= tmp; 182 } 183 if (view->opts.viewport.height>view->canvas_height) { 184 int tmp; 185 tmp= (view->opts.viewport.height-view->canvas_height)/2; 186 view->opts.margin_height+= tmp; 187 } 188 bzero(view->state,XkbMaxLegalKeyCode+1); 189 190 xgcv.foreground= view->opts.fg; 191 xgcv.background= view->opts.bg; 192 view->gc= XCreateGC(view->dpy,view->win,GCForeground|GCBackground,&xgcv); 193 view->xscale= ((double)width)/((double)xkb->geom->width_mm); 194 view->yscale= ((double)height)/((double)xkb->geom->height_mm); 195 196 _XkbUI_AllocateColors(view); 197 return view; 198} 199 200Status 201XkbUI_SetViewOpts(XkbUI_ViewPtr view,XkbUI_ViewOptsPtr opts) 202{ 203 if ((!view)||(!opts)) 204 return BadValue; 205 if (opts->present==0) 206 return Success; 207 if (opts->present&XkbUI_BackgroundMask) 208 view->opts.bg= opts->bg; 209 if (opts->present&XkbUI_ForegroundMask) 210 view->opts.fg= opts->fg; 211 if (opts->present&XkbUI_LabelModeMask) 212 view->opts.label_mode= opts->label_mode; 213 if (opts->present&XkbUI_ColorModeMask) 214 view->opts.color_mode= opts->color_mode; 215 if (opts->present&XkbUI_WidthMask) 216 view->opts.viewport.width= opts->viewport.width; 217 if (opts->present&XkbUI_HeightMask) 218 view->opts.viewport.height= opts->viewport.height; 219 if (opts->present&XkbUI_XOffsetMask) 220 view->opts.viewport.x= opts->viewport.x; 221 if (opts->present&XkbUI_YOffsetMask) 222 view->opts.viewport.y= opts->viewport.y; 223 if (opts->present&XkbUI_MarginWidthMask) 224 view->opts.margin_width= opts->margin_width; 225 if (opts->present&XkbUI_MarginHeightMask) 226 view->opts.margin_height= opts->margin_height; 227 if (opts->present&XkbUI_ColormapMask) { 228 view->opts.cmap= opts->cmap; 229 _XkbUI_AllocateColors(view); 230 } 231 return Success; 232} 233 234Status 235XbUI_GetViewOpts(XkbUI_ViewPtr view,XkbUI_ViewOptsPtr opts_rtrn) 236{ 237 if ((!view)||(!opts_rtrn)) 238 return BadValue; 239 *opts_rtrn= view->opts; 240 return Success; 241} 242 243Status 244XkbUI_SetCanvasSize(XkbUI_ViewPtr view,int width,int height) 245{ 246 if ((!view)||(!view->xkb)||(!view->xkb->geom)) 247 return BadValue; 248 view->canvas_width= width; 249 view->canvas_height= height; 250 view->xscale= ((double)width)/((double)view->xkb->geom->width_mm); 251 view->yscale= ((double)height)/((double)view->xkb->geom->height_mm); 252 return Success; 253} 254 255Status 256XkbUI_GetCanvasSize(XkbUI_ViewPtr view,int *width_rtrn,int *height_rtrn) 257{ 258 if (!view) 259 return BadValue; 260 if (width_rtrn) *width_rtrn= view->canvas_width; 261 if (height_rtrn) *height_rtrn= view->canvas_height; 262 return Success; 263} 264 265/***====================================================================***/ 266 267static void 268_RotatePoints( double rangle, 269 int corner_x, 270 int corner_y, 271 int nPts, 272 XkbUI_PointPtr pts) 273{ 274register int i; 275double rr,rx,ry,rt; 276 277 for (i=0;i<nPts;i++,pts++) { 278 rx= pts->x-corner_x; ry= pts->y-corner_y; /* translate */ 279 rr= hypot(rx,ry); 280 rt= atan2(ry,rx)+rangle; 281 rx= rr*cos(rt); 282 ry= rr*sin(rt); 283 pts->x= rx+corner_x; pts->y= ry+corner_y; 284 } 285 return; 286} 287 288static void 289_DrawPoints(XkbUI_ViewPtr view,int nPts,XkbUI_PointPtr pts,XPoint *xpts) 290{ 291register int i; 292 293 for (i=0;i<nPts;i++) { 294 if (pts[i].x>=0.0) xpts[i].x= pts[i].x*view->xscale+0.5; 295 else xpts[i].x= pts[i].x*view->xscale-0.5; 296 xpts[i].x+= view->opts.viewport.x; 297 if (pts[i].y>=0.0) xpts[i].y= pts[i].y*view->yscale+0.5; 298 else xpts[i].x= pts[i].y*view->yscale-0.5; 299 xpts[i].y+= view->opts.viewport.y; 300 } 301 if ((xpts[nPts-1].x!=xpts[0].x)||(xpts[nPts-1].y!=xpts[0].y)) 302 xpts[nPts++]= xpts[0]; /* close the shape, if necessary */ 303 XDrawLines(view->dpy,view->win,view->gc,xpts,nPts,CoordModeOrigin); 304XFlush(view->dpy); 305 return; 306} 307 308static void 309_DrawSolidPoints(XkbUI_ViewPtr view,int nPts,XkbUI_PointPtr pts,XPoint *xpts) 310{ 311register int i; 312 313 for (i=0;i<nPts;i++) { 314 if (pts[i].x>=0.0) xpts[i].x= pts[i].x*view->xscale+0.5; 315 else xpts[i].x= pts[i].x*view->xscale-0.5; 316 xpts[i].x+= view->opts.viewport.x; 317 if (pts[i].y>=0.0) xpts[i].y= pts[i].y*view->yscale+0.5; 318 else xpts[i].x= pts[i].y*view->yscale-0.5; 319 xpts[i].y+= view->opts.viewport.y; 320 } 321 if ((xpts[nPts-1].x!=xpts[0].x)||(xpts[nPts-1].y!=xpts[0].y)) 322 xpts[nPts++]= xpts[0]; /* close the shape, if necessary */ 323 XFillPolygon(view->dpy,view->win,view->gc,xpts,nPts,Nonconvex, 324 CoordModeOrigin); 325XFlush(view->dpy); 326 return; 327} 328 329static void 330_DrawShape( XkbUI_ViewPtr view, 331 double rangle, 332 int xoff, 333 int yoff, 334 int rotx, 335 int roty, 336 XkbShapePtr shape, 337 Bool key) 338{ 339XkbOutlinePtr ol; 340register int o; 341int maxPts; 342XkbUI_PointPtr uipts; 343XPoint * xpts; 344 345 for (maxPts=4,o=0,ol=shape->outlines;o<shape->num_outlines;o++,ol++) { 346 if ((shape->num_outlines>1)&&(ol==shape->approx)) 347 continue; 348 if (ol->num_points>maxPts) 349 maxPts= ol->num_points; 350 } 351 uipts= _XkbTypedCalloc(maxPts,XkbUI_PointRec); 352 xpts= _XkbTypedCalloc(maxPts+1,XPoint); 353 XSetForeground(view->dpy,view->gc,view->xkb->geom->label_color->pixel); 354 for (o=0,ol=shape->outlines;o<shape->num_outlines;o++,ol++) { 355 XkbPointPtr gpts; 356 register int p; 357 if ((shape->num_outlines>1)&&(ol==shape->approx)) 358 continue; 359 gpts= ol->points; 360 if (ol->num_points==1) { 361 uipts[0].x= xoff; uipts[0].y= yoff; 362 uipts[1].x= xoff+gpts[0].x; uipts[1].y= yoff; 363 uipts[2].x= xoff+gpts[0].x; uipts[2].y= yoff+gpts[0].y; 364 uipts[3].x= xoff; uipts[3].y= yoff+gpts[0].y; 365 p= 4; 366 } 367 else if (ol->num_points==2) { 368 uipts[0].x= xoff+gpts[0].x; uipts[0].y= yoff+gpts[0].y; 369 uipts[1].x= xoff+gpts[1].x; uipts[1].y= yoff+gpts[0].y; 370 uipts[2].x= xoff+gpts[1].x; uipts[2].y= yoff+gpts[1].y; 371 uipts[3].x= xoff+gpts[0].x; uipts[3].y= yoff+gpts[1].y; 372 p= 4; 373 } 374 else { 375 for (p=0;p<ol->num_points;p++) { 376 uipts[p].x= xoff+gpts[p].x; 377 uipts[p].y= yoff+gpts[p].y; 378 } 379 p= ol->num_points; 380 } 381 if (rangle!=0.0) 382 _RotatePoints(rangle,rotx,roty,p,uipts); 383 if (key) { 384 if (o==0) { 385 XSetForeground(view->dpy,view->gc, 386 view->xkb->geom->base_color->pixel); 387 _DrawSolidPoints(view,p,uipts,xpts); 388 XSetForeground(view->dpy,view->gc, 389 view->xkb->geom->label_color->pixel); 390 } 391 _DrawPoints(view,p,uipts,xpts); 392 } 393 else { 394 _DrawPoints(view,p,uipts,xpts); 395 } 396 } 397 _XkbFree(uipts); 398 _XkbFree(xpts); 399 return; 400} 401 402static void 403_DrawRect( XkbUI_ViewPtr view, 404 double rangle, 405 int x1, 406 int y1, 407 int x2, 408 int y2, 409 Bool key) 410{ 411XkbUI_PointRec uipts[4]; 412XPoint xpts[4]; 413 414 XSetForeground(view->dpy,view->gc,view->xkb->geom->label_color->pixel); 415 uipts[0].x= x1; uipts[0].y= y1; 416 uipts[1].x= x2; uipts[1].y= y1; 417 uipts[2].x= x2; uipts[2].y= y2; 418 uipts[3].x= x1; uipts[3].y= y2; 419 if (rangle!=0.0) 420 _RotatePoints(rangle,0,0,4,uipts); 421 if (key) { 422 XSetForeground(view->dpy,view->gc,view->xkb->geom->base_color->pixel); 423 _DrawSolidPoints(view,4,uipts,xpts); 424 XSetForeground(view->dpy,view->gc,view->xkb->geom->label_color->pixel); 425 _DrawPoints(view,4,uipts,xpts); 426 } 427 else { 428 _DrawPoints(view,4,uipts,xpts); 429 } 430 return; 431} 432 433static void 434_DrawDoodad( XkbUI_ViewPtr view, 435 double rangle, 436 int xoff, 437 int yoff, 438 XkbDoodadPtr doodad) 439{ 440int x; 441int y; 442XkbShapePtr shape; 443Bool solid; 444 445 x= doodad->any.left+xoff; 446 y= doodad->any.top+yoff; 447 shape= NULL; 448 solid= False; 449 switch (doodad->any.type) { 450 case XkbOutlineDoodad: 451 shape= XkbShapeDoodadShape(view->xkb->geom,(&doodad->shape)); 452 break; 453 case XkbSolidDoodad: 454 shape= XkbShapeDoodadShape(view->xkb->geom,(&doodad->shape)); 455 solid= True; 456 break; 457 case XkbTextDoodad: 458 break; 459 case XkbIndicatorDoodad: 460 shape= XkbIndicatorDoodadShape(view->xkb->geom,&doodad->indicator); 461 solid= True; 462 break; 463 case XkbLogoDoodad: 464 shape= XkbLogoDoodadShape(view->xkb->geom,&doodad->logo); 465 solid= True; 466 break; 467 } 468 if (shape) 469 _DrawShape(view,rangle,x,y,x,y,shape,solid); 470 return; 471} 472 473static void 474_DrawRow( XkbUI_ViewPtr view, 475 double rangle, 476 int xoff, 477 int yoff, 478 XkbRowPtr row) 479{ 480register int k,x,y; 481XkbKeyPtr key; 482 483 x= xoff+row->left; y= yoff+row->top; 484 for (k=0,key=row->keys;k<row->num_keys;k++,key++) { 485 XkbShapePtr shape; 486 shape= XkbKeyShape(view->xkb->geom,key); 487 if (row->vertical) { 488 y+= key->gap; 489 _DrawShape(view,rangle,x,y,xoff,yoff,shape,True); 490 y+= shape->bounds.y2; 491 } 492 else { 493 x+= key->gap; 494 _DrawShape(view,rangle,x,y,xoff,yoff,shape,True); 495 x+= shape->bounds.x2; 496 } 497 } 498 return; 499} 500 501static void 502_DrawSection(XkbUI_ViewPtr view,XkbSectionPtr section) 503{ 504double rangle; 505 506 rangle= ((((double)(section->angle%3600))/3600.0)*(2.0*M_PI)); 507 if (section->doodads) { 508 XkbDrawablePtr first,draw; 509 first= XkbGetOrderedDrawables(NULL,section); 510 if (first) { 511 for (draw=first;draw!=NULL;draw=draw->next) { 512 _DrawDoodad(view,rangle,section->left,section->top,draw->u.doodad); 513 } 514 XkbFreeOrderedDrawables(first); 515 } 516 } 517 if (section->rows) { 518 register int r; 519 XkbRowPtr row; 520 for (r=0,row=section->rows;r<section->num_rows;r++,row++) { 521 _DrawRow(view,rangle,section->left,section->top,row); 522 } 523 } 524 return; 525} 526 527static void 528_DrawAll(XkbUI_ViewPtr view) 529{ 530XkbGeometryPtr geom; 531XkbDrawablePtr first,draw; 532Bool dfltBorder; 533 534 geom= view->xkb->geom; 535 first= XkbGetOrderedDrawables(geom,NULL); 536 if (first) { 537 dfltBorder= True; 538 for (draw=first;draw!=NULL;draw=draw->next) { 539 char *name; 540 if ((draw->type!=XkbDW_Doodad)|| 541 ((draw->u.doodad->any.type!=XkbOutlineDoodad)&& 542 (draw->u.doodad->any.type!=XkbSolidDoodad))) { 543 continue; 544 } 545 name= XkbAtomGetString(view->dpy,draw->u.doodad->any.name); 546 if (name != NULL) { 547 if (strcmp(name, "edges") == 0) { 548 _XkbFree(name); 549 dfltBorder= False; 550 break; 551 } 552 _XkbFree(name); 553 } 554 } 555 if (dfltBorder) 556 _DrawRect(view,0.0,0,0,geom->width_mm,geom->height_mm,True); 557 for (draw=first;draw!=NULL;draw=draw->next) { 558 switch (draw->type) { 559 case XkbDW_Section: 560 _DrawSection(view,draw->u.section); 561 break; 562 case XkbDW_Doodad: 563 _DrawDoodad(view,0.0,0,0,draw->u.doodad); 564 break; 565 } 566 } 567 XkbFreeOrderedDrawables(first); 568 } 569 XFlush(view->dpy); 570 return; 571} 572 573static void 574_RedrawKey(XkbUI_ViewPtr view,KeyCode kc) 575{ 576/* _DrawAll(view);*/ 577 return; 578} 579 580/***====================================================================***/ 581 582Bool 583XkbUI_SetKeyAppearance(XkbUI_ViewPtr view,KeyCode kc,unsigned int flags) 584{ 585XkbDescPtr xkb; 586unsigned old; 587 588 if ((!view)||(!view->xkb)) 589 return False; 590 xkb= view->xkb; 591 if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code)) 592 return False; 593 old= view->state[kc]; 594 view->state[kc]= (flags&(~XkbUI_Obscured)); 595 if (old&XkbUI_Obscured) 596 view->state[kc]|= XkbUI_Obscured; 597 else if (old!=view->state[kc]) 598 _RedrawKey(view,kc); 599 return True; 600} 601 602Bool 603XkbUI_SetKeyAppearanceByName( XkbUI_ViewPtr view, 604 XkbKeyNamePtr name, 605 unsigned int flags) 606{ 607KeyCode kc; 608 609 if ((!view)||(!view->xkb)||(!name)) 610 return False; 611 kc= XkbFindKeycodeByName(view->xkb,name->name,True); 612 if (!kc) 613 return False; 614 return XkbUI_SetKeyAppearance(view,kc,flags); 615} 616 617Bool 618XkbUI_ResetKeyAppearance( XkbUI_ViewPtr view, 619 unsigned int mask, 620 unsigned int values) 621{ 622register int i; 623unsigned new_val; 624 625 if ((!view)||(!view->xkb)) 626 return False; 627 if (!mask) 628 return True; 629 for (i=view->xkb->min_key_code;i<=view->xkb->max_key_code;i++) { 630 new_val= (view->state[i]&(~mask)); 631 new_val|= (mask&values); 632 XkbUI_SetKeyAppearance(view,i,new_val); 633 } 634 return True; 635} 636 637Bool 638XkbUI_DrawRegion(XkbUI_ViewPtr view,XRectangle *viewport) 639{ 640 if (!view) 641 return False; 642 _DrawAll(view); 643 return True; 644} 645 646Bool 647XkbUI_DrawChanged( XkbUI_ViewPtr view, 648 XRectangle * viewport, 649 XkbChangesPtr changes, 650 int num_keys, 651 XkbKeyNamePtr keys) 652{ 653 return False; 654} 655 656Bool 657XkbUI_Select( XkbUI_ViewPtr view, 658 XPoint * coord, 659 unsigned int which, 660 XkbSectionPtr section) 661{ 662 return False; 663} 664