875 lines
19 KiB
C
875 lines
19 KiB
C
/* $XTermId: cachedGCs.c,v 1.75 2018/07/15 18:21:17 tom Exp $ */
|
|
|
|
/*
|
|
* Copyright 2007-2017,2018 by Thomas E. Dickey
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name(s) of the above copyright
|
|
* holders shall not be used in advertising or otherwise to promote the
|
|
* sale, use or other dealings in this Software without prior written
|
|
* authorization.
|
|
*/
|
|
|
|
#include <data.h>
|
|
#include <xstrings.h>
|
|
#include <fontutils.h>
|
|
|
|
#include <X11/Xmu/Drawing.h>
|
|
|
|
/*
|
|
* hide (or eliminate) calls to
|
|
* XCreateGC()
|
|
* XFreeGC()
|
|
* XGetGCValues()
|
|
* XSetBackground()
|
|
* XSetFont()
|
|
* XSetForeground()
|
|
* XtGetGC()
|
|
* XtReleaseGC()
|
|
* by associating an integer with each GC, maintaining a cache which
|
|
* reflects frequency of use rather than most recent usage.
|
|
*
|
|
* FIXME: XTermFonts should hold gc, font, fs.
|
|
*/
|
|
typedef struct {
|
|
GC gc;
|
|
unsigned used;
|
|
unsigned cset;
|
|
XTermFonts *font;
|
|
Pixel tile;
|
|
Pixel fg;
|
|
Pixel bg;
|
|
} CgsCacheData;
|
|
|
|
#define DEPTH 8
|
|
#define ITEM() (int) (me->data - me->list)
|
|
#define LIST(item) me->list[item]
|
|
#define LINK(item) me->data = (me->list + (item))
|
|
#define THIS(field) me->data->field
|
|
#define NEXT(field) me->next.field
|
|
|
|
#define HaveFont(font) (Boolean) ((font) != 0 && (font)->fs != 0)
|
|
|
|
#define GC_CSet GCFunction
|
|
|
|
typedef struct {
|
|
CgsCacheData list[DEPTH];
|
|
CgsCacheData *data; /* points to current list[] entry */
|
|
XtGCMask mask; /* changes since the last getCgsGC() */
|
|
CgsCacheData next; /* updated values, apply in getCgsGC() */
|
|
} CgsCache;
|
|
|
|
#if OPT_TRACE
|
|
#define CASE(name) case gc##name: result = #name; break
|
|
static const char *
|
|
traceCgsEnum(CgsEnum value)
|
|
{
|
|
const char *result = "?";
|
|
switch (value) {
|
|
CASE(Norm);
|
|
CASE(Bold);
|
|
CASE(NormReverse);
|
|
CASE(BoldReverse);
|
|
CASE(Border);
|
|
CASE(Filler);
|
|
#if OPT_BOX_CHARS
|
|
CASE(Line);
|
|
CASE(Dots);
|
|
#endif
|
|
#if OPT_DEC_CHRSET
|
|
CASE(CNorm);
|
|
CASE(CBold);
|
|
#endif
|
|
#if OPT_WIDE_CHARS
|
|
CASE(Wide);
|
|
CASE(WBold);
|
|
CASE(WideReverse);
|
|
CASE(WBoldReverse);
|
|
#endif
|
|
CASE(VTcursNormal);
|
|
CASE(VTcursFilled);
|
|
CASE(VTcursReverse);
|
|
CASE(VTcursOutline);
|
|
#if OPT_TEK4014
|
|
CASE(TKcurs);
|
|
#endif
|
|
CASE(MAX);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#undef CASE
|
|
|
|
static const char *
|
|
traceVTwin(XtermWidget xw, VTwin *value)
|
|
{
|
|
const char *result = "?";
|
|
if (value == 0)
|
|
result = "null";
|
|
else if (value == &(TScreenOf(xw)->fullVwin))
|
|
result = "fullVwin";
|
|
#ifndef NO_ACTIVE_ICON
|
|
else if (value == &(TScreenOf(xw)->iconVwin))
|
|
result = "iconVwin";
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
#if OPT_TRACE > 1
|
|
static String
|
|
traceCSet(unsigned cset)
|
|
{
|
|
static char result[80];
|
|
switch (cset) {
|
|
case CSET_SWL:
|
|
strcpy(result, "SWL");
|
|
break;
|
|
case CSET_DHL_TOP:
|
|
strcpy(result, "DHL_TOP");
|
|
break;
|
|
case CSET_DHL_BOT:
|
|
strcpy(result, "DHL_BOT");
|
|
break;
|
|
case CSET_DWL:
|
|
strcpy(result, "DWL");
|
|
break;
|
|
default:
|
|
sprintf(result, "%#x", cset);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static String
|
|
traceFont(XTermFonts * font)
|
|
{
|
|
static char result[80];
|
|
|
|
if (HaveFont(font)) {
|
|
XFontStruct *fs = font->fs;
|
|
sprintf(result, "%p(%dx%d %d %#lx)",
|
|
fs,
|
|
fs->max_bounds.width,
|
|
fs->max_bounds.ascent + fs->max_bounds.descent,
|
|
fs->max_bounds.descent,
|
|
(unsigned long) (fs->fid));
|
|
} else {
|
|
strcpy(result, "null");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static String
|
|
tracePixel(XtermWidget xw, Pixel value)
|
|
{
|
|
#define CASE(name) { name, #name }
|
|
static struct {
|
|
TermColors code;
|
|
String name;
|
|
} t_colors[] = {
|
|
CASE(TEXT_FG),
|
|
CASE(TEXT_BG),
|
|
CASE(TEXT_CURSOR),
|
|
CASE(MOUSE_FG),
|
|
CASE(MOUSE_BG),
|
|
#if OPT_TEK4014
|
|
CASE(TEK_FG),
|
|
CASE(TEK_BG),
|
|
#endif
|
|
#if OPT_HIGHLIGHT_COLOR
|
|
CASE(HIGHLIGHT_BG),
|
|
CASE(HIGHLIGHT_FG),
|
|
#endif
|
|
#if OPT_TEK4014
|
|
CASE(TEK_CURSOR),
|
|
#endif
|
|
};
|
|
TScreen *screen = TScreenOf(xw);
|
|
String result = 0;
|
|
int n;
|
|
|
|
for (n = 0; n < NCOLORS; ++n) {
|
|
if (value == T_COLOR(screen, t_colors[n].code)) {
|
|
result = t_colors[n].name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (result == 0) {
|
|
for (n = 0; n < MAXCOLORS; ++n) {
|
|
#if OPT_COLOR_RES
|
|
if (screen->Acolors[n].mode > 0
|
|
&& value == screen->Acolors[n].value) {
|
|
result = screen->Acolors[n].resource;
|
|
break;
|
|
}
|
|
#else
|
|
if (value == screen->Acolors[n]) {
|
|
char temp[80];
|
|
sprintf(temp, "Acolors[%d]", n);
|
|
result = x_strdup(temp);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (result == 0) {
|
|
char temp[80];
|
|
sprintf(temp, "%#lx", value);
|
|
result = x_strdup(temp);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#undef CASE
|
|
|
|
#endif /* OPT_TRACE > 1 */
|
|
#endif /* OPT_TRACE */
|
|
|
|
static CgsCache *
|
|
allocCache(void **cache_pointer)
|
|
{
|
|
if (*cache_pointer == 0) {
|
|
*cache_pointer = TypeCallocN(CgsCache, gcMAX);
|
|
TRACE(("allocCache %p\n", *cache_pointer));
|
|
}
|
|
return *((CgsCache **) cache_pointer);
|
|
}
|
|
|
|
#define ALLOC_CACHE(p) ((*(p) == 0) ? allocCache(p) : *(p))
|
|
|
|
static int
|
|
dataIndex(CgsCache * me)
|
|
{
|
|
return ITEM();
|
|
}
|
|
|
|
static void
|
|
relinkData(CgsCache * me, int item)
|
|
{
|
|
LINK(item);
|
|
}
|
|
|
|
/*
|
|
* Returns the appropriate cache pointer.
|
|
*/
|
|
static CgsCache *
|
|
myCache(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
|
|
{
|
|
CgsCache *result = 0;
|
|
|
|
if ((int) cgsId >= 0 && cgsId < gcMAX) {
|
|
#ifdef NO_ACTIVE_ICON
|
|
(void) xw;
|
|
(void) cgsWin;
|
|
#else
|
|
if (cgsWin == &(TScreenOf(xw)->iconVwin))
|
|
result = ALLOC_CACHE(&(TScreenOf(xw)->icon_cgs_cache));
|
|
else
|
|
#endif
|
|
result = ALLOC_CACHE(&(TScreenOf(xw)->main_cgs_cache));
|
|
|
|
result += cgsId;
|
|
if (result->data == 0) {
|
|
result->data = result->list;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static Display *
|
|
myDisplay(XtermWidget xw)
|
|
{
|
|
return TScreenOf(xw)->display;
|
|
}
|
|
|
|
static Drawable
|
|
myDrawable(XtermWidget xw, VTwin *cgsWin)
|
|
{
|
|
Drawable drawable = 0;
|
|
|
|
if (cgsWin != 0 && cgsWin->window != 0)
|
|
drawable = cgsWin->window;
|
|
if (drawable == 0)
|
|
drawable = RootWindowOfScreen(XtScreen(xw));
|
|
return drawable;
|
|
}
|
|
|
|
static GC
|
|
newCache(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, CgsCache * me)
|
|
{
|
|
XGCValues xgcv;
|
|
XtGCMask mask;
|
|
|
|
THIS(font) = NEXT(font);
|
|
THIS(cset) = NEXT(cset);
|
|
THIS(fg) = NEXT(fg);
|
|
THIS(bg) = NEXT(bg);
|
|
|
|
memset(&xgcv, 0, sizeof(xgcv));
|
|
xgcv.font = NEXT(font)->fs->fid;
|
|
mask = (GCForeground | GCBackground | GCFont);
|
|
|
|
switch (cgsId) {
|
|
case gcFiller:
|
|
case gcBorder:
|
|
mask &= (XtGCMask) ~ GCFont;
|
|
/* FALLTHRU */
|
|
case gcNorm:
|
|
case gcBold:
|
|
case gcNormReverse:
|
|
case gcBoldReverse:
|
|
#if OPT_WIDE_CHARS
|
|
case gcWide:
|
|
case gcWBold:
|
|
case gcWideReverse:
|
|
case gcWBoldReverse:
|
|
#endif
|
|
mask |= (GCGraphicsExposures | GCFunction);
|
|
xgcv.graphics_exposures = True; /* default */
|
|
xgcv.function = GXcopy;
|
|
break;
|
|
#if OPT_BOX_CHARS
|
|
case gcLine:
|
|
mask |= (GCGraphicsExposures | GCFunction);
|
|
xgcv.graphics_exposures = True; /* default */
|
|
xgcv.function = GXcopy;
|
|
break;
|
|
case gcDots:
|
|
xgcv.fill_style = FillTiled;
|
|
xgcv.tile =
|
|
XmuCreateStippledPixmap(XtScreen((Widget) xw),
|
|
THIS(fg),
|
|
THIS(bg),
|
|
xw->core.depth);
|
|
THIS(tile) = xgcv.tile;
|
|
mask = (GCForeground | GCBackground);
|
|
mask |= (GCGraphicsExposures | GCFunction | GCTile | GCFillStyle);
|
|
xgcv.graphics_exposures = True; /* default */
|
|
xgcv.function = GXcopy;
|
|
break;
|
|
#endif
|
|
#if OPT_DEC_CHRSET
|
|
case gcCNorm:
|
|
case gcCBold:
|
|
break;
|
|
#endif
|
|
case gcVTcursNormal: /* FALLTHRU */
|
|
case gcVTcursFilled: /* FALLTHRU */
|
|
case gcVTcursReverse: /* FALLTHRU */
|
|
case gcVTcursOutline: /* FALLTHRU */
|
|
break;
|
|
#if OPT_TEK4014
|
|
case gcTKcurs: /* FALLTHRU */
|
|
/* FIXME */
|
|
#endif
|
|
case gcMAX: /* should not happen */
|
|
return 0;
|
|
}
|
|
xgcv.foreground = NEXT(fg);
|
|
xgcv.background = NEXT(bg);
|
|
|
|
THIS(gc) = XCreateGC(myDisplay(xw), myDrawable(xw, cgsWin), mask, &xgcv);
|
|
TRACE(("getCgsGC(%s) created gc %p(%d)\n",
|
|
traceCgsEnum(cgsId), (void *) THIS(gc), ITEM()));
|
|
|
|
THIS(used) = 0;
|
|
return THIS(gc);
|
|
}
|
|
|
|
#define SameFont(a, b) \
|
|
(Boolean) (HaveFont(a) \
|
|
&& HaveFont(b) \
|
|
&& (((a)->fs == (b)->fs) \
|
|
|| !memcmp((a)->fs, (b)->fs, sizeof(*((a)->fs)))))
|
|
|
|
#define SameColor(a,b) ((a) == (b))
|
|
#define SameCSet(a,b) ((a) == (b))
|
|
|
|
static GC
|
|
chgCache(XtermWidget xw, CgsEnum cgsId GCC_UNUSED, CgsCache * me, Bool both)
|
|
{
|
|
XGCValues xgcv;
|
|
XtGCMask mask = (GCForeground | GCBackground | GCFont);
|
|
|
|
memset(&xgcv, 0, sizeof(xgcv));
|
|
|
|
TRACE2(("chgCache(%s) old data fg=%s, bg=%s, font=%s cset %s\n",
|
|
traceCgsEnum(cgsId),
|
|
tracePixel(xw, THIS(fg)),
|
|
tracePixel(xw, THIS(bg)),
|
|
traceFont(THIS(font)),
|
|
traceCSet(THIS(cset))));
|
|
#if OPT_TRACE > 1
|
|
if (!SameFont(THIS(font), NEXT(font)))
|
|
TRACE2(("...chgCache new font=%s\n", traceFont(NEXT(font))));
|
|
if (!SameCSet(THIS(cset), NEXT(cset)))
|
|
TRACE2(("...chgCache new cset=%s\n", traceCSet(NEXT(cset))));
|
|
if (!SameColor(THIS(fg), NEXT(fg)))
|
|
TRACE2(("...chgCache new fg=%s\n", tracePixel(xw, NEXT(fg))));
|
|
if (!SameColor(THIS(bg), NEXT(bg)))
|
|
TRACE2(("...chgCache new bg=%s\n", tracePixel(xw, NEXT(bg))));
|
|
#endif
|
|
|
|
if (both) {
|
|
THIS(font) = NEXT(font);
|
|
THIS(cset) = NEXT(cset);
|
|
}
|
|
THIS(fg) = NEXT(fg);
|
|
THIS(bg) = NEXT(bg);
|
|
|
|
xgcv.font = THIS(font)->fs->fid;
|
|
xgcv.foreground = THIS(fg);
|
|
xgcv.background = THIS(bg);
|
|
|
|
XChangeGC(myDisplay(xw), THIS(gc), mask, &xgcv);
|
|
TRACE2(("...chgCache(%s) updated gc %p(%d)\n",
|
|
traceCgsEnum(cgsId), THIS(gc), ITEM()));
|
|
|
|
THIS(used) = 0;
|
|
return THIS(gc);
|
|
}
|
|
|
|
/*
|
|
* Use the "setCgsXXXX()" calls to initialize parameters for a new GC.
|
|
*/
|
|
void
|
|
setCgsFore(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel fg)
|
|
{
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
|
|
NEXT(fg) = fg;
|
|
me->mask |= GCForeground;
|
|
}
|
|
}
|
|
|
|
void
|
|
setCgsBack(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, Pixel bg)
|
|
{
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
|
|
NEXT(bg) = bg;
|
|
me->mask |= GCBackground;
|
|
}
|
|
}
|
|
|
|
#if OPT_DEC_CHRSET
|
|
void
|
|
setCgsCSet(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, unsigned cset)
|
|
{
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
|
|
NEXT(cset) = cset;
|
|
me->mask |= GC_CSet;
|
|
}
|
|
}
|
|
#else
|
|
#define setCgsCSet(xw, cgsWin, dstCgsId, cset) /* nothing */
|
|
#endif
|
|
|
|
void
|
|
setCgsFont(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId, XTermFonts * font)
|
|
{
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
|
|
TScreen *screen = TScreenOf(xw);
|
|
if (!HaveFont(font)) {
|
|
if (cgsId != gcNorm)
|
|
(void) getCgsGC(xw, cgsWin, gcNorm);
|
|
#ifndef NO_ACTIVE_ICON
|
|
if (cgsWin == &(TScreenOf(xw)->iconVwin))
|
|
font = getIconicFont(screen);
|
|
else
|
|
#endif
|
|
font = GetNormalFont(screen, fNorm);
|
|
}
|
|
if (HaveFont(font) && okFont(font->fs)) {
|
|
TRACE2(("setCgsFont next: %s for %s slot %p, gc %p\n",
|
|
traceFont(font), traceCgsEnum(cgsId),
|
|
me, THIS(gc)));
|
|
TRACE2(("...next font was %s\n", traceFont(NEXT(font))));
|
|
NEXT(font) = font;
|
|
me->mask |= GCFont;
|
|
} else {
|
|
/* EMPTY */
|
|
TRACE2(("...NOT updated font for %s\n",
|
|
traceCgsEnum(cgsId)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Discard all of the font information, e.g., we are resizing the font.
|
|
* Keep the GC's so we can simply change them rather than creating new ones.
|
|
*/
|
|
void
|
|
clrCgsFonts(XtermWidget xw, VTwin *cgsWin, XTermFonts * font)
|
|
{
|
|
if (HaveFont(font)) {
|
|
int j;
|
|
for_each_gc(j) {
|
|
CgsCache *me;
|
|
if ((me = myCache(xw, cgsWin, (CgsEnum) j)) != 0) {
|
|
int k;
|
|
for (k = 0; k < DEPTH; ++k) {
|
|
if (SameFont(LIST(k).font, font)) {
|
|
TRACE2(("clrCgsFonts %s gc %p(%d) %s\n",
|
|
traceCgsEnum((CgsEnum) j),
|
|
LIST(k).gc,
|
|
k,
|
|
traceFont(font)));
|
|
LIST(k).font = 0;
|
|
LIST(k).cset = 0;
|
|
}
|
|
}
|
|
if (SameFont(NEXT(font), font)) {
|
|
TRACE2(("clrCgsFonts %s next %s\n",
|
|
traceCgsEnum((CgsEnum) j),
|
|
traceFont(font)));
|
|
NEXT(font) = 0;
|
|
NEXT(cset) = 0;
|
|
me->mask &= (unsigned) ~(GCFont | GC_CSet);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return a GC associated with the given id, allocating if needed.
|
|
*/
|
|
GC
|
|
getCgsGC(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
|
|
{
|
|
CgsCache *me;
|
|
GC result = 0;
|
|
|
|
if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
|
|
TRACE2(("getCgsGC(%s, %s)\n",
|
|
traceVTwin(xw, cgsWin), traceCgsEnum(cgsId)));
|
|
if (me->mask != 0) {
|
|
int j;
|
|
unsigned used = 0;
|
|
|
|
/* fill in the unchanged fields */
|
|
if (!(me->mask & GC_CSet))
|
|
NEXT(cset) = 0; /* OPT_DEC_CHRSET */
|
|
if (!(me->mask & GCFont))
|
|
NEXT(font) = THIS(font);
|
|
if (!(me->mask & GCForeground))
|
|
NEXT(fg) = THIS(fg);
|
|
if (!(me->mask & GCBackground))
|
|
NEXT(bg) = THIS(bg);
|
|
|
|
if (NEXT(font) == 0) {
|
|
setCgsFont(xw, cgsWin, cgsId, 0);
|
|
}
|
|
|
|
TRACE2(("...Cgs new data fg=%s, bg=%s, font=%s cset %s\n",
|
|
tracePixel(xw, NEXT(fg)),
|
|
tracePixel(xw, NEXT(bg)),
|
|
traceFont(NEXT(font)),
|
|
traceCSet(NEXT(cset))));
|
|
|
|
/* try to find the given data in an already-created GC */
|
|
for (j = 0; j < DEPTH; ++j) {
|
|
if (LIST(j).gc != 0
|
|
&& SameFont(LIST(j).font, NEXT(font))
|
|
&& SameCSet(LIST(j).cset, NEXT(cset))
|
|
&& SameColor(LIST(j).fg, NEXT(fg))
|
|
&& SameColor(LIST(j).bg, NEXT(bg))) {
|
|
LINK(j);
|
|
result = THIS(gc);
|
|
TRACE2(("getCgsGC existing %p(%d)\n", result, ITEM()));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (result == 0) {
|
|
/* try to find an empty slot, to create a new GC */
|
|
used = 0;
|
|
for (j = 0; j < DEPTH; ++j) {
|
|
if (LIST(j).gc == 0) {
|
|
LINK(j);
|
|
result = newCache(xw, cgsWin, cgsId, me);
|
|
break;
|
|
}
|
|
if (used < LIST(j).used)
|
|
used = LIST(j).used;
|
|
}
|
|
}
|
|
|
|
if (result == 0) {
|
|
int k;
|
|
/* if none were empty, pick the least-used slot, to modify */
|
|
for (j = 0, k = -1; j < DEPTH; ++j) {
|
|
if (used >= LIST(j).used) {
|
|
used = LIST(j).used;
|
|
k = j;
|
|
}
|
|
}
|
|
LINK(k);
|
|
TRACE2(("...getCgsGC least-used(%d) was %d\n", k, THIS(used)));
|
|
result = chgCache(xw, cgsId, me, True);
|
|
}
|
|
me->next = *(me->data);
|
|
} else {
|
|
result = THIS(gc);
|
|
}
|
|
me->mask = 0;
|
|
THIS(used) += 1;
|
|
TRACE2(("...getCgsGC(%s, %s) gc %p(%d), used %d\n",
|
|
traceVTwin(xw, cgsWin),
|
|
traceCgsEnum(cgsId), result, ITEM(), THIS(used)));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Return the font for the given GC.
|
|
*/
|
|
CgsEnum
|
|
getCgsId(XtermWidget xw, VTwin *cgsWin, GC gc)
|
|
{
|
|
int n;
|
|
CgsEnum result = gcNorm;
|
|
|
|
for_each_gc(n) {
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
|
|
if (THIS(gc) == gc) {
|
|
result = (CgsEnum) n;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Return the font for the given GC.
|
|
*/
|
|
XTermFonts *
|
|
getCgsFont(XtermWidget xw, VTwin *cgsWin, GC gc)
|
|
{
|
|
int n;
|
|
XTermFonts *result = 0;
|
|
|
|
for_each_gc(n) {
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
|
|
if (THIS(gc) == gc) {
|
|
result = THIS(font);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Return the foreground color for the given GC.
|
|
*/
|
|
Pixel
|
|
getCgsFore(XtermWidget xw, VTwin *cgsWin, GC gc)
|
|
{
|
|
int n;
|
|
Pixel result = 0;
|
|
|
|
for_each_gc(n) {
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
|
|
if (THIS(gc) == gc) {
|
|
result = THIS(fg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Return the background color for the given GC.
|
|
*/
|
|
Pixel
|
|
getCgsBack(XtermWidget xw, VTwin *cgsWin, GC gc)
|
|
{
|
|
int n;
|
|
Pixel result = 0;
|
|
|
|
for_each_gc(n) {
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, (CgsEnum) n)) != 0) {
|
|
if (THIS(gc) == gc) {
|
|
result = THIS(bg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Copy the parameters (except GC of course) from one cache record to another.
|
|
*/
|
|
void
|
|
copyCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum dstCgsId, CgsEnum srcCgsId)
|
|
{
|
|
if (dstCgsId != srcCgsId) {
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, srcCgsId)) != 0) {
|
|
TRACE(("copyCgs from %s to %s\n",
|
|
traceCgsEnum(srcCgsId),
|
|
traceCgsEnum(dstCgsId)));
|
|
TRACE2(("copyCgs from %s (me %p, fg %s, bg %s, cset %s) to %s {{\n",
|
|
traceCgsEnum(srcCgsId),
|
|
me,
|
|
tracePixel(xw, THIS(fg)),
|
|
tracePixel(xw, THIS(bg)),
|
|
traceCSet(THIS(cset)),
|
|
traceCgsEnum(dstCgsId)));
|
|
setCgsCSet(xw, cgsWin, dstCgsId, THIS(cset));
|
|
setCgsFore(xw, cgsWin, dstCgsId, THIS(fg));
|
|
setCgsBack(xw, cgsWin, dstCgsId, THIS(bg));
|
|
setCgsFont(xw, cgsWin, dstCgsId, THIS(font));
|
|
TRACE2(("...copyCgs }}\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Interchange colors in the cache, e.g., for reverse-video.
|
|
*/
|
|
void
|
|
redoCgs(XtermWidget xw, Pixel fg, Pixel bg, CgsEnum cgsId)
|
|
{
|
|
VTwin *cgsWin = WhichVWin(TScreenOf(xw));
|
|
CgsCache *me = myCache(xw, cgsWin, cgsId);
|
|
|
|
if (me != 0) {
|
|
CgsCacheData *save_data = me->data;
|
|
int n;
|
|
|
|
for (n = 0; n < DEPTH; ++n) {
|
|
if (LIST(n).gc != 0 && HaveFont(LIST(n).font)) {
|
|
LINK(n);
|
|
|
|
if (LIST(n).fg == fg
|
|
&& LIST(n).bg == bg) {
|
|
setCgsFore(xw, cgsWin, cgsId, bg);
|
|
setCgsBack(xw, cgsWin, cgsId, fg);
|
|
} else if (LIST(n).fg == bg
|
|
&& LIST(n).bg == fg) {
|
|
setCgsFore(xw, cgsWin, cgsId, fg);
|
|
setCgsBack(xw, cgsWin, cgsId, bg);
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
(void) chgCache(xw, cgsId, me, False);
|
|
}
|
|
}
|
|
me->data = save_data;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Swap the cache records, e.g., when doing reverse-video.
|
|
*/
|
|
void
|
|
swapCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum dstCgsId, CgsEnum srcCgsId)
|
|
{
|
|
if (dstCgsId != srcCgsId) {
|
|
CgsCache *src;
|
|
|
|
if ((src = myCache(xw, cgsWin, srcCgsId)) != 0) {
|
|
CgsCache *dst;
|
|
|
|
if ((dst = myCache(xw, cgsWin, dstCgsId)) != 0) {
|
|
CgsCache tmp;
|
|
int srcIndex = dataIndex(src);
|
|
int dstIndex = dataIndex(dst);
|
|
|
|
EXCHANGE(*src, *dst, tmp);
|
|
|
|
relinkData(src, dstIndex);
|
|
relinkData(dst, srcIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free any GC associated with the given id.
|
|
*/
|
|
GC
|
|
freeCgs(XtermWidget xw, VTwin *cgsWin, CgsEnum cgsId)
|
|
{
|
|
CgsCache *me;
|
|
|
|
if ((me = myCache(xw, cgsWin, cgsId)) != 0) {
|
|
int j;
|
|
|
|
for (j = 0; j < DEPTH; ++j) {
|
|
if (LIST(j).gc != 0) {
|
|
TRACE(("freeCgs(%s, %s) gc %p(%d)\n",
|
|
traceVTwin(xw, cgsWin),
|
|
traceCgsEnum(cgsId), (void *) LIST(j).gc, j));
|
|
clrCgsFonts(xw, cgsWin, LIST(j).font);
|
|
#if OPT_BOX_CHARS
|
|
if (cgsId == gcDots) {
|
|
XmuReleaseStippledPixmap(XtScreen((Widget) xw), LIST(j).tile);
|
|
}
|
|
#endif
|
|
XFreeGC(TScreenOf(xw)->display, LIST(j).gc);
|
|
memset(&LIST(j), 0, sizeof(LIST(j)));
|
|
}
|
|
LINK(0);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef NO_LEAKS
|
|
void
|
|
noleaks_cachedCgs(XtermWidget xw)
|
|
{
|
|
#ifndef NO_ACTIVE_ICON
|
|
free(TScreenOf(xw)->icon_cgs_cache);
|
|
#endif
|
|
free(TScreenOf(xw)->main_cgs_cache);
|
|
}
|
|
#endif
|