grid.c revision 9e0146f7
1/* 2 * $XdotOrg: grid.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ 3 * $Xorg: grid.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ 4 * 5 * 6Copyright 1989, 1998 The Open Group 7 8Permission to use, copy, modify, distribute, and sell this software and its 9documentation for any purpose is hereby granted without fee, provided that 10the above copyright notice appear in all copies and that both that 11copyright notice and this permission notice appear in supporting 12documentation. 13 14The above copyright notice and this permission notice shall be included in 15all copies or substantial portions of the Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of The Open Group shall not be 25used in advertising or otherwise to promote the sale, use or other dealings 26in this Software without prior written authorization from The Open Group. 27 * * 28 * Author: Jim Fulton, MIT X Consortium 29 */ 30/* $XFree86: xc/programs/xfd/grid.c,v 1.9 2002/07/06 00:46:42 keithp Exp $ */ 31 32 33#include <X11/IntrinsicP.h> 34#include <X11/StringDefs.h> 35#include <X11/Xaw/SimpleP.h> 36#include <X11/Xmu/Converters.h> 37#include <X11/Xos.h> 38#include "gridP.h" 39 40#ifdef XKB 41#include <X11/extensions/XKBbells.h> 42#else 43#define XkbBI_MinorError 2 44#define XkbBI_Ignore 11 45#endif 46 47#ifdef XKB 48#define Bell(w,n) XkbStdBell(XtDisplay(w), XtWindow(w), 50, n) 49#else 50#define Bell(w,n) XBell(XtDisplay(w), 0) 51#endif 52 53static GC get_gc(FontGridWidget fgw, Pixel fore); 54static void ClassInitialize(void); 55static void Initialize(Widget request, Widget new, ArgList args, 56 Cardinal *num_args); 57static void Realize(Widget gw, Mask *valueMask, 58 XSetWindowAttributes *attributes); 59static void Destroy(Widget gw); 60static void Resize(Widget gw); 61static void Redisplay(Widget gw, XEvent *event, Region region); 62static void paint_grid(FontGridWidget fgw, int col, int row, 63 int ncols, int nrows); 64static Boolean SetValues(Widget current, Widget request, Widget new, 65 ArgList args, Cardinal *num_args); 66static void Notify(Widget gw, XEvent *event, String *params, 67 Cardinal *nparams); 68 69#define Offset(field) XtOffsetOf(FontGridRec, fontgrid.field) 70 71static XtResource resources[] = { 72 { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), 73 Offset(text_font), XtRString, (XtPointer) NULL }, 74 { XtNcellColumns, XtCCellColumns, XtRInt, sizeof(int), 75 Offset(cell_cols), XtRImmediate, (XtPointer) 0 }, 76 { XtNcellRows, XtCCellRows, XtRInt, sizeof(int), 77 Offset(cell_rows), XtRImmediate, (XtPointer) 0 }, 78 { XtNcellWidth, XtCCellWidth, XtRInt, sizeof(int), 79 Offset(cell_width), XtRImmediate, (XtPointer) 0 }, 80 { XtNcellHeight, XtCCellHeight, XtRInt, sizeof(int), 81 Offset(cell_height), XtRImmediate, (XtPointer) 0 }, 82 { XtNstartChar, XtCStartChar, XtRLong, sizeof(long), 83 Offset(start_char), XtRImmediate, (XtPointer) 0xffffffff }, 84#ifndef XRENDER 85 { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), 86 Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground }, 87#endif 88 { XtNcenterChars, XtCCenterChars, XtRBoolean, sizeof(Boolean), 89 Offset(center_chars), XtRImmediate, (XtPointer) FALSE }, 90 { XtNboxChars, XtCBoxChars, XtRBoolean, sizeof(Boolean), 91 Offset(box_chars), XtRImmediate, (XtPointer) FALSE }, 92 { XtNboxColor, XtCForeground, XtRPixel, sizeof(Pixel), 93 Offset(box_pixel), XtRString, (XtPointer) XtDefaultForeground }, 94 { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer), 95 Offset(callbacks), XtRCallback, (XtPointer) NULL }, 96 { XtNinternalPad, XtCInternalPad, XtRInt, sizeof(int), 97 Offset(internal_pad), XtRImmediate, (XtPointer) 4 }, 98 { XtNgridWidth, XtCGridWidth, XtRInt, sizeof(int), 99 Offset(grid_width), XtRImmediate, (XtPointer) 1 }, 100#ifdef XRENDER 101 {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor), 102 Offset(fg_color), XtRString, XtDefaultForeground}, 103 {XtNface, XtCFace, XtRXftFont, sizeof (XftFont *), 104 Offset (text_face), XtRString, NULL}, 105#endif 106}; 107 108#undef Offset 109 110static char defaultTranslations[] = 111 "<ButtonPress>: notify()"; 112 113static XtActionsRec actions_list[] = { 114 { "notify", Notify }, 115}; 116 117FontGridClassRec fontgridClassRec = { 118 { /* core fields */ 119 /* superclass */ (WidgetClass) &simpleClassRec, 120 /* class_name */ "FontGrid", 121 /* widget_size */ sizeof(FontGridRec), 122 /* class_initialize */ ClassInitialize, 123 /* class_part_initialize */ NULL, 124 /* class_inited */ FALSE, 125 /* initialize */ Initialize, 126 /* initialize_hook */ NULL, 127 /* realize */ Realize, 128 /* actions */ actions_list, 129 /* num_actions */ XtNumber(actions_list), 130 /* resources */ resources, 131 /* num_resources */ XtNumber(resources), 132 /* xrm_class */ NULLQUARK, 133 /* compress_motion */ TRUE, 134 /* compress_exposure */ TRUE, 135 /* compress_enterleave */ TRUE, 136 /* visible_interest */ FALSE, 137 /* destroy */ Destroy, 138 /* resize */ Resize, 139 /* expose */ Redisplay, 140 /* set_values */ SetValues, 141 /* set_values_hook */ NULL, 142 /* set_values_almost */ XtInheritSetValuesAlmost, 143 /* get_values_hook */ NULL, 144 /* accept_focus */ NULL, 145 /* version */ XtVersion, 146 /* callback_private */ NULL, 147 /* tm_table */ defaultTranslations, 148 /* query_geometry */ XtInheritQueryGeometry, 149 /* display_accelerator */ XtInheritDisplayAccelerator, 150 /* extension */ NULL 151 }, 152 { /* simple fields */ 153 /* change_sensitive */ XtInheritChangeSensitive 154 } 155}; 156 157WidgetClass fontgridWidgetClass = (WidgetClass) &fontgridClassRec; 158 159 160long 161GridFirstChar (Widget w) 162{ 163 FontGridWidget fgw = (FontGridWidget) w; 164 XFontStruct *fs = fgw->fontgrid.text_font; 165#ifdef XRENDER 166 XftFont *xft = fgw->fontgrid.text_face; 167 if (xft) 168 { 169 FcChar32 map[FC_CHARSET_MAP_SIZE]; 170 FcChar32 next; 171 FcChar32 first; 172 int i; 173 174 first = FcCharSetFirstPage (xft->charset, map, &next); 175 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) 176 if (map[i]) 177 { 178 FcChar32 bits = map[i]; 179 first += i * 32; 180 while (!(bits & 0x1)) 181 { 182 bits >>= 1; 183 first++; 184 } 185 break; 186 } 187 return first; 188 } 189 else 190#endif 191 if (fs) 192 { 193 return (fs->min_byte1 << 8) | (fs->min_char_or_byte2); 194 } 195 else 196 return 0; 197} 198 199long 200GridLastChar (Widget w) 201{ 202 FontGridWidget fgw = (FontGridWidget) w; 203 XFontStruct *fs = fgw->fontgrid.text_font; 204#ifdef XRENDER 205 XftFont *xft = fgw->fontgrid.text_face; 206 if (xft) 207 { 208 FcChar32 this, last, next; 209 FcChar32 map[FC_CHARSET_MAP_SIZE]; 210 int i; 211 last = FcCharSetFirstPage (xft->charset, map, &next); 212 while ((this = FcCharSetNextPage (xft->charset, map, &next)) != FC_CHARSET_DONE) 213 last = this; 214 last &= ~0xff; 215 for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) 216 if (map[i]) 217 { 218 FcChar32 bits = map[i]; 219 last += i * 32 + 31; 220 while (!(bits & 0x80000000)) 221 { 222 last--; 223 bits <<= 1; 224 } 225 break; 226 } 227 return (long) last; 228 } 229 else 230#endif 231 if (fs) 232 { 233 return (fs->max_byte1 << 8) | (fs->max_char_or_byte2); 234 } 235 else 236 return 0; 237} 238 239/* 240 * CI_GET_CHAR_INFO_1D - return the charinfo struct for the indicated 8bit 241 * character. If the character is in the column and exists, then return the 242 * appropriate metrics (note that fonts with common per-character metrics will 243 * return min_bounds). 244 */ 245 246#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 247 (((cs)->rbearing|(cs)->lbearing| \ 248 (cs)->ascent|(cs)->descent) == 0)) 249 250#define CI_GET_CHAR_INFO_1D(fs,col,cs) \ 251{ \ 252 cs = NULL; \ 253 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 254 if (fs->per_char == NULL) { \ 255 cs = &fs->min_bounds; \ 256 } else { \ 257 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 258 } \ 259 if (CI_NONEXISTCHAR(cs)) \ 260 cs = NULL; \ 261 } \ 262} 263 264/* 265 * CI_GET_CHAR_INFO_2D - return the charinfo struct for the indicated row and 266 * column. This is used for fonts that have more than row zero. 267 */ 268#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \ 269{ \ 270 cs = NULL; \ 271 if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 272 col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 273 if (fs->per_char == NULL) { \ 274 cs = &fs->min_bounds; \ 275 } else { \ 276 cs = &fs->per_char[((row - fs->min_byte1) * \ 277 (fs->max_char_or_byte2 - \ 278 fs->min_char_or_byte2 + 1)) + \ 279 (col - fs->min_char_or_byte2)]; \ 280 } \ 281 if (CI_NONEXISTCHAR(cs)) \ 282 cs = NULL; \ 283 } \ 284} 285 286static Boolean 287GridHasChar (Widget w, long ch) 288{ 289 FontGridWidget fgw = (FontGridWidget) w; 290#ifdef XRENDER 291 XftFont *xft = fgw->fontgrid.text_face; 292 if (xft) 293 { 294 return FcCharSetHasChar (xft->charset, (FcChar32) ch); 295 } 296 else 297#endif 298 { 299 XFontStruct *fs = fgw->fontgrid.text_font; 300 XCharStruct *cs; 301 302 if (!fs) 303 return False; 304 if (fs->max_byte1 == 0) 305 { 306 CI_GET_CHAR_INFO_1D (fs, ch, cs); 307 } 308 else 309 { 310 unsigned int r = (ch >> 8); 311 unsigned int c = (ch & 0xff); 312 CI_GET_CHAR_INFO_2D (fs, r, c, cs); 313 } 314 return cs != NULL; 315 } 316} 317 318/* 319 * public routines 320 */ 321 322void 323GetFontGridCellDimensions(Widget w, long *startp, 324 int *ncolsp, int *nrowsp) 325{ 326 FontGridWidget fgw = (FontGridWidget) w; 327 *startp = fgw->fontgrid.start_char; 328 *ncolsp = fgw->fontgrid.cell_cols; 329 *nrowsp = fgw->fontgrid.cell_rows; 330} 331 332 333void 334GetPrevNextStates(Widget w, Bool *prevvalidp, Bool *nextvalidp, 335 Bool *prev16validp, Bool *next16validp) 336{ 337 FontGridWidget fgw = (FontGridWidget) w; 338 long minn = (long) GridFirstChar (w); 339 long maxn = (long) GridLastChar (w); 340 341 *prev16validp = (fgw->fontgrid.start_char - 0xf00 > minn); 342 *prevvalidp = (fgw->fontgrid.start_char > minn); 343 *nextvalidp = (fgw->fontgrid.start_char + 344 (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows) 345 < maxn); 346 *next16validp =((fgw->fontgrid.start_char + 0xf00 + 347 (fgw->fontgrid.cell_cols * fgw->fontgrid.cell_rows)) 348 < maxn); 349} 350 351 352 353/* 354 * private routines and methods 355 */ 356 357 358static GC 359get_gc(FontGridWidget fgw, Pixel fore) 360{ 361 XtGCMask mask; 362 XGCValues gcv; 363 364 mask = (GCForeground | GCBackground | GCFunction); 365 gcv.foreground = fore; 366 gcv.background = fgw->core.background_pixel; 367 gcv.function = GXcopy; 368 if (fgw->fontgrid.text_font) 369 { 370 mask |= GCFont; 371 gcv.font = fgw->fontgrid.text_font->fid; 372 } 373 gcv.cap_style = CapProjecting; 374 mask |= GCCapStyle; 375 if (fgw->fontgrid.grid_width > 0) { 376 mask |= GCLineWidth; 377 gcv.line_width = ((fgw->fontgrid.grid_width < 2) ? 0 : 378 fgw->fontgrid.grid_width); 379 } 380 return (XtGetGC ((Widget) fgw, mask, &gcv)); 381} 382 383 384#ifdef XRENDER 385static XtConvertArgRec xftColorConvertArgs[] = { 386 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), 387 sizeof(Screen *)}, 388 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), 389 sizeof(Colormap)} 390}; 391 392#define donestr(type, value, tstr) \ 393 { \ 394 if (toVal->addr != NULL) { \ 395 if (toVal->size < sizeof(type)) { \ 396 toVal->size = sizeof(type); \ 397 XtDisplayStringConversionWarning(dpy, \ 398 (char*) fromVal->addr, tstr); \ 399 return False; \ 400 } \ 401 *(type*)(toVal->addr) = (value); \ 402 } \ 403 else { \ 404 static type static_val; \ 405 static_val = (value); \ 406 toVal->addr = (XPointer)&static_val; \ 407 } \ 408 toVal->size = sizeof(type); \ 409 return True; \ 410 } 411 412static void 413XmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, XtPointer closure, 414 XrmValuePtr args, Cardinal *num_args) 415{ 416 Screen *screen; 417 Colormap colormap; 418 XftColor *color; 419 420 if (*num_args != 2) 421 { 422 XtAppErrorMsg (app, 423 "freeXftColor", "wrongParameters", 424 "XtToolkitError", 425 "Freeing an XftColor requires screen and colormap arguments", 426 (String *) NULL, (Cardinal *)NULL); 427 return; 428 } 429 430 screen = *((Screen **) args[0].addr); 431 colormap = *((Colormap *) args[1].addr); 432 color = (XftColor *) toVal->addr; 433 XftColorFree (DisplayOfScreen (screen), 434 DefaultVisual (DisplayOfScreen (screen), 435 XScreenNumberOfScreen (screen)), 436 colormap, color); 437} 438 439static Boolean 440XmuCvtStringToXftColor(Display *dpy, 441 XrmValue *args, Cardinal *num_args, 442 XrmValue *fromVal, XrmValue *toVal, 443 XtPointer *converter_data) 444{ 445 char *spec; 446 XRenderColor renderColor; 447 XftColor xftColor; 448 Screen *screen; 449 Colormap colormap; 450 451 if (*num_args != 2) 452 { 453 XtAppErrorMsg (XtDisplayToApplicationContext (dpy), 454 "cvtStringToXftColor", "wrongParameters", 455 "XtToolkitError", 456 "String to render color conversion needs screen and colormap arguments", 457 (String *) NULL, (Cardinal *)NULL); 458 return False; 459 } 460 461 screen = *((Screen **) args[0].addr); 462 colormap = *((Colormap *) args[1].addr); 463 464 spec = (char *) fromVal->addr; 465 if (strcasecmp (spec, XtDefaultForeground) == 0) 466 { 467 renderColor.red = 0; 468 renderColor.green = 0; 469 renderColor.blue = 0; 470 renderColor.alpha = 0xffff; 471 } 472 else if (strcasecmp (spec, XtDefaultBackground) == 0) 473 { 474 renderColor.red = 0xffff; 475 renderColor.green = 0xffff; 476 renderColor.blue = 0xffff; 477 renderColor.alpha = 0xffff; 478 } 479 else if (!XRenderParseColor (dpy, spec, &renderColor)) 480 return False; 481 if (!XftColorAllocValue (dpy, 482 DefaultVisual (dpy, 483 XScreenNumberOfScreen (screen)), 484 colormap, 485 &renderColor, 486 &xftColor)) 487 return False; 488 489 donestr (XftColor, xftColor, XtRXftColor); 490} 491 492static void 493XmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure, 494 XrmValuePtr args, Cardinal *num_args) 495{ 496 Screen *screen; 497 XftFont *font; 498 499 if (*num_args != 1) 500 { 501 XtAppErrorMsg (app, 502 "freeXftFont", "wrongParameters", 503 "XtToolkitError", 504 "Freeing an XftFont requires screen argument", 505 (String *) NULL, (Cardinal *)NULL); 506 return; 507 } 508 509 screen = *((Screen **) args[0].addr); 510 font = *((XftFont **) toVal->addr); 511 if (font) 512 XftFontClose (DisplayOfScreen (screen), font); 513} 514 515static Boolean 516XmuCvtStringToXftFont(Display *dpy, 517 XrmValue *args, Cardinal *num_args, 518 XrmValue *fromVal, XrmValue *toVal, 519 XtPointer *converter_data) 520{ 521 char *name; 522 XftFont *font; 523 Screen *screen; 524 525 if (*num_args != 1) 526 { 527 XtAppErrorMsg (XtDisplayToApplicationContext (dpy), 528 "cvtStringToXftFont", "wrongParameters", 529 "XtToolkitError", 530 "String to XftFont conversion needs screen argument", 531 (String *) NULL, (Cardinal *)NULL); 532 return False; 533 } 534 535 screen = *((Screen **) args[0].addr); 536 name = (char *) fromVal->addr; 537 538 font = NULL; 539 if (name) 540 { 541 font = XftFontOpenName (dpy, 542 XScreenNumberOfScreen (screen), 543 name); 544 if (!font) 545 { 546 XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont); 547 return False; 548 } 549 } 550 donestr (XftFont *, font, XtRXftFont); 551} 552 553static XtConvertArgRec xftFontConvertArgs[] = { 554 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), 555 sizeof(Screen *)}, 556}; 557 558#endif 559 560static void 561ClassInitialize(void) 562{ 563 XtAddConverter (XtRString, XtRLong, XmuCvtStringToLong, NULL, 0); 564#ifdef XRENDER 565 XtSetTypeConverter (XtRString, XtRXftColor, 566 XmuCvtStringToXftColor, 567 xftColorConvertArgs, XtNumber(xftColorConvertArgs), 568 XtCacheByDisplay, XmuFreeXftColor); 569 XtSetTypeConverter (XtRString, XtRXftFont, 570 XmuCvtStringToXftFont, 571 xftFontConvertArgs, XtNumber(xftFontConvertArgs), 572 XtCacheByDisplay, XmuFreeXftFont); 573#endif 574} 575 576 577static void 578Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args) 579{ 580 FontGridWidget reqfg = (FontGridWidget) request; 581 FontGridWidget newfg = (FontGridWidget) new; 582 XFontStruct *fs = newfg->fontgrid.text_font; 583#ifdef XRENDER 584 XftFont *xft = newfg->fontgrid.text_face; 585#endif 586 unsigned maxn; 587 588 if (reqfg->fontgrid.cell_cols <= 0) 589 newfg->fontgrid.cell_cols = 16; 590 591 if (reqfg->fontgrid.cell_rows <= 0) { 592#ifdef XRENDER 593 if (xft) 594 newfg->fontgrid.cell_rows = 16; 595 else 596#endif 597 if (fs && fs->max_byte1 == 0) { 598 newfg->fontgrid.cell_rows = (fs->max_char_or_byte2 / 599 newfg->fontgrid.cell_cols) + 1; 600 if (newfg->fontgrid.cell_rows > 16) 601 newfg->fontgrid.cell_rows = 16; 602 } else 603 newfg->fontgrid.cell_rows = 16; 604 } 605 606 if (reqfg->fontgrid.cell_width <= 0) 607 newfg->fontgrid.cell_width = DefaultCellWidth (newfg); 608 if (reqfg->fontgrid.cell_height <= 0) 609 newfg->fontgrid.cell_height = DefaultCellHeight (newfg); 610 611 /* give a nice size that fits one screen full */ 612 if (newfg->core.width == 0) 613 newfg->core.width = (newfg->fontgrid.cell_width * 614 newfg->fontgrid.cell_cols + 615 newfg->fontgrid.grid_width * 616 (newfg->fontgrid.cell_cols + 1)); 617 618 if (newfg->core.height == 0) 619 newfg->core.height = (newfg->fontgrid.cell_height * 620 newfg->fontgrid.cell_rows + 621 newfg->fontgrid.grid_width * 622 (newfg->fontgrid.cell_rows + 1)); 623 624 /* 625 * select the first character 626 */ 627 628 if (newfg->fontgrid.start_char == 0xffffffff) 629 newfg->fontgrid.start_char = GridFirstChar(new) & ~0xff; 630 maxn = GridLastChar (new); 631 if (newfg->fontgrid.start_char > maxn) 632 newfg->fontgrid.start_char = (maxn + 1 - 633 (newfg->fontgrid.cell_cols * 634 newfg->fontgrid.cell_rows)); 635} 636 637static void 638Realize(Widget gw, Mask *valueMask, XSetWindowAttributes *attributes) 639{ 640 FontGridWidget fgw = (FontGridWidget) gw; 641 FontGridPart *p = &fgw->fontgrid; 642 643 p->text_gc = get_gc (fgw, GridForeground (fgw)); 644 p->box_gc = get_gc (fgw, p->box_pixel); 645 Resize (gw); 646 647 (*(XtSuperclass(gw)->core_class.realize)) (gw, valueMask, attributes); 648#ifdef XRENDER 649 p->draw = XftDrawCreate (XtDisplay (gw), XtWindow (gw), 650 DefaultVisual (XtDisplay (gw), 651 DefaultScreen(XtDisplay (gw))), 652 fgw->core.colormap); 653#endif 654 return; 655} 656 657 658 659static void 660Destroy(Widget gw) 661{ 662 FontGridWidget fgw = (FontGridWidget) gw; 663 664 XtReleaseGC (gw, fgw->fontgrid.text_gc); 665 XtReleaseGC (gw, fgw->fontgrid.box_gc); 666} 667 668 669static void 670Resize(Widget gw) 671{ 672 FontGridWidget fgw = (FontGridWidget) gw; 673 674 /* recompute in case we've changed size */ 675 fgw->fontgrid.cell_width = CellWidth (fgw); 676 if (fgw->fontgrid.cell_width <= 0) 677 fgw->fontgrid.cell_width = 1; 678 fgw->fontgrid.cell_height = CellHeight (fgw); 679 if (fgw->fontgrid.cell_height <= 0) 680 fgw->fontgrid.cell_height = 1; 681 fgw->fontgrid.xoff = (fgw->fontgrid.cell_width - 682 DefaultCellWidth (fgw)) / 2; 683 fgw->fontgrid.yoff = (fgw->fontgrid.cell_height - 684 DefaultCellHeight (fgw)) / 2; 685 686} 687 688 689/* ARGSUSED */ 690static void 691Redisplay(Widget gw, XEvent *event, Region region) 692{ 693 FontGridWidget fgw = (FontGridWidget) gw; 694 XRectangle rect; /* bounding rect for region */ 695 int left, right, top, bottom; /* which cells were damaged */ 696 int cw, ch; /* cell size */ 697 698#ifdef XRENDER 699 if (!fgw->fontgrid.text_face) 700#endif 701 if (!fgw->fontgrid.text_font) { 702 Bell (gw, XkbBI_BadValue); 703 return; 704 } 705 706 /* 707 * compute the left, right, top, and bottom cells that were damaged 708 */ 709 XClipBox (region, &rect); 710 cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width; 711 ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width; 712 if ((left = (((int) rect.x) / cw)) < 0) left = 0; 713 right = (((int) (rect.x + rect.width - 1)) / cw); 714 if ((top = (((int) rect.y) / ch)) < 0) top = 0; 715 bottom = (((int) (rect.y + rect.height - 1)) / ch); 716 717 paint_grid (fgw, left, top, right - left + 1, bottom - top + 1); 718} 719 720 721static void 722paint_grid(FontGridWidget fgw, /* widget in which to draw */ 723 int col, int row, /* where to start */ 724 int ncols, int nrows) /* number of cells */ 725{ 726 FontGridPart *p = &fgw->fontgrid; 727 int i, j; 728 Display *dpy = XtDisplay(fgw); 729 Window wind = XtWindow(fgw); 730 int cw = p->cell_width + p->grid_width; 731 int ch = p->cell_height + p->grid_width; 732 int tcols = p->cell_cols; 733 int trows = p->cell_rows; 734 int x1, y1, x2, y2, x, y; 735 unsigned maxn = GridLastChar ((Widget) fgw); 736 unsigned n, prevn; 737 int startx; 738 739 if (col + ncols >= tcols) { 740 ncols = tcols - col; 741 if (ncols < 1) return; 742 } 743 744 if (row + nrows >= trows) { 745 nrows = trows - row; 746 if (nrows < 1) return; 747 } 748 749 /* 750 * paint the grid lines for the indicated rows 751 */ 752 if (p->grid_width > 0) { 753 int half_grid_width = p->grid_width >> 1; 754 x1 = col * cw + half_grid_width; 755 y1 = row * ch + half_grid_width; 756 x2 = x1 + ncols * cw; 757 y2 = y1 + nrows * ch; 758 for (i = 0, x = x1; i <= ncols; i++, x += cw) { 759 XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2); 760 } 761 for (i = 0, y = y1; i <= nrows; i++, y += ch) { 762 XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y); 763 } 764 } 765 /* 766 * Draw a character in every box; treat all fonts as if they were 16bit 767 * fonts. Store the high eight bits in byte1 and the low eight bits in 768 * byte2. 769 */ 770 prevn = p->start_char + col + row * tcols; 771 startx = col * cw + p->internal_pad + p->grid_width; 772 for (j = 0, 773 y = row * ch + p->internal_pad + p->grid_width + GridFontAscent (fgw); 774 j < nrows; j++, y += ch) { 775 n = prevn; 776 for (i = 0, x = startx; i < ncols; i++, x += cw) { 777 int xoff = p->xoff, yoff = p->yoff; 778 if (n > maxn) goto done; /* no break out of nested */ 779 780#ifdef XRENDER 781 if (fgw->fontgrid.text_face) 782 { 783 XftFont *xft = p->text_face; 784 FcChar32 c = n; 785 XGlyphInfo extents; 786 XftTextExtents32 (dpy, xft, &c, 1, &extents); 787 if (p->center_chars) 788 { 789 xoff = (p->cell_width - extents.width) / 2 - extents.x; 790 yoff = (p->cell_height - extents.height) / 2 - extents.y; 791 } 792 if (extents.width && extents.height) 793 { 794 XClearArea (dpy, wind, x + xoff - extents.x, 795 y + yoff - extents.y, 796 extents.width, extents.height, False); 797 if (p->box_chars) 798 XDrawRectangle (dpy, wind, p->box_gc, 799 x + xoff - extents.x, 800 y + yoff - extents.y, 801 extents.width - 1, 802 extents.height - 1); 803 } 804 XftDrawString32 (p->draw, &p->fg_color, xft, 805 x + xoff, y + yoff, &c, 1); 806 } 807 else 808#endif 809 { 810 XChar2b thechar; 811 812 thechar.byte1 = (n >> 8); /* high eight bits */ 813 thechar.byte2 = (n & 255); /* low eight bits */ 814 if (p->box_chars || p->center_chars) { 815 XCharStruct metrics; 816 int direction, fontascent, fontdescent; 817 818 XTextExtents16 (p->text_font, &thechar, 1, &direction, 819 &fontascent, &fontdescent, &metrics); 820 821 if (p->center_chars) { 822 /* 823 * We want to move the origin by enough to center the ink 824 * within the cell. The left edge will then be at 825 * (cell_width - (rbearing - lbearing)) / 2; so we subtract 826 * the lbearing to find the origin. Ditto for vertical. 827 */ 828 xoff = (((p->cell_width - 829 (metrics.rbearing - metrics.lbearing)) / 2) - 830 p->internal_pad - metrics.lbearing); 831 yoff = (((p->cell_height - 832 (metrics.descent + metrics.ascent)) / 2) - 833 p->internal_pad - 834 p->text_font->ascent + metrics.ascent); 835 } 836 if (p->box_chars) { 837 XDrawRectangle (dpy, wind, p->box_gc, 838 x + xoff, y + yoff - p->text_font->ascent, 839 metrics.width - 1, 840 fontascent + fontdescent - 1); 841 } 842 } 843 XDrawString16 (dpy, wind, p->text_gc, x + xoff, y + yoff, 844 &thechar, 1); 845 } 846 n++; 847 } 848 prevn += tcols; 849 } 850 851 done: 852 /* 853 * paint the grid lines for the indicated rows 854 */ 855 if (p->grid_width > 0) { 856 int half_grid_width = p->grid_width >> 1; 857 x1 = col * cw + half_grid_width; 858 y1 = row * ch + half_grid_width; 859 x2 = x1 + ncols * cw; 860 y2 = y1 + nrows * ch; 861 for (i = 0, x = x1; i <= ncols; i++, x += cw) { 862 XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2); 863 } 864 for (i = 0, y = y1; i <= nrows; i++, y += ch) { 865 XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y); 866 } 867 } 868 869 870 return; 871} 872 873static Boolean 874PageBlank (Widget w, long first, long last) 875{ 876 while (first <= last) 877 { 878 if (GridHasChar (w, first)) 879 return False; 880 first++; 881 } 882 return True; 883} 884 885/*ARGSUSED*/ 886static Boolean 887SetValues(Widget current, Widget request, Widget new, 888 ArgList args, Cardinal *num_args) 889{ 890 FontGridWidget curfg = (FontGridWidget) current; 891 FontGridWidget newfg = (FontGridWidget) new; 892 Boolean redisplay = FALSE; 893 894 if (curfg->fontgrid.text_font != newfg->fontgrid.text_font || 895 curfg->fontgrid.internal_pad != newfg->fontgrid.internal_pad) { 896 newfg->fontgrid.cell_width = DefaultCellWidth (newfg); 897 newfg->fontgrid.cell_height = DefaultCellHeight (newfg); 898 redisplay = TRUE; 899 } 900 901 if (GridForeground(curfg) != GridForeground (newfg)) { 902 XtReleaseGC (new, curfg->fontgrid.text_gc); 903 newfg->fontgrid.text_gc = get_gc (newfg, GridForeground (newfg)); 904 redisplay = TRUE; 905 } 906 907 if (curfg->fontgrid.box_pixel != newfg->fontgrid.box_pixel) { 908 XtReleaseGC (new, curfg->fontgrid.text_gc); 909 newfg->fontgrid.box_gc = get_gc (newfg, newfg->fontgrid.box_pixel); 910 redisplay = TRUE; 911 } 912 913 if (curfg->fontgrid.center_chars != newfg->fontgrid.center_chars || 914 curfg->fontgrid.box_chars != newfg->fontgrid.box_chars) 915 redisplay = TRUE; 916 917 if (curfg->fontgrid.start_char != newfg->fontgrid.start_char) { 918 long maxn = GridLastChar (new); 919 long page = newfg->fontgrid.cell_cols * newfg->fontgrid.cell_rows; 920 long dir = page; 921 long start = newfg->fontgrid.start_char; 922 923 if (start < curfg->fontgrid.start_char) 924 dir = -page; 925 926 if (start < 0) 927 start = 0; 928 if (start > maxn) 929 start = (maxn / page) * page; 930 931 while (PageBlank (new, start, start + page - 1)) 932 { 933 long next = start + dir; 934 935 if (next < 0 || maxn < next) 936 break; 937 start = next; 938 } 939 940 newfg->fontgrid.start_char = start; 941 redisplay = (curfg->fontgrid.start_char != newfg->fontgrid.start_char); 942 } 943 944 return redisplay; 945} 946 947 948/* ARGSUSED */ 949static void 950Notify(Widget gw, XEvent *event, String *params, Cardinal *nparams) 951{ 952 FontGridWidget fgw = (FontGridWidget) gw; 953 int x, y; /* where the event happened */ 954 FontGridCharRec rec; /* callback data */ 955 956 /* 957 * only allow events with (x,y) 958 */ 959 switch (event->type) { 960 case KeyPress: 961 case KeyRelease: 962 x = event->xkey.x; 963 y = event->xkey.y; 964 break; 965 case ButtonPress: 966 case ButtonRelease: 967 x = event->xbutton.x; 968 y = event->xbutton.y; 969 break; 970 case MotionNotify: 971 x = event->xmotion.x; 972 y = event->xmotion.y; 973 break; 974 default: 975 Bell (gw, XkbBI_Ignore); 976 return; 977 } 978 979 /* 980 * compute the callback data 981 */ 982 { 983 int cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width; 984 int ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width; 985 unsigned n; 986 987 if (x > (fgw->fontgrid.cell_cols * cw)) { 988 Bell (gw, XkbBI_InvalidLocation); 989 return; 990 } 991 992 n= (fgw->fontgrid.start_char + 993 ((y / ch) * fgw->fontgrid.cell_cols) + (x / cw)); 994 995 rec.thefont = fgw->fontgrid.text_font; 996#ifdef XRENDER 997 rec.theface = fgw->fontgrid.text_face; 998#endif 999 rec.thechar = n; 1000 } 1001 1002 XtCallCallbacks (gw, XtNcallback, (XtPointer) &rec); 1003} 1004 1005