adding tests, removing -f (it was too clumsy)
[xmenu] / xmenu.c
diff --git a/xmenu.c b/xmenu.c
index 68c8360..9aa3fb6 100644 (file)
--- a/xmenu.c
+++ b/xmenu.c
@@ -41,6 +41,7 @@ static struct Menu *parsestdin(void);
 
 /* text drawer, and its helper routine */
 static FcChar32 getnextutf8char(const char *s, const char **end_ret);
 
 /* text drawer, and its helper routine */
 static FcChar32 getnextutf8char(const char *s, const char **end_ret);
+static XftFont *getfontucode(FcChar32 ucode);
 static int drawtext(XftDraw *draw, XftColor *color, int x, int y, unsigned h, const char *text);
 
 /* structure setters, and their helper routines */
 static int drawtext(XftDraw *draw, XftColor *color, int x, int y, unsigned h, const char *text);
 
 /* structure setters, and their helper routines */
@@ -95,7 +96,6 @@ static Atom wmdelete;
 static Atom netatom[NetLast];
 
 /* flags */
 static Atom netatom[NetLast];
 
 /* flags */
-static int fflag = 0;   /* whether glyphs should align based on the first font */
 static int iflag = 0;   /* whether to disable icons */
 static int mflag = 0;   /* whether the user specified a monitor with -p */
 static int pflag = 0;   /* whether the user specified a position with -p */
 static int iflag = 0;   /* whether to disable icons */
 static int mflag = 0;   /* whether the user specified a monitor with -p */
 static int pflag = 0;   /* whether the user specified a position with -p */
@@ -117,11 +117,8 @@ main(int argc, char *argv[])
        XClassHint classh;
        int ch;
 
        XClassHint classh;
        int ch;
 
-       while ((ch = getopt(argc, argv, "fip:w")) != -1) {
+       while ((ch = getopt(argc, argv, "ip:w")) != -1) {
                switch (ch) {
                switch (ch) {
-               case 'f':
-                       fflag = 1;
-                       break;
                case 'i':
                        iflag = 1;
                        break;
                case 'i':
                        iflag = 1;
                        break;
@@ -259,12 +256,17 @@ parsefonts(const char *s)
                i = 0;
                while (isspace(*p))
                        p++;
                i = 0;
                while (isspace(*p))
                        p++;
-               while (*p != '\0' && *p != ',') {
+               while (i < sizeof buf && *p != '\0' && *p != ',') {
                        buf[i++] = *p++;
                }
                        buf[i++] = *p++;
                }
+               if (i >= sizeof buf)
+                       errx(1, "font name too long");
                if (*p == ',')
                        p++;
                buf[i] = '\0';
                if (*p == ',')
                        p++;
                buf[i] = '\0';
+               if (nfont == 0)
+                       if ((dc.pattern = FcNameParse((FcChar8 *)buf)) == NULL)
+                               errx(1, "the first font in the cache must be loaded from a font string");
                if ((dc.fonts[nfont++] = XftFontOpenName(dpy, screen, buf)) == NULL)
                        errx(1, "cannot load font");
        }
                if ((dc.fonts[nfont++] = XftFontOpenName(dpy, screen, buf)) == NULL)
                        errx(1, "cannot load font");
        }
@@ -638,53 +640,87 @@ getnextutf8char(const char *s, const char **next_ret)
        return ucode;
 }
 
        return ucode;
 }
 
