Introduction
Introduction Statistics Contact Development Disclaimer Help
drw.c - libsl - draw back-ends for dwm, dmenu, etc
git clone git://git.codemadness.org/libsl
Log
Files
Refs
LICENSE
---
drw.c (11609B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <X11/Xlib.h>
6 #include <X11/Xft/Xft.h>
7
8 #include "drw.h"
9 #include "util.h"
10
11 #define UTF_INVALID 0xFFFD
12 #define UTF_SIZ 4
13
14 static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE…
15 static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF…
16 static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, …
17 static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, …
18
19 static long
20 utf8decodebyte(const char c, size_t *i)
21 {
22 for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
23 if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
24 return (unsigned char)c & ~utfmask[*i];
25 return 0;
26 }
27
28 static size_t
29 utf8validate(long *u, size_t i)
30 {
31 if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0x…
32 *u = UTF_INVALID;
33 for (i = 1; *u > utfmax[i]; ++i)
34 ;
35 return i;
36 }
37
38 static size_t
39 utf8decode(const char *c, long *u, size_t clen)
40 {
41 size_t i, j, len, type;
42 long udecoded;
43
44 *u = UTF_INVALID;
45 if (!clen)
46 return 0;
47 udecoded = utf8decodebyte(c[0], &len);
48 if (!BETWEEN(len, 1, UTF_SIZ))
49 return 1;
50 for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
51 udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
52 if (type)
53 return j;
54 }
55 if (j < len)
56 return 0;
57 *u = udecoded;
58 utf8validate(u, len);
59
60 return len;
61 }
62
63 Drw *
64 drw_create(Display *dpy, int screen, Window root, unsigned int w, unsign…
65 {
66 Drw *drw = ecalloc(1, sizeof(Drw));
67
68 drw->dpy = dpy;
69 drw->screen = screen;
70 drw->root = root;
71 drw->w = w;
72 drw->h = h;
73 drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy,…
74 drw->gc = XCreateGC(dpy, root, 0, NULL);
75 XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMite…
76
77 return drw;
78 }
79
80 void
81 drw_resize(Drw *drw, unsigned int w, unsigned int h)
82 {
83 if (!drw)
84 return;
85
86 drw->w = w;
87 drw->h = h;
88 if (drw->drawable)
89 XFreePixmap(drw->dpy, drw->drawable);
90 drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, Default…
91 }
92
93 void
94 drw_free(Drw *drw)
95 {
96 XFreePixmap(drw->dpy, drw->drawable);
97 XFreeGC(drw->dpy, drw->gc);
98 drw_fontset_free(drw->fonts);
99 free(drw);
100 }
101
102 /* This function is an implementation detail. Library users should use
103 * drw_fontset_create instead.
104 */
105 static Fnt *
106 xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
107 {
108 Fnt *font;
109 XftFont *xfont = NULL;
110 FcPattern *pattern = NULL;
111
112 if (fontname) {
113 /* Using the pattern found at font->xfont->pattern does …
114 * same substitution results as using the pattern return…
115 * FcNameParse; using the latter results in the desired …
116 * behaviour whereas the former just results in missing-…
117 * rectangles being drawn, at least with some fonts. */
118 if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fon…
119 fprintf(stderr, "error, cannot load font from na…
120 return NULL;
121 }
122 if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
123 fprintf(stderr, "error, cannot parse font name t…
124 XftFontClose(drw->dpy, xfont);
125 return NULL;
126 }
127 } else if (fontpattern) {
128 if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))…
129 fprintf(stderr, "error, cannot load font from pa…
130 return NULL;
131 }
132 } else {
133 die("no font specified.");
134 }
135
136 /* Do not allow using color fonts. This is a workaround for a Ba…
137 * error from Xft with color glyphs. Modelled on the Xterm worka…
138 * https://bugzilla.redhat.com/show_bug.cgi?id=1498269
139 * https://lists.suckless.org/dev/1701/30932.html
140 * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
141 * and lots more all over the internet.
142 */
143 FcBool iscol;
144 if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcRe…
145 XftFontClose(drw->dpy, xfont);
146 return NULL;
147 }
148
149 font = ecalloc(1, sizeof(Fnt));
150 font->xfont = xfont;
151 font->pattern = pattern;
152 font->h = xfont->ascent + xfont->descent;
153 font->dpy = drw->dpy;
154
155 return font;
156 }
157
158 static void
159 xfont_free(Fnt *font)
160 {
161 if (!font)
162 return;
163 if (font->pattern)
164 FcPatternDestroy(font->pattern);
165 XftFontClose(font->dpy, font->xfont);
166 free(font);
167 }
168
169 Fnt*
170 drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
171 {
172 Fnt *cur, *ret = NULL;
173 size_t i;
174
175 if (!drw || !fonts)
176 return NULL;
177
178 for (i = 1; i <= fontcount; i++) {
179 if ((cur = xfont_create(drw, fonts[fontcount - i], NULL)…
180 cur->next = ret;
181 ret = cur;
182 }
183 }
184 return (drw->fonts = ret);
185 }
186
187 void
188 drw_fontset_free(Fnt *font)
189 {
190 if (font) {
191 drw_fontset_free(font->next);
192 xfont_free(font);
193 }
194 }
195
196 void
197 drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
198 {
199 if (!drw || !dest || !clrname)
200 return;
201
202 if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->sc…
203 DefaultColormap(drw->dpy, drw->screen),
204 clrname, dest))
205 die("error, cannot allocate color '%s'", clrname);
206 }
207
208 /* Wrapper to create color schemes. The caller has to call free(3) on the
209 * returned color scheme when done using it. */
210 Clr *
211 drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
212 {
213 size_t i;
214 Clr *ret;
215
216 /* need at least two colors for a scheme */
217 if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcoun…
218 return NULL;
219
220 for (i = 0; i < clrcount; i++)
221 drw_clr_create(drw, &ret[i], clrnames[i]);
222 return ret;
223 }
224
225 void
226 drw_setfontset(Drw *drw, Fnt *set)
227 {
228 if (drw)
229 drw->fonts = set;
230 }
231
232 void
233 drw_setscheme(Drw *drw, Clr *scm)
234 {
235 if (drw)
236 drw->scheme = scm;
237 }
238
239 void
240 drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int fil…
241 {
242 if (!drw || !drw->scheme)
243 return;
244 XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pi…
245 if (filled)
246 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w…
247 else
248 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w…
249 }
250
251 int
252 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigne…
253 {
254 int i, ty, ellipsis_x = 0;
255 unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
256 XftDraw *d = NULL;
257 Fnt *usedfont, *curfont, *nextfont;
258 int utf8strlen, utf8charlen, render = x || y || w || h;
259 long utf8codepoint = 0;
260 const char *utf8str;
261 FcCharSet *fccharset;
262 FcPattern *fcpattern;
263 FcPattern *match;
264 XftResult result;
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;…
269 static unsigned int ellipsis_width = 0;
270
271 if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->f…
272 return 0;
273
274 if (!render) {
275 w = invert ? invert : ~invert;
276 } else {
277 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? C…
278 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w…
279 d = XftDrawCreate(drw->dpy, drw->drawable,
280 DefaultVisual(drw->dpy, drw->screen),
281 DefaultColormap(drw->dpy, drw->screen)…
282 x += lpad;
283 w -= lpad;
284 }
285
286 usedfont = drw->fonts;
287 if (!ellipsis_width && render)
288 ellipsis_width = drw_fontset_getwidth(drw, "...");
289 while (1) {
290 ew = ellipsis_len = utf8strlen = 0;
291 utf8str = text;
292 nextfont = NULL;
293 while (*text) {
294 utf8charlen = utf8decode(text, &utf8codepoint, U…
295 for (curfont = drw->fonts; curfont; curfont = cu…
296 charexists = charexists || XftCharExists…
297 if (charexists) {
298 drw_font_getexts(curfont, text, …
299 if (ew + ellipsis_width <= w) {
300 /* keep track where the …
301 ellipsis_x = x + ew;
302 ellipsis_w = w - ew;
303 ellipsis_len = utf8strle…
304 }
305
306 if (ew + tmpw > w) {
307 overflow = 1;
308 /* called from drw_fonts…
309 * it wants the width AF…
310 */
311 if (!render)
312 x += tmpw;
313 else
314 utf8strlen = ell…
315 } else if (curfont == usedfont) {
316 utf8strlen += utf8charle…
317 text += utf8charlen;
318 ew += tmpw;
319 } else {
320 nextfont = curfont;
321 }
322 break;
323 }
324 }
325
326 if (overflow || !charexists || nextfont)
327 break;
328 else
329 charexists = 0;
330 }
331
332 if (utf8strlen) {
333 if (render) {
334 ty = y + (h - usedfont->h) / 2 + usedfon…
335 XftDrawStringUtf8(d, &drw->scheme[invert…
336 usedfont->xfont, x, ty…
337 }
338 x += ew;
339 w -= ew;
340 }
341 if (render && overflow)
342 drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "…
343
344 if (!*text || overflow) {
345 break;
346 } else if (nextfont) {
347 charexists = 0;
348 usedfont = nextfont;
349 } else {
350 /* Regardless of whether or not a fallback font …
351 * character must be drawn. */
352 charexists = 1;
353
354 for (i = 0; i < nomatches_len; ++i) {
355 /* avoid calling XftFontMatch if we know…
356 if (utf8codepoint == nomatches.codepoint…
357 goto no_match;
358 }
359
360 fccharset = FcCharSetCreate();
361 FcCharSetAddChar(fccharset, utf8codepoint);
362
363 if (!drw->fonts->pattern) {
364 /* Refer to the comment in xfont_create …
365 die("the first font in the cache must be…
366 }
367
368 fcpattern = FcPatternDuplicate(drw->fonts->patte…
369 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccha…
370 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
371 FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
372
373 FcConfigSubstitute(NULL, fcpattern, FcMatchPatte…
374 FcDefaultSubstitute(fcpattern);
375 match = XftFontMatch(drw->dpy, drw->screen, fcpa…
376
377 FcCharSetDestroy(fccharset);
378 FcPatternDestroy(fcpattern);
379
380 if (match) {
381 usedfont = xfont_create(drw, NULL, match…
382 if (usedfont && XftCharExists(drw->dpy, …
383 for (curfont = drw->fonts; curfo…
384 ; /* NOP */
385 curfont->next = usedfont;
386 } else {
387 xfont_free(usedfont);
388 nomatches.codepoint[++nomatches.…
389 no_match:
390 usedfont = drw->fonts;
391 }
392 }
393 }
394 }
395 if (d)
396 XftDrawDestroy(d);
397
398 return x + (render ? w : 0);
399 }
400
401 void
402 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int…
403 {
404 if (!drw)
405 return;
406
407 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, …
408 XSync(drw->dpy, False);
409 }
410
411 unsigned int
412 drw_fontset_getwidth(Drw *drw, const char *text)
413 {
414 if (!drw || !drw->fonts || !text)
415 return 0;
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);
426 }
427
428 void
429 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned…
430 {
431 XGlyphInfo ext;
432
433 if (!font || !text)
434 return;
435
436 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len…
437 if (w)
438 *w = ext.xOff;
439 if (h)
440 *h = font->h;
441 }
442
443 Cur *
444 drw_cur_create(Drw *drw, int shape)
445 {
446 Cur *cur;
447
448 if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
449 return NULL;
450
451 cur->cursor = XCreateFontCursor(drw->dpy, shape);
452
453 return cur;
454 }
455
456 void
457 drw_cur_free(Drw *drw, Cur *cursor)
458 {
459 if (!cursor)
460 return;
461
462 XFreeCursor(drw->dpy, cursor->cursor);
463 free(cursor);
464 }
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.