cachedGCs.c revision 894e0ac8
1/* $XTermId: cachedGCs.c,v 1.62 2014/06/12 23:04:07 tom Exp $ */
2
3/*
4 * Copyright 2007-2011,2014 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/*
453 * Use the "setCgsXXXX()" calls to initialize parameters for a new GC.
454 */
455void
456setCgsFore(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel fg)
457{
458    CgsCache *me;
459
460    if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
461	NEXT(fg) = fg;
462	me->mask |= GCForeground;
463    }
464}
465
466void
467setCgsBack(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel bg)
468{
469    CgsCache *me;
470
471    if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
472	NEXT(bg) = bg;
473	me->mask |= GCBackground;
474    }
475}
476
477#if OPT_DEC_CHRSET
478void
479setCgsCSet(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, unsigned cset)
480{
481    CgsCache *me;
482
483    if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
484	NEXT(cset) = cset;
485	me->mask |= GC_CSet;
486    }
487}
488#else
489#define setCgsCSet(xw, cgsWin, dstCgsId, cset)	/* nothing */
490#endif
491
492void
493setCgsFont(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, XTermFonts * font)
494{
495    CgsCache *me;
496
497    if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
498	if (!HaveFont(font)) {
499	    if (cgsId != gcNorm)
500		(void) getCgsGC(xw, cgsWin, gcNorm);
501#ifndef NO_ACTIVE_ICON
502	    if (cgsWin == &(TScreenOf(xw)->iconVwin))
503		font = &(TScreenOf(xw)->fnt_icon);
504	    else
505#endif
506		font = &(TScreenOf(xw)->fnts[fNorm]);
507	}
508	if (HaveFont(font) && okFont(font->fs)) {
509	    TRACE2(("setCgsFont next: %s for %s slot %p, gc %#x\n",
510		    traceFont(font), traceCgsEnum(cgsId),
511		    me, (unsigned) THIS(gc)));
512	    TRACE2(("...next font was %s\n", traceFont(NEXT(font))));
513	    NEXT(font) = font;
514	    me->mask |= GCFont;
515	} else {
516	    /* EMPTY */
517	    TRACE2(("...NOT updated font for %s\n",
518		    traceCgsEnum(cgsId)));
519	}
520    }
521}
522
523/*
524 * Discard all of the font information, e.g., we are resizing the font.
525 * Keep the GC's so we can simply change them rather than creating new ones.
526 */
527void
528clrCgsFonts(XtermWidget xw, VTwin *cgsWin, XTermFonts * font)
529{
530    CgsCache *me;
531    int j, k;
532
533    if (HaveFont(font)) {
534	for_each_gc(j) {
535	    if ((me = myCache(xw, cgsWin, (CgsEnum) j)) != 0) {
536		for (k = 0; k < DEPTH; ++k) {
537		    if (SameFont(LIST(k).font, font)) {
538			TRACE2(("clrCgsFonts %s gc %p(%d) %s\n",
539				traceCgsEnum((CgsEnum) j),
540				LIST(k).gc,
541				k,
542				traceFont(font)));
543			LIST(k).font = 0;
544			LIST(k).cset = 0;
545		    }
546		}
547		if (SameFont(NEXT(font), font)) {
548		    TRACE2(("clrCgsFonts %s next %s\n",
549			    traceCgsEnum((CgsEnum) j),
550			    traceFont(font)));
551		    NEXT(font) = 0;
552		    NEXT(cset) = 0;
553		    me->mask &= (unsigned) ~(GCFont | GC_CSet);
554		}
555	    }
556	}
557    }
558}
559
560/*
561 * Return a GC associated with the given id, allocating if needed.
562 */
563GC
564getCgsGC(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
565{
566    CgsCache *me;
567    GC result = 0;
568    int j, k;
569    unsigned used = 0;
570
571    if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
572	TRACE2(("getCgsGC(%s, %s)\n",
573		traceVTwin(xw, cgsWin), traceCgsEnum(cgsId)));
574	if (me->mask != 0) {
575
576	    /* fill in the unchanged fields */
577	    if (!(me->mask & GC_CSet))
578		NEXT(cset) = 0;	/* OPT_DEC_CHRSET */
579	    if (!(me->mask & GCFont))
580		NEXT(font) = THIS(font);
581	    if (!(me->mask & GCForeground))
582		NEXT(fg) = THIS(fg);
583	    if (!(me->mask & GCBackground))
584		NEXT(bg) = THIS(bg);
585
586	    if (NEXT(font) == 0) {
587		setCgsFont(xw, cgsWin, cgsId, 0);
588	    }
589
590	    TRACE2(("...Cgs new data fg=%s, bg=%s, font=%s cset %s\n",
591		    tracePixel(xw, NEXT(fg)),
592		    tracePixel(xw, NEXT(bg)),
593		    traceFont(NEXT(font)),
594		    traceCSet(NEXT(cset))));
595
596	    /* try to find the given data in an already-created GC */
597	    for (j = 0; j < DEPTH; ++j) {
598		if (LIST(j).gc != 0
599		    && SameFont(LIST(j).font, NEXT(font))
600		    && SameCSet(LIST(j).cset, NEXT(cset))
601		    && SameColor(LIST(j).fg, NEXT(fg))
602		    && SameColor(LIST(j).bg, NEXT(bg))) {
603		    LINK(j);
604		    result = THIS(gc);
605		    TRACE2(("getCgsGC existing %p(%d)\n", result, ITEM()));
606		    break;
607		}
608	    }
609
610	    if (result == 0) {
611		/* try to find an empty slot, to create a new GC */
612		used = 0;
613		for (j = 0; j < DEPTH; ++j) {
614		    if (LIST(j).gc == 0) {
615			LINK(j);
616			result = newCache(xw, cgsWin, cgsId, me);
617			break;
618		    }
619		    if (used < LIST(j).used)
620			used = LIST(j).used;
621		}
622	    }
623
624	    if (result == 0) {
625		/* if none were empty, pick the least-used slot, to modify */
626		for (j = 0, k = -1; j < DEPTH; ++j) {
627		    if (used >= LIST(j).used) {
628			used = LIST(j).used;
629			k = j;
630		    }
631		}
632		LINK(k);
633		TRACE2(("...getCgsGC least-used(%d) was %d\n", k, THIS(used)));
634		result = chgCache(xw, cgsId, me, True);
635	    }
636	    me->next = *(me->data);
637	} else {
638	    result = THIS(gc);
639	}
640	me->mask = 0;
641	THIS(used) += 1;
642	TRACE2(("...getCgsGC(%s, %s) gc %p(%d), used %d\n",
643		traceVTwin(xw, cgsWin),
644		traceCgsEnum(cgsId), result, ITEM(), THIS(used)));
645    }
646    return result;
647}
648
649/*
650 * Return the font for the given GC.
651 */
652CgsEnum
653getCgsId(XtermWidget xw, VTwin *cgsWin, GC gc)
654{
655    int n;
656    CgsEnum result = gcNorm;
657
658    for_each_gc(n) {
659	CgsCache *me;
660
661	if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
662	    if (THIS(gc) == gc) {
663		result = (CgsEnum) n;
664		break;
665	    }
666	}
667    }
668    return result;
669}
670
671/*
672 * Return the font for the given GC.
673 */
674XTermFonts *
675getCgsFont(XtermWidget xw, VTwin *cgsWin, GC gc)
676{
677    int n;
678    XTermFonts *result = 0;
679
680    for_each_gc(n) {
681	CgsCache *me;
682
683	if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
684	    if (THIS(gc) == gc) {
685		result = THIS(font);
686		break;
687	    }
688	}
689    }
690    return result;
691}
692
693/*
694 * Return the foreground color for the given GC.
695 */
696Pixel
697getCgsFore(XtermWidget xw, VTwin *cgsWin, GC gc)
698{
699    int n;
700    Pixel result = 0;
701
702    for_each_gc(n) {
703	CgsCache *me;
704
705	if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
706	    if (THIS(gc) == gc) {
707		result = THIS(fg);
708		break;
709	    }
710	}
711    }
712    return result;
713}
714
715/*
716 * Return the background color for the given GC.
717 */
718Pixel
719getCgsBack(XtermWidget xw, VTwin *cgsWin, GC gc)
720{
721    int n;
722    Pixel result = 0;
723
724    for_each_gc(n) {
725	CgsCache *me;
726
727	if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
728	    if (THIS(gc) == gc) {
729		result = THIS(bg);
730		break;
731	    }
732	}
733    }
734    return result;
735}
736
737/*
738 * Copy the parameters (except GC of course) from one cache record to another.
739 */
740void
741copyCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum dstCgsId, CgsEnum srcCgsId)
742{
743    if (dstCgsId != srcCgsId) {
744	CgsCache *me;
745
746	if ((me = myCache(xw, cgsWin, srcCgsId)) != 0) {
747	    TRACE(("copyCgs from %s to %s\n",
748		   traceCgsEnum(srcCgsId),
749		   traceCgsEnum(dstCgsId)));
750	    TRACE2(("copyCgs from %s (me %p, fg %s, bg %s, cset %s) to %s {{\n",
751		    traceCgsEnum(srcCgsId),
752		    me,
753		    tracePixel(xw, THIS(fg)),
754		    tracePixel(xw, THIS(bg)),
755		    traceCSet(THIS(cset)),
756		    traceCgsEnum(dstCgsId)));
757	    setCgsCSet(xw, cgsWin, dstCgsId, THIS(cset));
758	    setCgsFore(xw, cgsWin, dstCgsId, THIS(fg));
759	    setCgsBack(xw, cgsWin, dstCgsId, THIS(bg));
760	    setCgsFont(xw, cgsWin, dstCgsId, THIS(font));
761	    TRACE2(("...copyCgs }}\n"));
762	}
763    }
764}
765
766/*
767 * Interchange colors in the cache, e.g., for reverse-video.
768 */
769void
770redoCgs(XtermWidget xw, Pixel fg, Pixel bg, CgsEnum cgsId)
771{
772    int n;
773    VTwin *cgsWin = WhichVWin(TScreenOf(xw));
774    CgsCache *me = myCache(xw, cgsWin, cgsId);
775
776    if (me != 0) {
777	CgsCacheData *save_data = me->data;
778
779	for (n = 0; n < DEPTH; ++n) {
780	    if (LIST(n).gc != 0 && HaveFont(LIST(n).font)) {
781		LINK(n);
782
783		if (LIST(n).fg == fg
784		    && LIST(n).bg == bg) {
785		    setCgsFore(xw, cgsWin, cgsId, bg);
786		    setCgsBack(xw, cgsWin, cgsId, fg);
787		} else if (LIST(n).fg == bg
788			   && LIST(n).bg == fg) {
789		    setCgsFore(xw, cgsWin, cgsId, fg);
790		    setCgsBack(xw, cgsWin, cgsId, bg);
791		} else {
792		    continue;
793		}
794
795		(void) chgCache(xw, cgsId, me, False);
796	    }
797	}
798	me->data = save_data;
799    }
800}
801
802/*
803 * Swap the cache records, e.g., when doing reverse-video.
804 */
805void
806swapCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum dstCgsId, CgsEnum srcCgsId)
807{
808    if (dstCgsId != srcCgsId) {
809	CgsCache *dst;
810	CgsCache *src;
811	CgsCache tmp;
812
813	if ((src = myCache(xw, cgsWin, srcCgsId)) != 0) {
814	    if ((dst = myCache(xw, cgsWin, dstCgsId)) != 0) {
815		int srcIndex = dataIndex(src);
816		int dstIndex = dataIndex(dst);
817
818		EXCHANGE(*src, *dst, tmp);
819
820		relinkData(src, dstIndex);
821		relinkData(dst, srcIndex);
822	    }
823	}
824    }
825}
826
827/*
828 * Free any GC associated with the given id.
829 */
830GC
831freeCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
832{
833    CgsCache *me;
834    int j;
835
836    if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
837	for (j = 0; j < DEPTH; ++j) {
838	    if (LIST(j).gc != 0) {
839		TRACE(("freeCgs(%s, %s) gc %p(%d)\n",
840		       traceVTwin(xw, cgsWin),
841		       traceCgsEnum(cgsId), (void *) LIST(j).gc, j));
842		clrCgsFonts(xw, cgsWin, LIST(j).font);
843#if OPT_BOX_CHARS
844		if (cgsId == gcDots) {
845		    XmuReleaseStippledPixmap(XtScreen((Widget) xw), LIST(j).tile);
846		}
847#endif
848		XFreeGC(TScreenOf(xw)->display, LIST(j).gc);
849		memset(&LIST(j), 0, sizeof(LIST(j)));
850	    }
851	    LINK(0);
852	}
853    }
854    return 0;
855}
856
857#ifdef NO_LEAKS
858void
859noleaks_cachedCgs(XtermWidget xw)
860{
861#ifndef NO_ACTIVE_ICON
862    free(TScreenOf(xw)->icon_cgs_cache);
863#endif
864    free(TScreenOf(xw)->main_cgs_cache);
865}
866#endif
867