1 diff --git a/dmenu.c b/dmenu.c 2 index 5c835dd..71efe52 100644 3 --- a/dmenu.c 4 +++ b/dmenu.c 5 @@ -131,9 +131,10 @@ drawitem(struct item *item, int x, int y, int w) 6 static void 7 drawmenu(void) 8 { 9 - unsigned int curpos; 10 + static int curpos, oldcurlen; 11 struct item *item; 12 int x = 0, y = 0, w; 13 + int curlen, rcurlen; 14 15 drw_setscheme(drw, scheme[SchemeNorm]); 16 drw_rect(drw, 0, 0, mw, mh, 1, 1); 17 @@ -144,14 +145,21 @@ drawmenu(void) 18 } 19 /* draw input field */ 20 w = (lines > 0 || !matches) ? mw - x : inputw; 21 - drw_setscheme(drw, scheme[SchemeNorm]); 22 - drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); 23 + w -= lrpad / 2; 24 + x += lrpad / 2; 25 26 - curpos = TEXTW(text) - TEXTW(&text[cursor]); 27 - if ((curpos += lrpad / 2 - 1) < w) { 28 - drw_setscheme(drw, scheme[SchemeNorm]); 29 - drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); 30 - } 31 + rcurlen = drw_fontset_getwidth(drw, text + cursor); 32 + curlen = drw_fontset_getwidth(drw, text) - rcurlen; 33 + curpos += curlen - oldcurlen; 34 + curpos = MIN(w, MAX(0, curpos)); 35 + curpos = MAX(curpos, w - rcurlen); 36 + curpos = MIN(curpos, curlen); 37 + oldcurlen = curlen; 38 + 39 + drw_setscheme(drw, scheme[SchemeNorm]); 40 + drw_text_align(drw, x, 0, curpos, bh, text, cursor, AlignR); 41 + drw_text_align(drw, x + curpos, 0, w - curpos, bh, text + cursor, strlen(text) - cursor, AlignL); 42 + drw_rect(drw, x + curpos - 1, 2, 2, bh - 4, 1, 0); 43 44 if (lines > 0) { 45 /* draw vertical list */ 46 diff --git a/drw.c b/drw.c 47 index c638323..bfffbc1 100644 48 --- a/drw.c 49 +++ b/drw.c 50 @@ -364,6 +364,175 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp 51 return x + (render ? w : 0); 52 } 53 54 +int 55 +utf8nextchar(const char *str, int len, int i, int inc) 56 +{ 57 + int n; 58 + 59 + for (n = i + inc; n + inc >= 0 && n + inc <= len 60 + && (str[n] & 0xc0) == 0x80; n += inc) 61 + ; 62 + return n; 63 +} 64 + 65 +int 66 +drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align) 67 +{ 68 + int ty; 69 + unsigned int ew; 70 + XftDraw *d = NULL; 71 + Fnt *usedfont, *curfont, *nextfont; 72 + size_t len; 73 + int utf8strlen, utf8charlen, render = x || y || w || h; 74 + long utf8codepoint = 0; 75 + const char *utf8str; 76 + FcCharSet *fccharset; 77 + FcPattern *fcpattern; 78 + FcPattern *match; 79 + XftResult result; 80 + int charexists = 0; 81 + int i, n; 82 + 83 + if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0 84 + || (align != AlignL && align != AlignR)) 85 + return 0; 86 + 87 + if (!render) { 88 + w = ~w; 89 + } else { 90 + XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel); 91 + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); 92 + d = XftDrawCreate(drw->dpy, drw->drawable, 93 + DefaultVisual(drw->dpy, drw->screen), 94 + DefaultColormap(drw->dpy, drw->screen)); 95 + } 96 + 97 + usedfont = drw->fonts; 98 + i = align == AlignL ? 0 : textlen; 99 + x = align == AlignL ? x : x + w; 100 + while (1) { 101 + utf8strlen = 0; 102 + nextfont = NULL; 103 + /* if (align == AlignL) */ 104 + utf8str = text + i; 105 + 106 + while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) { 107 + if (align == AlignL) { 108 + utf8charlen = utf8decode(text + i, &utf8codepoint, MIN(textlen - i, UTF_SIZ)); 109 + if (!utf8charlen) { 110 + textlen = i; 111 + break; 112 + } 113 + } else { 114 + n = utf8nextchar(text, textlen, i, -1); 115 + utf8charlen = utf8decode(text + n, &utf8codepoint, MIN(textlen - n, UTF_SIZ)); 116 + if (!utf8charlen) { 117 + textlen -= i; 118 + text += i; 119 + i = 0; 120 + break; 121 + } 122 + } 123 + for (curfont = drw->fonts; curfont; curfont = curfont->next) { 124 + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); 125 + if (charexists) { 126 + if (curfont == usedfont) { 127 + utf8strlen += utf8charlen; 128 + i += align == AlignL ? utf8charlen : -utf8charlen; 129 + } else { 130 + nextfont = curfont; 131 + } 132 + break; 133 + } 134 + } 135 + 136 + if (!charexists || nextfont) 137 + break; 138 + else 139 + charexists = 0; 140 + } 141 + 142 + if (align == AlignR) 143 + utf8str = text + i; 144 + 145 + if (utf8strlen) { 146 + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); 147 + /* shorten text if necessary */ 148 + if (align == AlignL) { 149 + for (len = utf8strlen; len && ew > w; ) { 150 + len = utf8nextchar(utf8str, len, len, -1); 151 + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); 152 + } 153 + } else { 154 + for (len = utf8strlen; len && ew > w; ) { 155 + n = utf8nextchar(utf8str, len, 0, +1); 156 + utf8str += n; 157 + len -= n; 158 + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); 159 + } 160 + } 161 + 162 + if (len) { 163 + if (render) { 164 + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; 165 + XftDrawStringUtf8(d, &drw->scheme[ColFg], 166 + usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len); 167 + } 168 + x += align == AlignL ? ew : -ew; 169 + w -= ew; 170 + } 171 + if (len < utf8strlen) 172 + break; 173 + } 174 + 175 + if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) { 176 + break; 177 + } else if (nextfont) { 178 + charexists = 0; 179 + usedfont = nextfont; 180 + } else { 181 + /* Regardless of whether or not a fallback font is found, the 182 + * character must be drawn. */ 183 + charexists = 1; 184 + 185 + fccharset = FcCharSetCreate(); 186 + FcCharSetAddChar(fccharset, utf8codepoint); 187 + 188 + if (!drw->fonts->pattern) { 189 + /* Refer to the comment in xfont_create for more information. */ 190 + die("the first font in the cache must be loaded from a font string."); 191 + } 192 + 193 + fcpattern = FcPatternDuplicate(drw->fonts->pattern); 194 + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); 195 + FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); 196 + 197 + FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); 198 + FcDefaultSubstitute(fcpattern); 199 + match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); 200 + 201 + FcCharSetDestroy(fccharset); 202 + FcPatternDestroy(fcpattern); 203 + 204 + if (match) { 205 + usedfont = xfont_create(drw, NULL, match); 206 + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { 207 + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) 208 + ; /* NOP */ 209 + curfont->next = usedfont; 210 + } else { 211 + xfont_free(usedfont); 212 + usedfont = drw->fonts; 213 + } 214 + } 215 + } 216 + } 217 + if (d) 218 + XftDrawDestroy(d); 219 + 220 + return x; 221 +} 222 + 223 void 224 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) 225 { 226 diff --git a/drw.h b/drw.h 227 index 4c67419..b66a83e 100644 228 --- a/drw.h 229 +++ b/drw.h 230 @@ -13,6 +13,7 @@ typedef struct Fnt { 231 } Fnt; 232 233 enum { ColFg, ColBg }; /* Clr scheme index */ 234 +enum { AlignL, AlignR }; 235 typedef XftColor Clr; 236 237 typedef struct { 238 @@ -52,6 +53,7 @@ void drw_setscheme(Drw *drw, Clr *scm); 239 /* Drawing functions */ 240 void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); 241 int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); 242 +int drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align); 243 244 /* Map functions */ 245 void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);