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 {
|
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 */
|
/** The xcb-id for the font */
|
||||||
xcb_font_t id;
|
xcb_font_t id;
|
||||||
|
|
||||||
|
@ -41,9 +53,8 @@ struct Font {
|
||||||
|
|
||||||
/** Font table for this font (may be NULL) */
|
/** Font table for this font (may be NULL) */
|
||||||
xcb_charinfo_t *table;
|
xcb_charinfo_t *table;
|
||||||
|
} xcb;
|
||||||
/** The height of the font, built from font_ascent + font_descent */
|
} specific;
|
||||||
int height;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Since this file also gets included by utilities which don’t use the i3 log
|
/* 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 load_font(const char *pattern, const bool fallback) {
|
||||||
i3Font font;
|
i3Font font;
|
||||||
|
font.type = FONT_TYPE_NONE;
|
||||||
|
|
||||||
|
|
||||||
/* Send all our requests first */
|
/* Send all our requests first */
|
||||||
font.id = xcb_generate_id(conn);
|
font.specific.xcb.id = xcb_generate_id(conn);
|
||||||
xcb_void_cookie_t font_cookie = xcb_open_font_checked(conn, font.id,
|
xcb_void_cookie_t font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
|
||||||
strlen(pattern), pattern);
|
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. */
|
/* Check for errors. If errors, fall back to default font. */
|
||||||
xcb_generic_error_t *error;
|
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",
|
ELOG("Could not open font %s (X error %d). Trying fallback to 'fixed'.\n",
|
||||||
pattern, error->error_code);
|
pattern, error->error_code);
|
||||||
pattern = "fixed";
|
pattern = "fixed";
|
||||||
font_cookie = xcb_open_font_checked(conn, font.id, strlen(pattern), pattern);
|
font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
|
||||||
info_cookie = xcb_query_font(conn, font.id);
|
strlen(pattern), pattern);
|
||||||
|
info_cookie = xcb_query_font(conn, font.specific.xcb.id);
|
||||||
|
|
||||||
/* Check if we managed to open 'fixed' */
|
/* Check if we managed to open 'fixed' */
|
||||||
error = xcb_request_check(conn, font_cookie);
|
error = xcb_request_check(conn, font_cookie);
|
||||||
|
@ -50,8 +53,9 @@ i3Font load_font(const char *pattern, const bool fallback) {
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
ELOG("Could not open fallback font 'fixed', trying with '-misc-*'.\n");
|
ELOG("Could not open fallback font 'fixed', trying with '-misc-*'.\n");
|
||||||
pattern = "-misc-*";
|
pattern = "-misc-*";
|
||||||
font_cookie = xcb_open_font_checked(conn, font.id, strlen(pattern), pattern);
|
font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
|
||||||
info_cookie = xcb_query_font(conn, font.id);
|
strlen(pattern), pattern);
|
||||||
|
info_cookie = xcb_query_font(conn, font.specific.xcb.id);
|
||||||
|
|
||||||
if ((error = xcb_request_check(conn, font_cookie)) != NULL)
|
if ((error = xcb_request_check(conn, font_cookie)) != NULL)
|
||||||
errx(EXIT_FAILURE, "Could open neither requested font nor fallbacks "
|
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 */
|
/* 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);
|
errx(EXIT_FAILURE, "Could not load font \"%s\"", pattern);
|
||||||
|
|
||||||
/* Get the font table, if possible */
|
/* Get the font table, if possible */
|
||||||
if (xcb_query_font_char_infos_length(font.info) == 0)
|
if (xcb_query_font_char_infos_length(font.specific.xcb.info) == 0)
|
||||||
font.table = NULL;
|
font.specific.xcb.table = NULL;
|
||||||
else
|
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 */
|
/* 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;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,10 +94,21 @@ void set_font(i3Font *font) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void free_font(void) {
|
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 */
|
/* Close the font and free the info */
|
||||||
xcb_close_font(conn, savedFont->id);
|
xcb_close_font(conn, savedFont->specific.xcb.id);
|
||||||
if (savedFont->info)
|
if (savedFont->specific.xcb.info)
|
||||||
free(savedFont->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) {
|
void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background) {
|
||||||
assert(savedFont != NULL);
|
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 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);
|
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);
|
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,
|
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) {
|
xcb_gcontext_t gc, int x, int y, int max_width) {
|
||||||
/* X11 coordinates for fonts start at the baseline */
|
/* 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
|
/* The X11 protocol limits text drawing to 255 chars, so we may need
|
||||||
* multiple calls */
|
* 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) {
|
xcb_gcontext_t gc, int x, int y, int max_width) {
|
||||||
assert(savedFont != NULL);
|
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),
|
draw_text_xcb(i3string_as_ucs2(text), i3string_get_num_glyphs(text),
|
||||||
drawable, gc, x, y, max_width);
|
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) {
|
xcb_gcontext_t gc, int x, int y, int max_width) {
|
||||||
assert(savedFont != NULL);
|
assert(savedFont != NULL);
|
||||||
|
|
||||||
|
switch (savedFont->type) {
|
||||||
|
case FONT_TYPE_NONE:
|
||||||
|
/* Nothing to do */
|
||||||
|
return;
|
||||||
|
case FONT_TYPE_XCB:
|
||||||
|
{
|
||||||
size_t text_len = strlen(text);
|
size_t text_len = strlen(text);
|
||||||
if (text_len > 255) {
|
if (text_len > 255) {
|
||||||
/* The text is too long to draw it directly to X */
|
/* 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);
|
i3string_free(str);
|
||||||
} else {
|
} else {
|
||||||
/* X11 coordinates for fonts start at the baseline */
|
/* 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);
|
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) {
|
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 */
|
/* Query the text width */
|
||||||
xcb_generic_error_t *error;
|
xcb_generic_error_t *error;
|
||||||
xcb_query_text_extents_cookie_t cookie = xcb_query_text_extents(conn,
|
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,
|
xcb_query_text_extents_reply_t *reply = xcb_query_text_extents_reply(conn,
|
||||||
cookie, &error);
|
cookie, &error);
|
||||||
if (reply == NULL) {
|
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. */
|
* a crash. Plus, the user will see the error in his log. */
|
||||||
fprintf(stderr, "Could not get text extents (X error code %d)\n",
|
fprintf(stderr, "Could not get text extents (X error code %d)\n",
|
||||||
error->error_code);
|
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;
|
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;
|
return 0;
|
||||||
|
|
||||||
int width;
|
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 */
|
/* If we don't have a font table, fall back to querying the server */
|
||||||
width = xcb_query_text_width(input, text_len);
|
width = xcb_query_text_width(input, text_len);
|
||||||
} else {
|
} else {
|
||||||
/* Save some pointers for convenience */
|
/* Save some pointers for convenience */
|
||||||
xcb_query_font_reply_t *font_info = savedFont->info;
|
xcb_query_font_reply_t *font_info = savedFont->specific.xcb.info;
|
||||||
xcb_charinfo_t *font_table = savedFont->table;
|
xcb_charinfo_t *font_table = savedFont->specific.xcb.table;
|
||||||
|
|
||||||
/* Calculate the width using the font table */
|
/* Calculate the width using the font table */
|
||||||
width = 0;
|
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) {
|
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));
|
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);
|
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");
|
ELOG("You did not specify required configuration option \"font\"\n");
|
||||||
config.font = load_font("fixed", true);
|
config.font = load_font("fixed", true);
|
||||||
set_font(&config.font);
|
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);
|
xcb_cursor_t cursor_id = xcb_generate_id(conn);
|
||||||
i3Font cursor_font = load_font("cursor", false);
|
i3Font cursor_font = load_font("cursor", false);
|
||||||
int xcb_cursor = xcursor_get_xcb_cursor(cursor);
|
int xcb_cursor = xcursor_get_xcb_cursor(cursor);
|
||||||
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
|
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.specific.xcb.id,
|
||||||
xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
|
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_change_window_attributes(conn, result, XCB_CW_CURSOR, &cursor_id);
|
||||||
xcb_free_cursor(conn, 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);
|
xcb_cursor_t cursor_id = xcb_generate_id(conn);
|
||||||
i3Font cursor_font = load_font("cursor", false);
|
i3Font cursor_font = load_font("cursor", false);
|
||||||
int xcb_cursor = xcursor_get_xcb_cursor(cursor);
|
int xcb_cursor = xcursor_get_xcb_cursor(cursor);
|
||||||
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
|
xcb_create_glyph_cursor(conn, cursor_id, cursor_font.specific.xcb.id,
|
||||||
xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
|
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_change_window_attributes(conn, root, XCB_CW_CURSOR, &cursor_id);
|
||||||
xcb_free_cursor(conn, cursor_id);
|
xcb_free_cursor(conn, cursor_id);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
Loading…
Reference in New Issue