-/* draw text into XftDraw */
+/* get which font contains a given code point */
+static XftFont *
+getfontucode(FcChar32 ucode)
+{
+       FcCharSet *fccharset = NULL;
+       FcPattern *fcpattern = NULL;
+       FcPattern *match = NULL;
+       XftFont *retfont = NULL;
+       XftResult result;
+       size_t i;
+
+       for (i = 0; i < dc.nfonts; i++)
+               if (XftCharExists(dpy, dc.fonts[i], ucode) == FcTrue)
+                       return dc.fonts[i];
+
+       /* create a charset containing our code point */
+       fccharset = FcCharSetCreate();
+       FcCharSetAddChar(fccharset, ucode);
+
+       /* create a pattern akin to the dc.pattern but containing our charset */
+       if (fccharset) {
+               fcpattern = FcPatternDuplicate(dc.pattern);
+               FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
+       }
+
+       /* find pattern matching fcpattern */
+       if (fcpattern) {
+               FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
+               FcDefaultSubstitute(fcpattern);
+               match = XftFontMatch(dpy, screen, fcpattern, &result);
+       }
+
+       /* if found a pattern, open its font */
+       if (match) {
+               retfont = XftFontOpenPattern(dpy, match);
+               if (retfont && XftCharExists(dpy, retfont, ucode) == FcTrue) {
+                       if ((dc.fonts = realloc(dc.fonts, dc.nfonts+1)) == NULL)
+                               err(1, "realloc");
+                       dc.fonts[dc.nfonts] = retfont;
+                       return dc.fonts[dc.nfonts++];
+               } else {
+                       XftFontClose(dpy, retfont);
+               }
+       }
+
+       /* in case no fount was found, return the first one */
+       return dc.fonts[0];
+}
+
+/* draw text into XftDraw, return width of text glyphs */
 static int
 drawtext(XftDraw *draw, XftColor *color, int x, int y, unsigned h, const char *text)
 {
 static int
 drawtext(XftDraw *draw, XftColor *color, int x, int y, unsigned h, const char *text)
 {
-       const char *s, *nexts;
-       FcChar32 ucode;
-       XftFont *currfont;
-       int textlen = 0;
-       int texty;
-
-       texty = y + (h - (dc.fonts[0]->ascent + dc.fonts[0]->descent))/2 + dc.fonts[0]->ascent;
+       int textwidth = 0;
 
 
-       s = text;
-       while (*s) {
+       while (*text) {
+               XftFont *currfont;
                XGlyphInfo ext;
                XGlyphInfo ext;
-               int charexists;
+               FcChar32 ucode;
+               const char *next;
                size_t len;
                size_t len;
-               size_t i;
 
 
-               charexists = 0;
-               ucode = getnextutf8char(s, &nexts);
-               for (i = 0; i < dc.nfonts; i++) {
-                       charexists = XftCharExists(dpy, dc.fonts[i], ucode);
-                       if (charexists)
-                               break;
-               }
-               if (charexists)
-                       currfont = dc.fonts[i];
+               ucode = getnextutf8char(text, &next);
+               currfont = getfontucode(ucode);
 
 
-               len = nexts - s;
-
-               XftTextExtentsUtf8(dpy, currfont, (XftChar8 *)s,
-                                  len, &ext);
-               textlen += ext.xOff;
+               len = next - text;
+               XftTextExtentsUtf8(dpy, currfont, (XftChar8 *)text, len, &ext);
+               textwidth += ext.xOff;
 
                if (draw) {
 
                if (draw) {
-                       if (!fflag)
-                               texty = y + (h - (currfont->ascent + currfont->descent))/2 + currfont->ascent;
-                       XftDrawStringUtf8(draw, color, currfont, x, texty,
-                                         (XftChar8 *)s, len);
+                       int texty;
+
+                       texty = y + (h - (currfont->ascent + currfont->descent))/2 + currfont->ascent;
+                       XftDrawStringUtf8(draw, color, currfont, x, texty, (XftChar8 *)text, len);
                        x += ext.xOff;
                }
 
                        x += ext.xOff;
                }
 
-               s = nexts;
+               text = next;
        }
 
        }
 
-       return textlen;
+       return textwidth;
 }
 
 /* setup the height, width and icon of the items of a menu */
 }
 
 /* setup the height, width and icon of the items of a menu */
@@ -1278,6 +1314,6 @@ cleanup(void)
 static void
 usage(void)
 {
 static void
 usage(void)
 {
-       (void)fprintf(stderr, "usage: xmenu [-fiw] [-p position] [title]\n");
+       (void)fprintf(stderr, "usage: xmenu [-iw] [-p position] [title]\n");
        exit(1);
 }
        exit(1);
 }