diff --git a/include/winX.h b/include/winX.h index 2a62f892e..0754ffaef 100644 --- a/include/winX.h +++ b/include/winX.h @@ -9,6 +9,10 @@ #ifndef WINX_H #define WINX_H +#ifdef USE_XFT +#include +#endif + #ifndef COLOR_H #include "color.h" /* CLR_MAX */ #endif @@ -317,6 +321,16 @@ typedef struct { Pixel pet_mark_color; /* color of pet mark */ String pilemark_bitmap; /* X11 bitmap file used to mark item piles */ Pixel pilemark_color; /* color of item pile mark */ +#ifdef USE_XFT + String font_map; /* font for the map */ + String font_menu; /* font for menus */ + String font_message; /* font for the message window */ + String font_status; /* font for the status window */ + String font_text; /* font for text windows */ +#ifdef GRAPHIC_TOMBSTONE + String font_rip; /* font for tombstone */ +#endif +#endif #ifdef GRAPHIC_TOMBSTONE String tombstone; /* name of XPM file for tombstone */ int tombtext_x; /* x-coord of center of first tombstone text */ @@ -525,6 +539,12 @@ extern XFontStruct *X11_italic_font(Display *, XFontStruct *); extern XFontStruct *X11_unicode_font(Display *, XFontStruct *); #endif +#ifdef USE_XFT +extern XftFont *X11_new_font(Widget w, boolean bold, int win_type); +extern void X11_release_font(Widget w, XftFont *font); +extern void X11_new_color(Widget w, Pixel pixel, XftColor *color); +#endif + /* ### winlabel.c ### */ /* Functions for management of enhanced labels */ extern void X11_wrap_widget(Widget); diff --git a/sys/unix/hints/linux.500 b/sys/unix/hints/linux.500 index c786f4f62..45da9ee12 100755 --- a/sys/unix/hints/linux.500 +++ b/sys/unix/hints/linux.500 @@ -397,6 +397,7 @@ endif # MAKEFILE_SRC ifdef WANT_WIN_X11 USE_XPM=1 +USE_XFT=1 WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm ifndef CROSSCOMPILE @@ -408,6 +409,10 @@ POSTINSTALL += bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; ( cd $(HACKDIR); X11CFLAGS = -I/opt/X11/include # avoid repeated complaints about _X_NONNULL(args...) in X11CFLAGS += -Wno-variadic-macros +ifdef USE_XFT +X11CFLAGS += -DUSE_XFT $(shell pkg-config --cflags xft fontconfig) +WINX11LIB += $(shell pkg-config --libs xft fontconfig) +endif ifdef USE_XPM CFLAGS += -DUSE_XPM WINX11LIB += -lXpm diff --git a/sys/unix/hints/macOS.500 b/sys/unix/hints/macOS.500 index be6402ace..223dfb7c3 100755 --- a/sys/unix/hints/macOS.500 +++ b/sys/unix/hints/macOS.500 @@ -277,6 +277,7 @@ HINTOBJ=$(CHAINOBJ) endif # WANT_WIN_CHAIN ifdef WANT_WIN_X11 +USE_XFT=1 USE_XPM=1 WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm @@ -287,6 +288,10 @@ POSTINSTALL += bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; ( cd $(HACKDIR); X11CFLAGS = -I/opt/X11/include # avoid repeated complaints about _X_NONNULL(args...) in X11CFLAGS += -Wno-variadic-macros +ifdef USE_XFT +X11CFLAGS += -DUSE_XFT $(shell pkg-config --cflags xft fontconfig) +WINX11LIB += $(shell pkg-config --libs xft fontconfig) +endif ifdef USE_XPM CFLAGS += -DUSE_XPM WINX11LIB += -lXpm diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index ecd654034..f12110f6f 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -27,6 +27,18 @@ NetHack*tombstone*font: NETHACK_FONT NetHack*text*rip*font: -*-times-medium-r-*-*-12-*-*-*-*-*-*-* NetHack*text*borderWidth: 0 +! Vector font to be used if Xft support is enabled +! These correspond to the .nethackrc settings font_map, font_menu, +! font_message, font_status and font_text +NetHack.font_map: mono-10 +NetHack.font_menu: mono-10 +NetHack.font_message: sans-10 +NetHack.font_status: sans-10 +NetHack.font_text: mono-10 + +! No .nethackrc setting for this, but it gets the right size +NetHack.font_rip: sans-9 + ! tile_file names a file containing full-color tiles for the map. ! If you use a 100dpi (or greater) monitor you may wish to double the ! tile size so you can see the figures. If NetHack was compiled to diff --git a/win/X11/winX.c b/win/X11/winX.c index 1a86c3b3d..4596190b4 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1513,6 +1513,22 @@ static XtResource resources[] = { { nhStr("pilemark_color"), nhStr("Pilemark_color"), XtRPixel, sizeof(XtRPixel), XtOffset(AppResources *, pilemark_color), XtRString, nhStr("Green") }, +#ifdef USE_XFT + { nhStr("font_map"), nhStr("Font_map"), XtRString, sizeof(String), + XtOffset(AppResources *, font_map), XtRString, nhStr("mono-10") }, + { nhStr("font_menu"), nhStr("Font_menu"), XtRString, sizeof(String), + XtOffset(AppResources *, font_menu), XtRString, nhStr("mono-10") }, + { nhStr("font_message"), nhStr("Font_message"), XtRString, sizeof(String), + XtOffset(AppResources *, font_message), XtRString, nhStr("sans-10") }, + { nhStr("font_status"), nhStr("Font_status"), XtRString, sizeof(String), + XtOffset(AppResources *, font_status), XtRString, nhStr("sans-10") }, + { nhStr("font_text"), nhStr("Font_text"), XtRString, sizeof(String), + XtOffset(AppResources *, font_text), XtRString, nhStr("mono-10") }, +#ifdef GRAPHIC_TOMBSTONE + { nhStr("font_rip"), nhStr("Font_rip"), XtRString, sizeof(String), + XtOffset(AppResources *, font_rip), XtRString, nhStr("sans-9") }, +#endif +#endif #ifdef GRAPHIC_TOMBSTONE { nhStr("tombstone"), nhStr("Tombstone"), XtRString, sizeof(String), XtOffset(AppResources *, tombstone), XtRString, nhStr("rip.xpm") }, @@ -3130,4 +3146,132 @@ X11_unicode_font(Display *display, XFontStruct *font) } #endif /* ENHANCED_SYMBOLS */ +#ifdef USE_XFT + +/* Open a vector font for the given widget */ + +extern XftFont * +X11_new_font(Widget w, boolean bold, int win_type) +{ + const char *font_name = NULL; + const char *iflags_font_name = NULL; + int font_size = 0; + char name[512]; + + switch (win_type) { + case NHW_MESSAGE: + font_name = appResources.font_message; + iflags_font_name = iflags.wc_font_message; + font_size = iflags.wc_fontsiz_message; + break; + + case NHW_STATUS: + font_name = appResources.font_status; + iflags_font_name = iflags.wc_font_status; + font_size = iflags.wc_fontsiz_status; + break; + + case NHW_MAP: + font_name = appResources.font_map; + iflags_font_name = iflags.wc_font_map; + font_size = iflags.wc_fontsiz_map; + break; + + case NHW_MENU: + case NHW_PERMINVENT: + font_name = appResources.font_menu; + iflags_font_name = iflags.wc_font_menu; + font_size = iflags.wc_fontsiz_menu; + break; + + case NHW_TEXT: + font_name = appResources.font_text; + iflags_font_name = iflags.wc_font_text; + font_size = iflags.wc_fontsiz_text; + break; + + default: + break; + } + + if (font_name == NULL) { + font_name = "mono-10"; + } + + /* Override the font name if specified in the configuration file */ + if (iflags_font_name != NULL) { + font_name = iflags_font_name; + } + + /* + * Specify font size as follows: + * * Use any font size specified in the configuration file + * * If no such size is specified, use the one in the font name; + * e.g., "Courier-14" specifies 14 points + * * If still no size, use 10 points + */ + size_t name_len = strlen(font_name); + const char *dash = strrchr(font_name, '-'); + if (dash) { + char *end; + long size = strtol(dash + 1, &end, 10); + if (*end == '\0') { + /* The name ends in a size */ + name_len = (size_t) (dash - font_name); + /* Use font_size if specified; + else use the size from font_name */ + if (font_size <= 0) { + font_size = (int) size; + } + } + } + + /* Use 10 if no size specified */ + if (font_size <= 0) { + font_size = 10; + } + + /* Set reasonable bounds on the font size */ + font_size = min(max(font_size, 6), 50); + + Snprintf(name, sizeof(name), "%.*s-%d:%s", + (int) name_len, font_name, font_size, + bold ? "bold" : "medium"); + + Display *display = XtDisplay(w); + XftFont *font = XftFontOpenName(display, DefaultScreen(display), name); + + return font; +} + +/* Free the font returned by X11_new_font */ + +void +X11_release_font(Widget w, XftFont *font) +{ + Display *display = XtDisplay(w); + XftFontClose(display, font); +} + +/* Assign a new color having the given RGB components */ + +void +X11_new_color(Widget w, Pixel pixel, XftColor *color) +{ + XRenderColor rcolor; + rcolor.red = ((pixel >> 16) & 0xFF) * 0x0101; + rcolor.green = ((pixel >> 8) & 0xFF) * 0x0101; + rcolor.blue = ((pixel >> 0) & 0xFF) * 0x0101; + rcolor.alpha = 0xFFFF; + + Display *display = XtDisplay(w); + Screen *screen = DefaultScreenOfDisplay(display); + Visual *visual = DefaultVisualOfScreen(screen); + Colormap cmap = DefaultColormapOfScreen(screen); + + XftColorAllocValue(display, visual, cmap, &rcolor, color); +} + +#endif /* USE_XFT */ + /*winX.c*/ diff --git a/win/X11/winmap.c b/win/X11/winmap.c index a99ebef5a..3befe1887 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -59,17 +59,23 @@ extern int total_tiles_used, Tile_corr; #define NH_INVERSE_COLOR 0x40000000 #define NH_ENHANCED_COLOR 0x80000000 +#ifdef USE_XFT +static void X11_get_color(struct xwindow *wp, X11_color nhcolor, XftColor *color); +static void X11_draw_image_string(XftDraw *draw, XftFont *font, + XftColor *fgcolor, XftColor *bgcolor, + int x, int y, + const X11_map_symbol *string, int length); +#else /* !USE_XFT */ static GC X11_make_gc(struct xwindow *wp, struct text_map_info_t *text_map, X11_color color, boolean inverted); -#ifdef ENHANCED_SYMBOLS static void X11_free_gc(struct xwindow *wp, GC gc, X11_color color); -#endif -#ifdef ENHANCED_SYMBOLS -static void X11_set_map_font(struct xwindow *wp); -#endif static void X11_draw_image_string(Display *display, Drawable d, GC ggc, int x, int y, const X11_map_symbol *string, int length); +#endif /* ?USE_XFT */ +#ifdef ENHANCED_SYMBOLS +static void X11_set_map_font(struct xwindow *wp); +#endif static Font X11_get_map_font(struct xwindow *wp); static XFontStruct *X11_get_map_font_struct(struct xwindow *wp); static boolean init_tiles(struct xwindow *); @@ -1031,6 +1037,16 @@ clear_map_window(struct xwindow *wp) static void get_char_info(struct xwindow *wp) { +#ifdef USE_XFT + struct map_info_t *map_info = wp->map_information; + struct text_map_info_t *text_map = &map_info->text_map; + XftFont *font = X11_new_font(wp->w, FALSE, NHW_MAP); + text_map->square_width = font->max_advance_width; + text_map->square_height = font->height; + text_map->square_ascent = 0; + text_map->square_lbearing = 0; + X11_release_font(wp->w, font); +#else /* !USE_XFT */ XFontStruct *fs; struct map_info_t *map_info = wp->map_information; struct text_map_info_t *text_map = &map_info->text_map; @@ -1062,6 +1078,7 @@ get_char_info(struct xwindow *wp) if (fs->min_bounds.width != fs->max_bounds.width) X11_raw_print("Warning: map font is not monospaced!"); +#endif /* ?USE_XFT */ } /* @@ -1400,48 +1417,142 @@ map_update(struct xwindow *wp, int start_row, int stop_row, int start_col, int s } else { struct text_map_info_t *text_map = &map_info->text_map; - { - X11_color *c_ptr; - X11_map_symbol *t_ptr; - int cur_col, win_ystart; - X11_color color; - GC ggc; +#ifdef USE_XFT + /* Set up font and background color */ + Display *display = XtDisplay(wp->w); + Screen *screen = DefaultScreenOfDisplay(display); + Visual *visual = DefaultVisualOfScreen(screen); + Colormap cmap = DefaultColormapOfScreen(screen); - for (row = start_row; row <= stop_row; row++) { - win_ystart = - text_map->square_ascent + (row * text_map->square_height); + Pixel bgpixel; + Arg arg[1]; + XtSetArg(arg[0], XtNbackground, &bgpixel); + XtGetValues(wp->w, arg, 1); - t_ptr = &(text_map->text[row][start_col]); - c_ptr = &(text_map->colors[row][start_col]); - cur_col = start_col; - while (cur_col <= stop_col) { - color = *c_ptr++; - count = 1; - while ((cur_col + count) <= stop_col && *c_ptr == color) { - count++; - c_ptr++; - } + XftDraw *draw = XftDrawCreate(display, XtWindow(wp->w), visual, cmap); + XftFont *font = X11_new_font(wp->w, FALSE, NHW_MAP); + XftColor bgcolor; + X11_new_color(wp->w, bgpixel, &bgcolor); +#endif /* USE_XFT */ - ggc = X11_make_gc(wp, text_map, color, inverted); - X11_draw_image_string(XtDisplay(wp->w), XtWindow(wp->w), - ggc, - text_map->square_lbearing - + (text_map->square_width - * (cur_col - COL0_OFFSET)), - win_ystart, t_ptr, count); -#ifdef ENHANCED_SYMBOLS - X11_free_gc(wp, ggc, color); -#endif + for (row = start_row; row <= stop_row; row++) { + int win_ystart = + text_map->square_ascent + (row * text_map->square_height); - /* move text pointer and column count */ - t_ptr += count; - cur_col += count; - } /* col loop */ - } /* row loop */ - } + X11_map_symbol *t_ptr = &(text_map->text[row][start_col]); + X11_color *c_ptr = &(text_map->colors[row][start_col]); + int cur_col = start_col; + while (cur_col <= stop_col) { + X11_color color = *c_ptr++; + count = 1; + while ((cur_col + count) <= stop_col && *c_ptr == color) { + count++; + c_ptr++; + } + +#ifdef USE_XFT + XftColor fgcolor; + X11_get_color(wp, color, &fgcolor); + boolean cur_inv = !!inverted ^ ((color & NH_INVERSE_COLOR) != 0); + X11_draw_image_string(draw, font, + cur_inv ? &bgcolor : &fgcolor, + cur_inv ? &fgcolor : &bgcolor, + text_map->square_lbearing + + (text_map->square_width + * (cur_col - COL0_OFFSET)), + win_ystart, t_ptr, count); + XftColorFree(display, visual, cmap, &fgcolor); +#else /* !USE_XFT */ + GC ggc = X11_make_gc(wp, text_map, color, inverted); + X11_draw_image_string(XtDisplay(wp->w), XtWindow(wp->w), + ggc, + text_map->square_lbearing + + (text_map->square_width + * (cur_col - COL0_OFFSET)), + win_ystart, t_ptr, count); + X11_free_gc(wp, ggc, color); +#endif /* ?USE_XFT */ + + /* move text pointer and column count */ + t_ptr += count; + cur_col += count; + } /* col loop */ + } /* row loop */ + +#ifdef USE_XFT + /* Free resources from Xft */ + XftColorFree(display, visual, cmap, &bgcolor); + X11_release_font(wp->w, font); + XftDrawDestroy(draw); +#endif /* USE_XFT */ } } +#ifdef USE_XFT +static void +X11_get_color(struct xwindow *wp, X11_color nhcolor, XftColor *color) +{ + Pixel pixel; + + if ((nhcolor & NH_ENHANCED_COLOR) != 0) { + pixel = COLORVAL(nhcolor); + } else { + static struct { + const char *name; + Pixel rgb; + } map_colors[] = { + { XtNblack, 0xFFFFFFFF }, /* CLR_BLACK */ + { XtNred, 0xFFFFFFFF }, /* CLR_RED */ + { XtNgreen, 0xFFFFFFFF }, /* CLR_GREEN */ + { XtNbrown, 0xFFFFFFFF }, /* CLR_BROWN */ + { XtNblue, 0xFFFFFFFF }, /* CLR_BLUE */ + { XtNmagenta, 0xFFFFFFFF }, /* CLR_MAGENTA */ + { XtNcyan, 0xFFFFFFFF }, /* CLR_CYAN */ + { XtNgray, 0xFFFFFFFF }, /* CLR_GRAY */ + { XtNforeground, 0xFFFFFFFF }, /* NO_COLOR */ + { XtNorange, 0xFFFFFFFF }, /* CLR_ORANGE */ + { XtNbright_green, 0xFFFFFFFF }, /* CLR_BRIGHT_GREEN */ + { XtNyellow, 0xFFFFFFFF }, /* CLR_YELLOW */ + { XtNbright_blue, 0xFFFFFFFF }, /* CLR_BRIGHT_BLUE */ + { XtNbright_magenta, 0xFFFFFFFF }, /* CLR_BRIGHT_MAGENTA */ + { XtNbright_cyan, 0xFFFFFFFF }, /* CLR_BRIGHT_CYAN */ + { XtNwhite, 0xFFFFFFFF }, /* CLR_WHITE */ + }; + pixel = map_colors[nhcolor & 0xF].rgb; + if (pixel == 0xFFFFFFFF) { + /* Retrieve resource */ + Arg arg[1]; + XtSetArg(arg[0], (char *) map_colors[nhcolor & 0xF].name, &pixel); + XtGetValues(wp->w, arg, 1); + map_colors[nhcolor & 0xF].rgb = pixel; + } + } + + X11_new_color(wp->w, pixel, color); +} + +static void +X11_draw_image_string( + XftDraw *draw, XftFont *font, + XftColor *fgcolor, XftColor *bgcolor, + int x, int y, + const X11_map_symbol *string, int length) +{ + XftDrawRect(draw, bgcolor, x, y, + length * font->max_advance_width, + font->height); + + int xt = x; + int yt = y + font->ascent; +#ifdef ENHANCED_SYMBOLS + XftDrawString32(draw, fgcolor, font, xt, yt, string, length); +#else /* !ENHANCED_SYMBOLS */ + XftDrawString8(draw, fgcolor, font, xt, yt, string, length); +#endif /* ?ENHANCED_SYMBOLS */ +} + +#else /* !USE_XFT */ + static GC X11_make_gc( struct xwindow *wp UNUSED, @@ -1503,16 +1614,16 @@ X11_make_gc( return ggc; } -#ifdef ENHANCED_SYMBOLS static void X11_free_gc(struct xwindow *wp, GC ggc, X11_color color) { +#ifdef ENHANCED_SYMBOLS if ((color & NH_ENHANCED_COLOR) != 0 && iflags.use_color) { /* X11_make_gc allocated a new GC */ XtReleaseGC(wp->w, ggc); } -} #endif +} static void X11_draw_image_string( @@ -1546,6 +1657,8 @@ X11_draw_image_string( #endif /* ?ENHANCED_SYMBOLS */ } +#endif /* ?USE_XFT */ + /* Adjust the number of rows and columns on the given map window */ void set_map_size(struct xwindow *wp, Dimension cols, Dimension rows)