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