libi3: Rework font to support multiple backends
This commit is contained in:
parent
edd9007ebf
commit
ec17a26b0e
|
@ -33,6 +33,18 @@ typedef struct Font i3Font;
|
|||
*
|
||||
*/
|
||||
struct Font {
|
||||
/** The type of font */
|
||||
enum {
|
||||
FONT_TYPE_NONE = 0,
|
||||
FONT_TYPE_XCB,
|
||||
FONT_TYPE_PANGO
|
||||
} type;
|
||||
|
||||
/** The height of the font, built from font_ascent + font_descent */
|
||||
int height;
|
||||
|
||||
union {
|
||||
struct {
|
||||
/** The xcb-id for the font */
|
||||
xcb_font_t id;
|
||||
|
||||
|
@ -41,9 +53,8 @@ struct Font {
|
|||
|
||||
/** Font table for this font (may be NULL) */
|
||||
xcb_charinfo_t *table;
|
||||
|
||||
/** The height of the font, built from font_ascent + font_descent */
|
||||
int height;
|
||||
} xcb;
|
||||
} specific;
|
||||
};
|
||||
|
||||
/* Since this file also gets included by utilities which don’t use the i3 log
|
||||
|
|
107
libi3/font.c
107
libi3/font.c
|
@ -24,12 +24,14 @@ static const i3Font *savedFont = NULL;
|
|||
*/
|
||||
i3Font load_font(const char *pattern, const bool fallback) {
|
||||
i3Font font;
|
||||
font.type = FONT_TYPE_NONE;
|
||||
|
||||
|
||||
/* Send all our requests first */
|
||||
font.id = xcb_generate_id(conn);
|
||||
xcb_void_cookie_t font_cookie = xcb_open_font_checked(conn, font.id,
|
||||
font.specific.xcb.id = xcb_generate_id(conn);
|
||||
xcb_void_cookie_t font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
|
||||
strlen(pattern), pattern);
|
||||
xcb_query_font_cookie_t info_cookie = xcb_query_font(conn, font.id);
|
||||
xcb_query_font_cookie_t info_cookie = xcb_query_font(conn, font.specific.xcb.id);
|
||||
|
||||
/* Check for errors. If errors, fall back to default font. */
|
||||
xcb_generic_error_t *error;
|
||||
|
@ -40,8 +42,9 @@ i3Font load_font(const char *pattern, const bool fallback) {
|
|||
ELOG("Could not open font %s (X error %d). Trying fallback to 'fixed'.\n",
|
||||
pattern, error->error_code);
|
||||
pattern = "fixed";
|
||||
font_cookie = xcb_open_font_checked(conn, font.id, strlen(pattern), pattern);
|
||||
info_cookie = xcb_query_font(conn, font.id);
|
||||
font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
|
||||
strlen(pattern), pattern);
|
||||
info_cookie = xcb_query_font(conn, font.specific.xcb.id);
|
||||
|
||||
/* Check if we managed to open 'fixed' */
|
||||
error = xcb_request_check(conn, font_cookie);
|
||||
|
@ -50,8 +53,9 @@ i3Font load_font(const char *pattern, const bool fallback) {
|
|||
if (error != NULL) {
|
||||
ELOG("Could not open fallback font 'fixed', trying with '-misc-*'.\n");
|
||||
pattern = "-misc-*";
|
||||
font_cookie = xcb_open_font_checked(conn, font.id, strlen(pattern), pattern);
|
||||
info_cookie = xcb_query_font(conn, font.id);
|
||||
font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
|
||||
strlen(pattern), pattern);
|
||||
info_cookie = xcb_query_font(conn, font.specific.xcb.id);
|
||||
|
||||
if ((error = xcb_request_check(conn, font_cookie)) != NULL)
|
||||
errx(EXIT_FAILURE, "Could open neither requested font nor fallbacks "
|
||||
|
@ -60,18 +64,20 @@ i3Font load_font(const char *pattern, const bool fallback) {
|
|||
}
|
||||
|
||||
/* Get information (height/name) for this font */
|
||||
if (!(font.info = xcb_query_font_reply(conn, info_cookie, NULL)))
|
||||
if (!(font.specific.xcb.info = xcb_query_font_reply(conn, info_cookie, NULL)))
|
||||
errx(EXIT_FAILURE, "Could not load font \"%s\"", pattern);
|
||||
|
||||
/* Get the font table, if possible */
|
||||
if (xcb_query_font_char_infos_length(font.info) == 0)
|
||||
font.table = NULL;
|
||||
if (xcb_query_font_char_infos_length(font.specific.xcb.info) == 0)
|
||||
font.specific.xcb.table = NULL;
|
||||
else
|
||||
font.table = xcb_query_font_char_infos(font.info);
|
||||
font.specific.xcb.table = xcb_query_font_char_infos(font.specific.xcb.info);
|
||||
|
||||
/* Calculate the font height */
|
||||
font.height = font.info->font_ascent + font.info->font_descent;
|
||||
font.height = font.specific.xcb.info->font_ascent + font.specific.xcb.info->font_descent;
|
||||
|
||||
/* Set the font type and return successfully */
|
||||
font.type = FONT_TYPE_XCB;
|
||||
return font;
|
||||
}
|
||||
|
||||
|
@ -88,10 +94,21 @@ void set_font(i3Font *font) {
|
|||
*
|
||||
*/
|
||||
void free_font(void) {
|
||||
switch (savedFont->type) {
|
||||
case FONT_TYPE_NONE:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
case FONT_TYPE_XCB: {
|
||||
/* Close the font and free the info */
|
||||
xcb_close_font(conn, savedFont->id);
|
||||
if (savedFont->info)
|
||||
free(savedFont->info);
|
||||
xcb_close_font(conn, savedFont->specific.xcb.id);
|
||||
if (savedFont->specific.xcb.info)
|
||||
free(savedFont->specific.xcb.info);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -100,9 +117,22 @@ void free_font(void) {
|
|||
*/
|
||||
void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background) {
|
||||
assert(savedFont != NULL);
|
||||
|
||||
switch (savedFont->type) {
|
||||
case FONT_TYPE_NONE:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
case FONT_TYPE_XCB: {
|
||||
/* Change the font and colors in the GC */
|
||||
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
|
||||
uint32_t values[] = { foreground, background, savedFont->id };
|
||||
uint32_t values[] = { foreground, background, savedFont->specific.xcb.id };
|
||||
xcb_change_gc(conn, gc, mask, values);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int predict_text_width_xcb(const xcb_char2b_t *text, size_t text_len);
|
||||
|
@ -110,7 +140,7 @@ static int predict_text_width_xcb(const xcb_char2b_t *text, size_t text_len);
|
|||
static void draw_text_xcb(const xcb_char2b_t *text, size_t text_len, xcb_drawable_t drawable,
|
||||
xcb_gcontext_t gc, int x, int y, int max_width) {
|
||||
/* X11 coordinates for fonts start at the baseline */
|
||||
int pos_y = y + savedFont->info->font_ascent;
|
||||
int pos_y = y + savedFont->specific.xcb.info->font_ascent;
|
||||
|
||||
/* The X11 protocol limits text drawing to 255 chars, so we may need
|
||||
* multiple calls */
|
||||
|
@ -148,8 +178,17 @@ void draw_text(i3String *text, xcb_drawable_t drawable,
|
|||
xcb_gcontext_t gc, int x, int y, int max_width) {
|
||||
assert(savedFont != NULL);
|
||||
|
||||
switch (savedFont->type) {
|
||||
case FONT_TYPE_NONE:
|
||||
/* Nothing to do */
|
||||
return;
|
||||
case FONT_TYPE_XCB:
|
||||
draw_text_xcb(i3string_as_ucs2(text), i3string_get_num_glyphs(text),
|
||||
drawable, gc, x, y, max_width);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -160,6 +199,12 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
|
|||
xcb_gcontext_t gc, int x, int y, int max_width) {
|
||||
assert(savedFont != NULL);
|
||||
|
||||
switch (savedFont->type) {
|
||||
case FONT_TYPE_NONE:
|
||||
/* Nothing to do */
|
||||
return;
|
||||
case FONT_TYPE_XCB:
|
||||
{
|
||||
size_t text_len = strlen(text);
|
||||
if (text_len > 255) {
|
||||
/* The text is too long to draw it directly to X */
|
||||
|
@ -168,10 +213,15 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
|
|||
i3string_free(str);
|
||||
} else {
|
||||
/* X11 coordinates for fonts start at the baseline */
|
||||
int pos_y = y + savedFont->info->font_ascent;
|
||||
int pos_y = y + savedFont->specific.xcb.info->font_ascent;
|
||||
|
||||
xcb_image_text_8(conn, text_len, drawable, gc, x, pos_y, text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int xcb_query_text_width(const xcb_char2b_t *text, size_t text_len) {
|
||||
|
@ -185,7 +235,7 @@ static int xcb_query_text_width(const xcb_char2b_t *text, size_t text_len) {
|
|||
/* Query the text width */
|
||||
xcb_generic_error_t *error;
|
||||
xcb_query_text_extents_cookie_t cookie = xcb_query_text_extents(conn,
|
||||
savedFont->id, text_len, (xcb_char2b_t*)text);
|
||||
savedFont->specific.xcb.id, text_len, (xcb_char2b_t*)text);
|
||||
xcb_query_text_extents_reply_t *reply = xcb_query_text_extents_reply(conn,
|
||||
cookie, &error);
|
||||
if (reply == NULL) {
|
||||
|
@ -193,7 +243,7 @@ static int xcb_query_text_width(const xcb_char2b_t *text, size_t text_len) {
|
|||
* a crash. Plus, the user will see the error in his log. */
|
||||
fprintf(stderr, "Could not get text extents (X error code %d)\n",
|
||||
error->error_code);
|
||||
return savedFont->info->max_bounds.character_width * text_len;
|
||||
return savedFont->specific.xcb.info->max_bounds.character_width * text_len;
|
||||
}
|
||||
|
||||
int width = reply->overall_width;
|
||||
|
@ -206,13 +256,13 @@ static int predict_text_width_xcb(const xcb_char2b_t *input, size_t text_len) {
|
|||
return 0;
|
||||
|
||||
int width;
|
||||
if (savedFont->table == NULL) {
|
||||
if (savedFont->specific.xcb.table == NULL) {
|
||||
/* If we don't have a font table, fall back to querying the server */
|
||||
width = xcb_query_text_width(input, text_len);
|
||||
} else {
|
||||
/* Save some pointers for convenience */
|
||||
xcb_query_font_reply_t *font_info = savedFont->info;
|
||||
xcb_charinfo_t *font_table = savedFont->table;
|
||||
xcb_query_font_reply_t *font_info = savedFont->specific.xcb.info;
|
||||
xcb_charinfo_t *font_table = savedFont->specific.xcb.table;
|
||||
|
||||
/* Calculate the width using the font table */
|
||||
width = 0;
|
||||
|
@ -251,5 +301,16 @@ static int predict_text_width_xcb(const xcb_char2b_t *input, size_t text_len) {
|
|||
*
|
||||
*/
|
||||
int predict_text_width(i3String *text) {
|
||||
assert(savedFont != NULL);
|
||||
|
||||
switch (savedFont->type) {
|
||||
case FONT_TYPE_NONE:
|
||||
/* Nothing to do */
|
||||
return 0;
|
||||
case FONT_TYPE_XCB:
|
||||
return predict_text_width_xcb(i3string_as_ucs2(text), i3string_get_num_glyphs(text));
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,7 +394,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
|
|||
grab_all_keys(conn, false);
|
||||
}
|
||||
|
||||
if (config.font.id == 0) {
|
||||
if (config.font.type == FONT_TYPE_NONE) {
|
||||
ELOG("You did not specify required configuration option \"font\"\n");
|
||||
config.font = load_font("fixed", true);
|
||||
set_font(&config.font);
|
||||
|
|
10
src/xcb.c
10
src/xcb.c
|
@ -50,8 +50,9 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims,
|
|||
xcb_cursor_t cursor_id = xcb_generate_id(conn);
|
||||
i3Font cursor_font = load_font("cursor", false);
|
||||
int xcb_cursor = xcursor_get_xcb_cursor(cursor);
|
||||
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
|
||||
xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
|
||||
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.specific.xcb.id,
|
||||
cursor_font.specific.xcb.id, xcb_cursor, xcb_cursor + 1, 0, 0, 0,
|
||||
65535, 65535, 65535);
|
||||
xcb_change_window_attributes(conn, result, XCB_CW_CURSOR, &cursor_id);
|
||||
xcb_free_cursor(conn, cursor_id);
|
||||
}
|
||||
|
@ -195,8 +196,9 @@ void xcb_set_root_cursor(int cursor) {
|
|||
xcb_cursor_t cursor_id = xcb_generate_id(conn);
|
||||
i3Font cursor_font = load_font("cursor", false);
|
||||
int xcb_cursor = xcursor_get_xcb_cursor(cursor);
|
||||
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
|
||||
xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
|
||||
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.specific.xcb.id,
|
||||
cursor_font.specific.xcb.id, xcb_cursor, xcb_cursor + 1, 0, 0, 0,
|
||||
65535, 65535, 65535);
|
||||
xcb_change_window_attributes(conn, root, XCB_CW_CURSOR, &cursor_id);
|
||||
xcb_free_cursor(conn, cursor_id);
|
||||
xcb_flush(conn);
|
||||
|
|
Loading…
Reference in New Issue