1 /* $XTermId: cachedGCs.c,v 1.84 2024/12/01 19:24:57 tom Exp $ */ 2 3 /* 4 * Copyright 2007-2021,2024 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 */ 32 33 #include <data.h> 34 #include <xstrings.h> 35 #include <fontutils.h> 36 37 #include <X11/Xmu/Drawing.h> 38 39 /* 40 * hide (or eliminate) calls to 41 * XCreateGC() 42 * XFreeGC() 43 * XGetGCValues() 44 * XSetBackground() 45 * XSetFont() 46 * XSetForeground() 47 * XtGetGC() 48 * XtReleaseGC() 49 * by associating an integer with each GC, maintaining a cache which 50 * reflects frequency of use rather than most recent usage. 51 * 52 * FIXME: XTermFonts should hold gc, font, fs. 53 */ 54 typedef struct { 55 GC gc; 56 unsigned used; 57 unsigned cset; 58 XTermFonts *font; 59 Pixel tile; 60 Pixel fg; 61 Pixel bg; 62 } CgsCacheData; 63 64 #define DEPTH 8 65 #define ITEM() (int) (me->data - me->list) 66 #define LIST(item) me->list[item] 67 #define LINK(item) me->data = (me->list + (item)) 68 #define THIS(field) me->data->field 69 #define NEXT(field) me->next.field 70 71 #define HaveFont(font) (Boolean) ((font) != NULL && (font)->fs != NULL) 72 73 #define GC_CSet GCFunction 74 75 typedef struct { 76 CgsCacheData list[DEPTH]; 77 CgsCacheData *data; /* points to current list[] entry */ 78 XtGCMask mask; /* changes since the last getCgsGC() */ 79 CgsCacheData next; /* updated values, apply in getCgsGC() */ 80 } CgsCache; 81 82 #if OPT_TRACE 83 #define CASE(name) case gc##name: result = #name; break 84 static const char * 85 traceCgsEnum(CgsEnum value) 86 { 87 const char *result = "?"; 88 switch (value) { 89 CASE(Norm); 90 CASE(Bold); 91 CASE(NormReverse); 92 CASE(BoldReverse); 93 CASE(Border); 94 CASE(Filler); 95 #if OPT_BOX_CHARS || OPT_WIDE_CHARS 96 CASE(Line); 97 CASE(Dots); 98 #endif 99 #if OPT_DEC_CHRSET 100 CASE(CNorm); 101 CASE(CBold); 102 #endif 103 #if OPT_WIDE_CHARS 104 CASE(Wide); 105 CASE(WBold); 106 CASE(WideReverse); 107 CASE(WBoldReverse); 108 #endif 109 CASE(VTcursNormal); 110 CASE(VTcursFilled); 111 CASE(VTcursReverse); 112 CASE(VTcursOutline); 113 #if OPT_TEK4014 114 CASE(TKcurs); 115 #endif 116 CASE(MAX); 117 } 118 return result; 119 } 120 121 #undef CASE 122 123 static const char * 124 traceVTwin(XtermWidget xw, const VTwin *value) 125 { 126 const char *result = "?"; 127 if (value == NULL) 128 result = "null"; 129 else if (value == &(TScreenOf(xw)->fullVwin)) 130 result = "fullVwin"; 131 #ifndef NO_ACTIVE_ICON 132 else if (value == &(TScreenOf(xw)->iconVwin)) 133 result = "iconVwin"; 134 #endif 135 return result; 136 } 137 138 #if OPT_TRACE > 1 139 static String 140 traceCSet(unsigned cset) 141 { 142 static char result[80]; 143 switch (cset) { 144 case CSET_SWL: 145 strcpy(result, "SWL"); 146 break; 147 case CSET_DHL_TOP: 148 strcpy(result, "DHL_TOP"); 149 break; 150 case CSET_DHL_BOT: 151 strcpy(result, "DHL_BOT"); 152 break; 153 case CSET_DWL: 154 strcpy(result, "DWL"); 155 break; 156 default: 157 sprintf(result, "%#x", cset); 158 break; 159 } 160 return result; 161 } 162 163 static String 164 traceFont(XTermFonts * font) 165 { 166 static char result[80]; 167 168 if (HaveFont(font)) { 169 XFontStruct *fs = font->fs; 170 sprintf(result, "%p(%dx%d %d %#lx)", 171 fs, 172 fs->max_bounds.width, 173 fs->max_bounds.ascent + fs->max_bounds.descent, 174 fs->max_bounds.descent, 175 (unsigned long) (fs->fid)); 176 } else { 177 strcpy(result, "null"); 178 } 179 return result; 180 } 181 182 static String 183 tracePixel(XtermWidget xw, Pixel value) 184 { 185 #define CASE(name) { name, #name } 186 static struct { 187 TermColors code; 188 String name; 189 } t_colors[] = { 190 CASE(TEXT_FG), 191 CASE(TEXT_BG), 192 CASE(TEXT_CURSOR), 193 CASE(MOUSE_FG), 194 CASE(MOUSE_BG), 195 #if OPT_TEK4014 196 CASE(TEK_FG), 197 CASE(TEK_BG), 198 #endif 199 #if OPT_HIGHLIGHT_COLOR 200 CASE(HIGHLIGHT_BG), 201 CASE(HIGHLIGHT_FG), 202 #endif 203 #if OPT_TEK4014 204 CASE(TEK_CURSOR), 205 #endif 206 }; 207 TScreen *screen = TScreenOf(xw); 208 String result = 0; 209 int n; 210 211 for (n = 0; n < NCOLORS; ++n) { 212 if (value == T_COLOR(screen, t_colors[n].code)) { 213 result = t_colors[n].name; 214 break; 215 } 216 } 217 218 if (result == 0) { 219 for (n = 0; n < MAXCOLORS; ++n) { 220 if (screen->Acolors[n].mode > 0 221 && value == screen->Acolors[n].value) { 222 result = screen->Acolors[n].resource; 223 break; 224 } 225 } 226 } 227 228 if (result == 0) { 229 char temp[80]; 230 sprintf(temp, "%#lx", value); 231 result = x_strdup(temp); 232 } 233 234 return result; 235 } 236 237 #undef CASE 238 239 #endif /* OPT_TRACE > 1 */ 240 #endif /* OPT_TRACE */ 241 242 static CgsCache * 243 allocCache(void **cache_pointer) 244 { 245 if (*cache_pointer == NULL) { 246 *cache_pointer = TypeCallocN(CgsCache, gcMAX); 247 TRACE(("allocCache %p\n", *cache_pointer)); 248 } 249 return *((CgsCache **) cache_pointer); 250 } 251 252 #define ALLOC_CACHE(p) ((*(p) == NULL) ? allocCache(p) : *(p)) 253 254 static int 255 dataIndex(CgsCache * me) 256 { 257 return ITEM(); 258 } 259 260 static void 261 relinkData(CgsCache * me, int item) 262 { 263 LINK(item); 264 } 265 266 /* 267 * Returns the appropriate cache pointer. 268 */ 269 static CgsCache * 270 myCache(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId) 271 { 272 CgsCache *result = NULL; 273 274 if ((int) cgsId >= 0 && cgsId < gcMAX) { 275 #ifdef NO_ACTIVE_ICON 276 (void) xw; 277 (void) cgsWin; 278 #else 279 if (cgsWin == &(TScreenOf(xw)->iconVwin)) 280 result = ALLOC_CACHE(&(TScreenOf(xw)->icon_cgs_cache)); 281 else 282 #endif 283 result = ALLOC_CACHE(&(TScreenOf(xw)->main_cgs_cache)); 284 285 result += cgsId; 286 if (result->data == NULL) { 287 result->data = result->list; 288 } 289 } 290 291 return result; 292 } 293 294 static Display * 295 myDisplay(XtermWidget xw) 296 { 297 return TScreenOf(xw)->display; 298 } 299 300 static Drawable 301 myDrawable(XtermWidget xw, VTwin *cgsWin) 302 { 303 Drawable drawable = 0; 304 305 if (cgsWin != NULL && cgsWin->window != 0) 306 drawable = cgsWin->window; 307 if (drawable == 0) 308 drawable = RootWindowOfScreen(XtScreen(xw)); 309 return drawable; 310 } 311 312 static GC 313 newCache(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, CgsCache * me) 314 { 315 XGCValues xgcv; 316 XtGCMask mask; 317 318 THIS(font) = NEXT(font); 319 THIS(cset) = NEXT(cset); 320 THIS(fg) = NEXT(fg); 321 THIS(bg) = NEXT(bg); 322 323 memset(&xgcv, 0, sizeof(xgcv)); 324 xgcv.font = NEXT(font)->fs->fid; 325 mask = (GCForeground | GCBackground | GCFont); 326 327 switch (cgsId) { 328 case gcFiller: 329 case gcBorder: 330 mask &= (XtGCMask) ~ GCFont; 331 /* FALLTHRU */ 332 case gcNorm: 333 case gcBold: 334 case gcNormReverse: 335 case gcBoldReverse: 336 #if OPT_WIDE_CHARS 337 case gcWide: 338 case gcWBold: 339 case gcWideReverse: 340 case gcWBoldReverse: 341 #endif 342 mask |= (GCGraphicsExposures | GCFunction); 343 xgcv.graphics_exposures = True; /* default */ 344 xgcv.function = GXcopy; 345 break; 346 #if OPT_BOX_CHARS || OPT_WIDE_CHARS 347 case gcLine: 348 mask |= (GCGraphicsExposures | GCFunction); 349 xgcv.graphics_exposures = True; /* default */ 350 xgcv.function = GXcopy; 351 break; 352 case gcDots: 353 xgcv.fill_style = FillTiled; 354 xgcv.tile = 355 XmuCreateStippledPixmap(XtScreen((Widget) xw), 356 THIS(fg), 357 THIS(bg), 358 xw->core.depth); 359 THIS(tile) = xgcv.tile; 360 mask = (GCForeground | GCBackground); 361 mask |= (GCGraphicsExposures | GCFunction | GCTile | GCFillStyle); 362 xgcv.graphics_exposures = True; /* default */ 363 xgcv.function = GXcopy; 364 break; 365 #endif 366 #if OPT_DEC_CHRSET 367 case gcCNorm: 368 case gcCBold: 369 break; 370 #endif 371 case gcVTcursNormal: /* FALLTHRU */ 372 case gcVTcursFilled: /* FALLTHRU */ 373 case gcVTcursReverse: /* FALLTHRU */ 374 case gcVTcursOutline: /* FALLTHRU */ 375 break; 376 #if OPT_TEK4014 377 case gcTKcurs: /* FALLTHRU */ 378 /* FIXME */ 379 #endif 380 case gcMAX: /* should not happen */ 381 return NULL; 382 } 383 xgcv.foreground = NEXT(fg); 384 xgcv.background = NEXT(bg); 385 386 THIS(gc) = XCreateGC(myDisplay(xw), myDrawable(xw, cgsWin), mask, &xgcv); 387 TRACE(("getCgsGC(%s) created gc %p(%d)\n", 388 traceCgsEnum(cgsId), (void *) THIS(gc), ITEM())); 389 390 THIS(used) = 0; 391 return THIS(gc); 392 } 393 394 #define SameFont(a, b) \ 395 (Boolean) (HaveFont(a) \ 396 && HaveFont(b) \ 397 && (((a)->fs == (b)->fs) \ 398 || !memcmp((a)->fs, (b)->fs, sizeof(*((a)->fs))))) 399 400 #define SameColor(a,b) ((a) == (b)) 401 #define SameCSet(a,b) ((a) == (b)) 402 403 static GC 404 chgCache(XtermWidget xw, CgsEnum cgsId GCC_UNUSED, CgsCache * me, Bool both) 405 { 406 XGCValues xgcv; 407 XtGCMask mask = (GCForeground | GCBackground | GCFont); 408 409 memset(&xgcv, 0, sizeof(xgcv)); 410 411 TRACE2(("chgCache(%s) old data fg=%s, bg=%s, font=%s cset %s\n", 412 traceCgsEnum(cgsId), 413 tracePixel(xw, THIS(fg)), 414 tracePixel(xw, THIS(bg)), 415 traceFont(THIS(font)), 416 traceCSet(THIS(cset)))); 417 #if OPT_TRACE > 1 418 if (!SameFont(THIS(font), NEXT(font))) 419 TRACE2(("...chgCache new font=%s\n", traceFont(NEXT(font)))); 420 if (!SameCSet(THIS(cset), NEXT(cset))) 421 TRACE2(("...chgCache new cset=%s\n", traceCSet(NEXT(cset)))); 422 if (!SameColor(THIS(fg), NEXT(fg))) 423 TRACE2(("...chgCache new fg=%s\n", tracePixel(xw, NEXT(fg)))); 424 if (!SameColor(THIS(bg), NEXT(bg))) 425 TRACE2(("...chgCache new bg=%s\n", tracePixel(xw, NEXT(bg)))); 426 #endif 427 428 if (both) { 429 THIS(font) = NEXT(font); 430 THIS(cset) = NEXT(cset); 431 } 432 THIS(fg) = NEXT(fg); 433 THIS(bg) = NEXT(bg); 434 435 xgcv.font = THIS(font)->fs->fid; 436 xgcv.foreground = THIS(fg); 437 xgcv.background = THIS(bg); 438 439 XChangeGC(myDisplay(xw), THIS(gc), mask, &xgcv); 440 TRACE2(("...chgCache(%s) updated gc %p(%d)\n", 441 traceCgsEnum(cgsId), THIS(gc), ITEM())); 442 443 THIS(used) = 0; 444 return THIS(gc); 445 } 446 447 /* 448 * Use the "setCgsXXXX()" calls to initialize parameters for a new GC. 449 */ 450 void 451 setCgsFore(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel fg) 452 { 453 CgsCache *me; 454 455 if ((me = myCache(xw, cgsWin, cgsId)) != NULL) { 456 NEXT(fg) = fg; 457 me->mask |= GCForeground; 458 TRACE2(("setCgsFore(%s) %s\n", 459 traceCgsEnum(cgsId), 460 tracePixel(xw, NEXT(fg)))); 461 } 462 } 463 464 void 465 setCgsBack(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel bg) 466 { 467 CgsCache *me; 468 469 if ((me = myCache(xw, cgsWin, cgsId)) != NULL) { 470 NEXT(bg) = bg; 471 me->mask |= GCBackground; 472 TRACE2(("setCgsBack(%s) %s\n", 473 traceCgsEnum(cgsId), 474 tracePixel(xw, NEXT(bg)))); 475 } 476 } 477 478 #if OPT_DEC_CHRSET 479 void 480 setCgsCSet(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, unsigned cset) 481 { 482 CgsCache *me; 483 484 if ((me = myCache(xw, cgsWin, cgsId)) != NULL) { 485 NEXT(cset) = cset; 486 me->mask |= GC_CSet; 487 } 488 } 489 #else 490 #define setCgsCSet(xw, cgsWin, dstCgsId, cset) /* nothing */ 491 #endif 492 493 void 494 setCgsFont2(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, XTermFonts * font, unsigned which) 495 { 496 CgsCache *me; 497 498 if ((me = myCache(xw, cgsWin, cgsId)) != NULL) { 499 TScreen *screen = TScreenOf(xw); 500 if (!HaveFont(font)) { 501 if (cgsId != gcNorm) 502 (void) getCgsGC(xw, cgsWin, gcNorm); 503 #ifndef NO_ACTIVE_ICON 504 if (cgsWin == &(TScreenOf(xw)->iconVwin)) 505 font = getIconicFont(screen); 506 else 507 #endif 508 font = GetNormalFont(screen, which); 509 } 510 if (HaveFont(font) && okFont(font->fs)) { 511 TRACE2(("setCgsFont next: %s for %s slot %p, gc %p\n", 512 traceFont(font), traceCgsEnum(cgsId), 513 me, THIS(gc))); 514 TRACE2(("...next font was %s\n", traceFont(NEXT(font)))); 515 NEXT(font) = font; 516 me->mask |= GCFont; 517 } else { 518 /* EMPTY */ 519 TRACE2(("...NOT updated font for %s\n", 520 traceCgsEnum(cgsId))); 521 } 522 } 523 } 524 525 void 526 setCgsFont(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, XTermFonts * font) 527 { 528 setCgsFont2(xw, cgsWin, cgsId, font, fNorm); 529 } 530 531 /* 532 * Discard all of the font information, e.g., we are resizing the font. 533 * Keep the GC's so we can simply change them rather than creating new ones. 534 */ 535 void 536 clrCgsFonts(XtermWidget xw, VTwin *cgsWin, XTermFonts * font) 537 { 538 if (HaveFont(font)) { 539 int j; 540 for_each_gc(j) { 541 CgsCache *me; 542 if ((me = myCache(xw, cgsWin, (CgsEnum) j)) != NULL) { 543 int k; 544 for (k = 0; k < DEPTH; ++k) { 545 if (SameFont(LIST(k).font, font)) { 546 TRACE2(("clrCgsFonts %s gc %p(%d) %s\n", 547 traceCgsEnum((CgsEnum) j), 548 LIST(k).gc, 549 k, 550 traceFont(font))); 551 LIST(k).font = NULL; 552 LIST(k).cset = 0; 553 } 554 } 555 if (SameFont(NEXT(font), font)) { 556 TRACE2(("clrCgsFonts %s next %s\n", 557 traceCgsEnum((CgsEnum) j), 558 traceFont(font))); 559 NEXT(font) = NULL; 560 NEXT(cset) = 0; 561 me->mask &= (unsigned) ~(GCFont | GC_CSet); 562 } 563 } 564 } 565 } 566 } 567 568 /* 569 * Return a GC associated with the given id, allocating if needed. 570 */ 571 GC 572 getCgsGC(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId) 573 { 574 CgsCache *me; 575 GC result = NULL; 576 577 if ((me = myCache(xw, cgsWin, cgsId)) != NULL) { 578 TRACE2(("getCgsGC(%s, %s)\n", 579 traceVTwin(xw, cgsWin), traceCgsEnum(cgsId))); 580 if (me->mask != 0) { 581 int j; 582 unsigned used = 0; 583 584 /* fill in the unchanged fields */ 585 if (!(me->mask & GC_CSet)) 586 NEXT(cset) = 0; /* OPT_DEC_CHRSET */ 587 if (!(me->mask & GCFont)) 588 NEXT(font) = THIS(font); 589 if (!(me->mask & GCForeground)) 590 NEXT(fg) = THIS(fg); 591 if (!(me->mask & GCBackground)) 592 NEXT(bg) = THIS(bg); 593 594 if (NEXT(font) == NULL) { 595 setCgsFont(xw, cgsWin, cgsId, NULL); 596 } 597 598 TRACE2(("...Cgs new data fg=%s, bg=%s, font=%s cset %s\n", 599 tracePixel(xw, NEXT(fg)), 600 tracePixel(xw, NEXT(bg)), 601 traceFont(NEXT(font)), 602 traceCSet(NEXT(cset)))); 603 604 /* try to find the given data in an already-created GC */ 605 for (j = 0; j < DEPTH; ++j) { 606 if (LIST(j).gc != NULL 607 && SameFont(LIST(j).font, NEXT(font)) 608 && SameCSet(LIST(j).cset, NEXT(cset)) 609 && SameColor(LIST(j).fg, NEXT(fg)) 610 && SameColor(LIST(j).bg, NEXT(bg))) { 611 LINK(j); 612 result = THIS(gc); 613 TRACE2(("getCgsGC existing %p(%d)\n", result, ITEM())); 614 break; 615 } 616 } 617 618 if (result == NULL) { 619 /* try to find an empty slot, to create a new GC */ 620 used = 0; 621 for (j = 0; j < DEPTH; ++j) { 622 if (LIST(j).gc == NULL) { 623 LINK(j); 624 result = newCache(xw, cgsWin, cgsId, me); 625 break; 626 } 627 if (used < LIST(j).used) 628 used = LIST(j).used; 629 } 630 } 631 632 if (result == NULL) { 633 int k; 634 /* if none were empty, pick the least-used slot, to modify */ 635 for (j = 0, k = -1; j < DEPTH; ++j) { 636 if (used >= LIST(j).used) { 637 used = LIST(j).used; 638 k = j; 639 } 640 } 641 if (k >= 0) { 642 LINK(k); 643 TRACE2(("...getCgsGC least-used(%d) was %d\n", k, THIS(used))); 644 result = chgCache(xw, cgsId, me, True); 645 } 646 } 647 me->next = *(me->data); 648 } else { 649 result = THIS(gc); 650 } 651 me->mask = 0; 652 THIS(used) += 1; 653 TRACE2(("...getCgsGC(%s, %s) gc %p(%d), used %d\n", 654 traceVTwin(xw, cgsWin), 655 traceCgsEnum(cgsId), result, ITEM(), THIS(used))); 656 } 657 return result; 658 } 659 660 /* 661 * Return the font for the given GC. 662 */ 663 CgsEnum 664 getCgsId(XtermWidget xw, VTwin *cgsWin, GC gc) 665 { 666 int n; 667 CgsEnum result = gcNorm; 668 669 for_each_gc(n) { 670 CgsCache *me; 671 672 if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != NULL) { 673 if (THIS(gc) == gc) { 674 result = (CgsEnum) n; 675 break; 676 } 677 } 678 } 679 return result; 680 } 681 682 /* 683 * Return the font for the given GC. 684 */ 685 XTermFonts * 686 getCgsFont(XtermWidget xw, VTwin *cgsWin, GC gc) 687 { 688 int n; 689 XTermFonts *result = NULL; 690 691 for_each_gc(n) { 692 CgsCache *me; 693 694 if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != NULL) { 695 if (THIS(gc) == gc) { 696 result = THIS(font); 697 break; 698 } 699 } 700 } 701 return result; 702 } 703 704 /* 705 * Return the foreground color for the given GC. 706 */ 707 Pixel 708 getCgsFore(XtermWidget xw, VTwin *cgsWin, GC gc) 709 { 710 int n; 711 Pixel result = 0; 712 713 for_each_gc(n) { 714 CgsCache *me; 715 716 if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != NULL) { 717 if (THIS(gc) == gc) { 718 result = THIS(fg); 719 break; 720 } 721 } 722 } 723 return result; 724 } 725 726 /* 727 * Return the background color for the given GC. 728 */ 729 Pixel 730 getCgsBack(XtermWidget xw, VTwin *cgsWin, GC gc) 731 { 732 int n; 733 Pixel result = 0; 734 735 for_each_gc(n) { 736 CgsCache *me; 737 738 if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != NULL) { 739 if (THIS(gc) == gc) { 740 result = THIS(bg); 741 break; 742 } 743 } 744 } 745 return result; 746 } 747 748 /* 749 * Copy the parameters (except GC of course) from one cache record to another. 750 */ 751 void 752 copyCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum dstCgsId, CgsEnum srcCgsId) 753 { 754 if (dstCgsId != srcCgsId) { 755 CgsCache *me; 756 757 if ((me = myCache(xw, cgsWin, srcCgsId)) != NULL) { 758 TRACE(("copyCgs from %s to %s\n", 759 traceCgsEnum(srcCgsId), 760 traceCgsEnum(dstCgsId))); 761 TRACE2(("copyCgs from %s (me %p, fg %s, bg %s, cset %s) to %s " 762 TRACE_L "\n", 763 traceCgsEnum(srcCgsId), 764 me, 765 tracePixel(xw, THIS(fg)), 766 tracePixel(xw, THIS(bg)), 767 traceCSet(THIS(cset)), 768 traceCgsEnum(dstCgsId))); 769 setCgsCSet(xw, cgsWin, dstCgsId, THIS(cset)); 770 setCgsFore(xw, cgsWin, dstCgsId, THIS(fg)); 771 setCgsBack(xw, cgsWin, dstCgsId, THIS(bg)); 772 setCgsFont(xw, cgsWin, dstCgsId, THIS(font)); 773 TRACE2(("...copyCgs " TRACE_R "\n")); 774 } 775 } 776 } 777 778 /* 779 * Interchange colors in the cache, e.g., for reverse-video. 780 */ 781 void 782 redoCgs(XtermWidget xw, Pixel fg, Pixel bg, CgsEnum cgsId) 783 { 784 VTwin *cgsWin = WhichVWin(TScreenOf(xw)); 785 CgsCache *me = myCache(xw, cgsWin, cgsId); 786 787 if (me != NULL) { 788 CgsCacheData *save_data = me->data; 789 int n; 790 791 for (n = 0; n < DEPTH; ++n) { 792 if (LIST(n).gc != NULL && HaveFont(LIST(n).font)) { 793 LINK(n); 794 795 if (LIST(n).fg == fg 796 && LIST(n).bg == bg) { 797 setCgsFore(xw, cgsWin, cgsId, bg); 798 setCgsBack(xw, cgsWin, cgsId, fg); 799 } else if (LIST(n).fg == bg 800 && LIST(n).bg == fg) { 801 setCgsFore(xw, cgsWin, cgsId, fg); 802 setCgsBack(xw, cgsWin, cgsId, bg); 803 } else { 804 continue; 805 } 806 807 (void) chgCache(xw, cgsId, me, False); 808 } 809 } 810 me->data = save_data; 811 } 812 } 813 814 /* 815 * Swap the cache records, e.g., when doing reverse-video. 816 */ 817 void 818 swapCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum dstCgsId, CgsEnum srcCgsId) 819 { 820 if (dstCgsId != srcCgsId) { 821 CgsCache *src; 822 823 if ((src = myCache(xw, cgsWin, srcCgsId)) != NULL) { 824 CgsCache *dst; 825 826 if ((dst = myCache(xw, cgsWin, dstCgsId)) != NULL) { 827 CgsCache tmp; 828 int srcIndex = dataIndex(src); 829 int dstIndex = dataIndex(dst); 830 831 EXCHANGE(*src, *dst, tmp); 832 833 relinkData(src, dstIndex); 834 relinkData(dst, srcIndex); 835 } 836 } 837 } 838 } 839 840 /* 841 * Free any GC associated with the given id. 842 */ 843 GC 844 freeCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId) 845 { 846 CgsCache *me; 847 848 if ((me = myCache(xw, cgsWin, cgsId)) != NULL) { 849 int j; 850 851 for (j = 0; j < DEPTH; ++j) { 852 if (LIST(j).gc != NULL) { 853 TRACE(("freeCgs(%s, %s) gc %p(%d)\n", 854 traceVTwin(xw, cgsWin), 855 traceCgsEnum(cgsId), (void *) LIST(j).gc, j)); 856 clrCgsFonts(xw, cgsWin, LIST(j).font); 857 #if OPT_BOX_CHARS 858 if (cgsId == gcDots) { 859 XmuReleaseStippledPixmap(XtScreen((Widget) xw), LIST(j).tile); 860 } 861 #endif 862 XFreeGC(TScreenOf(xw)->display, LIST(j).gc); 863 memset(&LIST(j), 0, sizeof(LIST(j))); 864 } 865 LINK(0); 866 } 867 } 868 return NULL; 869 } 870 871 #ifdef NO_LEAKS 872 void 873 noleaks_cachedCgs(XtermWidget xw) 874 { 875 #ifndef NO_ACTIVE_ICON 876 free(TScreenOf(xw)->icon_cgs_cache); 877 #endif 878 free(TScreenOf(xw)->main_cgs_cache); 879 } 880 #endif 881