Compare commits
	
		
			No commits in common. "9cd511a2e2164561ad3f3225e64e372706b0fc93" and "13cf0da8c4e7efbb966444cb7e0964c1a7e8466d" have entirely different histories.
		
	
	
		
			9cd511a2e2
			...
			13cf0da8c4
		
	
		
							
								
								
									
										2
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								NEWS
									
									
									
									
									
								
							| @ -7,7 +7,7 @@ Unreleased | |||||||
| 
 | 
 | ||||||
|  * Escape no longer quits the program |  * Escape no longer quits the program | ||||||
| 
 | 
 | ||||||
|  * X11: added support for font fallbacks and italic fonts |  * X11: added italic font support | ||||||
| 
 | 
 | ||||||
|  * X11: fixed rendering of overflowing, partially visible list items |  * X11: fixed rendering of overflowing, partially visible list items | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										307
									
								
								nncmpp.c
									
									
									
									
									
								
							
							
						
						
									
										307
									
								
								nncmpp.c
									
									
									
									
									
								
							| @ -1313,24 +1313,6 @@ enum player_state { PLAYER_STOPPED, PLAYER_PLAYING, PLAYER_PAUSED }; | |||||||
| // around a pointer to this, hence it is a simple global variable as well.
 | // around a pointer to this, hence it is a simple global variable as well.
 | ||||||
| // There is enough global state as it is.
 | // There is enough global state as it is.
 | ||||||
| 
 | 
 | ||||||
| #ifdef WITH_X11 |  | ||||||
| 
 |  | ||||||
| /// Wraps Xft fonts into a linked list with fallbacks.
 |  | ||||||
