grid.c revision 31e5d586
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 /* extension */ NULL 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 173 first = FcCharSetFirstPage (xft->charset, map, &next); 174 for (int 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 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 (int 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) \ 250do { \ 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} while (0) 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) \ 268do { \ 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} while (0) 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 do { \ 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 } while (0) 410 411static void 412XmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, 413 XtPointer closure _X_UNUSED, 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 _X_UNUSED) 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 _X_UNUSED, 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 _X_UNUSED) 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 XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont); 546 } 547 donestr (XftFont *, font, XtRXftFont); 548} 549 550static XtConvertArgRec xftFontConvertArgs[] = { 551 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), 552 sizeof(Screen *)}, 553}; 554 555#endif 556 557static void 558ClassInitialize(void) 559{ 560 XtAddConverter (XtRString, XtRLong, XmuCvtStringToLong, NULL, 0); 561#ifdef XRENDER 562 XtSetTypeConverter (XtRString, XtRXftColor, 563 XmuCvtStringToXftColor, 564 xftColorConvertArgs, XtNumber(xftColorConvertArgs), 565 XtCacheByDisplay, XmuFreeXftColor); 566 XtSetTypeConverter (XtRString, XtRXftFont, 567 XmuCvtStringToXftFont, 568 xftFontConvertArgs, XtNumber(xftFontConvertArgs), 569 XtCacheByDisplay, XmuFreeXftFont); 570#endif 571} 572 573 574static void 575Initialize(Widget request, Widget new, 576 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 577{ 578 FontGridWidget reqfg = (FontGridWidget) request; 579 FontGridWidget newfg = (FontGridWidget) new; 580 XFontStruct *fs = newfg->fontgrid.text_font; 581#ifdef XRENDER 582 XftFont *xft = newfg->fontgrid.text_face; 583#endif 584 unsigned maxn; 585 586 if (reqfg->fontgrid.cell_cols <= 0) 587 newfg->fontgrid.cell_cols = 16; 588 589 if (reqfg->fontgrid.cell_rows <= 0) { 590#ifdef XRENDER 591 if (xft) 592 newfg->fontgrid.cell_rows = 16; 593 else 594#endif 595 if (fs && fs->max_byte1 == 0) { 596 newfg->fontgrid.cell_rows = (fs->max_char_or_byte2 / 597 newfg->fontgrid.cell_cols) + 1; 598 if (newfg->fontgrid.cell_rows > 16) 599 newfg->fontgrid.cell_rows = 16; 600 } else 601 newfg->fontgrid.cell_rows = 16; 602 } 603 604 if (reqfg->fontgrid.cell_width <= 0) 605 newfg->fontgrid.cell_width = DefaultCellWidth (newfg); 606 if (reqfg->fontgrid.cell_height <= 0) 607 newfg->fontgrid.cell_height = DefaultCellHeight (newfg); 608 609 /* give a nice size that fits one screen full */ 610 if (newfg->core.width == 0) 611 newfg->core.width = (newfg->fontgrid.cell_width * 612 newfg->fontgrid.cell_cols + 613 newfg->fontgrid.grid_width * 614 (newfg->fontgrid.cell_cols + 1)); 615 616 if (newfg->core.height == 0) 617 newfg->core.height = (newfg->fontgrid.cell_height * 618 newfg->fontgrid.cell_rows + 619 newfg->fontgrid.grid_width * 620 (newfg->fontgrid.cell_rows + 1)); 621 622 /* 623 * select the first character 624 */ 625 626 if (newfg->fontgrid.start_char == 0xffffffff) 627 newfg->fontgrid.start_char = GridFirstChar(new) & ~0xff; 628 maxn = GridLastChar (new); 629 if (newfg->fontgrid.start_char > maxn) 630 newfg->fontgrid.start_char = (maxn + 1 - 631 (newfg->fontgrid.cell_cols * 632 newfg->fontgrid.cell_rows)); 633} 634 635static void 636Realize(Widget gw, Mask *valueMask, XSetWindowAttributes *attributes) 637{ 638 FontGridWidget fgw = (FontGridWidget) gw; 639 FontGridPart *p = &fgw->fontgrid; 640 641 p->text_gc = get_gc (fgw, GridForeground (fgw)); 642 p->box_gc = get_gc (fgw, p->box_pixel); 643 Resize (gw); 644 645 (*(XtSuperclass(gw)->core_class.realize)) (gw, valueMask, attributes); 646#ifdef XRENDER 647 p->draw = XftDrawCreate (XtDisplay (gw), XtWindow (gw), 648 DefaultVisual (XtDisplay (gw), 649 DefaultScreen(XtDisplay (gw))), 650 fgw->core.colormap); 651#endif 652 return; 653} 654 655 656 657static void 658Destroy(Widget gw) 659{ 660 FontGridWidget fgw = (FontGridWidget) gw; 661 662 XtReleaseGC (gw, fgw->fontgrid.text_gc); 663 XtReleaseGC (gw, fgw->fontgrid.box_gc); 664} 665 666 667static void 668Resize(Widget gw) 669{ 670 FontGridWidget fgw = (FontGridWidget) gw; 671 672 /* recompute in case we've changed size */ 673 fgw->fontgrid.cell_width = CellWidth (fgw); 674 if (fgw->fontgrid.cell_width <= 0) 675 fgw->fontgrid.cell_width = 1; 676 fgw->fontgrid.cell_height = CellHeight (fgw); 677 if (fgw->fontgrid.cell_height <= 0) 678 fgw->fontgrid.cell_height = 1; 679 fgw->fontgrid.xoff = (fgw->fontgrid.cell_width - 680 DefaultCellWidth (fgw)) / 2; 681 fgw->fontgrid.yoff = (fgw->fontgrid.cell_height - 682 DefaultCellHeight (fgw)) / 2; 683 684} 685 686 687/* ARGSUSED */ 688static void 689Redisplay(Widget gw, XEvent *event _X_UNUSED, Region region) 690{ 691 FontGridWidget fgw = (FontGridWidget) gw; 692 XRectangle rect; /* bounding rect for region */ 693 int left, right, top, bottom; /* which cells were damaged */ 694 int cw, ch; /* cell size */ 695 696#ifdef XRENDER 697 if (!fgw->fontgrid.text_face) 698#endif 699 if (!fgw->fontgrid.text_font) { 700 Bell (gw, XkbBI_BadValue); 701 return; 702 } 703 704 /* 705 * compute the left, right, top, and bottom cells that were damaged 706 */ 707 XClipBox (region, &rect); 708 cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width; 709 ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width; 710 if ((left = (((int) rect.x) / cw)) < 0) left = 0; 711 right = (((int) (rect.x + rect.width - 1)) / cw); 712 if ((top = (((int) rect.y) / ch)) < 0) top = 0; 713 bottom = (((int) (rect.y + rect.height - 1)) / ch); 714 715 paint_grid (fgw, left, top, right - left + 1, bottom - top + 1); 716} 717 718 719static void 720paint_grid(FontGridWidget fgw, /* widget in which to draw */ 721 int col, int row, /* where to start */ 722 int ncols, int nrows) /* number of cells */ 723{ 724 FontGridPart *p = &fgw->fontgrid; 725 int i, j; 726 Display *dpy = XtDisplay(fgw); 727 Window wind = XtWindow(fgw); 728 int cw = p->cell_width + p->grid_width; 729 int ch = p->cell_height + p->grid_width; 730 int tcols = p->cell_cols; 731 int trows = p->cell_rows; 732 int x1, y1, x2, y2, x, y; 733 unsigned maxn = GridLastChar ((Widget) fgw); 734 unsigned n, prevn; 735 int startx; 736 737 if (col + ncols >= tcols) { 738 ncols = tcols - col; 739 if (ncols < 1) return; 740 } 741 742 if (row + nrows >= trows) { 743 nrows = trows - row; 744 if (nrows < 1) return; 745 } 746 747 /* 748 * paint the grid lines for the indicated rows 749 */ 750 if (p->grid_width > 0) { 751 int half_grid_width = p->grid_width >> 1; 752 x1 = col * cw + half_grid_width; 753 y1 = row * ch + half_grid_width; 754 x2 = x1 + ncols * cw; 755 y2 = y1 + nrows * ch; 756 for (i = 0, x = x1; i <= ncols; i++, x += cw) { 757 XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2); 758 } 759 for (i = 0, y = y1; i <= nrows; i++, y += ch) { 760 XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y); 761 } 762 } 763 /* 764 * Draw a character in every box; treat all fonts as if they were 16bit 765 * fonts. Store the high eight bits in byte1 and the low eight bits in 766 * byte2. 767 */ 768 prevn = p->start_char + col + row * tcols; 769 startx = col * cw + p->internal_pad + p->grid_width; 770 for (j = 0, 771 y = row * ch + p->internal_pad + p->grid_width + GridFontAscent (fgw); 772 j < nrows; j++, y += ch) { 773 n = prevn; 774 for (i = 0, x = startx; i < ncols; i++, x += cw) { 775 int xoff = p->xoff, yoff = p->yoff; 776 if (n > maxn) goto done; /* no break out of nested */ 777 778#ifdef XRENDER 779 if (fgw->fontgrid.text_face) 780 { 781 XftFont *xft = p->text_face; 782 FcChar32 c = n; 783 XGlyphInfo extents; 784 XftTextExtents32 (dpy, xft, &c, 1, &extents); 785 if (p->center_chars) 786 { 787 xoff = (p->cell_width - extents.width) / 2 - extents.x; 788 yoff = (p->cell_height - extents.height) / 2 - extents.y; 789 } 790 if (extents.width && extents.height) 791 { 792 XClearArea (dpy, wind, x + xoff - extents.x, 793 y + yoff - extents.y, 794 extents.width, extents.height, False); 795 if (p->box_chars) 796 XDrawRectangle (dpy, wind, p->box_gc, 797 x + xoff - extents.x, 798 y + yoff - extents.y, 799 extents.width - 1, 800 extents.height - 1); 801 } 802 XftDrawString32 (p->draw, &p->fg_color, xft, 803 x + xoff, y + yoff, &c, 1); 804 } 805 else 806#endif 807 { 808 XChar2b thechar; 809 810 thechar.byte1 = (n >> 8); /* high eight bits */ 811 thechar.byte2 = (n & 255); /* low eight bits */ 812 if (p->box_chars || p->center_chars) { 813 XCharStruct metrics; 814 int direction, fontascent, fontdescent; 815 816 XTextExtents16 (p->text_font, &thechar, 1, &direction, 817 &fontascent, &fontdescent, &metrics); 818 819 if (p->center_chars) { 820 /* 821 * We want to move the origin by enough to center the ink 822 * within the cell. The left edge will then be at 823 * (cell_width - (rbearing - lbearing)) / 2; so we subtract 824 * the lbearing to find the origin. Ditto for vertical. 825 */ 826 xoff = (((p->cell_width - 827 (metrics.rbearing - metrics.lbearing)) / 2) - 828 p->internal_pad - metrics.lbearing); 829 yoff = (((p->cell_height - 830 (metrics.descent + metrics.ascent)) / 2) - 831 p->internal_pad - 832 p->text_font->ascent + metrics.ascent); 833 } 834 if (p->box_chars) { 835 XDrawRectangle (dpy, wind, p->box_gc, 836 x + xoff, y + yoff - p->text_font->ascent, 837 metrics.width - 1, 838 fontascent + fontdescent - 1); 839 } 840 } 841 XDrawString16 (dpy, wind, p->text_gc, x + xoff, y + yoff, 842 &thechar, 1); 843 } 844 n++; 845 } 846 prevn += tcols; 847 } 848 849 done: 850 /* 851 * paint the grid lines for the indicated rows 852 */ 853 if (p->grid_width > 0) { 854 int half_grid_width = p->grid_width >> 1; 855 x1 = col * cw + half_grid_width; 856 y1 = row * ch + half_grid_width; 857 x2 = x1 + ncols * cw; 858 y2 = y1 + nrows * ch; 859 for (i = 0, x = x1; i <= ncols; i++, x += cw) { 860 XDrawLine (dpy, wind, p->box_gc, x, y1, x, y2); 861 } 862 for (i = 0, y = y1; i <= nrows; i++, y += ch) { 863 XDrawLine (dpy, wind, p->box_gc, x1, y, x2, y); 864 } 865 } 866 867 868 return; 869} 870 871static Boolean 872PageBlank (Widget w, long first, long last) 873{ 874 while (first <= last) 875 { 876 if (GridHasChar (w, first)) 877 return False; 878 first++; 879 } 880 return True; 881} 882 883/*ARGSUSED*/ 884static Boolean 885SetValues(Widget current, Widget request _X_UNUSED, Widget new, 886 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 887{ 888 FontGridWidget curfg = (FontGridWidget) current; 889 FontGridWidget newfg = (FontGridWidget) new; 890 Boolean redisplay = FALSE; 891 892 if (curfg->fontgrid.text_font != newfg->fontgrid.text_font || 893 curfg->fontgrid.internal_pad != newfg->fontgrid.internal_pad) { 894 newfg->fontgrid.cell_width = DefaultCellWidth (newfg); 895 newfg->fontgrid.cell_height = DefaultCellHeight (newfg); 896 redisplay = TRUE; 897 } 898 899 if (GridForeground(curfg) != GridForeground (newfg)) { 900 XtReleaseGC (new, curfg->fontgrid.text_gc); 901 newfg->fontgrid.text_gc = get_gc (newfg, GridForeground (newfg)); 902 redisplay = TRUE; 903 } 904 905 if (curfg->fontgrid.box_pixel != newfg->fontgrid.box_pixel) { 906 XtReleaseGC (new, curfg->fontgrid.text_gc); 907 newfg->fontgrid.box_gc = get_gc (newfg, newfg->fontgrid.box_pixel); 908 redisplay = TRUE; 909 } 910 911 if (curfg->fontgrid.center_chars != newfg->fontgrid.center_chars || 912 curfg->fontgrid.box_chars != newfg->fontgrid.box_chars) 913 redisplay = TRUE; 914 915 if (curfg->fontgrid.start_char != newfg->fontgrid.start_char) { 916 long maxn = GridLastChar (new); 917 long page = newfg->fontgrid.cell_cols * newfg->fontgrid.cell_rows; 918 long dir = page; 919 long start = newfg->fontgrid.start_char; 920 921 if (start < curfg->fontgrid.start_char) 922 dir = -page; 923 924 if (start < 0) 925 start = 0; 926 if (start > maxn) 927 start = (maxn / page) * page; 928 929 while (PageBlank (new, start, start + page - 1)) 930 { 931 long next = start + dir; 932 933 if (next < 0 || maxn < next) 934 break; 935 start = next; 936 } 937 938 newfg->fontgrid.start_char = start; 939 redisplay = (curfg->fontgrid.start_char != newfg->fontgrid.start_char); 940 } 941 942 return redisplay; 943} 944 945 946/* ARGSUSED */ 947static void 948Notify(Widget gw, XEvent *event, 949 String *params _X_UNUSED, Cardinal *nparams _X_UNUSED) 950{ 951 FontGridWidget fgw = (FontGridWidget) gw; 952 int x, y; /* where the event happened */ 953 FontGridCharRec rec; /* callback data */ 954 955 /* 956 * only allow events with (x,y) 957 */ 958 switch (event->type) { 959 case KeyPress: 960 case KeyRelease: 961 x = event->xkey.x; 962 y = event->xkey.y; 963 break; 964 case ButtonPress: 965 case ButtonRelease: 966 x = event->xbutton.x; 967 y = event->xbutton.y; 968 break; 969 case MotionNotify: 970 x = event->xmotion.x; 971 y = event->xmotion.y; 972 break; 973 default: 974 Bell (gw, XkbBI_Ignore); 975 return; 976 } 977 978 /* 979 * compute the callback data 980 */ 981 { 982 int cw = fgw->fontgrid.cell_width + fgw->fontgrid.grid_width; 983 int ch = fgw->fontgrid.cell_height + fgw->fontgrid.grid_width; 984 unsigned n; 985 986 if (x > (fgw->fontgrid.cell_cols * cw)) { 987 Bell (gw, XkbBI_InvalidLocation); 988 return; 989 } 990 991 n= (fgw->fontgrid.start_char + 992 ((y / ch) * fgw->fontgrid.cell_cols) + (x / cw)); 993 994 rec.thefont = fgw->fontgrid.text_font; 995#ifdef XRENDER 996 rec.theface = fgw->fontgrid.text_face; 997#endif 998 rec.thechar = n; 999 } 1000 1001 XtCallCallbacks (gw, XtNcallback, (XtPointer) &rec); 1002} 1003 1004