#define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field)
#include <fontutils.h>
#include <main.h>
#include <data.h>
#include <menu.h>
#include <xstrings.h>
#include <xterm.h>
#include <stdio.h>
#include <ctype.h>
#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
(((cs)->rbearing|(cs)->lbearing| \
(cs)->ascent|(cs)->descent) == 0))
#define CI_GET_CHAR_INFO_1D(fs,col,def,cs) \
{ \
cs = def; \
if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
if (fs->per_char == NULL) { \
cs = &fs->min_bounds; \
} else { \
cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
if (CI_NONEXISTCHAR(cs)) cs = def; \
} \
} \
}
#define CI_GET_CHAR_INFO_2D(fs,row,col,def,cs) \
{ \
cs = def; \
if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
if (fs->per_char == NULL) { \
cs = &fs->min_bounds; \
} else { \
cs = &fs->per_char[((row - fs->min_byte1) * \
(fs->max_char_or_byte2 - \
fs->min_char_or_byte2 + 1)) + \
(col - fs->min_char_or_byte2)]; \
if (CI_NONEXISTCHAR(cs)) cs = def; \
} \
} \
}
#define MAX_FONTNAME 200
typedef struct {
char *beginning;
char *weight;
char *slant;
char *wideness;
char *add_style;
int pixel_size;
char *point_size;
int res_x;
int res_y;
char *spacing;
int average_width;
char *end;
} FontNameProperties;
static char *
n_fields(char **source, int start, int stop)
{
int i;
char *str, *str1;
for (i = start - 1, str = *source; i; i--, str++)
if ((str = strchr(str, '-')) == 0)
return 0;
for (i = stop - start + 1, str1 = str; i; i--, str1++)
if ((str1 = strchr(str1, '-')) == 0)
return 0;
*(str1 - 1) = '\0';
*source = str1;
return str;
}
static FontNameProperties *
get_font_name_props(Display * dpy, XFontStruct * fs, char *result)
{
static FontNameProperties props;
static char *last_name;
register XFontProp *fp;
register int i;
Atom fontatom = XInternAtom(dpy, "FONT", False);
char *name;
char *str;
for (name = 0, i = 0, fp = fs->properties;
i < fs->n_properties;
i++, fp++)
if (fp->name == fontatom)
name = XGetAtomName(dpy, fp->card32);
if (name == 0)
return 0;
if (last_name != 0)
XFree(last_name);
last_name = name;
if (result != 0)
strcpy(result, name);
if ((props.beginning = n_fields(&name, 1, 3)) == 0)
return 0;
if ((props.weight = n_fields(&name, 1, 1)) == 0)
return 0;
if ((props.slant = n_fields(&name, 1, 1)) == 0)
return 0;
if ((props.wideness = n_fields(&name, 1, 1)) == 0)
return 0;
if ((props.add_style = n_fields(&name, 1, 1)) == 0)
return 0;
if ((str = n_fields(&name, 1, 1)) == 0)
return 0;
if ((props.pixel_size = atoi(str)) == 0)
return 0;
if ((props.point_size = n_fields(&name, 1, 1)) == 0)
return 0;
if ((str = n_fields(&name, 1, 1)) == 0)
return 0;
if ((props.res_x = atoi(str)) == 0)
return 0;
if ((str = n_fields(&name, 1, 1)) == 0)
return 0;
if ((props.res_y = atoi(str)) == 0)
return 0;
if ((props.spacing = n_fields(&name, 1, 1)) == 0)
return 0;
if ((str = n_fields(&name, 1, 1)) == 0)
return 0;
if ((props.average_width = atoi(str)) == 0)
return 0;
props.end = name;
return &props;
}
static char *
bold_font_name(FontNameProperties * props, Bool useWidth)
{
static char ret[MAX_FONTNAME];
char average_width[MAX_FONTNAME];
if (useWidth)
sprintf(average_width, "%d", props->average_width);
else
strcpy(average_width, "*");
sprintf(ret, "%s-bold-%s-%s-%s-%d-%s-%d-%d-%s-%s-%s",
props->beginning,
props->slant,
props->wideness,
props->add_style,
props->pixel_size,
props->point_size,
props->res_x,
props->res_y,
props->spacing,
average_width,
props->end);
return ret;
}
#if OPT_WIDE_CHARS
static char *
wide_font_name(FontNameProperties * props)
{
static char ret[MAX_FONTNAME];
sprintf(ret, "%s-%s-%s-*-*-%d-%s-%d-%d-%s-%i-%s",
props->beginning,
props->weight,
props->slant,
props->pixel_size,
props->point_size,
props->res_x,
props->res_y,
props->spacing,
props->average_width * 2,
props->end);
return ret;
}
#endif
#if OPT_DEC_CHRSET
char *
xtermSpecialFont(unsigned atts, unsigned chrset)
{
#if OPT_TRACE
static char old_spacing[80];
static FontNameProperties old_props;
#endif
TScreen *screen = &term->screen;
FontNameProperties *props;
char tmp[MAX_FONTNAME];
char *ret;
char *width;
int pixel_size;
int res_x;
int res_y;
props = get_font_name_props(screen->display, screen->fnt_norm, (char *) 0);
if (props == 0)
return 0;
pixel_size = props->pixel_size;
res_x = props->res_x;
res_y = props->res_y;
if (atts & BOLD)
width = "bold";
else
width = props->weight;
if (CSET_DOUBLE(chrset))
res_x *= 2;
if (chrset == CSET_DHL_TOP
|| chrset == CSET_DHL_BOT) {
res_y *= 2;
pixel_size *= 2;
}
#if OPT_TRACE
if (old_props.res_x != res_x
|| old_props.res_x != res_y
|| old_props.pixel_size != pixel_size
|| strcmp(old_props.spacing, props->spacing)) {
TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset));
TRACE(("res_x = %d\n", res_x));
TRACE(("res_y = %d\n", res_y));
TRACE(("point_size = %s\n", props->point_size));
TRACE(("pixel_size = %d\n", pixel_size));
TRACE(("spacing = %s\n", props->spacing));
old_props.res_x = res_x;
old_props.res_x = res_y;
old_props.pixel_size = pixel_size;
old_props.spacing = strcpy(old_spacing, props->spacing);
}
#endif
if (atts & NORESOLUTION)
sprintf(tmp, "%s-%s-%s-%s-%s-%d-%s-*-*-%s-*-%s",
props->beginning,
width,
props->slant,
props->wideness,
props->add_style,
pixel_size,
props->point_size,
props->spacing,
props->end);
else
sprintf(tmp, "%s-%s-%s-%s-%s-%d-%s-%d-%d-%s-*-%s",
props->beginning,
width,
props->slant,
props->wideness,
props->add_style,
pixel_size,
props->point_size,
res_x,
res_y,
props->spacing,
props->end);
ret = XtMalloc(strlen(tmp) + 1);
strcpy(ret, tmp);
return ret;
}
#endif
static Boolean
same_font_name(char *pattern, char *match)
{
while (*pattern && *match) {
if (*pattern == *match) {
pattern++;
match++;
} else if (*pattern == '*' || *match == '*') {
if (same_font_name(pattern + 1, match)) {
return True;
} else if (same_font_name(pattern, match + 1)) {
return True;
} else {
return False;
}
} else {
if (char2lower(*pattern++) != char2lower(*match++))
return False;
}
}
return (*pattern == *match);
}
static int
got_bold_font(Display * dpy, XFontStruct * fs, char *requested)
{
char actual[MAX_FONTNAME];
int got;
if (get_font_name_props(dpy, fs, actual) == 0)
got = 0;
else
got = same_font_name(requested, actual);
return got;
}
static int
same_font_size(XFontStruct * nfs, XFontStruct * bfs)
{
TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
nfs->ascent + nfs->descent,
bfs->ascent + bfs->descent,
nfs->min_bounds.width, bfs->min_bounds.width,
nfs->max_bounds.width, bfs->max_bounds.width));
return term->screen.free_bold_box
|| ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
&& (nfs->min_bounds.width == bfs->min_bounds.width
|| nfs->min_bounds.width == bfs->min_bounds.width + 1)
&& (nfs->max_bounds.width == bfs->max_bounds.width
|| nfs->max_bounds.width == bfs->max_bounds.width + 1));
}
static int
is_fixed_font(XFontStruct * fs)
{
if (fs)
return (fs->min_bounds.width == fs->max_bounds.width);
return 1;
}
#if OPT_WIDE_CHARS
static int
is_double_width_font(XFontStruct * fs)
{
return ((2 * fs->min_bounds.width) == fs->max_bounds.width);
}
#else
#define is_double_width_font(fs) 0
#endif
#if OPT_WIDE_CHARS && defined(XRENDERFONT) && defined(HAVE_TYPE_FCCHAR32)
#define HALF_WIDTH_TEST_STRING "1234567890"
#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
"\xe5\x9b\x9b\xe4\xba\x94" \
"\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
"\xe4\xb9\x9d\xef\xa6\xb2"
#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
"\xec\x82\xac\xec\x98\xa4" \
"\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
"\xea\xb5\xac\xec\x98\x81"
#define HALF_WIDTH_CHAR1 0x0031
#define HALF_WIDTH_CHAR2 0x0057
#define FULL_WIDTH_CHAR1 0x4E00
#define FULL_WIDTH_CHAR2 0xAC00
static int
is_double_width_font_xft(Display * dpy, XftFont * font)
{
XGlyphInfo gi1, gi2;
FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
char *fwstr = FULL_WIDTH_TEST_STRING;
char *hwstr = HALF_WIDTH_TEST_STRING;
if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
return 0;
else
fwstr = FULL_WIDTH_TEST_STRING2;
}
XftTextExtents32(dpy, font, &c1, 1, &gi1);
XftTextExtents32(dpy, font, &c2, 1, &gi2);
if (gi1.xOff != gi2.xOff)
return 0;
XftTextExtentsUtf8(dpy, font, (FcChar8 *) hwstr, strlen(hwstr), &gi1);
XftTextExtentsUtf8(dpy, font, (FcChar8 *) fwstr, strlen(fwstr), &gi2);
return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
}
#else
#define is_double_width_font_xft(dpy, xftfont) 0
#endif
#define EmptyFont(fs) (fs != 0 \
&& ((fs)->ascent + (fs)->descent == 0 \
|| (fs)->max_bounds.width == 0))
#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
* (fs)->max_bounds.width)
const VTFontNames *
xtermFontName(char *normal)
{
static VTFontNames data;
memset(&data, 0, sizeof(data));
data.f_n = normal;
return &data;
}
int
xtermLoadFont(TScreen * screen,
const VTFontNames * fonts,
Bool doresize,
int fontnum)
{
VTFontNames myfonts;
FontNameProperties *fp;
XFontStruct *nfs = NULL;
XFontStruct *bfs = NULL;
#if OPT_WIDE_CHARS
XFontStruct *wfs = NULL;
XFontStruct *wbfs = NULL;
#endif
XGCValues xgcv;
unsigned long mask;
GC new_normalGC = NULL;
GC new_normalboldGC = NULL;
GC new_reverseGC = NULL;
GC new_reverseboldGC = NULL;
Pixel new_normal;
Pixel new_revers;
char *tmpname = NULL;
char normal[MAX_FONTNAME];
Boolean proportional = False;
int ch;
memset(&myfonts, 0, sizeof(myfonts));
if (fonts != 0)
myfonts = *fonts;
if (myfonts.f_n == 0)
return 0;
if (fontnum == fontMenu_fontescape
&& myfonts.f_n != screen->menu_font_names[fontnum]) {
if ((tmpname = x_strdup(myfonts.f_n)) == 0)
return 0;
}
TRACE(("xtermLoadFont normal %s\n", myfonts.f_n));
if (!(nfs = XLoadQueryFont(screen->display, myfonts.f_n)))
goto bad;
if (EmptyFont(nfs))
goto bad;
strcpy(normal, myfonts.f_n);
if (myfonts.f_b == 0) {
fp = get_font_name_props(screen->display, nfs, normal);
if (fp != 0) {
myfonts.f_b = bold_font_name(fp, True);
if ((bfs = XLoadQueryFont(screen->display, myfonts.f_b)) == 0) {
myfonts.f_b = bold_font_name(fp, False);
bfs = XLoadQueryFont(screen->display, myfonts.f_b);
}
TRACE(("...derived bold %s\n", myfonts.f_b));
}
if (fp == 0 || bfs == 0) {
bfs = nfs;
TRACE(("...cannot load a matching bold font\n"));
} else if (same_font_size(nfs, bfs)
&& got_bold_font(screen->display, bfs, myfonts.f_b)) {
TRACE(("...got a matching bold font\n"));
} else {
XFreeFont(screen->display, bfs);
bfs = nfs;
TRACE(("...did not get a matching bold font\n"));
}
} else if ((bfs = XLoadQueryFont(screen->display, myfonts.f_b)) == 0) {
bfs = nfs;
TRACE(("...cannot load bold font %s\n", myfonts.f_b));
}
if_OPT_WIDE_CHARS(screen, {
if (myfonts.f_w == 0 && !is_double_width_font(nfs)) {
fp = get_font_name_props(screen->display, nfs, normal);
if (fp != 0) {
myfonts.f_w = wide_font_name(fp);
TRACE(("...derived wide %s\n", myfonts.f_w));
}
}
if (myfonts.f_w) {
wfs = XLoadQueryFont(screen->display, myfonts.f_w);
} else {
wfs = nfs;
}
if (myfonts.f_wb) {
wbfs = XLoadQueryFont(screen->display, myfonts.f_wb);
} else if (is_double_width_font(bfs)) {
wbfs = bfs;
} else {
wbfs = wfs;
TRACE(("...cannot load wide bold font %s\n", myfonts.f_wb));
}
if (EmptyFont(wbfs))
goto bad;
});
if (EmptyFont(bfs))
goto bad;
if (!same_font_size(nfs, bfs)
&& (is_fixed_font(nfs) && is_fixed_font(bfs))) {
XFreeFont(screen->display, bfs);
bfs = nfs;
TRACE(("...fixing mismatched normal/bold fonts\n"));
if (myfonts.f_b != 0) {
myfonts.f_b = 0;
return xtermLoadFont(screen,
&myfonts,
doresize,
fontnum);
}
}
if_OPT_WIDE_CHARS(screen, {
if (wfs != 0
&& wbfs != 0
&& !same_font_size(wfs, wbfs)
&& (is_fixed_font(wfs) && is_fixed_font(wbfs))) {
XFreeFont(screen->display, wbfs);
wbfs = wfs;
TRACE(("...fixing mismatched normal/bold wide fonts\n"));
if (myfonts.f_wb != 0) {
myfonts.f_wb = 0;
return xtermLoadFont(screen,
&myfonts,
doresize,
fontnum);
}
}
});
if (!is_fixed_font(nfs)
|| !is_fixed_font(bfs)
|| nfs->max_bounds.width != bfs->max_bounds.width) {
TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
nfs->min_bounds.width,
nfs->max_bounds.width,
bfs->min_bounds.width,
bfs->max_bounds.width));
proportional = True;
}
if_OPT_WIDE_CHARS(screen, {
if (wfs != 0
&& wbfs != 0
&& (!is_fixed_font(wfs)
|| !is_fixed_font(wbfs)
|| wfs->max_bounds.width != wbfs->max_bounds.width)) {
TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
wfs->min_bounds.width,
wfs->max_bounds.width,
wbfs->min_bounds.width,
wbfs->max_bounds.width));
proportional = True;
}
});
mask = (GCFont | GCForeground | GCBackground | GCGraphicsExposures |
GCFunction);
new_normal = getXtermForeground(term->flags, term->cur_foreground);
new_revers = getXtermBackground(term->flags, term->cur_background);
xgcv.font = nfs->fid;
xgcv.foreground = new_normal;
xgcv.background = new_revers;
xgcv.graphics_exposures = TRUE;
xgcv.function = GXcopy;
new_normalGC = XtGetGC((Widget) term, mask, &xgcv);
if (!new_normalGC)
goto bad;
if (nfs == bfs) {
new_normalboldGC = new_normalGC;
} else {
xgcv.font = bfs->fid;
new_normalboldGC = XtGetGC((Widget) term, mask, &xgcv);
if (!new_normalboldGC)
goto bad;
}
xgcv.font = nfs->fid;
xgcv.foreground = new_revers;
xgcv.background = new_normal;
new_reverseGC = XtGetGC((Widget) term, mask, &xgcv);
if (!new_reverseGC)
goto bad;
if (nfs == bfs) {
new_reverseboldGC = new_reverseGC;
} else {
xgcv.font = bfs->fid;
new_reverseboldGC = XtGetGC((Widget) term, mask, &xgcv);
if (!new_reverseboldGC)
goto bad;
}
if (NormalGC(screen) != NormalBoldGC(screen))
XtReleaseGC((Widget) term, NormalBoldGC(screen));
XtReleaseGC((Widget) term, NormalGC(screen));
if (ReverseGC(screen) != ReverseBoldGC(screen))
XtReleaseGC((Widget) term, ReverseBoldGC(screen));
XtReleaseGC((Widget) term, ReverseGC(screen));
NormalGC(screen) = new_normalGC;
NormalBoldGC(screen) = new_normalboldGC;
ReverseGC(screen) = new_reverseGC;
ReverseBoldGC(screen) = new_reverseboldGC;
if (screen->fnt_bold != 0
&& screen->fnt_bold != screen->fnt_norm)
XFreeFont(screen->display, screen->fnt_bold);
if (screen->fnt_norm != 0)
XFreeFont(screen->display, screen->fnt_norm);
screen->fnt_norm = nfs;
screen->fnt_bold = bfs;
#if OPT_WIDE_CHARS
screen->fnt_dwd = wfs;
if (wbfs == NULL)
wbfs = wfs;
screen->fnt_dwdb = wbfs;
#endif
screen->fnt_prop = proportional;
screen->fnt_boxes = True;
#if OPT_BOX_CHARS
#ifdef XRENDERFONT
if (screen->renderFont != 0) {
screen->fnt_boxes = False;
} else
#endif
{
for (ch = 1; ch < 32; ch++) {
int n = ch;
#if OPT_WIDE_CHARS
if (screen->utf8_mode) {
n = dec2ucs(ch);
if (n == UCS_REPL)
continue;
}
#endif
if (xtermMissingChar(n, nfs)
|| xtermMissingChar(n, bfs)) {
screen->fnt_boxes = False;
break;
}
}
}
TRACE(("Will %suse internal line-drawing characters\n",
screen->fnt_boxes ? "not " : ""));
#endif
screen->enbolden = screen->bold_mode
&& ((nfs == bfs) || same_font_name(normal, myfonts.f_b));
TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
screen->enbolden ? "" : "not "));
set_menu_font(False);
screen->menu_font_number = fontnum;
set_menu_font(True);
if (tmpname) {
if (screen->menu_font_names[fontnum])
free(screen->menu_font_names[fontnum]);
screen->menu_font_names[fontnum] = tmpname;
if (fontnum == fontMenu_fontescape) {
set_sensitivity(term->screen.fontMenu,
fontMenuEntries[fontMenu_fontescape].widget,
TRUE);
}
#if OPT_SHIFT_FONTS
screen->menu_font_sizes[fontnum] = FontSize(nfs);
#endif
}
set_cursor_gcs(screen);
xtermUpdateFontInfo(screen, doresize);
return 1;
bad:
if (tmpname)
free(tmpname);
if (new_normalGC)
XtReleaseGC((Widget) term, new_normalGC);
if (new_normalboldGC && new_normalGC != new_normalboldGC)
XtReleaseGC((Widget) term, new_normalboldGC);
if (new_reverseGC)
XtReleaseGC((Widget) term, new_reverseGC);
if (new_reverseboldGC && new_reverseGC != new_reverseboldGC)
XtReleaseGC((Widget) term, new_reverseboldGC);
if (nfs)
XFreeFont(screen->display, nfs);
if (bfs && nfs != bfs)
XFreeFont(screen->display, bfs);
#if OPT_WIDE_CHARS
if (wfs)
XFreeFont(screen->display, wfs);
if (wbfs && wbfs != wfs)
XFreeFont(screen->display, wbfs);
#endif
return 0;
}
#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
typedef struct {
VTFontNames default_font;
char *menu_font_names[fontMenu_lastBuiltin + 1];
} SubResourceRec;
#define MERGE_SUBFONT(src,dst,name) if (dst.name == 0) dst.name = src.name
#define COPY_MENU_FONTS(src,dst) \
for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) \
dst.menu_font_names[n] = src.menu_font_names[n]
Bool
xtermLoadVTFonts(XtermWidget w, char *myName, char *myClass)
{
static Boolean initialized = False;
static SubResourceRec original, referenceRec, subresourceRec;
static XtResource font_resources[] =
{
Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
#if OPT_WIDE_CHARS
Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
#endif
Sres(XtNfont1, XtCFont1, menu_font_names[fontMenu_font1], NULL),
Sres(XtNfont2, XtCFont2, menu_font_names[fontMenu_font2], NULL),
Sres(XtNfont3, XtCFont3, menu_font_names[fontMenu_font3], NULL),
Sres(XtNfont4, XtCFont4, menu_font_names[fontMenu_font4], NULL),
Sres(XtNfont5, XtCFont5, menu_font_names[fontMenu_font5], NULL),
Sres(XtNfont6, XtCFont6, menu_font_names[fontMenu_font6], NULL),
};
Cardinal n;
Boolean status = True;
if (!initialized) {
initialized = True;
TRACE(("xtermLoadVTFonts saving original\n"));
original.default_font = w->misc.default_font;
COPY_MENU_FONTS(w->screen, original);
}
if (myName == 0 || *myName == 0) {
TRACE(("xtermLoadVTFonts restoring original\n"));
w->misc.default_font = original.default_font;
COPY_MENU_FONTS(original, w->screen);
for (n = 0; n < XtNumber(original.menu_font_names); ++n)
w->screen.menu_font_names[n] = original.menu_font_names[n];
} else {
TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
memset(&subresourceRec, 0, sizeof(subresourceRec));
XtGetSubresources((Widget) w, (XtPointer) & subresourceRec,
myName, myClass,
font_resources,
(Cardinal) XtNumber(font_resources),
NULL, (Cardinal) 0);
if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))) {
MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_n);
MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_b);
#if OPT_WIDE_CHARS
MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_w);
MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_wb);
#endif
for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n)
MERGE_SUBFONT(w->screen, subresourceRec, menu_font_names[n]);
w->misc.default_font = subresourceRec.default_font;
COPY_MENU_FONTS(subresourceRec, w->screen);
w->screen.menu_font_names[fontMenu_fontdefault] = w->misc.default_font.f_n;
} else {
TRACE(("...no resources found\n"));
status = False;
}
}
return status;
}
#endif
#if OPT_LOAD_VTFONTS
void
HandleLoadVTFonts(Widget w GCC_UNUSED,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal * param_count GCC_UNUSED)
{
char buf[80];
char *myName = (*param_count > 0) ? params[0] : "";
char *convert = (*param_count > 1) ? params[1] : myName;
char *myClass = (char *) MyStackAlloc(strlen(convert), buf);
int n;
TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
strcpy(myClass, convert);
if (*param_count == 1
&& islower(CharOf(myClass[0])))
myClass[0] = toupper(CharOf(myClass[0]));
if (xtermLoadVTFonts(term, myName, myClass)) {
int font_number = term->screen.menu_font_number;
if (font_number > fontMenu_lastBuiltin)
font_number = fontMenu_lastBuiltin;
for (n = 0; n < NMENUFONTS; ++n)
term->screen.menu_font_sizes[n] = 0;
SetVTFont(font_number, TRUE,
((font_number == fontMenu_fontdefault)
? &(term->misc.default_font)
: NULL));
}
MyStackFree(myClass, buf);
}
#endif
void
xtermSetCursorBox(TScreen * screen)
{
static XPoint VTbox[NBOX];
XPoint *vp;
vp = &VTbox[1];
(vp++)->x = FontWidth(screen) - 1;
(vp++)->y = FontHeight(screen) - 1;
(vp++)->x = -(FontWidth(screen) - 1);
vp->y = -(FontHeight(screen) - 1);
screen->box = VTbox;
}
void
xtermComputeFontInfo(TScreen * screen,
struct _vtwin *win,
XFontStruct * font,
int sbwidth)
{
int i, j, width, height;
#ifdef XRENDERFONT
Display *dpy = screen->display;
if (!screen->renderFont && term->misc.face_name) {
XftPattern *pat, *match;
XftResult result;
pat = XftNameParse(term->misc.face_name);
XftPatternBuild(pat,
XFT_FAMILY, XftTypeString, "mono",
XFT_SIZE, XftTypeInteger, term->misc.face_size,
XFT_SPACING, XftTypeInteger, XFT_MONO,
(void *) 0);
match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &result);
screen->renderFont = XftFontOpenPattern(dpy, match);
if (!screen->renderFont && match)
XftPatternDestroy(match);
if (screen->renderFont) {
XftPatternBuild(pat,
XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD,
XFT_CHAR_WIDTH, XftTypeInteger, screen->renderFont->max_advance_width,
(void *) 0);
match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &result);
screen->renderFontBold = XftFontOpenPattern(dpy, match);
if (!screen->renderFontBold && match)
XftPatternDestroy(match);
if (screen->fnt_boxes) {
screen->fnt_boxes = False;
TRACE(("Xft opened - will %suse internal line-drawing characters\n",
screen->fnt_boxes ? "not " : ""));
}
}
if (pat)
XftPatternDestroy(pat);
}
if (screen->renderFont) {
win->f_width = screen->renderFont->max_advance_width;
win->f_height = screen->renderFont->height;
win->f_ascent = screen->renderFont->ascent;
win->f_descent = screen->renderFont->descent;
if (win->f_height < win->f_ascent + win->f_descent)
win->f_height = win->f_ascent + win->f_descent;
if (is_double_width_font_xft(screen->display, screen->renderFont))
win->f_width >>= 1;
} else
#endif
{
if (is_double_width_font(font)) {
win->f_width = (font->min_bounds.width);
} else {
win->f_width = (font->max_bounds.width);
}
win->f_height = (font->ascent + font->descent);
win->f_ascent = font->ascent;
win->f_descent = font->descent;
}
i = 2 * screen->border + sbwidth;
j = 2 * screen->border;
width = (screen->max_col + 1) * win->f_width + i;
height = (screen->max_row + 1) * win->f_height + j;
win->fullwidth = width;
win->fullheight = height;
win->width = width - i;
win->height = height - j;
}
void
xtermSaveFontInfo(TScreen * screen, XFontStruct * font)
{
screen->fnt_wide = (font->max_bounds.width);
screen->fnt_high = (font->ascent + font->descent);
}
void
xtermUpdateFontInfo(TScreen * screen, Bool doresize)
{
int scrollbar_width;
struct _vtwin *win = &(screen->fullVwin);
scrollbar_width = (term->misc.scrollbar
? screen->scrollWidget->core.width +
screen->scrollWidget->core.border_width
: 0);
xtermComputeFontInfo(screen, win, screen->fnt_norm, scrollbar_width);
xtermSaveFontInfo(screen, screen->fnt_norm);
if (doresize) {
if (VWindow(screen)) {
XClearWindow(screen->display, VWindow(screen));
}
DoResizeScreen(term);
if (screen->scrollWidget)
ResizeScrollBar(screen);
Redraw();
}
xtermSetCursorBox(screen);
}
#if OPT_BOX_CHARS
Bool
xtermMissingChar(unsigned ch, XFontStruct * font)
{
if (font != 0
&& font->per_char != 0
&& !font->all_chars_exist) {
static XCharStruct dft, *tmp = &dft, *pc = 0;
if (font->max_byte1 == 0) {
#if OPT_WIDE_CHARS
if (ch > 255) {
TRACE(("xtermMissingChar %#04x (row)\n", ch));
return True;
}
#endif
CI_GET_CHAR_INFO_1D(font, E2A(ch), tmp, pc);
}
#if OPT_WIDE_CHARS
else {
CI_GET_CHAR_INFO_2D(font, (ch >> 8), (ch & 0xff), tmp, pc);
}
#else
if (!pc)
return False;
#endif
if (CI_NONEXISTCHAR(pc)) {
TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
return True;
}
}
if (ch < 32
&& term->screen.force_box_chars) {
TRACE(("xtermMissingChar %#04x (forced off)\n", ch));
return True;
}
return False;
}
#define BOX_HIGH 60
#define BOX_WIDE 60
#define MID_HIGH (BOX_HIGH/2)
#define MID_WIDE (BOX_WIDE/2)
#define SCALE_X(n) n = (n * (font_width-1)) / (BOX_WIDE-1)
#define SCALE_Y(n) n = (n * (font_height-1)) / (BOX_HIGH-1)
#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
void
xtermDrawBoxChar(TScreen * screen, int ch, unsigned flags, GC gc, int x, int y)
{
static const short diamond[] =
{
SEG( MID_WIDE, BOX_HIGH/4, 3*BOX_WIDE/4, MID_WIDE),
SEG(3*BOX_WIDE/4, MID_WIDE, MID_WIDE, 3*BOX_HIGH/4),
SEG( MID_WIDE, 3*BOX_HIGH/4, BOX_WIDE/4, MID_HIGH),
SEG( BOX_WIDE/4, MID_HIGH, MID_WIDE, BOX_HIGH/4),
SEG( MID_WIDE, BOX_HIGH/3, 2*BOX_WIDE/3, MID_WIDE),
SEG(2*BOX_WIDE/3, MID_WIDE, MID_WIDE, 2*BOX_HIGH/3),
SEG( MID_WIDE, 2*BOX_HIGH/3, BOX_WIDE/3, MID_HIGH),
SEG( BOX_WIDE/3, MID_HIGH, MID_WIDE, BOX_HIGH/3),
SEG( BOX_WIDE/4, MID_HIGH, 3*BOX_WIDE/4, MID_HIGH),
SEG( MID_WIDE, BOX_HIGH/4, MID_WIDE, 3*BOX_HIGH/4),
-1
}, degrees[] =
{
SEG( MID_WIDE, BOX_HIGH/4, 2*BOX_WIDE/3, 3*BOX_HIGH/8),
SEG(2*BOX_WIDE/3, 3*BOX_HIGH/8, MID_WIDE, MID_HIGH),
SEG( MID_WIDE, MID_HIGH, BOX_WIDE/3, 3*BOX_HIGH/8),
SEG( BOX_WIDE/3, 3*BOX_HIGH/8, MID_WIDE, BOX_HIGH/4),
-1
}, lower_right_corner[] =
{
SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH),
SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0),
-1
}, upper_right_corner[] =
{
SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH),
SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
-1
}, upper_left_corner[] =
{
SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH),
SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
-1
}, lower_left_corner[] =
{
SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH),
SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH),
-1
}, cross[] =
{
SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
-1
}, scan_line_1[] =
{
SEG( 0, 0, BOX_WIDE, 0),
-1
}, scan_line_3[] =
{
SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4),
-1
}, scan_line_7[] =
{
SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
-1
}, scan_line_9[] =
{
SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3 * BOX_HIGH / 4),
-1
}, horizontal_line[] =
{
SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH),
-1
}, left_tee[] =
{
SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH),
-1
}, right_tee[] =
{
SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH),
-1
}, bottom_tee[] =
{
SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH),
-1
}, top_tee[] =
{
SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
-1
}, vertical_line[] =
{
SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
-1
}, less_than_or_equal[] =
{
SEG(5*BOX_WIDE/6, BOX_HIGH/6, BOX_WIDE/5, MID_HIGH),
SEG(5*BOX_WIDE/6, 5*BOX_HIGH/6, BOX_WIDE/5, MID_HIGH),
SEG( BOX_WIDE/6, 5*BOX_HIGH/6, 5*BOX_WIDE/6, 5*BOX_HIGH/6),
-1
}, greater_than_or_equal[] =
{
SEG( BOX_WIDE/6, BOX_HIGH /6, 5*BOX_WIDE/6, MID_HIGH),
SEG( BOX_WIDE/6, 5*BOX_HIGH/6, 5*BOX_WIDE/6, MID_HIGH),
SEG( BOX_WIDE/6, 5*BOX_HIGH/6, 5*BOX_WIDE/6, 5*BOX_HIGH/6),
-1
};
static const short *lines[] =
{
0,
diamond,
0,
0,
0,
0,
0,
degrees,
0,
0,
0,
lower_right_corner,
upper_right_corner,
upper_left_corner,
lower_left_corner,
cross,
scan_line_1,
scan_line_3,
scan_line_7,
scan_line_9,
horizontal_line,
left_tee,
right_tee,
bottom_tee,
top_tee,
vertical_line,
less_than_or_equal,
greater_than_or_equal,
0,
0,
0,
0,
};
XGCValues values;
GC gc2;
const short *p;
int font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide;
int font_height = ((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high;
#if OPT_WIDE_CHARS
if (screen->utf8_mode
#ifdef XRENDERFONT
&& screen->renderFont == 0
#endif
&& (ch > 127)
&& (ch != UCS_REPL)) {
unsigned n;
for (n = 1; n < 32; n++) {
if (dec2ucs(n) == ch
&& !xtermMissingChar(n, (flags & BOLD)
? screen->fnt_bold
: screen->fnt_norm)) {
TRACE(("...use xterm-style linedrawing\n"));
ch = n;
break;
}
}
}
#endif
TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
ch, font_height, font_width, y, x,
((ch < 0 || ch >= (int) (sizeof(lines) / sizeof(lines[0])))
? "-BAD"
: "")));
if (!XGetGCValues(screen->display, gc, GCBackground, &values))
return;
values.foreground = values.background;
gc2 = XCreateGC(screen->display, VWindow(screen), GCForeground, &values);
if (!(flags & NOBACKGROUND))
XFillRectangle(
screen->display, VWindow(screen), gc2, x, y,
font_width,
font_height);
XCopyGC(screen->display, gc, (1 << GCLastBit) - 1, gc2);
XSetLineAttributes(screen->display, gc2,
(flags & BOLD)
? ((font_height > 6)
? font_height / 6
: 1)
: ((font_height > 8)
? font_height / 8
: 1),
LineSolid,
CapProjecting,
JoinMiter);
if (ch >= 0
&& ch < (int) (sizeof(lines) / sizeof(lines[0]))
&& (p = lines[ch]) != 0) {
int coord[4];
int n = 0;
while (*p >= 0) {
coord[n++] = *p++;
if (n == 4) {
SCALE_X(coord[0]);
SCALE_Y(coord[1]);
SCALE_X(coord[2]);
SCALE_Y(coord[3]);
XDrawLine(
screen->display,
VWindow(screen), gc2,
x + coord[0], y + coord[1],
x + coord[2], y + coord[3]);
n = 0;
}
}
}
#if 0
else {
XDrawRectangle(
screen->display, VWindow(screen), gc, x, y,
font_width - 1,
font_height - 1);
}
#endif
XFreeGC(screen->display, gc2);
}
#endif
#if OPT_WIDE_CHARS
#define MY_UCS(ucs,dec) case ucs: result = dec; break
int
ucs2dec(int ch)
{
int result = ch;
if ((ch > 127)
&& (ch != UCS_REPL)) {
switch (ch) {
MY_UCS(0x25ae, 0);
MY_UCS(0x25c6, 1);
MY_UCS(0x2592, 2);
MY_UCS(0x2409, 3);
MY_UCS(0x240c, 4);
MY_UCS(0x240d, 5);
MY_UCS(0x240a, 6);
MY_UCS(0x00b0, 7);
MY_UCS(0x00b1, 8);
MY_UCS(0x2424, 9);
MY_UCS(0x240b, 10);
MY_UCS(0x2518, 11);
MY_UCS(0x2510, 12);
MY_UCS(0x250c, 13);
MY_UCS(0x2514, 14);
MY_UCS(0x253c, 15);
MY_UCS(0x23ba, 16);
MY_UCS(0x23bb, 17);
MY_UCS(0x2500, 18);
MY_UCS(0x23bc, 19);
MY_UCS(0x23bd, 20);
MY_UCS(0x251c, 21);
MY_UCS(0x2524, 22);
MY_UCS(0x2534, 23);
MY_UCS(0x252c, 24);
MY_UCS(0x2502, 25);
MY_UCS(0x2264, 26);
MY_UCS(0x2265, 27);
MY_UCS(0x03c0, 28);
MY_UCS(0x2260, 29);
MY_UCS(0x00a3, 30);
MY_UCS(0x00b7, 31);
}
}
return result;
}
#undef MY_UCS
#define MY_UCS(ucs,dec) case dec: result = ucs; break
int
dec2ucs(int ch)
{
int result = ch;
if (ch < 32) {
switch (ch) {
MY_UCS(0x25ae, 0);
MY_UCS(0x25c6, 1);
MY_UCS(0x2592, 2);
MY_UCS(0x2409, 3);
MY_UCS(0x240c, 4);
MY_UCS(0x240d, 5);
MY_UCS(0x240a, 6);
MY_UCS(0x00b0, 7);
MY_UCS(0x00b1, 8);
MY_UCS(0x2424, 9);
MY_UCS(0x240b, 10);
MY_UCS(0x2518, 11);
MY_UCS(0x2510, 12);
MY_UCS(0x250c, 13);
MY_UCS(0x2514, 14);
MY_UCS(0x253c, 15);
MY_UCS(0x23ba, 16);
MY_UCS(0x23bb, 17);
MY_UCS(0x2500, 18);
MY_UCS(0x23bc, 19);
MY_UCS(0x23bd, 20);
MY_UCS(0x251c, 21);
MY_UCS(0x2524, 22);
MY_UCS(0x2534, 23);
MY_UCS(0x252c, 24);
MY_UCS(0x2502, 25);
MY_UCS(0x2264, 26);
MY_UCS(0x2265, 27);
MY_UCS(0x03c0, 28);
MY_UCS(0x2260, 29);
MY_UCS(0x00a3, 30);
MY_UCS(0x00b7, 31);
}
}
return result;
}
#endif
#if OPT_SHIFT_FONTS
static XFontStruct *
xtermFindFont(TScreen * screen, int fontnum)
{
XFontStruct *nfs = 0;
char *name;
if ((name = screen->menu_font_names[fontnum]) != 0
&& (nfs = XLoadQueryFont(screen->display, name)) != 0) {
if (EmptyFont(nfs)) {
XFreeFont(screen->display, nfs);
nfs = 0;
}
}
return nfs;
}
static void
lookupFontSizes(TScreen * screen)
{
int n;
for (n = 0; n < NMENUFONTS; n++) {
if (screen->menu_font_sizes[n] == 0) {
XFontStruct *fs = xtermFindFont(screen, n);
screen->menu_font_sizes[n] = -1;
if (fs != 0) {
screen->menu_font_sizes[n] = FontSize(fs);
TRACE(("menu_font_sizes[%d] = %ld\n", n,
screen->menu_font_sizes[n]));
XFreeFont(screen->display, fs);
}
}
}
}
int
lookupRelativeFontSize(TScreen * screen, int old, int relative)
{
int n, m = -1;
lookupFontSizes(screen);
if (relative != 0) {
for (n = 0; n < NMENUFONTS; ++n) {
if (screen->menu_font_sizes[n] > 0 &&
screen->menu_font_sizes[n] != screen->menu_font_sizes[old]) {
int cmp_0 = ((screen->menu_font_sizes[n] >
screen->menu_font_sizes[old])
? relative
: -relative);
int cmp_m = ((m < 0)
? 1
: ((screen->menu_font_sizes[n] <
screen->menu_font_sizes[m])
? relative
: -relative));
if (cmp_0 > 0 && cmp_m > 0) {
m = n;
}
}
}
if (m >= 0) {
if (relative > 1)
m = lookupRelativeFontSize(screen, m, relative - 1);
else if (relative < -1)
m = lookupRelativeFontSize(screen, m, relative + 1);
}
}
return m;
}
void
HandleLargerFont(Widget w GCC_UNUSED,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal * param_count GCC_UNUSED)
{
if (term->misc.shift_fonts) {
TScreen *screen = &term->screen;
int m;
m = lookupRelativeFontSize(screen, screen->menu_font_number, 1);
if (m >= 0) {
SetVTFont(m, TRUE, NULL);
} else {
Bell(XkbBI_MinorError, 0);
}
}
}
void
HandleSmallerFont(Widget w GCC_UNUSED,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal * param_count GCC_UNUSED)
{
if (term->misc.shift_fonts) {
TScreen *screen = &term->screen;
int m;
m = lookupRelativeFontSize(screen, screen->menu_font_number, -1);
if (m >= 0) {
SetVTFont(m, TRUE, NULL);
} else {
Bell(XkbBI_MinorError, 0);
}
}
}
#endif
void
HandleSetFont(Widget w GCC_UNUSED,
XEvent * event GCC_UNUSED,
String * params,
Cardinal * param_count)
{
int fontnum;
VTFontNames fonts;
memset(&fonts, 0, sizeof(fonts));
if (*param_count == 0) {
fontnum = fontMenu_fontdefault;
} else {
Cardinal maxparams = 1;
switch (params[0][0]) {
case 'd':
case 'D':
case '0':
fontnum = fontMenu_fontdefault;
break;
case '1':
fontnum = fontMenu_font1;
break;
case '2':
fontnum = fontMenu_font2;
break;
case '3':
fontnum = fontMenu_font3;
break;
case '4':
fontnum = fontMenu_font4;
break;
case '5':
fontnum = fontMenu_font5;
break;
case '6':
fontnum = fontMenu_font6;
break;
case 'e':
case 'E':
fontnum = fontMenu_fontescape;
#if OPT_WIDE_CHARS
maxparams = 5;
#else
maxparams = 3;
#endif
break;
case 's':
case 'S':
fontnum = fontMenu_fontsel;
maxparams = 2;
break;
default:
Bell(XkbBI_MinorError, 0);
return;
}
if (*param_count > maxparams) {
Bell(XkbBI_MinorError, 0);
return;
}
switch (*param_count) {
#if OPT_WIDE_CHARS
case 5:
fonts.f_wb = params[4];
case 4:
fonts.f_w = params[3];
#endif
case 3:
fonts.f_b = params[2];
case 2:
fonts.f_n = params[1];
break;
}
}
SetVTFont(fontnum, True, &fonts);
}
void
SetVTFont(int i,
Bool doresize,
const VTFontNames * fonts)
{
TScreen *screen = &term->screen;
TRACE(("SetVTFont(i=%d, f_n=%s, f_b=%s)\n", i,
(fonts && fonts->f_n) ? fonts->f_n : "<null>",
(fonts && fonts->f_b) ? fonts->f_b : "<null>"));
if (i >= 0 && i < NMENUFONTS) {
VTFontNames myfonts;
memset(&myfonts, 0, sizeof(myfonts));
if (fonts != 0)
myfonts = *fonts;
if (i == fontMenu_fontsel) {
FindFontSelection(myfonts.f_n, False);
return;
} else {
if (myfonts.f_n == 0)
myfonts.f_n = screen->menu_font_names[i];
if (xtermLoadFont(screen,
&myfonts,
doresize, i)) {
return;
}
}
}
Bell(XkbBI_MinorError, 0);
return;
}