| struct x11_font_link |  | ||||||
| { |  | ||||||
| 	struct x11_font_link *next; |  | ||||||
| 	XftFont *font; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct x11_font |  | ||||||
| { |  | ||||||
| 	struct x11_font_link *list;         ///< Fonts of varying Unicode coverage
 |  | ||||||
| 	FcPattern *pattern;                 ///< Original unsubstituted pattern
 |  | ||||||
| 	FcCharSet *unavailable;             ///< Couldn't find a font for these
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #endif  // WITH_X11
 |  | ||||||
| 
 |  | ||||||
| static struct app_context | static struct app_context | ||||||
| { | { | ||||||
| 	// Event loop:
 | 	// Event loop:
 | ||||||
| @ -1413,9 +1395,9 @@ static struct app_context | |||||||
| 	Region x11_clip;                    ///< Invalidated region
 | 	Region x11_clip;                    ///< Invalidated region
 | ||||||
| 	Picture x11_pixmap_picture;         ///< XRender wrap for x11_pixmap
 | 	Picture x11_pixmap_picture;         ///< XRender wrap for x11_pixmap
 | ||||||
| 	XftDraw *xft_draw;                  ///< Xft rendering context
 | 	XftDraw *xft_draw;                  ///< Xft rendering context
 | ||||||
| 	struct x11_font xft_regular;        ///< Regular font
 | 	XftFont *xft_regular;               ///< Regular font
 | ||||||
| 	struct x11_font xft_bold;           ///< Bold font
 | 	XftFont *xft_bold;                  ///< Bold font
 | ||||||
| 	struct x11_font xft_italic;         ///< Italic font
 | 	XftFont *xft_italic;                ///< Italic font
 | ||||||
| 	char *x11_selection;                ///< CLIPBOARD selection
 | 	char *x11_selection;                ///< CLIPBOARD selection
 | ||||||
| 
 | 
 | ||||||
| 	XRenderColor x_fg[ATTRIBUTE_COUNT]; ///< Foreground per attribute
 | 	XRenderColor x_fg[ATTRIBUTE_COUNT]; ///< Foreground per attribute
 | ||||||
| @ -2079,19 +2061,14 @@ app_layout_header (void) | |||||||
| 		app_layout_text (header, APP_ATTR (HEADER)); | 		app_layout_text (header, APP_ATTR (HEADER)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct widget * |  | ||||||
| app_widget_by_id (int id) |  | ||||||
| { |  | ||||||
| 	LIST_FOR_EACH (struct widget, w, g.widgets.head) |  | ||||||
| 		if (w->id == id) |  | ||||||
| 			return w; |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int | static int | ||||||
| app_visible_items_height (void) | app_visible_items_height (void) | ||||||
| { | { | ||||||
| 	struct widget *list = app_widget_by_id (WIDGET_LIST); | 	struct widget *list = NULL; | ||||||
|  | 	LIST_FOR_EACH (struct widget, w, g.widgets.head) | ||||||
|  | 		if (w->id == WIDGET_LIST) | ||||||
|  | 			list = w; | ||||||
|  | 
 | ||||||
| 	hard_assert (list != NULL); | 	hard_assert (list != NULL); | ||||||
| 
 | 
 | ||||||
| 	// The raw number of items that would have fit on the terminal
 | 	// The raw number of items that would have fit on the terminal
 | ||||||
| @ -2971,7 +2948,11 @@ app_process_mouse (termo_mouse_event_t type, int x, int y, int button, | |||||||
| 		 && g.ui_dragging != WIDGET_SCROLLBAR) | 		 && g.ui_dragging != WIDGET_SCROLLBAR) | ||||||
| 			return true; | 			return true; | ||||||
| 
 | 
 | ||||||
| 		struct widget *target = app_widget_by_id (g.ui_dragging); | 		struct widget *target = NULL; | ||||||
|  | 		LIST_FOR_EACH (struct widget, w, g.widgets.head) | ||||||
|  | 			if (w->id == g.ui_dragging) | ||||||
|  | 				target = w; | ||||||
|  | 
 | ||||||
| 		x -= target->x; | 		x -= target->x; | ||||||
| 		y -= target->y; | 		y -= target->y; | ||||||
| 		return app_process_left_mouse_click (target, x, y, modifiers); | 		return app_process_left_mouse_click (target, x, y, modifiers); | ||||||
| @ -4843,7 +4824,10 @@ spectrum_redraw (void) | |||||||
| { | { | ||||||
| 	// A full refresh would be too computationally expensive,
 | 	// A full refresh would be too computationally expensive,
 | ||||||
| 	// let's hack around it in this case
 | 	// let's hack around it in this case
 | ||||||
| 	struct widget *spectrum = app_widget_by_id (WIDGET_SPECTRUM); | 	struct widget *spectrum = NULL; | ||||||
|  | 	LIST_FOR_EACH (struct widget, w, g.widgets.head) | ||||||
|  | 		if (w->id == WIDGET_SPECTRUM) | ||||||
|  | 			spectrum = w; | ||||||
| 	if (spectrum) | 	if (spectrum) | ||||||
| 		spectrum->on_render (spectrum); | 		spectrum->on_render (spectrum); | ||||||
| 
 | 
 | ||||||
| @ -5918,190 +5902,14 @@ static XRenderColor x11_default_fg = { .alpha = 0xffff }; | |||||||
| static XRenderColor x11_default_bg = { 0xffff, 0xffff, 0xffff, 0xffff }; | static XRenderColor x11_default_bg = { 0xffff, 0xffff, 0xffff, 0xffff }; | ||||||
| static XErrorHandler x11_default_error_handler; | static XErrorHandler x11_default_error_handler; | ||||||
| 
 | 
 | ||||||
| static struct x11_font_link * |  | ||||||
| x11_font_link_new (XftFont *font) |  | ||||||
| { |  | ||||||
| 	struct x11_font_link *self = xcalloc (1, sizeof *self); |  | ||||||
| 	self->font = font; |  | ||||||
| 	return self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| x11_font_link_destroy (struct x11_font_link *self) |  | ||||||
| { |  | ||||||
| 	XftFontClose (g.dpy, self->font); |  | ||||||
| 	free (self); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static struct x11_font_link * |  | ||||||
| x11_font_link_open (FcPattern *pattern) |  | ||||||
| { |  | ||||||
| 	XftFont *font = XftFontOpenPattern (g.dpy, pattern); |  | ||||||
| 	if (!font) |  | ||||||
| 	{ |  | ||||||
| 		FcPatternDestroy (pattern); |  | ||||||
| 		return NULL; |  | ||||||
| 	} |  | ||||||
| 	return x11_font_link_new (font); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool |  | ||||||
| x11_font_open (struct x11_font *self, FcPattern *pattern) |  | ||||||
| { |  | ||||||
| 	FcPattern *substituted = FcPatternDuplicate (pattern); |  | ||||||
| 	FcConfigSubstitute (NULL, substituted, FcMatchPattern); |  | ||||||
| 
 |  | ||||||
| 	FcResult result = 0; |  | ||||||
| 	FcPattern *match |  | ||||||
| 		= XftFontMatch (g.dpy, DefaultScreen (g.dpy), substituted, &result); |  | ||||||
| 	FcPatternDestroy (substituted); |  | ||||||
| 	if (!match || !(self->list = x11_font_link_open (match))) |  | ||||||
| 	{ |  | ||||||
| 		FcPatternDestroy (pattern); |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	self->pattern = pattern; |  | ||||||
| 	self->unavailable = FcCharSetCreate (); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| x11_font_free (struct x11_font *self) |  | ||||||
| { |  | ||||||
| 	FcPatternDestroy (self->pattern); |  | ||||||
| 	FcCharSetDestroy (self->unavailable); |  | ||||||
| 	LIST_FOR_EACH (struct x11_font_link, iter, self->list) |  | ||||||
| 		x11_font_link_destroy (iter); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Find or instantiate a font that can render the character given by cp.
 |  | ||||||
| static XftFont * | static XftFont * | ||||||
| x11_font_cover_codepoint (struct x11_font *self, ucs4_t cp) | x11_font (struct widget *self) | ||||||
| { |  | ||||||
| 	if (FcCharSetHasChar (self->unavailable, cp)) |  | ||||||
| 		return self->list->font; |  | ||||||
| 
 |  | ||||||
| 	struct x11_font_link **used = &self->list; |  | ||||||
| 	for (; *used; used = &(*used)->next) |  | ||||||
| 		if (XftCharExists (g.dpy, (*used)->font, cp)) |  | ||||||
| 			return (*used)->font; |  | ||||||
| 
 |  | ||||||
| 	FcCharSet *set = FcCharSetCreate (); |  | ||||||
| 	FcCharSetAddChar (set, cp); |  | ||||||
| 	FcPattern *needle = FcPatternDuplicate (self->pattern); |  | ||||||
| 	FcPatternAddCharSet (needle, FC_CHARSET, set); |  | ||||||
| 	FcConfigSubstitute (NULL, needle, FcMatchPattern); |  | ||||||
| 
 |  | ||||||
| 	FcResult result = 0; |  | ||||||
| 	FcPattern *match |  | ||||||
| 		= XftFontMatch (g.dpy, DefaultScreen (g.dpy), needle, &result); |  | ||||||
| 	FcCharSetDestroy (set); |  | ||||||
| 	FcPatternDestroy (needle); |  | ||||||
| 	if (!match) |  | ||||||
| 		goto fail; |  | ||||||
| 
 |  | ||||||
| 	struct x11_font_link *new = x11_font_link_open (match); |  | ||||||
| 	if (!new) |  | ||||||
| 		goto fail; |  | ||||||
| 
 |  | ||||||
| 	// The reverse may happen simply due to race conditions.
 |  | ||||||
| 	if (XftCharExists (g.dpy, new->font, cp)) |  | ||||||
| 		return (*used = new)->font; |  | ||||||
| 
 |  | ||||||
| 	x11_font_link_destroy (new); |  | ||||||
| fail: |  | ||||||
| 	FcCharSetAddChar (self->unavailable, cp); |  | ||||||
| 	return self->list->font; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TODO: Perhaps produce an array of FT_UInt glyph indexes, mainly so that
 |  | ||||||
| //   x11_font_{hadvance,draw,render}() can use the same data, through the use
 |  | ||||||
| //   of a new function that collects the spans in a data structure.
 |  | ||||||
| static size_t |  | ||||||
| x11_font_span (struct x11_font *self, const uint8_t *text, XftFont **font) |  | ||||||
| { |  | ||||||
| 	hard_assert (self->list != NULL); |  | ||||||
| 
 |  | ||||||
| 	// Xft similarly just stops on invalid UTF-8.
 |  | ||||||
| 	ucs4_t cp = 0; |  | ||||||
| 	const uint8_t *p = text; |  | ||||||
| 	if (!(p = u8_next (&cp, p))) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	*font = x11_font_cover_codepoint (self, cp); |  | ||||||
| 	for (const uint8_t *end = NULL; (end = u8_next (&cp, p)); p = end) |  | ||||||
| 	{ |  | ||||||
| 		if (x11_font_cover_codepoint (self, cp) != *font) |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| 	return p - text; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int |  | ||||||
| x11_font_draw (struct x11_font *self, XftColor *color, int x, int y, |  | ||||||
| 	const char *text) |  | ||||||
| { |  | ||||||
| 	int advance = 0; |  | ||||||
| 	size_t len = 0; |  | ||||||
| 	XftFont *font = NULL; |  | ||||||
| 	while ((len = x11_font_span (self, (const uint8_t *) text, &font))) |  | ||||||
| 	{ |  | ||||||
| 		if (color) |  | ||||||
| 		{ |  | ||||||
| 			XftDrawStringUtf8 (g.xft_draw, color, font, |  | ||||||
| 				x + advance, y + self->list->font->ascent, |  | ||||||
| 				(const FcChar8 *) text, len); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		XGlyphInfo extents = {}; |  | ||||||
| 		XftTextExtentsUtf8 (g.dpy, font, (const FcChar8 *) text, len, &extents); |  | ||||||
| 		text += len; |  | ||||||
| 		advance += extents.xOff; |  | ||||||
| 	} |  | ||||||
| 	return advance; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int |  | ||||||
| x11_font_hadvance (struct x11_font *self, const char *text) |  | ||||||
| { |  | ||||||
| 	return x11_font_draw (self, NULL, 0, 0, text); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int |  | ||||||
| x11_font_render (struct x11_font *self, int op, Picture src, int srcx, int srcy, |  | ||||||
| 	int x, int y, const char *text) |  | ||||||
| { |  | ||||||
| 	int advance = 0; |  | ||||||
| 	size_t len = 0; |  | ||||||
| 	XftFont *font = NULL; |  | ||||||
| 	while ((len = x11_font_span (self, (const uint8_t *) text, &font))) |  | ||||||
| 	{ |  | ||||||
| 		if (src) |  | ||||||
| 		{ |  | ||||||
| 			XftTextRenderUtf8 (g.dpy, op, src, font, g.x11_pixmap_picture, |  | ||||||
| 				srcx, srcy, x + advance, y + self->list->font->ascent, |  | ||||||
| 				(const FcChar8 *) text, len); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		XGlyphInfo extents = {}; |  | ||||||
| 		XftTextExtentsUtf8 (g.dpy, font, (const FcChar8 *) text, len, &extents); |  | ||||||
| 		text += len; |  | ||||||
| 		advance += extents.xOff; |  | ||||||
| 	} |  | ||||||
| 	return advance; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 |  | ||||||
| 
 |  | ||||||
| static struct x11_font * |  | ||||||
| x11_widget_font (struct widget *self) |  | ||||||
| { | { | ||||||
| 	if (self->attrs & A_BOLD) | 	if (self->attrs & A_BOLD) | ||||||
| 		return &g.xft_bold; | 		return g.xft_bold; | ||||||
| 	if (self->attrs & A_ITALIC) | 	if (self->attrs & A_ITALIC) | ||||||
| 		return &g.xft_italic; | 		return g.xft_italic; | ||||||
| 	return &g.xft_regular; | 	return g.xft_regular; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static XRenderColor * | static XRenderColor * | ||||||
| @ -6171,12 +5979,16 @@ x11_render_label (struct widget *self) | |||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	// TODO: Try to avoid re-measuring on each render.
 | 	// TODO: Try to avoid re-measuring on each render.
 | ||||||
| 	struct x11_font *font = x11_widget_font (self); | 	XftFont *font = x11_font (self); | ||||||
| 	int advance = x11_font_hadvance (font, self->text); | 	XGlyphInfo extents = {}; | ||||||
| 	if (advance <= space) | 	XftTextExtentsUtf8 (g.dpy, font, | ||||||
|  | 		(const FcChar8 *) self->text, strlen (self->text), &extents); | ||||||
|  | 	if (extents.xOff <= space) | ||||||
| 	{ | 	{ | ||||||
| 		XftColor color = { .color = *x11_fg (self) }; | 		XftColor color = { .color = *x11_fg (self) }; | ||||||
| 		x11_font_draw (font, &color, self->x, self->y, self->text); | 		XftDrawStringUtf8 (g.xft_draw, &color, font, | ||||||
|  | 			self->x, self->y + font->ascent, | ||||||
|  | 			(const FcChar8 *) self->text, strlen (self->text)); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -6184,15 +5996,16 @@ x11_render_label (struct widget *self) | |||||||
| 	XRenderColor solid = *x11_fg (self), colors[3] = { solid, solid, solid }; | 	XRenderColor solid = *x11_fg (self), colors[3] = { solid, solid, solid }; | ||||||
| 	colors[2].alpha = 0; | 	colors[2].alpha = 0; | ||||||
| 
 | 
 | ||||||
| 	double portion = MIN (1, 2.0 * font->list->font->height / space); | 	double portion = MIN (1, 2.0 * font->height / space); | ||||||
| 	XFixed stops[3] = { 0, XDoubleToFixed (1 - portion), XDoubleToFixed (1) }; | 	XFixed stops[3] = { 0, XDoubleToFixed (1 - portion), XDoubleToFixed (1) }; | ||||||
| 	XLinearGradient gradient = { {}, { XDoubleToFixed (space), 0 } }; | 	XLinearGradient gradient = { {}, { XDoubleToFixed (space), 0 } }; | ||||||
| 
 | 
 | ||||||
| 	// Note that this masking is a very expensive operation.
 | 	// Note that this masking is a very expensive operation.
 | ||||||
| 	Picture source = | 	Picture source = | ||||||
| 		XRenderCreateLinearGradient (g.dpy, &gradient, stops, colors, 3); | 		XRenderCreateLinearGradient (g.dpy, &gradient, stops, colors, 3); | ||||||
| 	x11_font_render (font, PictOpOver, source, -self->x, 0, self->x, self->y, | 	XftTextRenderUtf8 (g.dpy, PictOpOver, source, font, g.x11_pixmap_picture, | ||||||
| 		self->text); | 		-self->x, 0, self->x, self->y + font->ascent, | ||||||
|  | 		(const FcChar8 *) self->text, strlen (self->text)); | ||||||
| 	XRenderFreePicture (g.dpy, source); | 	XRenderFreePicture (g.dpy, source); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -6200,7 +6013,6 @@ static struct widget * | |||||||
| x11_make_label (chtype attrs, const char *label) | x11_make_label (chtype attrs, const char *label) | ||||||
| { | { | ||||||
| 	// Xft renders combining marks by themselves, NFC improves it a bit.
 | 	// Xft renders combining marks by themselves, NFC improves it a bit.
 | ||||||
| 	// We'd have to use HarfBuzz to do this correctly.
 |  | ||||||
| 	size_t label_len = strlen (label) + 1, normalized_len = 0; | 	size_t label_len = strlen (label) + 1, normalized_len = 0; | ||||||
| 	uint8_t *normalized = u8_normalize (UNINORM_NFC, | 	uint8_t *normalized = u8_normalize (UNINORM_NFC, | ||||||
| 		(const uint8_t *) label, label_len, NULL, &normalized_len); | 		(const uint8_t *) label, label_len, NULL, &normalized_len); | ||||||
| @ -6214,11 +6026,13 @@ x11_make_label (chtype attrs, const char *label) | |||||||
| 	w->on_render = x11_render_label; | 	w->on_render = x11_render_label; | ||||||
| 	w->attrs = attrs; | 	w->attrs = attrs; | ||||||
| 	memcpy (w + 1, normalized, normalized_len); | 	memcpy (w + 1, normalized, normalized_len); | ||||||
| 	free (normalized); |  | ||||||
| 
 | 
 | ||||||
| 	struct x11_font *font = x11_widget_font (w); | 	XftFont *font = x11_font (w); | ||||||
| 	w->width = x11_font_hadvance (font, w->text); | 	XGlyphInfo extents = {}; | ||||||
| 	w->height = font->list->font->height; | 	XftTextExtentsUtf8 (g.dpy, font, normalized, normalized_len - 1, &extents); | ||||||
|  | 	w->width = extents.xOff; | ||||||
|  | 	w->height = font->height; | ||||||
|  | 	free (normalized); | ||||||
| 	return w; | 	return w; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -6501,7 +6315,7 @@ x11_render_editor (struct widget *self) | |||||||
| { | { | ||||||
| 	x11_render_padding (self); | 	x11_render_padding (self); | ||||||
| 
 | 
 | ||||||
| 	XftFont *font = x11_widget_font (self)->list->font; | 	XftFont *font = x11_font (self); | ||||||
| 	XftColor color = { .color = *x11_fg (self) }; | 	XftColor color = { .color = *x11_fg (self) }; | ||||||
| 
 | 
 | ||||||
| 	// A simplistic adaptation of line_editor_write() follows.
 | 	// A simplistic adaptation of line_editor_write() follows.
 | ||||||
| @ -6515,7 +6329,6 @@ x11_render_editor (struct widget *self) | |||||||
| 		x += extents.xOff + g.ui_vunit / 4; | 		x += extents.xOff + g.ui_vunit / 4; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// TODO: Adapt x11_font_{hadvance,draw}().
 |  | ||||||
| 	// TODO: Make this scroll around the caret, and fade like labels.
 | 	// TODO: Make this scroll around the caret, and fade like labels.
 | ||||||
| 	XftDrawString32 (g.xft_draw, &color, font, x, y, | 	XftDrawString32 (g.xft_draw, &color, font, x, y, | ||||||
| 		g.editor.line, g.editor.len); | 		g.editor.line, g.editor.len); | ||||||
| @ -6575,9 +6388,9 @@ x11_destroy (void) | |||||||
| 	XRenderFreePicture (g.dpy, g.x11_pixmap_picture); | 	XRenderFreePicture (g.dpy, g.x11_pixmap_picture); | ||||||
| 	XFreePixmap (g.dpy, g.x11_pixmap); | 	XFreePixmap (g.dpy, g.x11_pixmap); | ||||||
| 	XftDrawDestroy (g.xft_draw); | 	XftDrawDestroy (g.xft_draw); | ||||||
| 	x11_font_free (&g.xft_regular); | 	XftFontClose (g.dpy, g.xft_regular); | ||||||
| 	x11_font_free (&g.xft_bold); | 	XftFontClose (g.dpy, g.xft_bold); | ||||||
| 	x11_font_free (&g.xft_italic); | 	XftFontClose (g.dpy, g.xft_italic); | ||||||
| 	cstr_set (&g.x11_selection, NULL); | 	cstr_set (&g.x11_selection, NULL); | ||||||
| 
 | 
 | ||||||
| 	poller_fd_reset (&g.x11_event); | 	poller_fd_reset (&g.x11_event); | ||||||
| @ -7077,9 +6890,8 @@ x11_init_fonts (void) | |||||||
| 	//   as well as Net/DoubleClick*.  See the XSETTINGS proposal for details.
 | 	//   as well as Net/DoubleClick*.  See the XSETTINGS proposal for details.
 | ||||||
| 	//   https://www.freedesktop.org/wiki/Specifications/XSettingsRegistry/
 | 	//   https://www.freedesktop.org/wiki/Specifications/XSettingsRegistry/
 | ||||||
| 	const char *name = get_config_string (g.config.root, "settings.x11_font"); | 	const char *name = get_config_string (g.config.root, "settings.x11_font"); | ||||||
| 
 | 	int screen = DefaultScreen (g.dpy); | ||||||
| 	if (!FcInit ()) | 	FcResult result = 0; | ||||||
| 		print_warning ("FontConfig initialization failed"); |  | ||||||
| 
 | 
 | ||||||
| 	FcPattern *query_regular = FcNameParse ((const FcChar8 *) name); | 	FcPattern *query_regular = FcNameParse ((const FcChar8 *) name); | ||||||
| 	FcPattern *query_bold = FcPatternDuplicate (query_regular); | 	FcPattern *query_bold = FcPatternDuplicate (query_regular); | ||||||
| @ -7089,12 +6901,29 @@ x11_init_fonts (void) | |||||||
| 	FcPatternAdd (query_italic, FC_STYLE, (FcValue) { | 	FcPatternAdd (query_italic, FC_STYLE, (FcValue) { | ||||||
| 		.type = FcTypeString, .u.s = (FcChar8 *) "Italic" }, FcFalse); | 		.type = FcTypeString, .u.s = (FcChar8 *) "Italic" }, FcFalse); | ||||||
| 
 | 
 | ||||||
| 	if (!x11_font_open (&g.xft_regular, query_regular)) | 	FcPattern *regular = XftFontMatch (g.dpy, screen, query_regular, &result); | ||||||
|  | 	FcPatternDestroy (query_regular); | ||||||
|  | 	if (!regular) | ||||||
|  | 		exit_fatal ("cannot open font: %s (%d)", name, result); | ||||||
|  | 	if (!(g.xft_regular = XftFontOpenPattern (g.dpy, regular))) | ||||||
|  | 	{ | ||||||
|  | 		FcPatternDestroy (regular); | ||||||
| 		exit_fatal ("cannot open font: %s", name); | 		exit_fatal ("cannot open font: %s", name); | ||||||
| 	if (!x11_font_open (&g.xft_bold, query_bold)) | 	} | ||||||
| 		exit_fatal ("cannot open bold font: %s", name); | 
 | ||||||
| 	if (!x11_font_open (&g.xft_italic, query_italic)) | 	FcPattern *bold = XftFontMatch (g.dpy, screen, query_bold, &result); | ||||||
| 		exit_fatal ("cannot open italic font: %s", name); | 	FcPatternDestroy (query_bold); | ||||||
|  | 	if (bold && !(g.xft_bold = XftFontOpenPattern (g.dpy, bold))) | ||||||
|  | 		FcPatternDestroy (bold); | ||||||
|  | 	if (!g.xft_bold) | ||||||
|  | 		g.xft_bold = XftFontCopy (g.dpy, g.xft_regular); | ||||||
|  | 
 | ||||||
|  | 	FcPattern *italic = XftFontMatch (g.dpy, screen, query_italic, &result); | ||||||
|  | 	FcPatternDestroy (query_italic); | ||||||
|  | 	if (italic && !(g.xft_italic = XftFontOpenPattern (g.dpy, italic))) | ||||||
|  | 		FcPatternDestroy (italic); | ||||||
|  | 	if (!g.xft_italic) | ||||||
|  | 		g.xft_italic = XftFontCopy (g.dpy, g.xft_regular); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| @ -7151,7 +6980,7 @@ x11_init (void) | |||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	// Approximate the average width of a character to half of the em unit.
 | 	// Approximate the average width of a character to half of the em unit.
 | ||||||
| 	g.ui_vunit = g.xft_regular.list->font->height; | 	g.ui_vunit = g.xft_regular->height; | ||||||
| 	g.ui_hunit = g.ui_vunit / 2; | 	g.ui_hunit = g.ui_vunit / 2; | ||||||
| 	// Base the window's size on the regular font size.
 | 	// Base the window's size on the regular font size.
 | ||||||
| 	// Roughly trying to match the 80x24 default dimensions of terminals.
 | 	// Roughly trying to match the 80x24 default dimensions of terminals.
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user