diff --git a/include/data.h b/include/data.h index 6171f8b2..b4dcd178 100644 --- a/include/data.h +++ b/include/data.h @@ -106,6 +106,8 @@ struct Font { int height; /* The xcb-id for the font */ xcb_font_t id; + + TAILQ_ENTRY(Font) fonts; }; /* diff --git a/src/font.c b/src/font.c index 6ab7110b..ec65eda7 100644 --- a/src/font.c +++ b/src/font.c @@ -20,30 +20,43 @@ #include "data.h" #include "util.h" +TAILQ_HEAD(cached_fonts_head, Font) cached_fonts = TAILQ_HEAD_INITIALIZER(cached_fonts); + +/* + * Loads a font for usage, getting its height. This function is used very often, so it + * maintains a cache. + * + */ i3Font *load_font(xcb_connection_t *c, const char *pattern) { - /* TODO: this function should be caching */ + /* Check if we got the font cached */ + i3Font *font; + TAILQ_FOREACH(font, &cached_fonts, fonts) + if (strcmp(font->pattern, pattern) == 0) + return font; + i3Font *new = malloc(sizeof(i3Font)); + /* Send all our requests first */ + new->id = xcb_generate_id(c); + xcb_void_cookie_t font_cookie = xcb_open_font_checked(c, new->id, strlen(pattern), pattern); xcb_list_fonts_with_info_cookie_t cookie = xcb_list_fonts_with_info(c, 1, strlen(pattern), pattern); + + check_error(c, font_cookie, "Could not open font"); + + /* Get information (height/name) for this font */ xcb_list_fonts_with_info_reply_t *reply = xcb_list_fonts_with_info_reply(c, cookie, NULL); - if (!reply) { + if (reply == NULL) { printf("Could not load font\n"); exit(1); } - /* Oh my, this is so ugly :-(. Why can’t they just return a null-terminated - * string? That’s what abstraction layers are for. */ - char buffer[xcb_list_fonts_with_info_name_length(reply)+1]; - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, xcb_list_fonts_with_info_name(reply), sizeof(buffer)-1); - new->name = strdup(buffer); + asprintf(&(new->name), "%.*s", xcb_list_fonts_with_info_name_length(reply), + xcb_list_fonts_with_info_name(reply)); new->pattern = strdup(pattern); new->height = reply->font_ascent + reply->font_descent; - /* Actually load the font */ - new->id = xcb_generate_id(c); - xcb_void_cookie_t font_cookie = xcb_open_font_checked(c, new->id, strlen(pattern), pattern); - check_error(c, font_cookie, "Could not open font"); + /* Insert into cache */ + TAILQ_INSERT_TAIL(&cached_fonts, new, fonts); return new; }