@@ -251,26 +251,28 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
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 ;
263
261
FcCharSet * fccharset ;
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,55 +284,64 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
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 ) {
290
294
utf8charlen = utf8decode (text , & utf8codepoint , UTF_SIZ );
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
}
300
322
break ;
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 ;
@@ -340,6 +351,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
340
351
* character must be drawn. */
341
352
charexists = 1 ;
342
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
+ }
359
+
343
360
fccharset = FcCharSetCreate ();
344
361
FcCharSetAddChar (fccharset , utf8codepoint );
345
362
@@ -368,6 +385,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
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
}
@@ -397,6 +416,15 @@ drw_fontset_getwidth(Drw *drw, const char *text)
397
416
return drw_text (drw , 0 , 0 , 0 , 0 , 0 , text , 0 );
398
417
}
399
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 );
426
+ }
427
+
400
428
void
401
429
drw_font_getexts (Fnt * font , const char * text , unsigned int len , unsigned int * w , unsigned int * h )
402
430
{
0 commit comments