@ -59,18 +59,23 @@ static cachefont_t *font_cache_find(const char *name, unsigned char type);
static void * font_cache_find_info ( const char * name , unsigned char type ) ;
static unsigned char get_corner ( const char * corner ) ;
/* The eterm_font_(add|delete) functions keep track of the names of the terminal fonts
as defined in the attributes / multicharset contexts . They do NOT call the cache
routines . The caller is responsible for adding / removing fonts to / from the cache . */
void
eterm_font_add ( char * * * plist , const char * fontname , unsigned char idx ) {
char * * flist ;
D_FONT ( ( " Adding \" %s \" at %u (%8p) \n " , NONULL ( fontname ) , ( unsigned int ) idx , plist ) ) ;
ASSERT ( plist ! = NULL ) ;
flist = * plist ;
ASSERT ( plist ! = NULL ) ; /* plist is the address of either etfonts or etmfonts */
/* If we're adding the font at an index we don't have yet, we must resize to fit it. */
if ( idx > = font_cnt ) {
unsigned char new_size = sizeof ( char * ) * ( idx + 1 ) ;
/* The below looks messy with all the cpp stuff, but it really just malloc's/realloc's
both etfonts and etmfonts at the same time to the same size , then prints some goop . */
if ( etfonts ) {
etfonts = ( char * * ) REALLOC ( etfonts , new_size ) ;
# ifdef MULTI_CHARSET
@ -88,22 +93,25 @@ eterm_font_add(char ***plist, const char *fontname, unsigned char idx) {
D_FONT ( ( " -> Allocating font list: %u bytes at %8p \n " , new_size , etfonts ) ) ;
# endif
}
/* Initialize the new memory so we don't think it's got valid font info. */
MEMSET ( etfonts + font_cnt , 0 , sizeof ( char * ) * ( idx - font_cnt + 1 ) ) ;
# ifdef MULTI_CHARSET
MEMSET ( etmfonts + font_cnt , 0 , sizeof ( char * ) * ( idx - font_cnt + 1 ) ) ;
# endif
font_cnt = idx + 1 ;
font_cnt = idx + 1 ; /* Update the font count. */
# ifdef MULTI_CHARSET
flist = ( ( plist = = & etfonts ) ? ( etfonts ) : ( etmfonts ) ) ;
# else
flist = etfonts ;
# endif
} else {
flist = * plist ;
if ( flist [ idx ] ) {
if ( ( flist [ idx ] = = fontname ) | | ( ! strcasecmp ( flist [ idx ] , fontname ) ) ) {
return ;
return ; /* We've already got the right font. */
}
FREE ( flist [ idx ] ) ;
FREE ( flist [ idx ] ) ; /* We're replacing an old font. Get rid of the old name. */
}
}
flist [ idx ] = STRDUP ( fontname ) ;
@ -121,6 +129,25 @@ eterm_font_delete(char **flist, unsigned char idx) {
flist [ idx ] = NULL ;
}
void
eterm_font_list_clear ( void )
{
unsigned char idx ;
for ( idx = 0 ; idx < font_cnt ; idx + + ) {
eterm_font_delete ( etfonts , idx ) ;
# ifdef MULTI_CHARSET
eterm_font_delete ( etmfonts , idx ) ;
# endif
}
FREE ( etfonts ) ;
# ifdef MULTI_CHARSET
FREE ( etmfonts ) ;
# endif
}
/* These font caching routines keep track of all the various fonts we allocate
in the X server so that we only allocate each font once . Saves memory . */
static void
font_cache_add ( const char * name , unsigned char type , void * info ) {
@ -128,6 +155,7 @@ font_cache_add(const char *name, unsigned char type, void *info) {
D_FONT ( ( " font_cache_add(%s, %d, %8p) called. \n " , NONULL ( name ) , type , info ) ) ;
/* Allocate the cache info for the font and store the data */
font = ( cachefont_t * ) MALLOC ( sizeof ( cachefont_t ) ) ;
font - > name = STRDUP ( name ) ;
font - > type = type ;
@ -139,6 +167,8 @@ font_cache_add(const char *name, unsigned char type, void *info) {
default : break ;
}
D_FONT ( ( " -> Created new cachefont_t struct at %p: \" %s \" , %d, %p \n " , font , font - > name , font - > type , font - > fontinfo . xfontinfo ) ) ;
/* Actually add the struct to the end of our cache linked list. */
if ( font_cache = = NULL ) {
font_cache = cur_font = font ;
font - > next = NULL ;
@ -162,10 +192,13 @@ font_cache_del(const void *info) {
D_FONT ( ( " font_cache_del(%8p) called. \n " , info ) ) ;
if ( font_cache = = NULL ) {
return ;
return ; /* No fonts in the cache. Theoretically this should never happen, but... */
}
/* Check the very first entry for a match. It's a special case. */
if ( ( ( font_cache - > type = = FONT_TYPE_X ) & & ( font_cache - > fontinfo . xfontinfo = = ( XFontStruct * ) info ) ) ) {
D_FONT ( ( " -> Match found at font_cache (%8p). Font name is \" %s \" \n " , font_cache , NONULL ( font_cache - > name ) ) ) ;
/* We've got a match. Decrement the reference count, and if it goes to 0, remove it from the cache. */
if ( - - ( font_cache - > ref_cnt ) = = 0 ) {
D_FONT ( ( " -> Reference count is now 0. Deleting from cache. \n " ) ) ;
current = font_cache ;
@ -177,9 +210,13 @@ font_cache_del(const void *info) {
D_FONT ( ( " -> Reference count is %d. Returning. \n " , font_cache - > ref_cnt ) ) ;
}
return ;
# if UNUSED_BLOCK
} else if ( ( font_cache - > type = = FONT_TYPE_TTF ) & & ( 0 ) ) {
} else if ( ( font_cache - > type = = FONT_TYPE_FNLIB ) & & ( 0 ) ) {
# endif
} else {
/* Search for a match. We test current->next, not current, so that we can
update the " next " pointer of the font prior to the one we ' re actually deleting . */
for ( current = font_cache ; current - > next ; current = current - > next ) {
if ( ( ( current - > next - > type = = FONT_TYPE_X ) & & ( current - > next - > fontinfo . xfontinfo = = ( XFontStruct * ) info ) ) ) {
D_FONT ( ( " -> Match found at current->next (%8p, current == %8p). Font name is \" %s \" \n " , current - > next , current , NONULL ( current - > next - > name ) ) ) ;
@ -197,11 +234,37 @@ font_cache_del(const void *info) {
D_FONT ( ( " -> Reference count is %d. Returning. \n " , font_cache - > ref_cnt ) ) ;
}
return ;
# if UNUSED_BLOCK
} else if ( ( current - > next - > type = = FONT_TYPE_TTF ) & & ( 0 ) ) {
} else if ( ( current - > next - > type = = FONT_TYPE_FNLIB ) & & ( 0 ) ) {
# endif
}
}
}
/* If we get here, there was no match. No big deal. */
}
void
font_cache_clear ( void )
{
cachefont_t * current , * tmp ;
D_FONT ( ( " Clearing the font cache. \n " ) ) ;
for ( current = font_cache ; current ; ) {
D_FONT ( ( " -> Deleting \" %s \" from cache. \n " , current - > name ) ) ;
tmp = current ;
current = current - > next ;
if ( tmp - > type = = FONT_TYPE_X ) {
XFreeFont ( Xdisplay , ( XFontStruct * ) tmp - > fontinfo . xfontinfo ) ;
FREE ( tmp - > name ) ;
FREE ( tmp ) ;
# if UNUSED_BLOCK
} else if ( current - > next - > type = = FONT_TYPE_TTF ) {
} else if ( current - > next - > type = = FONT_TYPE_FNLIB ) {
# endif
}
}
font_cache = cur_font = NULL ;
}
static cachefont_t *
@ -213,6 +276,7 @@ font_cache_find(const char *name, unsigned char type) {
D_FONT ( ( " font_cache_find(%s, %d) called. \n " , NONULL ( name ) , type ) ) ;
/* Find a matching name/type in the cache. Just a search; no reference counting happens here. */
for ( current = font_cache ; current ; current = current - > next ) {
D_FONT ( ( " -> Checking current (%8p), type == %d, name == %s \n " , current , current - > type , NONULL ( current - > name ) ) ) ;
if ( ( current - > type = = type ) & & ! strcasecmp ( current - > name , name ) ) {
@ -233,6 +297,7 @@ font_cache_find_info(const char *name, unsigned char type) {
D_FONT ( ( " font_cache_find_info(%s, %d) called. \n " , NONULL ( name ) , type ) ) ;
/* This is also a simple search, but it returns the fontinfo rather than the cache entry. */
for ( current = font_cache ; current ; current = current - > next ) {
D_FONT ( ( " -> Checking current (%8p), type == %d, name == %s \n " , current , current - > type , NONULL ( current - > name ) ) ) ;
if ( ( current - > type = = type ) & & ! strcasecmp ( current - > name , name ) ) {
@ -249,6 +314,7 @@ font_cache_find_info(const char *name, unsigned char type) {
return ( NULL ) ;
}
/* load_font() is the function that should be used to allocate fonts. */
void *
load_font ( const char * name , const char * fallback , unsigned char type )
{
@ -258,9 +324,12 @@ load_font(const char *name, const char *fallback, unsigned char type)
D_FONT ( ( " load_font(%s, %s, %d) called. \n " , NONULL ( name ) , NONULL ( fallback ) , type ) ) ;
/* Default type is X font. */
if ( type = = 0 ) {
type = FONT_TYPE_X ;
}
/* Specify some sane fallbacks */
if ( name = = NULL ) {
if ( fallback ) {
name = fallback ;
@ -278,6 +347,8 @@ load_font(const char *name, const char *fallback, unsigned char type)
}
D_FONT ( ( " -> Using name == \" %s \" and fallback == \" %s \" \n " , name , fallback ) ) ;
/* Look for the font name in the cache. If it's there, add one to the
reference count and return the existing fontinfo pointer to the caller . */
if ( ( font = font_cache_find ( name , type ) ) ! = NULL ) {
font_cache_add_ref ( font ) ;
D_FONT ( ( " -> Font found in cache. Incrementing reference count to %d and returning existing data. \n " , font - > ref_cnt ) ) ;
@ -288,6 +359,8 @@ load_font(const char *name, const char *fallback, unsigned char type)
default : return ( NULL ) ; break ;
}
}
/* No match in the cache, so we'll have to add it. */
if ( type = = FONT_TYPE_X ) {
if ( ( xfont = XLoadQueryFont ( Xdisplay , name ) ) = = NULL ) {
print_error ( " Unable to load font \" %s \" . Falling back on \" %s \" \n " , name , fallback ) ;
@ -300,23 +373,26 @@ load_font(const char *name, const char *fallback, unsigned char type)
font_cache_add ( name , type , ( void * ) xfont ) ;
}
return ( ( void * ) xfont ) ;
# if UNUSED_BLOCK
} else if ( type = = FONT_TYPE_TTF ) {
return ( NULL ) ;
} else if ( type = = FONT_TYPE_FNLIB ) {
return ( NULL ) ;
# endif
}
ASSERT_NOTREACHED_RVAL ( NULL ) ;
}
/* free_font() is the external function for deallocating fonts. */
void
free_font ( const void * info )
{
ASSERT ( info ! = NULL ) ;
font_cache_del ( info ) ;
}
/* change_font() handles the font changing escape sequences. It's also called to
initialize the terminal fonts ( loading and setting up size hints / info ) . */
void
change_font ( int init , const char * fontname )
{
@ -340,12 +416,13 @@ change_font(int init, const char *fontname)
ASSERT ( fontname ! = NULL ) ;
switch ( * fontname ) {
/* Empty font name. Reset to default. */
case ' \0 ' :
font_idx = def_font_idx ;
fontname = NULL ;
break ;
/* special (internal) prefix for font commands */
/* A font escape sequence. See which one it is. */
case FONT_CMD :
idx = atoi ( + + fontname ) ;
switch ( * fontname ) {
@ -359,15 +436,18 @@ change_font(int init, const char *fontname)
default :
if ( * fontname ! = ' \0 ' & & ! isdigit ( * fontname ) )
return ;
return ; /* It's not a number. Punt. */
/* Set current font to font N */
BOUND ( idx , 0 , ( font_cnt - 1 ) ) ;
font_idx = idx ;
break ;
}
/* NULL out the fontname so we don't try to load it */
fontname = NULL ;
break ;
default :
/* Change to the named font. See if we already have it, and if so, just set the index. */
for ( idx = 0 ; idx < font_cnt ; idx + + ) {
if ( ! strcasecmp ( etfonts [ idx ] , fontname ) ) {
font_idx = idx ;
@ -377,31 +457,38 @@ change_font(int init, const char *fontname)
}
break ;
}
/* If we get here with a non-NULL fontname, we have to load a new font. Rats. */
if ( fontname ! = NULL ) {
eterm_font_add ( & etfonts , fontname , font_idx ) ;
} else if ( font_idx = = old_idx ) {
/* Sigh. What a waste of time, changing to the same font. */
D_FONT ( ( " -> Change to the same font index (%d) we had before? I don't think so. \n " , font_idx ) ) ;
return ;
}
}
D_FONT ( ( " -> Changing to font index %u ( \" %s \" ) \n " , ( unsigned int ) font_idx , NONULL ( etfonts [ font_idx ] ) ) ) ;
if ( TermWin . font ) {
/* If we have a terminal font, but it's not our new current font, free it and load the new one. */
if ( font_cache_find_info ( etfonts [ font_idx ] , FONT_TYPE_X ) ! = TermWin . font ) {
free_font ( TermWin . font ) ;
TermWin . font = load_font ( etfonts [ font_idx ] , " fixed " , FONT_TYPE_X ) ;
}
} else {
/* Load the new font. */
TermWin . font = load_font ( etfonts [ font_idx ] , " fixed " , FONT_TYPE_X ) ;
}
# ifndef NO_BOLDFONT
if ( init & & rs_boldFont ! = NULL ) {
/* If we're initializing, load the bold font too. */
boldFont = load_font ( rs_boldFont , " -misc-fixed-bold-r-semicondensed--13-120-75-75-c-60-iso8859-1 " , FONT_TYPE_X ) ;
}
# endif
# ifdef MULTI_CHARSET
if ( TermWin . mfont ) {
/* Ditto the above, but for the multi-byte fonts. */
if ( font_cache_find_info ( etmfonts [ font_idx ] , FONT_TYPE_X ) ! = TermWin . mfont ) {
free_font ( TermWin . mfont ) ;
TermWin . mfont = load_font ( etmfonts [ font_idx ] , " k14 " , FONT_TYPE_X ) ;
@ -410,6 +497,7 @@ change_font(int init, const char *fontname)
TermWin . mfont = load_font ( etmfonts [ font_idx ] , " k14 " , FONT_TYPE_X ) ;
}
# ifdef USE_XIM
/* Changing fonts requires updating the FontSet */
if ( xim_input_context ) {
if ( TermWin . fontset ) {
XFreeFontSet ( Xdisplay , TermWin . fontset ) ;
@ -421,9 +509,11 @@ change_font(int init, const char *fontname)
# endif /* MULTI_CHARSET */
if ( ! init ) {
/* Unless we're initializing, set the font ID in the GC to our new font. */
XSetFont ( Xdisplay , TermWin . gc , TermWin . font - > fid ) ;
}
/* Check the font dimensions to update our TermWin info */
fw = TermWin . font - > min_bounds . width ;
# ifdef MULTI_CHARSET
fh = ( MAX ( ( encoding_method = = LATIN1 ? 0 : TermWin . mfont - > ascent ) , TermWin . font - > ascent )
@ -440,6 +530,7 @@ change_font(int init, const char *fontname)
else
TermWin . fprop = 1 ; /* Proportional font */
/* For proportional fonts with large size variations, do some math-fu to try and help the appearance */
if ( TermWin . fprop & & TermWin . font - > per_char & & ( TermWin . font - > max_bounds . width - TermWin . font - > min_bounds . width > = 3 ) ) {
int cw , n = 0 , sum = 0 , sumsq = 0 , min_w , max_w ;
unsigned int i ;
@ -469,16 +560,16 @@ change_font(int init, const char *fontname)
LOWER_BOUND ( fw , TermWin . font - > max_bounds . width ) ;
}
/* not the first time thru and sizes haven't changed */
/* If the sizes haven't changed, we don't have to update the hints */
if ( fw = = TermWin . fwidth & & fh = = TermWin . fheight )
return ;
TermWin . fwidth = fw ;
TermWin . fheight = fh ;
/* check that size of boldFont is okay */
/* Check the bold font size and make sure it matches the normal font */
# ifndef NO_BOLDFONT
TermWin . boldFont = NULL ;
TermWin . boldFont = NULL ; /* FIXME: Memory leak? Not that anyone uses bold fonts.... */
if ( boldFont ! = NULL ) {
fw = boldFont - > min_bounds . width ;
@ -502,6 +593,7 @@ change_font(int init, const char *fontname)
TermWin . height = TermWin . nrow * TermWin . fheight ;
D_FONT ( ( " -> New font width/height = %ldx%ld, making the terminal size %ldx%ld \n " , TermWin . fwidth , TermWin . fheight , TermWin . width , TermWin . height ) ) ;
/* If we're initializing, *we* do the size hints. If not, resize the parent window. */
if ( init ) {
szHint . width_inc = TermWin . fwidth ;
szHint . height_inc = TermWin . fheight ;