1 /* $XTermId: cachedGCs.c,v 1.81 2021/09/16 19:48:02 tom Exp $ */
2
3 /*
4 * Copyright 2007-2019,2021 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) != 0 && (font)->fs != 0)
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 *
traceCgsEnum(CgsEnum value)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
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 *
traceVTwin(XtermWidget xw,VTwin * value)124 traceVTwin(XtermWidget xw, VTwin *value)
125 {
126 const char *result = "?";
127 if (value == 0)
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
traceCSet(unsigned cset)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
traceFont(XTermFonts * font)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
tracePixel(XtermWidget xw,Pixel value)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 *
allocCache(void ** cache_pointer)243 allocCache(void **cache_pointer)
244 {
245 if (*cache_pointer == 0) {
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) == 0) ? allocCache(p) : *(p))
253
254 static int
dataIndex(CgsCache * me)255 dataIndex(CgsCache * me)
256 {
257 return ITEM();
258 }
259
260 static void
relinkData(CgsCache * me,int item)261 relinkData(CgsCache * me, int item)
262 {
263 LINK(item);
264 }
265
266 /*
267 * Returns the appropriate cache pointer.
268 */
269 static CgsCache *
myCache(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId)270 myCache(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
271 {
272 CgsCache *result = 0;
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 == 0) {
287 result->data = result->list;
288 }
289 }
290
291 return result;
292 }
293
294 static Display *
myDisplay(XtermWidget xw)295 myDisplay(XtermWidget xw)
296 {
297 return TScreenOf(xw)->display;
298 }
299
300 static Drawable
myDrawable(XtermWidget xw,VTwin * cgsWin)301 myDrawable(XtermWidget xw, VTwin *cgsWin)
302 {
303 Drawable drawable = 0;
304
305 if (cgsWin != 0 && cgsWin->window != 0)
306 drawable = cgsWin->window;
307 if (drawable == 0)
308 drawable = RootWindowOfScreen(XtScreen(xw));
309 return drawable;
310 }
311
312 static GC
newCache(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId,CgsCache * me)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
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 0;
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
chgCache(XtermWidget xw,CgsEnum cgsId GCC_UNUSED,CgsCache * me,Bool both)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
setCgsFore(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId,Pixel fg)451 setCgsFore(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel fg)
452 {
453 CgsCache *me;
454
455 if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
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
setCgsBack(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId,Pixel bg)465 setCgsBack(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel bg)
466 {
467 CgsCache *me;
468
469 if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
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
setCgsCSet(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId,unsigned cset)480 setCgsCSet(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, unsigned cset)
481 {
482 CgsCache *me;
483
484 if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
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
setCgsFont2(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId,XTermFonts * font,unsigned which)494 setCgsFont2(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, XTermFonts * font, unsigned which)
495 {
496 CgsCache *me;
497
498 if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
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
setCgsFont(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId,XTermFonts * font)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
clrCgsFonts(XtermWidget xw,VTwin * cgsWin,XTermFonts * font)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)) != 0) {
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 = 0;
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) = 0;
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
getCgsGC(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId)572 getCgsGC(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
573 {
574 CgsCache *me;
575 GC result = 0;
576
577 if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
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) == 0) {
595 setCgsFont(xw, cgsWin, cgsId, 0);
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 != 0
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 == 0) {
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 == 0) {
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 == 0) {
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
getCgsId(XtermWidget xw,VTwin * cgsWin,GC gc)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)) != 0) {
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 *
getCgsFont(XtermWidget xw,VTwin * cgsWin,GC gc)686 getCgsFont(XtermWidget xw, VTwin *cgsWin, GC gc)
687 {
688 int n;
689 XTermFonts *result = 0;
690
691 for_each_gc(n) {
692 CgsCache *me;
693
694 if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
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
getCgsFore(XtermWidget xw,VTwin * cgsWin,GC gc)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)) != 0) {
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
getCgsBack(XtermWidget xw,VTwin * cgsWin,GC gc)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)) != 0) {
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
copyCgs(XtermWidget xw,VTwin * cgsWin,CgsEnum dstCgsId,CgsEnum srcCgsId)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)) != 0) {
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
redoCgs(XtermWidget xw,Pixel fg,Pixel bg,CgsEnum cgsId)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 != 0) {
788 CgsCacheData *save_data = me->data;
789 int n;
790
791 for (n = 0; n < DEPTH; ++n) {
792 if (LIST(n).gc != 0 && 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
swapCgs(XtermWidget xw,VTwin * cgsWin,CgsEnum dstCgsId,CgsEnum srcCgsId)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)) != 0) {
824 CgsCache *dst;
825
826 if ((dst = myCache(xw, cgsWin, dstCgsId)) != 0) {
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
freeCgs(XtermWidget xw,VTwin * cgsWin,CgsEnum cgsId)844 freeCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
845 {
846 CgsCache *me;
847
848 if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
849 int j;
850
851 for (j = 0; j < DEPTH; ++j) {
852 if (LIST(j).gc != 0) {
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 0;
869 }
870
871 #ifdef NO_LEAKS
872 void
noleaks_cachedCgs(XtermWidget xw)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