dmenu

my fork of dmenu
Index Commits Files Refs README LICENSE
patches/dmenu-scroll-20180607-a314412.diff (7072B)
   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);