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