dmenu

Kris's build of dmenu
git clone git clone https://git.krisyotam.com/krisyotam/dmenu.git
Log | Files | Refs | README | LICENSE

scroll.c (4616B)


      1 int
      2 utf8nextchar(const char *str, int len, int i, int inc)
      3 {
      4 	int n;
      5 
      6 	for (n = i + inc; n + inc >= 0 && n + inc <= len
      7 	  && (str[n] & 0xc0) == 0x80; n += inc)
      8 		;
      9 	return n;
     10 }
     11 
     12 int
     13 drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align)
     14 {
     15 	int ty;
     16 	unsigned int ew;
     17 	XftDraw *d = NULL;
     18 	Fnt *usedfont, *curfont, *nextfont;
     19 	size_t len;
     20 	int utf8strlen, utf8charlen, render = x || y || w || h;
     21 	long utf8codepoint = 0;
     22 	const char *utf8str;
     23 	FcCharSet *fccharset;
     24 	FcPattern *fcpattern;
     25 	FcPattern *match;
     26 	XftResult result;
     27 	int charexists = 0;
     28 	int utf8err = 0;
     29 	int i, n;
     30 
     31 	if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0
     32 	  || (align != AlignL && align != AlignR))
     33 		return 0;
     34 
     35 	if (!render) {
     36 		w = ~w;
     37 	} else {
     38 		XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
     39 		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
     40 		#if ALPHA_PATCH
     41 		d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
     42 		#else
     43 		d = XftDrawCreate(drw->dpy, drw->drawable,
     44 		                  DefaultVisual(drw->dpy, drw->screen),
     45 		                  DefaultColormap(drw->dpy, drw->screen));
     46 		#endif // ALPHA_PATCH
     47 	}
     48 
     49 	#if BIDI_PATCH
     50 	apply_fribidi(text);
     51 	text = fribidi_text;
     52 	#endif // BIDI_PATCH
     53 
     54 	usedfont = drw->fonts;
     55 	i = align == AlignL ? 0 : textlen;
     56 	x = align == AlignL ? x : x + w;
     57 	while (1) {
     58 		utf8strlen = 0;
     59 		nextfont = NULL;
     60 		/* if (align == AlignL) */
     61 		utf8str = text + i;
     62 
     63 		while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) {
     64 			if (align == AlignL) {
     65 				utf8charlen = utf8decode(text + i, &utf8codepoint, &utf8err);
     66 				if (!utf8charlen) {
     67 					textlen = i;
     68 					break;
     69 				}
     70 			} else {
     71 				n = utf8nextchar(text, textlen, i, -1);
     72 				utf8charlen = utf8decode(text + n, &utf8codepoint, &utf8err);
     73 				if (!utf8charlen) {
     74 					textlen -= i;
     75 					text += i;
     76 					i = 0;
     77 					break;
     78 				}
     79 			}
     80 			for (curfont = drw->fonts; curfont; curfont = curfont->next) {
     81 				charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
     82 				if (charexists) {
     83 					if (curfont == usedfont) {
     84 						utf8strlen += utf8charlen;
     85 						i += align == AlignL ? utf8charlen : -utf8charlen;
     86 					} else {
     87 						nextfont = curfont;
     88 					}
     89 					break;
     90 				}
     91 			}
     92 
     93 			if (!charexists || nextfont)
     94 				break;
     95 			else
     96 				charexists = 0;
     97 		}
     98 
     99 		if (align == AlignR)
    100 			utf8str = text + i;
    101 
    102 		if (utf8strlen) {
    103 			drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
    104 			/* shorten text if necessary */
    105 			if (align == AlignL) {
    106 				for (len = utf8strlen; len && ew > w; ) {
    107 					len = utf8nextchar(utf8str, len, len, -1);
    108 					drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
    109 				}
    110 			} else {
    111 				for (len = utf8strlen; len && ew > w; ) {
    112 					n = utf8nextchar(utf8str, len, 0, +1);
    113 					utf8str += n;
    114 					len -= n;
    115 					drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
    116 				}
    117 			}
    118 
    119 			if (len) {
    120 				if (render) {
    121 					ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
    122 					XftDrawStringUtf8(d, &drw->scheme[ColFg],
    123 					                  usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len);
    124 				}
    125 				x += align == AlignL ? ew : -ew;
    126 				w -= ew;
    127 			}
    128 			if (len < utf8strlen)
    129 				break;
    130 		}
    131 
    132 		if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) {
    133 			break;
    134 		} else if (nextfont) {
    135 			charexists = 0;
    136 			usedfont = nextfont;
    137 		} else {
    138 			/* Regardless of whether or not a fallback font is found, the
    139 			 * character must be drawn. */
    140 			charexists = 1;
    141 
    142 			fccharset = FcCharSetCreate();
    143 			FcCharSetAddChar(fccharset, utf8codepoint);
    144 
    145 			if (!drw->fonts->pattern) {
    146 				/* Refer to the comment in xfont_create for more information. */
    147 				die("the first font in the cache must be loaded from a font string.");
    148 			}
    149 
    150 			fcpattern = FcPatternDuplicate(drw->fonts->pattern);
    151 			FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
    152 			FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
    153 
    154 			FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
    155 			FcDefaultSubstitute(fcpattern);
    156 			match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
    157 
    158 			FcCharSetDestroy(fccharset);
    159 			FcPatternDestroy(fcpattern);
    160 
    161 			if (match) {
    162 				usedfont = xfont_create(drw, NULL, match);
    163 				if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
    164 					for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
    165 						; /* NOP */
    166 					curfont->next = usedfont;
    167 				} else {
    168 					xfont_free(usedfont);
    169 					usedfont = drw->fonts;
    170 				}
    171 			}
    172 		}
    173 	}
    174 	if (d)
    175 		XftDrawDestroy(d);
    176 
    177 	return x;
    178 }