sync latest drw.{c,h} changes from dmenu
d3f93c7c
2 file(s) · +59 −30
| 251 | 251 | int |
|
| 252 | 252 | drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) |
|
| 253 | 253 | { |
|
| 254 | - | char buf[1024]; |
|
| 255 | - | int ty; |
|
| 256 | - | unsigned int ew; |
|
| 254 | + | int i, ty, ellipsis_x = 0; |
|
| 255 | + | unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; |
|
| 257 | 256 | XftDraw *d = NULL; |
|
| 258 | 257 | Fnt *usedfont, *curfont, *nextfont; |
|
| 259 | - | size_t i, len; |
|
| 260 | 258 | int utf8strlen, utf8charlen, render = x || y || w || h; |
|
| 261 | 259 | long utf8codepoint = 0; |
|
| 262 | 260 | const char *utf8str; |
|
| 264 | 262 | FcPattern *fcpattern; |
|
| 265 | 263 | FcPattern *match; |
|
| 266 | 264 | XftResult result; |
|
| 267 | - | int charexists = 0; |
|
| 265 | + | int charexists = 0, overflow = 0; |
|
| 266 | + | /* keep track of a couple codepoints for which we have no match. */ |
|
| 267 | + | enum { nomatches_len = 64 }; |
|
| 268 | + | static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; |
|
| 269 | + | static unsigned int ellipsis_width = 0; |
|
| 268 | 270 | ||
| 269 | - | if (!drw || (render && !drw->scheme) || !text || !drw->fonts) |
|
| 271 | + | if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) |
|
| 270 | 272 | return 0; |
|
| 271 | 273 | ||
| 272 | 274 | if (!render) { |
|
| 273 | - | w = ~w; |
|
| 275 | + | w = invert ? invert : ~invert; |
|
| 274 | 276 | } else { |
|
| 275 | 277 | XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); |
|
| 276 | 278 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
|
| 282 | 284 | } |
|
| 283 | 285 | ||
| 284 | 286 | usedfont = drw->fonts; |
|
| 287 | + | if (!ellipsis_width && render) |
|
| 288 | + | ellipsis_width = drw_fontset_getwidth(drw, "..."); |
|
| 285 | 289 | while (1) { |
|
| 286 | - | utf8strlen = 0; |
|
| 290 | + | ew = ellipsis_len = utf8strlen = 0; |
|
| 287 | 291 | utf8str = text; |
|
| 288 | 292 | nextfont = NULL; |
|
| 289 | 293 | while (*text) { |
|
| 291 | 295 | for (curfont = drw->fonts; curfont; curfont = curfont->next) { |
|
| 292 | 296 | charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); |
|
| 293 | 297 | if (charexists) { |
|
| 294 | - | if (curfont == usedfont) { |
|
| 298 | + | drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); |
|
| 299 | + | if (ew + ellipsis_width <= w) { |
|
| 300 | + | /* keep track where the ellipsis still fits */ |
|
| 301 | + | ellipsis_x = x + ew; |
|
| 302 | + | ellipsis_w = w - ew; |
|
| 303 | + | ellipsis_len = utf8strlen; |
|
| 304 | + | } |
|
| 305 | + | ||
| 306 | + | if (ew + tmpw > w) { |
|
| 307 | + | overflow = 1; |
|
| 308 | + | /* called from drw_fontset_getwidth_clamp(): |
|
| 309 | + | * it wants the width AFTER the overflow |
|
| 310 | + | */ |
|
| 311 | + | if (!render) |
|
| 312 | + | x += tmpw; |
|
| 313 | + | else |
|
| 314 | + | utf8strlen = ellipsis_len; |
|
| 315 | + | } else if (curfont == usedfont) { |
|
| 295 | 316 | utf8strlen += utf8charlen; |
|
| 296 | 317 | text += utf8charlen; |
|
| 318 | + | ew += tmpw; |
|
| 297 | 319 | } else { |
|
| 298 | 320 | nextfont = curfont; |
|
| 299 | 321 | } |
|
| 301 | 323 | } |
|
| 302 | 324 | } |
|
| 303 | 325 | ||
| 304 | - | if (!charexists || nextfont) |
|
| 326 | + | if (overflow || !charexists || nextfont) |
|
| 305 | 327 | break; |
|
| 306 | 328 | else |
|
| 307 | 329 | charexists = 0; |
|
| 308 | 330 | } |
|
| 309 | 331 | ||
| 310 | 332 | if (utf8strlen) { |
|
| 311 | - | drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); |
|
| 312 | - | /* shorten text if necessary */ |
|
| 313 | - | for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) |
|
| 314 | - | drw_font_getexts(usedfont, utf8str, len, &ew, NULL); |
|
| 315 | - | ||
| 316 | - | if (len) { |
|
| 317 | - | memcpy(buf, utf8str, len); |
|
| 318 | - | buf[len] = '\0'; |
|
| 319 | - | if (len < utf8strlen) |
|
| 320 | - | for (i = len; i && i > len - 3; buf[--i] = '.') |
|
| 321 | - | ; /* NOP */ |
|
| 322 | - | ||
| 323 | - | if (render) { |
|
| 324 | - | ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; |
|
| 325 | - | XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], |
|
| 326 | - | usedfont->xfont, x, ty, (XftChar8 *)buf, len); |
|
| 327 | - | } |
|
| 328 | - | x += ew; |
|
| 329 | - | w -= ew; |
|
| 333 | + | if (render) { |
|
| 334 | + | ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; |
|
| 335 | + | XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], |
|
| 336 | + | usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen); |
|
| 330 | 337 | } |
|
| 338 | + | x += ew; |
|
| 339 | + | w -= ew; |
|
| 331 | 340 | } |
|
| 341 | + | if (render && overflow) |
|
| 342 | + | drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); |
|
| 332 | 343 | ||
| 333 | - | if (!*text) { |
|
| 344 | + | if (!*text || overflow) { |
|
| 334 | 345 | break; |
|
| 335 | 346 | } else if (nextfont) { |
|
| 336 | 347 | charexists = 0; |
|
| 339 | 350 | /* Regardless of whether or not a fallback font is found, the |
|
| 340 | 351 | * character must be drawn. */ |
|
| 341 | 352 | charexists = 1; |
|
| 353 | + | ||
| 354 | + | for (i = 0; i < nomatches_len; ++i) { |
|
| 355 | + | /* avoid calling XftFontMatch if we know we won't find a match */ |
|
| 356 | + | if (utf8codepoint == nomatches.codepoint[i]) |
|
| 357 | + | goto no_match; |
|
| 358 | + | } |
|
| 342 | 359 | ||
| 343 | 360 | fccharset = FcCharSetCreate(); |
|
| 344 | 361 | FcCharSetAddChar(fccharset, utf8codepoint); |
|
| 368 | 385 | curfont->next = usedfont; |
|
| 369 | 386 | } else { |
|
| 370 | 387 | xfont_free(usedfont); |
|
| 388 | + | nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; |
|
| 389 | + | no_match: |
|
| 371 | 390 | usedfont = drw->fonts; |
|
| 372 | 391 | } |
|
| 373 | 392 | } |
|
| 395 | 414 | if (!drw || !drw->fonts || !text) |
|
| 396 | 415 | return 0; |
|
| 397 | 416 | return drw_text(drw, 0, 0, 0, 0, 0, text, 0); |
|
| 417 | + | } |
|
| 418 | + | ||
| 419 | + | unsigned int |
|
| 420 | + | drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n) |
|
| 421 | + | { |
|
| 422 | + | unsigned int tmp = 0; |
|
| 423 | + | if (drw && drw->fonts && text && n) |
|
| 424 | + | tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); |
|
| 425 | + | return MIN(n, tmp); |
|
| 398 | 426 | } |
|
| 399 | 427 | ||
| 400 | 428 | void |
|
| 35 | 35 | Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); |
|
| 36 | 36 | void drw_fontset_free(Fnt* set); |
|
| 37 | 37 | unsigned int drw_fontset_getwidth(Drw *drw, const char *text); |
|
| 38 | + | unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n); |
|
| 38 | 39 | void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); |
|
| 39 | 40 | ||
| 40 | 41 | /* Colorscheme abstraction */ |