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