2025-08-08 20:00:36 +02:00

1753 lines
48 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
/* */
/* NXAGENT, NX protocol compression and NX extensions to this software */
/* are copyright of the aforementioned persons and companies. */
/* */
/* Redistribution and use of the present software is allowed according */
/* to terms specified in the file LICENSE which comes in the source */
/* distribution. */
/* */
/* All rights reserved. */
/* */
/* NOTE: This software has received contributions from various other */
/* contributors, only the core maintainers and supporters are listed as */
/* copyright holders. Please contact us, if you feel you should be listed */
/* as copyright holder, as well. */
/* */
/**************************************************************************/
/*
Copyright 1993 by Davor Matic
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation. Davor Matic makes no representations about
the suitability of this software for any purpose. It is provided "as
is" without express or implied warranty.
*/
#include "scrnintstr.h"
#include "dixstruct.h"
#include <X11/fonts/font.h>
#include <X11/fonts/fontstruct.h>
#include "dixfontstr.h"
#include "misc.h"
#include "miscstruct.h"
#include "opaque.h"
#include "Agent.h"
#include "Display.h"
#include "Font.h"
#include "Error.h"
#include <stdio.h>
#include <sys/stat.h>
#include "resource.h"
#include "Reconnect.h"
#include "Args.h"
#include "Utils.h"
#include "compext/Compext.h"
#include <nx/NXalert.h>
#include <string.h>
#include <stdlib.h>
#define PANIC
#define WARNING
#undef TEST
#undef DEBUG
const char * nxagentFontDirs[] = {
SYSTEMFONTDIR,
"/usr/share/nx/fonts",
"/usr/share/X11/fonts",
"/usr/share/fonts/X11",
"/usr/X11R6/lib/X11/fonts",
NULL
};
const char * nxagentFontSubdirs[] = {
"Type1",
"75dpi",
"100dpi",
"TTF",
NULL
};
#undef NXAGENT_FONTCACHE_DEBUG
#undef NXAGENT_RECONNECT_FONT_DEBUG
#undef NXAGENT_FONTMATCH_DEBUG
#define FIELDS 14
static int reconnectFlexibility;
static void nxagentCleanCacheAfterReconnect(void);
static void nxagentFontReconnect(FontPtr, XID, void *);
static XFontStruct *nxagentLoadBestQueryFont(Display* dpy, char *fontName, FontPtr pFont);
static XFontStruct *nxagentLoadQueryFont(register Display *dpy , char *fontName , FontPtr pFont);
int nxagentFreeFont(XFontStruct *fs);
static Bool nxagentGetFontServerPath(char * fontServerPath, int size);
static char * nxagentMakeScalableFontName(const char *fontName, Bool scalableResolution);
RESTYPE RT_NX_FONT;
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
static void printFontCacheDump(char*);
#endif
typedef struct _nxagentFontRec
{
char *name;
int status;
} nxagentFontRec, *nxagentFontRecPtr;
typedef struct _nxagentFontList
{
nxagentFontRecPtr *list;
int length;
int listSize;
} nxagentFontList, *nxagentFontListPtr;
nxagentFontList nxagentRemoteFontList = {NULL, (int)0, (int)0};
int nxagentFontPrivateIndex;
typedef struct _nxCacheFontEntry
{
Atom atom;
XFontStruct *font_struct;
char *name;
} nxCacheFontEntryRec, *nxCacheFontEntryRecPtr;
static struct _nxagentFontCache
{
nxCacheFontEntryRecPtr *entry;
int index;
int size;
} nxagentFontCache = { NULL, (int) 0, (int) 0 };
#define CACHE_ENTRY_PTR (nxagentFontCache.entry)
#define CACHE_INDEX (nxagentFontCache.index)
#define CACHE_SIZE (nxagentFontCache.size)
#define CACHE_ENTRY(A) (CACHE_ENTRY_PTR[A])
#define CACHE_FSTRUCT(A) (CACHE_ENTRY(A) -> font_struct)
#define CACHE_NAME(A) (CACHE_ENTRY(A) -> name)
#define CACHE_ATOM(A) (CACHE_ENTRY(A) -> atom)
static struct _nxagentFailedToReconnectFonts
{
FontPtr *font;
XID *id;
int size;
int index;
} nxagentFailedToReconnectFonts = {NULL, NULL, 0, 0};
static void nxagentFreeRemoteFontList(nxagentFontList *listRec);
void nxagentFreeFontData(void)
{
nxagentFreeFontCache();
nxagentFreeRemoteFontList(&nxagentRemoteFontList);
}
/*
* This is used if nxagentFullGeneration is true in CloseDisplay().
*/
void nxagentFreeFontCache(void)
{
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: Freeing nxagent font cache\n");
#endif
if (CACHE_INDEX == 0)
return;
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: Freeing nxagent font cache, there are [%d] entries.\n", CACHE_INDEX);
#endif
for (int i = 0; i < CACHE_INDEX; i++)
{
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: Freeing nxagent font cache entry [%d] entry pointer is [%p], name [%s]\n",
i, CACHE_ENTRY(i), CACHE_NAME(i));
#endif
if (CACHE_FSTRUCT(i))
{
nxagentFreeFont(CACHE_FSTRUCT(i));
}
SAFE_free(CACHE_NAME(i));
SAFE_free(CACHE_ENTRY(i));
}
SAFE_free(CACHE_ENTRY_PTR);
CACHE_INDEX = 0;
CACHE_SIZE = 0;
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: nxagent font cache fully freed\n");
#endif
return;
}
void nxagentListRemoteFonts(const char *searchPattern, const int maxNames)
{
if (NXDisplayError(nxagentDisplay) == 1)
{
return;
}
/*
* Avoid querying again the remote fonts.
*/
if (nxagentRemoteFontList.length > 0)
{
return;
}
/*
* We can't retrieve the full remote font list with a single query,
* because the number of dashes in the pattern acts as a rule to
* select how to search for the font names, so the pattern '*' is
* useful to retrieve the font aliases, while the other one will
* select the 'real' fonts.
*/
const char *patterns[] = {"*", "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"};
const int numPatterns = 2;
for (int p = 0; p < numPatterns; p++)
{
int xLen = 0;
char **xList = XListFonts(nxagentDisplay, patterns[p], maxNames, &xLen);
#ifdef NXAGENT_FONTMATCH_DEBUG
fprintf(stderr, "nxagentListRemoteFonts: NXagent remote list [%s] has %d elements.\n", patterns[p], xLen);
#endif
/*
* Add the ListFont request pattern to the list with the last
* requested maxnames.
*/
nxagentListRemoteAddName(searchPattern, maxNames);
for (int i = 0; i < xLen; i++)
{
nxagentListRemoteAddName(xList[i], 1);
}
XFreeFontNames(xList);
}
#ifdef NXAGENT_FONTMATCH_DEBUG
fprintf(stderr, "nxagentListRemoteFonts: Printing remote font list.\n");
for (int i = 0; i < nxagentRemoteFontList.length; i++)
{
fprintf(stderr, "Font# %d, \"%s\"\n", i, nxagentRemoteFontList.list[i]->name);
}
fprintf(stderr, "nxagentListRemoteFonts: End of list\n");
#endif
}
void nxagentListRemoteAddName(const char *name, int status)
{
int pos;
if (nxagentFontFind(name, &pos))
{
if (nxagentRemoteFontList.list[pos]->status < status)
{
nxagentRemoteFontList.list[pos]->status = status;
#ifdef NXAGENT_FONTMATCH_DEBUG
fprintf(stderr, "Font: Font# %d, [%s] change status to %s\n",
pos, nxagentRemoteFontList.list[pos]->name,
nxagentRemoteFontList.list[pos]->status ? "OK" : "deleted");
#endif
}
return;
}
if (nxagentRemoteFontList.length == nxagentRemoteFontList.listSize)
{
int num = nxagentRemoteFontList.listSize + 1000;
nxagentFontRecPtr *tmp1 = realloc(nxagentRemoteFontList.list, sizeof(nxagentFontRecPtr) * num);
if (tmp1 == NULL)
{
FatalError("Font: remote list memory re-allocation failed!.\n");
}
nxagentRemoteFontList.list = tmp1;
nxagentRemoteFontList.listSize = num;
}
if (pos < nxagentRemoteFontList.length)
{
#ifdef NXAGENT_FONTMATCH_DEBUG
fprintf(stderr, "Font: Going to move list from %p to %p len = %d!.\n",
&nxagentRemoteFontList.list[pos], &nxagentRemoteFontList.list[pos+1],
(nxagentRemoteFontList.length - pos) * sizeof(nxagentFontRecPtr));
#endif
memmove(&nxagentRemoteFontList.list[pos+1],
&nxagentRemoteFontList.list[pos],
(nxagentRemoteFontList.length - pos) * sizeof(nxagentFontRecPtr));
}
if ((nxagentRemoteFontList.list[pos] = malloc(sizeof(nxagentFontRec))))
{
nxagentRemoteFontList.list[pos]->name = strdup(name);
if (nxagentRemoteFontList.list[pos]->name == NULL)
{
fprintf(stderr, "Font: remote list name memory allocation failed!.\n");
SAFE_free(nxagentRemoteFontList.list[pos]);
return;
}
}
else
{
fprintf(stderr, "Font: remote list record memory allocation failed!.\n");
return;
}
nxagentRemoteFontList.list[pos]->status = status;
nxagentRemoteFontList.length++;
#ifdef NXAGENT_FONTMATCH_DEBUG
fprintf(stderr, "Font: remote font list added [%s] in position [%d] as %s !.\n",
name, pos, status ? "OK" : "deleted");
fprintf(stderr, "Font: remote font list total len is [%d] Size is [%d] !.\n",
nxagentRemoteFontList.length, nxagentRemoteFontList.listSize);
#endif
}
static void nxagentFreeRemoteFontList(nxagentFontList *listRec)
{
for (int l = 0; l < listRec -> length; l++)
{
if (listRec -> list[l])
{
SAFE_free(listRec -> list[l] -> name);
SAFE_free(listRec -> list[l]);
}
}
listRec -> length = listRec -> listSize = 0;
SAFE_free(listRec -> list);
return;
}
Bool nxagentFontFind(const char *name, int *pos)
{
if (!nxagentRemoteFontList.length)
{
*pos=0;
return False;
}
int low = 0;
int high = nxagentRemoteFontList.length - 1;
int iter = 0;
int res = 1;
int lpos = nxagentRemoteFontList.length;
while (low <= high)
{
*pos = (high + low)/2;
iter ++;
res = strcasecmp(nxagentRemoteFontList.list[*pos]->name,name);
if (res > 0)
{
high = *pos - 1;
lpos = *pos;
continue;
}
else if (res < 0)
{
low = *pos + 1;
lpos = low;
continue;
}
break;
}
*pos = (res == 0) ? *pos : lpos;
#ifdef NXAGENT_FONTMATCH_DEBUG
if (res == 0)
fprintf(stderr, "Font: font found in %d iterations in pos = %d\n", iter, *pos);
else
fprintf(stderr, "Font: not font found in %d iterations insertion pos is = %d\n", iter, *pos);
#endif
return (res == 0);
}
Bool nxagentFontLookUp(const char *name)
{
int i;
if (name && strlen(name) == 0)
{
return False;
}
Bool result = nxagentFontFind(name, &i);
char *scalable = NULL;
/*
* Let's try with the scalable font description.
*/
if (!result)
{
if ((scalable = nxagentMakeScalableFontName(name, False)) != NULL)
{
result = nxagentFontFind(scalable, &i);
SAFE_free(scalable);
}
}
/*
* Let's try again after replacing zero to xdpi and ydpi in the pattern.
*/
if (!result)
{
if ((scalable = nxagentMakeScalableFontName(name, True)) != NULL)
{
result = nxagentFontFind(scalable, &i);
SAFE_free(scalable);
}
}
if (!result)
{
return False;
}
else
{
return (nxagentRemoteFontList.list[i]->status > 0);
}
}
/*
* NXAGENT uses useless screen pointer to pass the original font name
* to realizeFont, could be a source of problems in the future.
*/
Bool nxagentRealizeFont(ScreenPtr pScreen, FontPtr pFont)
{
#ifdef HAS_XFONT2
xfont2_font_set_private(pFont, nxagentFontPrivateIndex, NULL);
#else
FontSetPrivate(pFont, nxagentFontPrivateIndex, NULL);
#endif /* HAS_XFONT2 */
Atom name_atom = MakeAtom("FONT", 4, True);
Atom value_atom = 0L;
int nprops = pFont->info.nprops;
FontPropPtr props = pFont->info.props;
for (int i = 0; i < nprops; i++)
{
if ((Atom)props[i].name == name_atom)
{
value_atom = props[i].value;
break;
}
}
if (!value_atom)
return False;
const char *name = NameForAtom(value_atom);
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: nxagentRealizeFont, realizing font: %s\n", validateString(name));
fprintf(stderr, " atom: %ld\n", value_atom);
fprintf(stderr, "Font: Cache dump:\n");
for (int i = 0; i < CACHE_INDEX; i++)
{
fprintf(stderr, "nxagentFontCache.entry[%d]->name: %s font_struct at %p\n",
i, CACHE_NAME(i), CACHE_FSTRUCT(i));
}
#endif
if (!name)
return False;
char *origName = (char*) pScreen;
if ((strcasecmp(origName, name) != 0) && !strchr(origName,'*'))
{
#ifdef NXAGENT_FONTMATCH_DEBUG
fprintf(stderr, "Font: Changing font name to realize from [%s] to [%s]\n",
validateString(name), origName);
#endif
name = origName;
}
void *priv = (void *)malloc(sizeof(nxagentPrivFont));
#ifdef HAS_XFONT2
xfont2_font_set_private(pFont, nxagentFontPrivateIndex, priv);
#else
FontSetPrivate(pFont, nxagentFontPrivateIndex, priv);
#endif /* HAS_XFONT2 */
nxagentFontPriv(pFont) -> mirrorID = 0;
int fci;
for (fci = 0; fci < nxagentFontCache.index; fci++)
{
/* if (value_atom == CACHE_ATOM(i))*/
if (strcasecmp(CACHE_NAME(fci), name) == 0)
{
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: nxagentFontCache hit [%s] = [%s]!\n", CACHE_NAME(fci), validateString(name));
#endif
break;
}
}
if (fci < CACHE_INDEX)
{
nxagentFontPriv(pFont)->font_struct = CACHE_FSTRUCT(fci);
strcpy(nxagentFontPriv(pFont)->fontName, name);
}
else
{
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: nxagentFontCache fail.\n");
#endif
if (CACHE_INDEX == CACHE_SIZE)
{
int num = CACHE_SIZE + 100;
nxCacheFontEntryRecPtr *tmp1 = realloc(CACHE_ENTRY_PTR,
sizeof(nxCacheFontEntryRecPtr) * num);
if (tmp1 == NULL)
{
FatalError("Font: Cache list memory re-allocation failed.\n");
}
CACHE_ENTRY_PTR = tmp1;
CACHE_SIZE = num;
}
CACHE_ENTRY(CACHE_INDEX) = malloc(sizeof(nxCacheFontEntryRec));
if (CACHE_ENTRY(CACHE_INDEX) == NULL)
{
return False;
}
CACHE_NAME(CACHE_INDEX) = malloc(strlen(name) + 1);
if (CACHE_NAME(CACHE_INDEX) == NULL)
{
return False;
}
#ifdef NXAGENT_FONTMATCH_DEBUG
fprintf(stderr, "Font: Going to realize font [%s],[%s] on real X server.\n", validateString(name), origName);
#endif
if (nxagentRemoteFontList.length == 0 && (NXDisplayError(nxagentDisplay) == 0))
{
nxagentListRemoteFonts("*", nxagentMaxFontNames);
}
nxagentFontPriv(pFont)->font_struct = nxagentLoadQueryFont(nxagentDisplay, (char *)name, pFont);
strcpy(nxagentFontPriv(pFont)->fontName, name);
if (nxagentFontPriv(pFont)->font_struct != NULL)
{
CACHE_ATOM(fci) = value_atom;
strcpy(CACHE_NAME(fci), name);
CACHE_FSTRUCT(fci) = nxagentFontPriv(pFont)->font_struct;
CACHE_INDEX++;
nxagentFontPriv(pFont) -> mirrorID = FakeClientID(serverClient -> index);
AddResource(nxagentFontPriv(pFont) -> mirrorID, RT_NX_FONT, pFont);
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "Font: nxagentFontCache adds font [%s] in pos. [%d].\n",
validateString(name), CACHE_INDEX - 1);
#endif
}
}
#ifdef NXAGENT_FONTMATCH_DEBUG
if (nxagentFontPriv(pFont)->font_struct == NULL)
{
if (!nxagentFontLookUp(name))
{
fprintf(stderr, "Font: nxagentRealizeFont failed with font Font=%s, not in our remote list\n",
validateString(name));
}
else
{
fprintf(stderr, "Font: nxagentRealizeFont failed with font Font=%s but the font is in our remote list\n",
validateString(name));
}
}
else
{
fprintf(stderr, "Font: nxagentRealizeFont OK realizing font Font=%s\n",
validateString(name));
}
#endif
return (nxagentFontPriv(pFont)->font_struct != NULL);
}
Bool nxagentUnrealizeFont(ScreenPtr pScreen, FontPtr pFont)
{
if (nxagentFontPriv(pFont))
{
if (NXDisplayError(nxagentDisplay) == 0)
{
if (nxagentFontStruct(pFont))
{
int fci;
for (fci = 0; fci < CACHE_INDEX; fci++)
{
if (CACHE_FSTRUCT(fci) == nxagentFontStruct(pFont))
{
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "nxagentUnrealizeFont: Not freeing the font in cache.\n");
#endif
break;
}
}
if (fci == CACHE_INDEX)
{
/*
* This font is not in the cache.
*/
#ifdef NXAGENT_FONTCACHE_DEBUG
fprintf(stderr, "nxagentUnrealizeFont: Freeing font not found in cache '%d'\n",
CACHE_ATOM(fci));
#endif
XFreeFont(nxagentDisplay, nxagentFontStruct(pFont));
}
}
}
if (nxagentFontPriv(pFont) -> mirrorID)
FreeResource(nxagentFontPriv(pFont) -> mirrorID, RT_NONE);
free(nxagentFontPriv(pFont));
#ifdef HAS_XFONT2
xfont2_font_set_private(pFont, nxagentFontPrivateIndex, NULL);
#else
FontSetPrivate(pFont, nxagentFontPrivateIndex, NULL);
#endif /* HAS_XFONT2 */
}
return True;
}
int nxagentDestroyNewFontResourceType(void * p, XID id)
{
#ifdef TEST
fprintf(stderr, "%s: Destroying mirror id [%ld] for font at [%p].\n", __func__,
nxagentFontPriv((FontPtr) p) -> mirrorID, (void *) p);
#endif
/*
FIXME: It happens that this resource had been already destroyed. We
should verify if the same font is assigned both to the server
client and another client. We had a crash when freeing server
client resources.
*/
if (nxagentFontPriv((FontPtr) p) != NULL)
{
nxagentFontPriv((FontPtr) p) -> mirrorID = None;
}
return 1;
}
static XFontStruct *nxagentLoadBestQueryFont(Display* dpy, char *fontName, FontPtr pFont)
{
XFontStruct *fontStruct;
char substFontBuf[512];;
/* X Logical Font Description Conventions require 14 fields in the
* font names.
*
*/
char *searchFields[FIELDS+1];
char *fontNameFields[FIELDS+1];
int numSearchFields = 0;
int numFontFields = 0;
int weight = 0;
int tempWeight = 1;
int fieldOrder[14] = { 4, /* Slant */
11, /* Spacing */
12, /* Width info */
13, /* Charset */
14, /* Language */
7, /* Height */
6, /* Add-style */
3, /* Weight */
2, /* Name */
1, /* Foundry */
9, /* DPI_x */
5, /* Set-width */
8, /* Point size */
10 /* DPI_y */
};
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentLoadBestQueryFont: Searching font '%s' .\n", fontName);
#endif
numFontFields = nxagentSplitString(fontName, fontNameFields, FIELDS + 1, "-");
snprintf(substFontBuf, sizeof(substFontBuf), "%s", "fixed");
if (numFontFields <= FIELDS)
{
#ifdef WARNING
if (nxagentVerbose)
{
fprintf(stderr, "nxagentLoadBestQueryFont: WARNING! Font name in non standard format.\n");
}
#endif
}
else
{
for (int i = 1 ; i < nxagentRemoteFontList.length ; i++)
{
numSearchFields = nxagentSplitString(nxagentRemoteFontList.list[i]->name, searchFields, FIELDS+1, "-");
/* The following code attempts to find an accurate approximation
* of the missing font. The current candidate and the missing font are
* compared on the 14 fields of the X Logical Font Description Convention.
* The selection is performed by the analysis of the matching fields,
* shifting left the value of the Weight variable on the right matches
* and shifting right the value of the Weight on the wrong ones;
* due a probability of overmuch right shifting, the starting weight is set
* to a high value. At the end of matching the selected font is the one
* with the bigger final Weight. The shift operation has been used instead
* of other operation for a performance issue.
* In some check the shift is performed by more than one position, because
* of the relevance of the field; for example a correct slant or a matching
* charset is more relevant than the size.
*/
if (numSearchFields > FIELDS)
{
tempWeight = 0;
for (int j = 0; j < FIELDS; j++)
{
if (strcasecmp(searchFields[fieldOrder[j]], fontNameFields[fieldOrder[j]]) == 0 ||
strcmp(searchFields[fieldOrder[j]], "") == 0 ||
strcmp(fontNameFields[fieldOrder[j]], "") != 0 ||
strcmp(searchFields[fieldOrder[j]], "*") == 0 ||
strcmp(fontNameFields[fieldOrder[j]], "*") == 0)
{
tempWeight ++;
}
tempWeight <<= 1;
}
}
if (tempWeight > weight)
{
/* Found more accurate font */
weight = tempWeight;
snprintf(substFontBuf, sizeof(substFontBuf), "%s", nxagentRemoteFontList.list[i]->name);
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentLoadBestQueryFont: Weight '%d' of more accurate font '%s' .\n", weight, substFontBuf);
#endif
}
for (int j = 0; j < numSearchFields; j++)
{
SAFE_free(searchFields[j]);
}
}
}
#ifdef WARNING
if (nxagentVerbose)
{
fprintf(stderr, "nxagentLoadBestQueryFont: WARNING! Failed to load font '%s'. Replacing with '%s'.\n",
fontName, substFontBuf);
}
#endif
fontStruct = nxagentLoadQueryFont(dpy, substFontBuf, pFont);
for (int j = 0; j < numFontFields; j++)
{
SAFE_free(fontNameFields[j]);
}
return fontStruct;
}
static void nxagentFontDisconnect(FontPtr pFont, XID param1, void * param2)
{
Bool *pBool = (Bool*)param2;
if (pFont == NULL || !*pBool)
return;
nxagentPrivFont *privFont = nxagentFontPriv(pFont);
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFontDisconnect: pFont %p, XID %lx\n",
(void *) pFont, privFont -> font_struct ? nxagentFont(pFont) : 0);
#endif
for (int i = 0; i < CACHE_INDEX; i++)
{
if (strcasecmp(CACHE_NAME(i), privFont -> fontName) == 0)
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFontDisconnect: font %s found in cache at position %d\n",
privFont -> fontName, i);
#endif
privFont -> font_struct = NULL;
return;
}
}
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFontDisconnect: WARNING font %s not found in cache freeing it now\n",
privFont -> fontName);
#endif
if (privFont -> font_struct)
{
XFreeFont(nxagentDisplay, privFont -> font_struct);
privFont -> font_struct = NULL;
}
}
static void nxagentCollectFailedFont(FontPtr fpt, XID id)
{
if (nxagentFailedToReconnectFonts.font == NULL)
{
nxagentFailedToReconnectFonts.size = 8;
nxagentFailedToReconnectFonts.font = malloc(nxagentFailedToReconnectFonts.size *
sizeof(FontPtr));
nxagentFailedToReconnectFonts.id = malloc(nxagentFailedToReconnectFonts.size *
sizeof(XID));
if (nxagentFailedToReconnectFonts.font == NULL || nxagentFailedToReconnectFonts.id == NULL)
{
SAFE_free(nxagentFailedToReconnectFonts.font);
SAFE_free(nxagentFailedToReconnectFonts.id);
FatalError("Font: font not reconnected memory allocation failed!.\n");
}
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentCollectFailedFont: allocated [%d] bytes.\n",
8 * (sizeof(FontPtr)+ sizeof(XID)));
#endif
}
else if (nxagentFailedToReconnectFonts.index == nxagentFailedToReconnectFonts.size - 1)
{
int num = 2 * nxagentFailedToReconnectFonts.size;
FontPtr *tmp1 = realloc(nxagentFailedToReconnectFonts.font, num * sizeof(FontPtr));
XID *tmp2 = realloc(nxagentFailedToReconnectFonts.id, num * sizeof(XID));
if (tmp1 == NULL || tmp2 == NULL)
{
SAFE_free(tmp1);
SAFE_free(tmp2);
FatalError("Font: font not reconnected memory re-allocation failed!.\n");
}
nxagentFailedToReconnectFonts.size = num;
nxagentFailedToReconnectFonts.font = tmp1;
nxagentFailedToReconnectFonts.id = tmp2;
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr,"nxagentCollectFailedFont: reallocated memory.\n ");
#endif
}
nxagentFailedToReconnectFonts.font[nxagentFailedToReconnectFonts.index] = fpt;
nxagentFailedToReconnectFonts.id[nxagentFailedToReconnectFonts.index] = id;
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentCollectFailedFont: font not reconnected at [%p], "
"put in nxagentFailedToReconnectFonts.font[%d] = [%p], with XID = [%lu].\n",
(void*) fpt, nxagentFailedToReconnectFonts.index,
(void *)nxagentFailedToReconnectFonts.font[nxagentFailedToReconnectFonts.index],
nxagentFailedToReconnectFonts.id[nxagentFailedToReconnectFonts.index]);
#endif
nxagentFailedToReconnectFonts.index++;
}
static void nxagentFontReconnect(FontPtr pFont, XID param1, void * param2)
{
int i;
Bool *pBool = (Bool*)param2;
if (pFont == NULL)
return;
nxagentPrivFont *privFont = nxagentFontPriv(pFont);
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFontReconnect: pFont %p - XID %lx - name %s\n",
(void*) pFont, (privFont -> font_struct) ? nxagentFont(pFont) : 0,
privFont -> fontName);
#endif
for (i = 0; i < CACHE_INDEX; i++)
{
if (strcasecmp(CACHE_NAME(i), privFont -> fontName) == 0)
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "\tfound in cache");
#endif
if (!CACHE_FSTRUCT(i))
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, " --- font struct not valid\n");
#endif
break;
}
nxagentFontStruct(pFont) = CACHE_FSTRUCT(i);
return;
}
}
if (i == CACHE_INDEX)
{
FatalError("nxagentFontReconnect: font not found in cache.");
}
privFont -> font_struct = nxagentLoadQueryFont(nxagentDisplay, privFont -> fontName, pFont);
if ((privFont -> font_struct == NULL) && reconnectFlexibility)
{
privFont -> font_struct = nxagentLoadBestQueryFont(nxagentDisplay, privFont -> fontName, pFont);
}
if (privFont->font_struct != NULL)
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "\tXID %lx\n", privFont -> font_struct -> fid);
#endif
CACHE_FSTRUCT(i) = privFont -> font_struct;
}
else
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFontReconnect: failed\n");
#endif
nxagentCollectFailedFont(pFont, param1);
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFontReconnect: reconnection of font [%s] failed.\n",
privFont -> fontName);
#endif
nxagentSetReconnectError(FAILED_RESUME_FONTS_ALERT,
"Couldn't restore the font '%s'", privFont -> fontName);
*pBool = False;
}
return;
}
static void nxagentFreeCacheBeforeReconnect(void)
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
printFontCacheDump("nxagentFreeCacheBeforeReconnect");
#endif
for (int i = 0; i < CACHE_INDEX; i++)
{
if (CACHE_FSTRUCT(i))
{
nxagentFreeFont(CACHE_FSTRUCT(i));
CACHE_FSTRUCT(i) = NULL;
}
}
}
static void nxagentCleanCacheAfterReconnect(void)
{
int real_size = CACHE_INDEX;
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
printFontCacheDump("nxagentCleanCacheAfterReconnect");
#endif
for (int i = 0; i < CACHE_INDEX; i++)
{
if (CACHE_FSTRUCT(i) == NULL)
{
SAFE_XFree(CACHE_NAME(i));
real_size--;
}
}
for (int i = 0; i < real_size; i++)
{
int j;
nxCacheFontEntryRecPtr swapEntryPtr;
/* Find - first bad occurrence if exist. */
while ((i < real_size) && CACHE_FSTRUCT(i))
i++;
/* Really nothing more to do. */
if (i == real_size)
break;
/*
* Find - first good occurrence (moving backward from right end) entry in
* order to replace the bad one.
*/
for (j = CACHE_INDEX - 1; CACHE_FSTRUCT(j) == NULL; j--);
/*
* Now we can swap the two entry and reduce the Cache index
*/
swapEntryPtr = CACHE_ENTRY(i);
CACHE_ENTRY(i) = CACHE_ENTRY(j);
CACHE_ENTRY(j) = swapEntryPtr;
}
CACHE_INDEX = real_size;
}
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
static void printFontCacheDump(char* msg)
{
fprintf(stderr, "%s - begin -\n", msg);
for (int i = 0; i < CACHE_INDEX; i++)
{
if (CACHE_FSTRUCT(i))
{
fprintf(stderr, "\tXID %lx - %s\n", CACHE_FSTRUCT(i) -> fid, CACHE_NAME(i));
}
else
{
fprintf(stderr, "\tdestroyed - %s\n", CACHE_NAME(i));
}
}
fprintf(stderr, "%s - end -\n", msg);
}
#endif
Bool nxagentReconnectAllFonts(void *p0)
{
Bool fontSuccess = True;
reconnectFlexibility = *((int *) p0);
#if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_FONT_DEBUG)
fprintf(stderr, "nxagentReconnectAllFonts\n");
#endif
/*
* The resource type RT_NX_FONT is created on the server client
* only, so we can avoid to loop through all the clients.
*/
FindClientResourcesByType(clients[serverClient -> index], RT_NX_FONT,
(FindResType) nxagentFontReconnect, &fontSuccess);
for (int cid = 0; cid < MAXCLIENTS; cid++)
{
if (clients[cid])
{
FindClientResourcesByType(clients[cid], RT_FONT,
(FindResType) nxagentFontReconnect, &fontSuccess);
}
}
if (fontSuccess)
{
nxagentCleanCacheAfterReconnect();
}
return fontSuccess;
}
static void nxagentFailedFontReconnect(FontPtr pFont, XID param1, void * param2)
{
int i;
Bool *pBool = (Bool*)param2;
if (pFont == NULL)
return;
nxagentPrivFont *privFont = nxagentFontPriv(pFont);
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFailedFontReconnect: pFont %p - XID %lx - name %s\n",
(void*) pFont, (privFont -> font_struct) ? nxagentFont(pFont) : 0,
privFont -> fontName);
#endif
for (i = 0; i < CACHE_INDEX; i++)
{
if (strcasecmp(CACHE_NAME(i), privFont -> fontName) == 0)
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "\tfound in cache");
#endif
if (!CACHE_FSTRUCT(i))
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, " --- font struct not valid\n");
#endif
break;
}
nxagentFontStruct(pFont) = CACHE_FSTRUCT(i);
return;
}
}
if (i == CACHE_INDEX)
{
FatalError("nxagentFailedFontReconnect: font not found in cache.");
}
privFont -> font_struct = nxagentLoadQueryFont(nxagentDisplay, privFont -> fontName, pFont);
if (privFont -> font_struct == NULL)
{
privFont -> font_struct = nxagentLoadBestQueryFont(nxagentDisplay, privFont -> fontName, pFont);
}
if (privFont->font_struct != NULL)
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "\tXID %lx\n", privFont -> font_struct -> fid);
#endif
CACHE_FSTRUCT(i) = privFont -> font_struct;
}
else
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFailedFontReconnect: failed\n");
#endif
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentFailedFontReconnect: reconnection of font [%s] failed.\n",
privFont -> fontName);
#endif
nxagentSetReconnectError(FAILED_RESUME_FONTS_ALERT,
"Couldn't restore the font '%s'", privFont -> fontName);
*pBool = False;
}
return;
}
static void nxagentFreeFailedToReconnectFonts(void)
{
SAFE_free(nxagentFailedToReconnectFonts.font);
SAFE_free(nxagentFailedToReconnectFonts.id);
nxagentFailedToReconnectFonts.size = 0;
nxagentFailedToReconnectFonts.index = 0;
}
Bool nxagentReconnectFailedFonts(void *p0)
{
char fontServerPath[256] = "";
reconnectFlexibility = *((int *) p0);
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentReconnectFailedFonts: \n");
#endif
if (nxagentGetFontServerPath(fontServerPath, sizeof(fontServerPath)) == False)
{
#ifdef WARNING
fprintf(stderr, "nxagentReconnectFailedFonts: WARNING! "
"Font server tunneling not retrieved.\n");
#endif
}
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentReconnectFailedFonts: font server path [%s]\n", fontServerPath);
#endif
int nPaths = 0;
char **fontPaths = XGetFontPath(nxagentDisplay, &nPaths);
char **newFontPaths = malloc((nPaths + 1) * sizeof(char *));
if (newFontPaths == NULL)
{
FatalError("nxagentReconnectFailedFonts: malloc failed.");
}
memcpy(newFontPaths, fontPaths, nPaths * sizeof(char*));
char **localFontPaths = newFontPaths;
localFontPaths += nPaths;
*localFontPaths = fontServerPath;
int attempt = 1;
const int maxAttempt = 5;
Bool repeat = True;
while (repeat)
{
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentReconnectFailedFonts: attempt [%d].\n", attempt);
#endif
repeat = False;
XSetFontPath(nxagentDisplay, newFontPaths, nPaths + 1);
nxagentFreeRemoteFontList(&nxagentRemoteFontList);
nxagentListRemoteFonts("*", nxagentMaxFontNames);
for (int i = 0; i < nxagentFailedToReconnectFonts.index; i++)
{
Bool fontSuccess = True;
if (nxagentFailedToReconnectFonts.font[i])
{
nxagentFailedFontReconnect(nxagentFailedToReconnectFonts.font[i],
nxagentFailedToReconnectFonts.id[i],
&fontSuccess);
if (fontSuccess)
{
nxagentFailedToReconnectFonts.font[i] = NULL;
}
else
{
repeat = True;
}
}
}
attempt++;
if (attempt > maxAttempt)
{
nxagentFreeFailedToReconnectFonts();
XSetFontPath(nxagentDisplay, fontPaths, nPaths);
nxagentFreeRemoteFontList(&nxagentRemoteFontList);
nxagentListRemoteFonts("*", nxagentMaxFontNames);
XFreeFontPath(fontPaths);
SAFE_free(newFontPaths);
return False;
}
}
nxagentFreeFailedToReconnectFonts();
XSetFontPath(nxagentDisplay, fontPaths, nPaths);
XFreeFontPath(fontPaths);
SAFE_free(newFontPaths);
nxagentCleanCacheAfterReconnect();
return True;
}
Bool nxagentDisconnectAllFonts(void)
{
Bool fontSuccess = True;
#if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_FONT_DEBUG)
fprintf(stderr, "nxagentDisconnectAllFonts\n");
#endif
nxagentFreeRemoteFontList(&nxagentRemoteFontList);
nxagentFreeCacheBeforeReconnect();
/*
* The resource type RT_NX_FONT is created on the server client
* only, so we can avoid to loop through all the clients.
*/
FindClientResourcesByType(clients[serverClient -> index], RT_NX_FONT,
(FindResType) nxagentFontDisconnect, &fontSuccess);
for (int cid = 0; cid < MAXCLIENTS; cid++)
{
if (clients[cid] && fontSuccess)
{
FindClientResourcesByType(clients[cid], RT_FONT,
(FindResType) nxagentFontDisconnect, &fontSuccess);
}
}
return True;
}
static Bool nxagentGetFontServerPath(char * fontServerPath, int size)
{
char path[256] = {0};
if (NXGetFontParameters(nxagentDisplay, sizeof(path), path) == True)
{
/* the length is stored in the first byte and is therefore limited to 255 */
unsigned int len = *path;
if (len)
{
snprintf(fontServerPath, min(size, len + 1), "%s", path + 1);
#ifdef TEST
fprintf(stderr, "%s: Got path [%s].\n", __func__,
fontServerPath);
#endif
}
else
{
#ifdef TEST
fprintf(stderr, "%s: WARNING! Font server tunneling not enabled.\n", __func__);
#endif
return False;
}
}
else
{
#ifdef TEST
fprintf(stderr, "%s: WARNING! Failed to get path for font server tunneling.\n", __func__);
#endif
return False;
}
return True;
}
void nxagentVerifySingleFontPath(char **dest, const char *fontDir)
{
if (!dest || !*dest)
return;
#ifdef TEST
fprintf(stderr, "%s: Assuming fonts in directory [%s].\n", __func__,
validateString(fontDir));
#endif
for (int i = 0; ; i++)
{
char *tmppath = NULL;
int rc;
const char *subdir = nxagentFontSubdirs[i];
if (subdir == NULL)
return;
if (**dest != '\0')
{
rc = asprintf(&tmppath, "%s,%s/%s", *dest, fontDir, subdir);
}
else
{
rc = asprintf(&tmppath, "%s/%s", fontDir, subdir);
}
if (rc == -1)
return;
SAFE_free(*dest);
*dest = tmppath;
tmppath = NULL;
}
}
void nxagentVerifyDefaultFontPath(void)
{
static char *fontPath;
#ifdef TEST
fprintf(stderr, "%s: Going to search for one or more valid font paths.\n", __func__);
#endif
/*
* Set the default font path as the first choice.
*/
if ((fontPath = strdup(defaultFontPath)) == NULL)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Unable to allocate memory for a new font path. "
"Using the default font path [%s].\n", __func__,
validateString(defaultFontPath));
#endif
return;
}
for (int i = 0; ; i++)
{
int j;
const char *dir = nxagentFontDirs[i];
if (dir == NULL)
{
break;
}
else
{
for (j = 0; j <= i; j++)
{
//if (strcmp(nxagentFontDirs[j], dir) == 0)
if (nxagentFontDirs[j] == dir)
{
break;
}
}
if (j == i)
{
nxagentVerifySingleFontPath(&fontPath, dir);
}
#ifdef TEST
else
{
fprintf(stderr, "%s: Skipping duplicate font dir [%s].\n", __func__,
validateString(dir));
}
#endif
}
}
if (*fontPath == '\0')
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Can't find a valid font directory.\n", __func__);
fprintf(stderr, "%s: WARNING! Using font path [%s].\n", __func__,
validateString(defaultFontPath));
#endif
}
else
{
/* do _not_ free defaultFontPath here - it's either set at compile time or
part of argv */
defaultFontPath = fontPath;
#ifdef TEST
fprintf(stderr, "%s: Using font path [%s].\n", __func__,
validateString(defaultFontPath));
#endif
}
return;
}
XFontStruct* nxagentLoadQueryFont(register Display *dpy, char *name, FontPtr pFont)
{
XFontStruct* fs = (XFontStruct *) malloc (sizeof (XFontStruct));
if (fs == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentLoadQueryFont: WARNING! Failed allocation of XFontStruct.\n");
#endif
return (XFontStruct *)NULL;
}
#ifdef NXAGENT_RECONNECT_FONT_DEBUG
fprintf(stderr, "nxagentLoadQueryFont: Looking for font '%s'.\n", name);
#endif
if (!nxagentFontLookUp(name))
{
#ifdef DEBUG
fprintf(stderr, "nxagentLoadQueryFont: WARNING! Font not found '%s'.\n", name);
#endif
SAFE_free(fs);
return (XFontStruct *) NULL;
}
fs -> ext_data = NULL; /* Hook for extension to hang data.*/
fs -> fid = XLoadFont(dpy, name); /* Font id for this font. */
fs -> direction = pFont->info.drawDirection; /* Hint about the direction font is painted. */
fs -> min_char_or_byte2 = pFont->info.firstCol; /* First character. */
fs -> max_char_or_byte2 = pFont->info.lastCol; /* Last character. */
fs -> min_byte1 = pFont->info.firstRow; /* First row that exists. */
fs -> max_byte1 = pFont->info.lastRow; /* Last row that exists. */
fs -> all_chars_exist = pFont->info.allExist; /* Flag if all characters have nonzero size. */
fs -> default_char = pFont->info.defaultCh; /* Char to print for undefined character. */
fs -> n_properties = pFont->info.nprops; /* How many properties there are. */
/*
* If no properties defined for the font, then it is bad
* font, but shouldn't try to read nothing.
*/
if (fs -> n_properties > 0)
{
long nbytes;
nbytes = pFont -> info.nprops * sizeof(XFontProp);
fs -> properties = (XFontProp *) malloc((unsigned) nbytes);
if (fs -> properties == NULL)
{
#ifdef WARNING
fprintf(stderr, "nxagentLoadQueryFont: WARNING! Failed allocation of XFontProp.");
#endif
SAFE_free(fs);
return (XFontStruct *) NULL;
}
memmove(fs -> properties, pFont -> info.props, nbytes);
}
xCharInfo *xcip = (xCharInfo *) &pFont -> info.ink_minbounds;
fs -> min_bounds.lbearing = cvtINT16toShort(xcip -> leftSideBearing);
fs -> min_bounds.rbearing = cvtINT16toShort(xcip -> rightSideBearing);
fs -> min_bounds.width = cvtINT16toShort(xcip -> characterWidth);
fs -> min_bounds.ascent = cvtINT16toShort(xcip -> ascent);
fs -> min_bounds.descent = cvtINT16toShort(xcip -> descent);
fs -> min_bounds.attributes = xcip -> attributes;
xcip = (xCharInfo *) &pFont -> info.ink_maxbounds;
fs -> max_bounds.lbearing = cvtINT16toShort(xcip -> leftSideBearing);
fs -> max_bounds.rbearing = cvtINT16toShort(xcip -> rightSideBearing);
fs -> max_bounds.width = cvtINT16toShort(xcip -> characterWidth);
fs -> max_bounds.ascent = cvtINT16toShort(xcip -> ascent);
fs -> max_bounds.descent = cvtINT16toShort(xcip -> descent);
fs -> max_bounds.attributes = xcip -> attributes;
fs -> per_char = NULL; /* First_char to last_char information. */
fs -> ascent = pFont->info.fontAscent; /* Logical extent above baseline for spacing. */
fs -> descent = pFont->info.fontDescent; /* Logical decent below baseline for spacing. */
return fs;
}
int nxagentFreeFont(XFontStruct *fs)
{
if (fs->per_char)
{
#ifdef USE_XF86BIGFONT
_XF86BigfontFreeFontMetrics(fs);
#else
SAFE_free(fs->per_char);
#endif
}
SAFE_free(fs->properties);
SAFE_XFree(fs);
return 1;
}
int nxagentSplitString(char *string, char *fields[], int nfields, char *sep)
{
int seplen = strlen(sep);
int len = strlen(string);
char *current = string;
int i = 0;
Bool last = False;
for (;;)
{
char *next = NULL;
if (current < string + len)
{
next = strstr(current, sep);
}
if (next == NULL)
{
next = string + len;
last = True;
}
int fieldlen = next - current;
if (i < nfields)
{
fields[i] = strndup(current, fieldlen);
}
else
{
fields[i] = NULL;
}
current = next + seplen;
i++;
if (last)
{
break;
}
}
return i;
}
char *nxagentMakeScalableFontName(const char *fontName, Bool scalableResolution)
{
char *scalableFontName;
/* FIXME: use str(n)dup()? */
if ((scalableFontName = malloc(strlen(fontName) + 1)) == NULL)
{
#ifdef PANIC
fprintf(stderr, "nxagentMakeScalableFontName: PANIC! malloc() failed.\n");
#endif
return NULL;
}
scalableFontName[0] = '\0';
if (*fontName != '-')
{
goto MakeScalableFontNameError;
}
const char *s = fontName;
int field = 0;
while (s != NULL)
{
s = strchr(s + 1, '-');
if (s != NULL)
{
if (field == 6 || field == 7 || field == 11)
{
/*
* PIXEL_SIZE || POINT_SIZE || AVERAGE_WIDTH
*/
strcat(scalableFontName, "-0");
}
else if (scalableResolution && (field == 8 || field == 9))
{
/*
* RESOLUTION_X || RESOLUTION_Y
*/
strcat(scalableFontName, "-0");
}
else
{
strncat(scalableFontName, fontName, s - fontName);
}
fontName = s;
}
else
{
strcat(scalableFontName, fontName);
}
field++;
}
if (field != 14)
{
goto MakeScalableFontNameError;
}
return scalableFontName;
MakeScalableFontNameError:
SAFE_free(scalableFontName);
#ifdef DEBUG
fprintf(stderr, "nxagentMakeScalableFontName: Invalid font name.\n");
#endif
return NULL;
}