tReplace venam's xcbft.h by my own implementation - xmenu - drop-down menu for X11
 (HTM) git clone git://git.z3bra.org/xmenu.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit fd1386309fc2b03ccb4387c28cce4ad852bb2c2b
 (DIR) parent 8695651f358780a5fe85ac4f5b5a0a8ac5e5a4d6
 (HTM) Author: Willy Goiffon <dev@z3bra.org>
       Date:   Mon, 18 Nov 2019 08:15:46 +0100
       
       Replace venam's xcbft.h by my own implementation
       
       The main advantage is that I understand mine better :)
       There are less abstract structure types used to save stuff like face
       and glyphsets.
       This might be a more rigid model, but it suits our needs better.
       
       Diffstat:
         A font.c                              |     222 ++++++++++++++++++++++++++++++
         A font.h                              |      17 +++++++++++++++++
         M makefile                            |       3 ++-
         D utf8.h                              |      48 -------------------------------
         D xcbft.h                             |     813 ------------------------------
         M xmenu.c                             |      70 ++++----------------------------
       
       6 files changed, 248 insertions(+), 925 deletions(-)
       ---
 (DIR) diff --git a/font.c b/font.c
       t@@ -0,0 +1,222 @@
       +#include "font.h"
       +
       +/* internal variable holding last loaded font */
       +static FT_Face face;
       +
       +int
       +xft_loadfont(char *query, double dpi)
       +{
       +        FcResult result;
       +        FcPattern *pattern, *match;
       +        FcValue index, file, pxsz;
       +        FT_Library ft;
       +
       +        if (FcInit() != FcTrue)
       +                return -1;
       +
       +        /* match font pattern */
       +        pattern = FcNameParse((FcChar8 *)query);
       +        if (!pattern)
       +                return -1;
       +
       +        match = FcFontMatch(NULL, pattern, &result);
       +        if (result != FcResultMatch)
       +                return -1;
       +
       +        FcPatternDestroy(pattern);
       +
       +        /* get file associated with the font matched */
       +        if (FcPatternGet(match, FC_FILE, 0, &file) != FcResultMatch) {
       +                fprintf(stderr, "No font matched\n");
       +                return -1;
       +        }
       +
       +        /* use first font if no index matched */
       +        if (FcPatternGet(match, FC_INDEX, 0, &index) != FcResultMatch) {
       +                index.type = FcTypeInteger;
       +                index.u.i = 0;
       +        }
       +
       +        /* set pixel size to 12 by default */
       +        if (FcPatternGet(match, FC_PIXEL_SIZE, 0, &pxsz) != FcResultMatch) {
       +                pxsz.type = FcTypeInteger;
       +                pxsz.u.i = 12;
       +        }
       +
       +        FT_Init_FreeType(&ft);
       +
       +        if (FT_New_Face(ft, (const char *)file.u.s, index.u.i, &face))
       +                return -1;
       +
       +        FT_Set_Char_Size(face, 0, 64 * pxsz.u.d/(dpi/72.0), dpi, dpi);
       +
       +        return 0;
       +}
       +
       +static xcb_render_picture_t
       +xr_create_canvas(xcb_connection_t *dpy, xcb_drawable_t xid)
       +{
       +        int val[2];
       +        xcb_render_picture_t pic;
       +        xcb_render_pictforminfo_t *fmt;
       +        const xcb_render_query_pict_formats_reply_t *r;
       +
       +        /* create a canvas to draw text on */
       +        pic = xcb_generate_id(dpy);
       +
       +        val[0] = XCB_RENDER_POLY_MODE_IMPRECISE;
       +        val[1] = XCB_RENDER_POLY_EDGE_SMOOTH;
       +
       +        r = xcb_render_util_query_formats(dpy);
       +        fmt = xcb_render_util_find_standard_format(r,
       +                XCB_PICT_STANDARD_RGB_24);
       +
       +        xcb_render_create_picture(dpy, pic, xid, fmt->id,
       +                XCB_RENDER_CP_POLY_MODE | XCB_RENDER_CP_POLY_EDGE, val);
       +
       +        return pic;
       +} 
       +
       +static xcb_render_picture_t
       +xr_create_pen(xcb_connection_t *dpy, xcb_render_color_t color)
       +{
       +        int val[1];
       +        xcb_screen_t *screen;
       +        xcb_pixmap_t px;
       +        xcb_rectangle_t rect = { 0, 0, 1, 1 };
       +        xcb_render_picture_t pen;
       +        xcb_render_pictforminfo_t *fmt;
       +        const xcb_render_query_pict_formats_reply_t *r;
       +
       +        screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
       +
       +        px = xcb_generate_id(dpy);
       +        pen = xcb_generate_id(dpy);
       +
       +        r = xcb_render_util_query_formats(dpy);
       +        fmt = xcb_render_util_find_standard_format(r, XCB_PICT_STANDARD_ARGB_32);
       +
       +        val[0] = XCB_RENDER_REPEAT_NORMAL;
       +        xcb_create_pixmap(dpy, 32, px, screen->root, 1, 1);
       +        xcb_render_create_picture(dpy, pen, px, fmt->id, XCB_RENDER_CP_REPEAT, val);
       +
       +        xcb_render_fill_rectangles(dpy, XCB_RENDER_PICT_OP_OVER, pen, color, 1, &rect);
       +        xcb_free_pixmap(dpy, px);
       +
       +        return pen;
       +}
       +
       +int
       +xr_loadglyph(char c, xcb_render_glyphinfo_t *glyph)
       +{
       +        FT_Select_Charmap(face, FT_ENCODING_UNICODE);
       +        if (FT_Load_Char(face, c, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT))
       +                return -1;
       +
       +        glyph->x      = -face->glyph->bitmap_left;
       +        glyph->y      =  face->glyph->bitmap_top;
       +        glyph->width  =  face->glyph->bitmap.width;
       +        glyph->height =  face->glyph->bitmap.rows;
       +        glyph->x_off  =  face->glyph->advance.x / 64;
       +        glyph->y_off  =  face->glyph->advance.y / 64;
       +
       +        return 0;
       +}
       +
       +size_t
       +xft_txtw(char *text)
       +{
       +        size_t i, w;
       +        xcb_render_glyphinfo_t g;
       +
       +        for (i = w = 0; i < strlen(text); i++) {
       +                if (xr_loadglyph(text[i], &g) < 0)
       +                        return -1;
       +
       +                w += g.x_off;
       +        }
       +
       +        return w;
       +}
       +
       +size_t
       +xft_txth(char *text)
       +{
       +        size_t i, h;
       +        xcb_render_glyphinfo_t g;
       +
       +        for (i = h = 0; i < strlen(text); i++) {
       +                if (xr_loadglyph(text[i], &g) < 0)
       +                        return -1;
       +
       +                h = g.height > h ? g.height : h;
       +        }
       +
       +        return h;
       +}
       +
       +int
       +xft_drawtext(xcb_connection_t *dpy, xcb_drawable_t xid, int x, int y, int color, char *text)
       +{
       +        xcb_render_color_t argb;
       +        xcb_render_glyphset_t gs;
       +        xcb_render_picture_t pic, pen;
       +        xcb_render_pictforminfo_t *fmt;
       +        const xcb_render_query_pict_formats_reply_t *r;
       +        xcb_render_util_composite_text_stream_t *ts;
       +
       +        argb.red   = 0x00ff | (((color >> 16) & 0xff) << 8);
       +        argb.green = 0x00ff | (((color >> 8 ) & 0xff) << 8);
       +        argb.blue  = 0x00ff | (((color >> 0 ) & 0xff) << 8);
       +        argb.alpha = 0xffff;
       +
       +        pic = xr_create_canvas(dpy, xid);
       +        pen = xr_create_pen(dpy, argb);
       +
       +        /* preload all our glyphs */
       +        r = xcb_render_util_query_formats(dpy);
       +        fmt = xcb_render_util_find_standard_format(r, XCB_PICT_STANDARD_A_8);
       +        gs = xcb_generate_id(dpy);
       +        xcb_render_create_glyph_set(dpy, gs, fmt->id);
       +
       +        for (size_t i = 0; i < strlen(text); i++) {
       +                uint8_t *bmp;
       +                uint32_t gid;
       +                xcb_render_glyphinfo_t g;
       +                xr_loadglyph(text[i], &g);
       +
       +                int stride = (g.width + 3) & ~3;
       +                bmp = calloc(sizeof(*bmp), stride * g.height);
       +
       +                for (int y = 0; y < g.height; y++)
       +                        memcpy(bmp+y*stride, face->glyph->bitmap.buffer+y*g.width, g.width);
       +
       +                gid = text[i];
       +                xcb_render_add_glyphs(dpy, gs, 1, &gid, &g, stride * g.height, bmp);
       +                free(bmp);
       +        }
       +
       +        ts = xcb_render_util_composite_text_stream(gs, strlen(text), 0);
       +
       +        /*
       +         * X coordinates are expressed from top-left downwards, while
       +         * font is rendered from bottom-left upwards, so we must add
       +         * the text height to the Y coordinates to be more consistent with
       +         * what X expects
       +         */
       +        xcb_render_util_glyphs_8(ts, x, y + xft_txth(text), strlen(text), (uint8_t *)text);
       +        xcb_render_util_composite_text(dpy, XCB_RENDER_PICT_OP_OVER, pen, pic, 0, 0, 0, ts);
       +
       +        xcb_render_util_composite_text_free(ts);
       +        xcb_render_free_picture(dpy, pen);
       +        xcb_render_free_picture(dpy, pic);
       +        xcb_render_util_disconnect(dpy);
       +
       +        return 0;
       +}
       +
       +void
       +xft_unload(void)
       +{
       +        FcFini();
       +}
 (DIR) diff --git a/font.h b/font.h
       t@@ -0,0 +1,17 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <stdint.h>
       +
       +#include <fontconfig/fontconfig.h>
       +#include <ft2build.h>
       +#include FT_FREETYPE_H
       +
       +#include <xcb/render.h>
       +#include <xcb/xcb_renderutil.h>
       +
       +int xft_loadfont(char *, double);
       +int xft_drawtext(xcb_connection_t *, xcb_drawable_t, int, int, int, char *);
       +size_t xft_txtw(char *);
       +size_t xft_txth(char *);
       +void xft_unload(void);
 (DIR) diff --git a/makefile b/makefile
       t@@ -1,7 +1,8 @@
        include config.mk
        
       -xmenu: xmenu.o
       +xmenu: xmenu.o font.o
        xmenu.o: xmenu.c config.h
       +font.o: font.c font.h
        
        config.h: config.def.h
                cp config.def.h config.h
 (DIR) diff --git a/utf8.h b/utf8.h
       t@@ -1,48 +0,0 @@
       -#ifndef _UTF8_UTILS_
       -#define _UTF8_UTILS_
       -
       -#include <fontconfig/fontconfig.h>
       -
       -struct utf_holder {
       -        FcChar32 *str;
       -        unsigned int length;
       -};
       -struct utf_holder char_to_uint32(char *str);
       -void utf_holder_destroy(struct utf_holder holder);
       -
       -struct utf_holder
       -char_to_uint32(char *str)
       -{
       -        struct utf_holder holder;
       -        FcChar32 *output = NULL;
       -        int length = 0, shift = 0;
       -
       -        // there should be less than or same as the strlen of str
       -        output = (FcChar32 *)malloc(sizeof(FcChar32)*strlen(str));
       -        if (!output) {
       -                puts("couldn't allocate mem for char_to_uint32");
       -        }
       -
       -        while (*(str+shift)) {
       -                shift += FcUtf8ToUcs4(
       -                        (FcChar8*)(str+shift),
       -                        output+length,
       -                        strlen(str)-shift
       -                );
       -                length++;
       -        }
       -
       -        holder.length = length;
       -        holder.str = output;
       -
       -        return holder;
       -}
       -
       -void
       -utf_holder_destroy(struct utf_holder holder)
       -{
       -
       -        free(holder.str);
       -}
       -
       -#endif
 (DIR) diff --git a/xcbft.h b/xcbft.h
       t@@ -1,813 +0,0 @@
       -#ifndef _XCBFT
       -#define _XCBFT
       -
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include <stdint.h>
       -#include <errno.h>
       -#include <math.h>
       -
       -#include <fontconfig/fontconfig.h>
       -#include <ft2build.h>
       -#include FT_FREETYPE_H
       -
       -#include <xcb/xcb.h>
       -#include <xcb/render.h>
       -#include <xcb/xcb_renderutil.h>
       -#include <xcb/xcb_xrm.h>
       -
       -#include "utf8.h"
       -
       -struct xcbft_patterns_holder {
       -        FcPattern **patterns;
       -        uint8_t length;
       -};
       -
       -struct xcbft_face_holder {
       -        FT_Face *faces;
       -        uint8_t length;
       -        FT_Library library;
       -};
       -
       -struct xcbft_glyphset_and_advance {
       -        xcb_render_glyphset_t glyphset;
       -        FT_Vector advance;
       -};
       -
       -// signatures
       -bool xcbft_init(void);
       -void xcbft_done(void);
       -FcPattern* xcbft_query_fontsearch(FcChar8 *);
       -struct xcbft_face_holder xcbft_query_by_char_support(
       -                FcChar32, const FcPattern *, long);
       -struct xcbft_patterns_holder xcbft_query_fontsearch_all(FcStrSet *);
       -double xcbft_get_pixel_size(struct xcbft_patterns_holder patterns);
       -struct xcbft_face_holder xcbft_load_faces(
       -        struct xcbft_patterns_holder, long);
       -FcStrSet* xcbft_extract_fontsearch_list(char *);
       -void xcbft_patterns_holder_destroy(struct xcbft_patterns_holder);
       -void xcbft_face_holder_destroy(struct xcbft_face_holder);
       -FT_Vector xcbft_draw_text(xcb_connection_t*, xcb_drawable_t,
       -        int16_t, int16_t, struct utf_holder, xcb_render_color_t,
       -        struct xcbft_face_holder, long);
       -xcb_render_picture_t xcbft_create_pen(xcb_connection_t*,
       -                xcb_render_color_t);
       -struct xcbft_glyphset_and_advance xcbft_load_glyphset(xcb_connection_t *,
       -        struct xcbft_face_holder, struct utf_holder, long);
       -FT_Vector xcbft_load_glyph(xcb_connection_t *, xcb_render_glyphset_t,
       -        FT_Face, int);
       -long xcbft_get_dpi(xcb_connection_t *);
       -xcb_pixmap_t xcbft_create_text_pixmap(xcb_connection_t *,
       -        struct utf_holder, xcb_render_color_t, xcb_render_color_t,
       -        struct xcbft_patterns_holder, long);
       -static uint32_t xcb_color_to_uint32(xcb_render_color_t);
       -
       -void
       -xcbft_done(void)
       -{
       -        FcFini();
       -}
       -
       -bool
       -xcbft_init(void)
       -{
       -        FcBool status;
       -
       -        status = FcInit();
       -        if (status == FcFalse) {
       -                fprintf(stderr, "Could not initialize fontconfig");
       -        }
       -
       -        return status == FcTrue;
       -}
       -
       -// Inspired by https://www.codeproject.com/Articles/1202772/Color-Topics-for-Programmers
       -static uint32_t
       -xcb_color_to_uint32(xcb_render_color_t rgb)
       -{
       -        uint32_t sm1 = 65536 - 1; // from 2^16
       -        uint32_t scale = 256; // to 2^8
       -
       -        return
       -                  (uint32_t) ( ((double)rgb.red/sm1   * (scale-1)) * scale * scale)
       -                + (uint32_t) ( ((double)rgb.green/sm1 * (scale-1)) * scale)
       -                + (uint32_t) ( ((double)rgb.blue/sm1  * (scale-1)) );
       -}
       -
       -xcb_pixmap_t
       -xcbft_create_text_pixmap(
       -        xcb_connection_t *c,
       -        struct utf_holder text,
       -        xcb_render_color_t text_color,
       -        xcb_render_color_t background_color,
       -        struct xcbft_patterns_holder font_patterns,
       -        long dpi)
       -{
       -        xcb_pixmap_t pmap, resize_pmap;
       -        xcb_screen_t *screen;
       -        screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
       -        struct xcbft_face_holder faces;
       -        double pix_size = 12;
       -        uint32_t mask = 0;
       -        uint32_t values[2];
       -        xcb_gcontext_t gc;
       -        
       -        pix_size = xcbft_get_pixel_size(font_patterns);
       -        pmap = xcb_generate_id(c);
       -        faces = xcbft_load_faces(font_patterns, dpi);
       -
       -        // 0.2 being the factor padding on both side
       -        // 0.3 being the extra factor padding for the width protection
       -        uint16_t width = (pix_size*text.length/1.6)+pix_size*0.7;
       -        uint16_t height = pix_size+pix_size*0.4;
       -
       -        xcb_create_pixmap(c, screen->root_depth, pmap, screen->root, width, height);
       -
       -        xcb_rectangle_t rectangles[] = { { .x = 0, .y = 0,
       -                        .width = width, .height = height } };
       -        gc = xcb_generate_id(c);
       -        mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
       -        values[0] = xcb_color_to_uint32(background_color) | 0xff000000;
       -        values[1] = 0;
       -        xcb_create_gc(c, gc, pmap, mask, values);
       -        // draw a rectangle filling the whole pixmap with a single color
       -        xcb_poly_fill_rectangle(c, pmap, gc, 1, rectangles);
       -
       -        FT_Vector advance = xcbft_draw_text(c, pmap,
       -                0.2*pix_size, 0.2*pix_size+pix_size, // x, y
       -                text, text_color, faces, dpi);
       -
       -        resize_pmap = xcb_generate_id(c);
       -        width = advance.x+pix_size*0.4; // 0.2 on both sides
       -        xcb_create_pixmap(c, screen->root_depth, resize_pmap, screen->root, width, height);
       -        xcb_copy_area(c, pmap, resize_pmap, gc, 0, 0, 0, 0, width, height);
       -
       -        xcb_free_pixmap(c, pmap);
       -        xcbft_face_holder_destroy(faces);
       -
       -        return resize_pmap;
       -}
       -
       -/*
       - * Do the font queries through fontconfig and return the info
       - *
       - * Assumes:
       - *        Fontconfig is already init & cleaned outside
       - *        the FcPattern return needs to be cleaned outside
       - */
       -FcPattern*
       -xcbft_query_fontsearch(FcChar8 *fontquery)
       -{
       -        FcBool status;
       -        FcPattern *fc_finding_pattern, *pat_output;
       -        FcResult result;
       -
       -        fc_finding_pattern = FcNameParse(fontquery);
       -
       -        // to match we need to fix the pattern (fill unspecified info)
       -        FcDefaultSubstitute(fc_finding_pattern);
       -        status = FcConfigSubstitute(NULL, fc_finding_pattern, FcMatchPattern);
       -        if (status == FcFalse) {
       -                fprintf(stderr, "could not perform config font substitution");
       -                return NULL;
       -        }
       -
       -        pat_output = FcFontMatch(NULL, fc_finding_pattern, &result);
       -
       -        FcPatternDestroy(fc_finding_pattern);
       -        if (result == FcResultMatch) {
       -                return pat_output;
       -        } else if (result == FcResultNoMatch) {
       -                fprintf(stderr, "there wasn't a match");
       -        } else {
       -                fprintf(stderr, "the match wasn't as good as it should be");
       -        }
       -        return NULL;
       -}
       -
       -/*
       - * Query a font based on character support
       - * Optionally pass a pattern that it'll use as the base for the search
       - *
       - * fallback of font added to the list or somehow done when drawing,
       - * to do that we need to search by the charset we want to draw
       - * and if they are in one of the font already specified, thus need to
       - * know what the users want to insert as text. This needs more thinking
       - * to be decoupled.
       -
       -        Assumes the ft2 library is already loaded
       -        Assumes the face will be cleaned outside
       - */
       -struct xcbft_face_holder
       -xcbft_query_by_char_support(FcChar32 character,
       -                const FcPattern *copy_pattern, long dpi)
       -{
       -        FcBool status;
       -        FcResult result;
       -        FcCharSet *charset;
       -        FcPattern *charset_pattern, *pat_output;
       -        struct xcbft_patterns_holder patterns;
       -        struct xcbft_face_holder faces;
       -
       -        faces.length = 0;
       -
       -        // add characters we need to a charset
       -        charset = FcCharSetCreate();
       -        FcCharSetAddChar(charset, character);
       -
       -        // if we pass a pattern then copy it to get something close
       -        if (copy_pattern != NULL) {
       -                charset_pattern = FcPatternDuplicate(copy_pattern);
       -        } else {
       -                charset_pattern = FcPatternCreate();
       -        }
       -
       -        // use the charset for the pattern search
       -        FcPatternAddCharSet(charset_pattern, FC_CHARSET, charset);
       -        // also force it to be scalable
       -        FcPatternAddBool(charset_pattern, FC_SCALABLE, FcTrue);
       -
       -        // default & config substitutions, the usual
       -        FcDefaultSubstitute(charset_pattern);
       -        status = FcConfigSubstitute(NULL, charset_pattern, FcMatchPattern);
       -        if (status == FcFalse) {
       -                fprintf(stderr, "could not perform config font substitution");
       -                FcCharSetDestroy(charset);
       -                return faces;
       -        }
       -
       -        pat_output = FcFontMatch(NULL, charset_pattern, &result);
       -
       -        FcPatternDestroy(charset_pattern);
       -
       -        if (result != FcResultMatch) {
       -                fprintf(stderr, "there wasn't a match");
       -                FcCharSetDestroy(charset);
       -                return faces;
       -        }
       -
       -        patterns.patterns = malloc(sizeof(FcPattern *));
       -        patterns.length = 1;
       -        patterns.patterns[0] = pat_output;
       -
       -        faces = xcbft_load_faces(patterns, dpi);
       -
       -        // cleanup
       -        xcbft_patterns_holder_destroy(patterns);
       -        FcCharSetDestroy(charset);
       -
       -        return faces;
       -}
       -
       -struct xcbft_patterns_holder
       -xcbft_query_fontsearch_all(FcStrSet *queries)
       -{
       -        struct xcbft_patterns_holder font_patterns;
       -        FcPattern *font_pattern;
       -        uint8_t current_allocated;
       -
       -        font_patterns.patterns = NULL;
       -        font_patterns.length = 0;
       -
       -        // start with 5, expand if needed
       -        current_allocated = 5;
       -        font_patterns.patterns = malloc(sizeof(FcPattern *)*current_allocated);
       -
       -        // safely iterate over set
       -        FcStrList *iterator = FcStrListCreate(queries);
       -        FcChar8 *fontquery = NULL;
       -        FcStrListFirst(iterator);
       -        while ((fontquery = FcStrListNext(iterator)) != NULL) {
       -                font_pattern = xcbft_query_fontsearch(fontquery);
       -                if (font_pattern != NULL) {
       -                        if (font_patterns.length + 1 > current_allocated) {
       -                                current_allocated += 5;
       -                                font_patterns.patterns = realloc(
       -                                        font_patterns.patterns,
       -                                        sizeof(FcPattern*) * current_allocated);
       -                        }
       -                        font_patterns.patterns[font_patterns.length] = font_pattern;
       -                        font_patterns.length++;
       -                }
       -        }
       -        FcStrListDone(iterator);
       -        // end of safely iterate over set
       -
       -        return font_patterns;
       -}
       -
       -// There's no way to predict the width and height of every characters
       -// as they can go outside the em, so let's just use whatever we have as
       -// the biggest pixel size so far in all the loaded patterns
       -double
       -xcbft_get_pixel_size(struct xcbft_patterns_holder patterns)
       -{
       -        int i;
       -        double maximum_pix_size;
       -        FcValue fc_pixel_size;
       -        FcResult result;
       -
       -        maximum_pix_size = 0;
       -        for (i = 0; i < patterns.length; i++) {
       -                result = FcPatternGet(patterns.patterns[i], FC_PIXEL_SIZE, 0, &fc_pixel_size);
       -                if (result != FcResultMatch || fc_pixel_size.u.d == 0) {
       -                        fprintf(stderr, "font has no pixel size, using 12 by default");
       -                        fc_pixel_size.type = FcTypeInteger;
       -                        fc_pixel_size.u.d = 12.0;
       -                }
       -                if (fc_pixel_size.u.d > maximum_pix_size) {
       -                        maximum_pix_size = fc_pixel_size.u.d;
       -                }
       -        }
       -
       -        return maximum_pix_size;
       -}
       -
       -struct xcbft_face_holder
       -xcbft_load_faces(struct xcbft_patterns_holder patterns, long dpi)
       -{
       -        int i;
       -        struct xcbft_face_holder faces;
       -        FcResult result;
       -        FcValue fc_file, fc_index, fc_matrix, fc_pixel_size;
       -        FT_Matrix ft_matrix;
       -        FT_Error error;
       -        FT_Library library;
       -
       -        faces.length = 0;
       -        error = FT_Init_FreeType(&library);
       -        if (error != FT_Err_Ok) {
       -                perror(NULL);
       -                return faces;
       -        }
       -
       -        // allocate the same size as patterns as it should be <= its length
       -        faces.faces = malloc(sizeof(FT_Face)*patterns.length);
       -
       -        for (i = 0; i < patterns.length; i++) {
       -                // get the information needed from the pattern
       -                result = FcPatternGet(patterns.patterns[i], FC_FILE, 0, &fc_file);
       -                if (result != FcResultMatch) {
       -                        fprintf(stderr, "font has not file location");
       -                        continue;
       -                }
       -                result = FcPatternGet(patterns.patterns[i], FC_INDEX, 0, &fc_index);
       -                if (result != FcResultMatch) {
       -                        fprintf(stderr, "font has no index, using 0 by default");
       -                        fc_index.type = FcTypeInteger;
       -                        fc_index.u.i = 0;
       -                }
       -                // TODO: load more info like
       -                //        autohint
       -                //        hinting
       -                //        verticallayout
       -
       -                // load the face
       -                error = FT_New_Face(
       -                                library,
       -                                (const char *) fc_file.u.s,
       -                                fc_index.u.i,
       -                                &(faces.faces[faces.length]) );
       -                if (error == FT_Err_Unknown_File_Format) {
       -                        fprintf(stderr, "wrong file format");
       -                        continue;
       -                } else if (error == FT_Err_Cannot_Open_Resource) {
       -                        fprintf(stderr, "could not open resource");
       -                        continue;
       -                } else if (error) {
       -                        fprintf(stderr, "another sort of error");
       -                        continue;
       -                }
       -                if (faces.faces[faces.length] == NULL) {
       -                        fprintf(stderr, "face was empty");
       -                        continue;
       -                }
       -
       -                result = FcPatternGet(patterns.patterns[i], FC_MATRIX, 0, &fc_matrix);
       -                if (result == FcResultMatch) {
       -                        ft_matrix.xx = (FT_Fixed)(fc_matrix.u.m->xx * 0x10000L);
       -                        ft_matrix.xy = (FT_Fixed)(fc_matrix.u.m->xy * 0x10000L);
       -                        ft_matrix.yx = (FT_Fixed)(fc_matrix.u.m->yx * 0x10000L);
       -                        ft_matrix.yy = (FT_Fixed)(fc_matrix.u.m->yy * 0x10000L);
       -
       -                        // apply the matrix
       -                        FT_Set_Transform(
       -                                faces.faces[faces.length],
       -                                &ft_matrix,
       -                                NULL);
       -                }
       -
       -                result = FcPatternGet(patterns.patterns[i], FC_PIXEL_SIZE, 0, &fc_pixel_size);
       -                if (result != FcResultMatch || fc_pixel_size.u.d == 0) {
       -                        fprintf(stderr, "font has no pixel size, using 12 by default");
       -                        fc_pixel_size.type = FcTypeInteger;
       -                        fc_pixel_size.u.d = 12;
       -                }
       -                //error = FT_Set_Pixel_Sizes(
       -                //        faces.faces[faces.length],
       -                //        0, // width
       -                //        fc_pixel_size.u.d); // height
       -
       -                // pixel_size/ (dpi/72.0)
       -                FT_Set_Char_Size(
       -                        faces.faces[faces.length], 0,
       -                        (fc_pixel_size.u.d/((double)dpi/72.0))*64,
       -                        dpi, dpi);
       -                if (error != FT_Err_Ok) {
       -                        perror(NULL);
       -                        fprintf(stderr, "could not char size");
       -                        continue;
       -                }
       -
       -                faces.length++;
       -        }
       -
       -        faces.library = library;
       -
       -        return faces;
       -}
       -
       -FcStrSet*
       -xcbft_extract_fontsearch_list(char *string)
       -{
       -        FcStrSet *fontsearch = NULL;
       -        FcChar8 *fontquery;
       -        FcBool result = FcFalse;
       -        char *r = strdup(string);
       -        char *p_to_r = r;
       -        char *token = NULL;
       -
       -        fontsearch = FcStrSetCreate();
       -
       -        token = strtok(r, ",");
       -        while (token != NULL) {
       -                fontquery = (FcChar8*)token;
       -                result = FcStrSetAdd(fontsearch, fontquery);
       -                if (result == FcFalse) {
       -                        fprintf(stderr,
       -                                "Couldn't add fontquery to fontsearch set");
       -                }
       -                token = strtok(NULL, ",");
       -        }
       -
       -        free(p_to_r);
       -
       -        return fontsearch;
       -}
       -
       -
       -
       -void
       -xcbft_patterns_holder_destroy(struct xcbft_patterns_holder patterns)
       -{
       -        int i = 0;
       -
       -        for (; i < patterns.length; i++) {
       -                FcPatternDestroy(patterns.patterns[i]);
       -        }
       -        free(patterns.patterns);
       -        // FcFini(); // TODO: we can't leave that here, find a way for cleanup
       -}
       -
       -void
       -xcbft_face_holder_destroy(struct xcbft_face_holder faces)
       -{
       -        int i = 0;
       -
       -        for (; i < faces.length; i++) {
       -                FT_Done_Face(faces.faces[i]);
       -        }
       -        if (faces.faces) {
       -                free(faces.faces);
       -        }
       -        FT_Done_FreeType(faces.library);
       -}
       -
       -FT_Vector
       -xcbft_draw_text(
       -        xcb_connection_t *c, // conn
       -        xcb_drawable_t pmap, // win or pixmap
       -        int16_t x, int16_t y, // x, y
       -        struct utf_holder text, // text
       -        xcb_render_color_t color,
       -        struct xcbft_face_holder faces,
       -        long dpi)
       -{
       -        xcb_void_cookie_t cookie;
       -        uint32_t values[2];
       -        xcb_generic_error_t *error;
       -        xcb_render_picture_t picture;
       -        xcb_render_pictforminfo_t *fmt;
       -        const xcb_render_query_pict_formats_reply_t *fmt_rep =
       -                xcb_render_util_query_formats(c);
       -
       -        fmt = xcb_render_util_find_standard_format(
       -                fmt_rep,
       -                XCB_PICT_STANDARD_RGB_24
       -        );
       -
       -        // create the picture with its attribute and format
       -        picture = xcb_generate_id(c);
       -        values[0] = XCB_RENDER_POLY_MODE_IMPRECISE;
       -        values[1] = XCB_RENDER_POLY_EDGE_SMOOTH;
       -        cookie = xcb_render_create_picture_checked(c,
       -                picture, // pid
       -                pmap, // drawable from the user
       -                fmt->id, // format
       -                XCB_RENDER_CP_POLY_MODE|XCB_RENDER_CP_POLY_EDGE,
       -                values); // make it smooth
       -
       -        error = xcb_request_check(c, cookie);
       -        if (error) {
       -                fprintf(stderr, "ERROR: %s : %d\n",
       -                        "could not create picture",
       -                        error->error_code);
       -        }
       -
       -        // create a 1x1 pixel pen (on repeat mode) of a certain color
       -        xcb_render_picture_t fg_pen = xcbft_create_pen(c, color);
       -
       -        // load all the glyphs in a glyphset
       -        // TODO: maybe cache the xcb_render_glyphset_t
       -        struct xcbft_glyphset_and_advance glyphset_advance =
       -                xcbft_load_glyphset(c, faces, text, dpi);
       -
       -        // we now have a text stream - a bunch of glyphs basically
       -        xcb_render_util_composite_text_stream_t *ts =
       -                xcb_render_util_composite_text_stream(
       -                                glyphset_advance.glyphset,
       -                                text.length, 0);
       -
       -        // draw the text at a certain positions
       -        xcb_render_util_glyphs_32(ts, x, y, text.length, text.str);
       -
       -        // finally render using the repeated pen color on the picture
       -        // (which is related to the pixmap)
       -        xcb_render_util_composite_text(
       -                c, // connection
       -                XCB_RENDER_PICT_OP_OVER, //op
       -                fg_pen, // src
       -                picture, // dst
       -                0, // fmt
       -                0, // src x
       -                0, // src y
       -                ts); // txt stream
       -
       -        xcb_render_util_composite_text_free(ts);
       -        xcb_render_free_picture(c, picture);
       -        xcb_render_free_picture(c, fg_pen);
       -        xcb_render_util_disconnect(c);
       -
       -        return glyphset_advance.advance;
       -}
       -
       -xcb_render_picture_t
       -xcbft_create_pen(xcb_connection_t *c, xcb_render_color_t color)
       -{
       -        xcb_render_pictforminfo_t *fmt;
       -        const xcb_render_query_pict_formats_reply_t *fmt_rep =
       -                xcb_render_util_query_formats(c);
       -        // alpha can only be used with a picture containing a pixmap
       -        fmt = xcb_render_util_find_standard_format(
       -                fmt_rep,
       -                XCB_PICT_STANDARD_ARGB_32
       -        );
       -
       -        xcb_drawable_t root = xcb_setup_roots_iterator(
       -                        xcb_get_setup(c)
       -                ).data->root;
       -
       -        xcb_pixmap_t pm = xcb_generate_id(c);
       -        xcb_create_pixmap(c, 32, pm, root, 1, 1);
       -
       -        uint32_t values[1];
       -        values[0] = XCB_RENDER_REPEAT_NORMAL;
       -
       -        xcb_render_picture_t picture = xcb_generate_id(c);
       -
       -        xcb_render_create_picture(c,
       -                picture,
       -                pm,
       -                fmt->id,
       -                XCB_RENDER_CP_REPEAT,
       -                values);
       -
       -        xcb_rectangle_t rect = {
       -                .x = 0,
       -                .y = 0,
       -                .width = 1,
       -                .height = 1
       -        };
       -
       -        xcb_render_fill_rectangles(c,
       -                XCB_RENDER_PICT_OP_OVER,
       -                picture,
       -                color, 1, &rect);
       -
       -        xcb_free_pixmap(c, pm);
       -        return picture;
       -}
       -
       -struct xcbft_glyphset_and_advance
       -xcbft_load_glyphset(
       -        xcb_connection_t *c,
       -        struct xcbft_face_holder faces,
       -        struct utf_holder text,
       -        long dpi)
       -{
       -        unsigned int i, j;
       -        int glyph_index;
       -        xcb_render_glyphset_t gs;
       -        xcb_render_pictforminfo_t *fmt_a8;
       -        struct xcbft_face_holder faces_for_unsupported;
       -        const xcb_render_query_pict_formats_reply_t *fmt_rep =
       -                xcb_render_util_query_formats(c);
       -        FT_Vector total_advance, glyph_advance;
       -        struct xcbft_glyphset_and_advance glyphset_advance;
       -
       -        total_advance.x = total_advance.y = 0;
       -        glyph_index = 0;
       -        faces_for_unsupported.length = 0;
       -        // create a glyphset with a specific format
       -        fmt_a8 = xcb_render_util_find_standard_format(
       -                fmt_rep,
       -                XCB_PICT_STANDARD_A_8
       -        );
       -        gs = xcb_generate_id(c);
       -        xcb_render_create_glyph_set(c, gs, fmt_a8->id);
       -
       -        for (i = 0; i < text.length; i++) {
       -                for (j = 0; j < faces.length; j++) {
       -                        glyph_index = FT_Get_Char_Index(
       -                                faces.faces[j],
       -                                text.str[i]);
       -                        if (glyph_index != 0) break;
       -                }
       -                // here use face at index j
       -                if (glyph_index != 0) {
       -                        glyph_advance = xcbft_load_glyph(c, gs, faces.faces[j], text.str[i]);
       -                        total_advance.x += glyph_advance.x;
       -                        total_advance.y += glyph_advance.y;
       -                } else {
       -                        // fallback
       -                        // TODO pass at least some of the query (font size, italic, etc..)
       -
       -                        glyph_index = 0;
       -                        // check if we already loaded that face as fallback
       -                        if (faces_for_unsupported.length > 0) {
       -                                glyph_index = FT_Get_Char_Index(
       -                                        faces_for_unsupported.faces[0],
       -                                        text.str[i]);
       -                        }
       -                        if (glyph_index == 0) {
       -                                if (faces_for_unsupported.length > 0) {
       -                                        xcbft_face_holder_destroy(faces_for_unsupported);
       -                                }
       -                                faces_for_unsupported = xcbft_query_by_char_support(
       -                                        text.str[i],
       -                                        NULL, dpi);
       -                        }
       -                        if (faces_for_unsupported.length == 0) {
       -                                fprintf(stderr,
       -                                        "No faces found supporting character: %02x\n",
       -                                        text.str[i]);
       -                                // draw a block using whatever font
       -                                glyph_advance = xcbft_load_glyph(c, gs, faces.faces[0], text.str[i]);
       -                                total_advance.x += glyph_advance.x;
       -                                total_advance.y += glyph_advance.y;
       -                        } else {
       -                                FT_Set_Char_Size(
       -                                                faces_for_unsupported.faces[0],
       -                                                0, (faces.faces[0]->size->metrics.x_ppem/((double)dpi/72.0))*64,
       -                                                dpi, dpi);
       -
       -                                glyph_advance = xcbft_load_glyph(c, gs,
       -                                        faces_for_unsupported.faces[0],
       -                                        text.str[i]);
       -                                total_advance.x += glyph_advance.x;
       -                                total_advance.y += glyph_advance.y;
       -                        }
       -                }
       -        }
       -        if (faces_for_unsupported.length > 0) {
       -                xcbft_face_holder_destroy(faces_for_unsupported);
       -        }
       -
       -        glyphset_advance.advance = total_advance;
       -        glyphset_advance.glyphset = gs;
       -        return glyphset_advance;
       -}
       -
       -FT_Vector
       -xcbft_load_glyph(
       -        xcb_connection_t *c, xcb_render_glyphset_t gs, FT_Face face, int charcode)
       -{
       -        uint32_t gid;
       -        int glyph_index;
       -        FT_Vector glyph_advance;
       -        xcb_render_glyphinfo_t ginfo;
       -        FT_Bitmap *bitmap;
       -
       -        FT_Select_Charmap(face, ft_encoding_unicode);
       -        glyph_index = FT_Get_Char_Index(face, charcode);
       -
       -        FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
       -
       -        bitmap = &face->glyph->bitmap;
       -
       -        ginfo.x = -face->glyph->bitmap_left;
       -        ginfo.y = face->glyph->bitmap_top;
       -        ginfo.width = bitmap->width;
       -        ginfo.height = bitmap->rows;
       -        glyph_advance.x = face->glyph->advance.x/64;
       -        glyph_advance.y = face->glyph->advance.y/64;
       -        ginfo.x_off = glyph_advance.x;
       -        ginfo.y_off = glyph_advance.y;
       -
       -        // keep track of the max horiBearingY (yMax) and yMin
       -        // 26.6 fractional pixel format
       -        // yMax = face->glyph->metrics.horiBearingY/64; (yMax);
       -        // yMin = -(face->glyph->metrics.height -
       -        //                face->glyph->metrics.horiBearingY)/64;
       -
       -        gid = charcode;
       -
       -        int stride = (ginfo.width+3)&~3;
       -        uint8_t *tmpbitmap = calloc(sizeof(uint8_t),stride*ginfo.height);
       -        int y;
       -
       -        for (y = 0; y < ginfo.height; y++)
       -                memcpy(tmpbitmap+y*stride, bitmap->buffer+y*ginfo.width, ginfo.width);
       -
       -        xcb_render_add_glyphs_checked(c,
       -                gs, 1, &gid, &ginfo, stride*ginfo.height, tmpbitmap);
       -
       -        free(tmpbitmap);
       -
       -        xcb_flush(c);
       -        return glyph_advance;
       -}
       -
       -long
       -xcbft_get_dpi(xcb_connection_t *c)
       -{
       -        int i;
       -        long dpi;
       -        long xres;
       -        xcb_xrm_database_t *xrm_db;
       -        xcb_screen_iterator_t iter;
       -
       -        xrm_db = xcb_xrm_database_from_default(c);
       -        if (xrm_db != NULL) {
       -                i = xcb_xrm_resource_get_long(xrm_db, "Xft.dpi", NULL, &dpi);
       -                xcb_xrm_database_free(xrm_db);
       -                if (i < 0) {
       -                        fprintf(stderr,
       -                                "Could not fetch value of Xft.dpi from Xresources falling back to highest dpi found\n");
       -                } else {
       -                        return dpi;
       -                }
       -        } else {
       -                fprintf(stderr,
       -                        "Could not open Xresources database falling back to highest dpi found\n");
       -        }
       -
       -        iter = xcb_setup_roots_iterator(xcb_get_setup(c));
       -        dpi = 0;
       -        for (; iter.rem; xcb_screen_next(&iter)) {
       -                /*
       -                * Inspired by xdpyinfo
       -                *
       -                * there are 2.54 centimeters to an inch; so
       -                * there are 25.4 millimeters.
       -                *
       -                * dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
       -                *     = N pixels / (M inch / 25.4)
       -                *     = N * 25.4 pixels / M inch
       -                */
       -                if (iter.data != NULL) {
       -                        xres = ((((double) iter.data->width_in_pixels) * 25.4) /
       -                                ((double) iter.data->width_in_millimeters));
       -
       -                        // ignore y resolution for now
       -                        //yres = ((((double) iter.data->height_in_pixels) * 25.4) /
       -                        //        ((double) iter.data->height_in_millimeters));
       -                        if (xres > dpi) {
       -                                dpi = xres;
       -                        }
       -                }
       -        }
       -
       -        if (dpi == 0) {
       -                // if everything fails use 96
       -                fprintf(stderr,
       -                        "Could get highest dpi, using 96 as default\n");
       -
       -                dpi = 96;
       -        }
       -
       -        return dpi;
       -}
       -
       -#endif // _XCBFT
 (DIR) diff --git a/xmenu.c b/xmenu.c
       t@@ -10,7 +10,7 @@
        
        #include "arg.h"
        #include "config.h"
       -#include "xcbft.h"
       +#include "font.h"
        
        int verbose = 0;
        xcb_connection_t *dpy;
       t@@ -24,61 +24,11 @@ usage(FILE *fd, char *name)
        }
        
        int
       -setfont(char *fn, FT_Face *face)
       -{
       -        FcBool status;
       -        FcResult result;
       -        FcPattern *pattern, *match;
       -        FcValue file, index;
       -
       -        FT_Library lib;
       -
       -        FcInit();
       -        FT_Init_FreeType(&lib);
       -
       -        /* parse font name and fill default attributes */
       -        pattern = FcNameParse((FcChar8 *)fn);
       -        FcDefaultSubstitute(pattern);
       -        status = FcConfigSubstitute(NULL, pattern, FcMatchPattern);
       -        if (status == FcFalse) {
       -                fprintf(stderr, "Bad font name '%s'\n", fn);
       -                return -1;
       -        }
       -
       -        /* load and actual font from the previously matched pattern */
       -        match = FcFontMatch(NULL, pattern, &result);
       -        if (result != FcResultMatch) {
       -                fprintf(stderr, "Font not found: '%s'\n", fn);
       -                return -1;
       -        }
       -
       -        /* get fontconfig attributes from matched pattern like filename and index */
       -        if (FcPatternGet(match, FC_FILE, 0, &file) != FcResultMatch) {
       -                fprintf(stderr, "Font has no file: '%s'\n", fn);
       -                return -1;
       -        }
       -        if (FcPatternGet(match, FC_INDEX, 0, &index) != FcResultMatch) {
       -                fprintf(stderr, "Font has no file: '%s'\n", fn);
       -                index.type = FcTypeInteger;
       -                index.u.i = 0;
       -        }
       -
       -        /* allocate freetype face according from fontconfig result */
       -        return FT_New_Face(lib, (const char *)file.u.s, index.u.i, face);
       -}
       -
       -int
        main(int argc, char *argv[])
        {
                int mask, val[4];
                char *argv0;
       -
                long dpi;
       -        xcb_render_color_t color = { 0xffff, 0xffff, 0xffff, 0xffff };
       -        FcStrSet *fontsearch;
       -        struct xcbft_patterns_holder fontpattern;
       -        struct xcbft_face_holder faces;
       -        struct utf_holder text;
        
                ARGBEGIN {
                case 'h':
       t@@ -95,7 +45,7 @@ main(int argc, char *argv[])
                } ARGEND;
        
                if (argc < 1)
       -                return 0;
       +                return -1;
        
                dpy = xcb_connect(NULL, NULL);
                if (xcb_connection_has_error(dpy))
       t@@ -105,6 +55,9 @@ main(int argc, char *argv[])
                if (!screen)
                        return -1;
        
       +        /* 1 inch = 25.4 millimeters */
       +        dpi = (screen->height_in_pixels / screen->height_in_millimeters) * 25.4;
       +
                mask = XCB_CW_BACK_PIXEL
                        | XCB_CW_EVENT_MASK;
        
       t@@ -121,18 +74,9 @@ main(int argc, char *argv[])
        
                xcb_map_window(dpy, wid);
        
       -        xcbft_init();
       -        dpi = xcbft_get_dpi(dpy);
       -        fontsearch = xcbft_extract_fontsearch_list(font);
       -        fontpattern = xcbft_query_fontsearch_all(fontsearch);
       -        faces = xcbft_load_faces(fontpattern, dpi);
       -
       -        FcStrSetDestroy(fontsearch);
       -        xcbft_patterns_holder_destroy(fontpattern);
       +        xft_loadfont(font, dpi);
       +        xft_drawtext(dpy, wid, (width - xft_txtw(argv[0]))/2, 8, foreground, argv[0]);
        
       -        text = char_to_uint32(argv[0]);
       -        xcbft_draw_text(dpy, wid, 16, 28, text, color, faces, dpi);
       -        
                xcb_flush(dpy);
        
                sleep(50);