sync latest drw.{c,h} changes from dmenu d3f93c7c
Hiltjo Posthuma · 2022-05-10 19:07 2 file(s) · +59 −30
drw.c +58 −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
drw.h +1 −0
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 */