cachedGCs.c revision 5104ee6e
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 */ 54typedef 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 75typedef 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 84static const char * 85traceCgsEnum(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 123static const char * 124traceVTwin(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 139static String 140traceCSet(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 163static String 164traceFont(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 182static String 183tracePixel(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 242static CgsCache * 243allocCache(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 254static int 255dataIndex(CgsCache * me) 256{ 257 return ITEM(); 258} 259 260static void 261relinkData(CgsCache * me, int item) 262{ 263 LINK(item); 264} 265 266/* 267 * Returns the appropriate cache pointer. 268 */ 269static CgsCache * 270myCache(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 294static Display * 295myDisplay(XtermWidget xw) 296{ 297 return TScreenOf(xw)->display; 298} 299 300static Drawable 301myDrawable(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 312static GC 313newCache(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 403static GC 404chgCache(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 */ 450void 451setCgsFore(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 464void 465setCgsBack(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 479void 480setCgsCSet(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 493void 494setCgsFont2(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 525void 526setCgsFont(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 */ 535void 536clrCgsFonts(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 */ 571GC 572getCgsGC(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 */ 663CgsEnum 664getCgsId(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 */ 685XTermFonts * 686getCgsFont(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 */ 707Pixel 708getCgsFore(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 */ 729Pixel 730getCgsBack(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 */ 751void 752copyCgs(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 */ 781void 782redoCgs(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 */ 817void 818swapCgs(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 */ 843GC 844freeCgs(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 872void 873noleaks_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