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