Introduction
Introduction Statistics Contact Development Disclaimer Help
drw.c - dmenu - my customized version of dmenu (hiltjo branch)
git clone git://git.codemadness.org/dmenu
Log
Files
Refs
README
LICENSE
---
drw.c (11253B)
---
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 d = XftDrawCreate(drw->dpy, drw->drawable,
252 DefaultVisual(drw->dpy, drw->screen),
253 DefaultColormap(drw->dpy, drw->screen)…
254 x += lpad;
255 w -= lpad;
256 }
257
258 usedfont = drw->fonts;
259 if (!ellipsis_width && render)
260 ellipsis_width = drw_fontset_getwidth(drw, "...");
261 if (!invalid_width && render)
262 invalid_width = drw_fontset_getwidth(drw, invalid);
263 while (1) {
264 ew = ellipsis_len = utf8err = utf8charlen = utf8strlen =…
265 utf8str = text;
266 nextfont = NULL;
267 while (*text) {
268 utf8charlen = utf8decode(text, &utf8codepoint, &…
269 for (curfont = drw->fonts; curfont; curfont = cu…
270 charexists = charexists || XftCharExists…
271 if (charexists) {
272 drw_font_getexts(curfont, text, …
273 if (ew + ellipsis_width <= w) {
274 /* keep track where the …
275 ellipsis_x = x + ew;
276 ellipsis_w = w - ew;
277 ellipsis_len = utf8strle…
278 }
279
280 if (ew + tmpw > w) {
281 overflow = 1;
282 /* called from drw_fonts…
283 * it wants the width AF…
284 */
285 if (!render)
286 x += tmpw;
287 else
288 utf8strlen = ell…
289 } else if (curfont == usedfont) {
290 text += utf8charlen;
291 utf8strlen += utf8err ? …
292 ew += utf8err ? 0 : tmpw;
293 } else {
294 nextfont = curfont;
295 }
296 break;
297 }
298 }
299
300 if (overflow || !charexists || nextfont || utf8e…
301 break;
302 else
303 charexists = 0;
304 }
305
306 if (utf8strlen) {
307 if (render) {
308 ty = y + (h - usedfont->h) / 2 + usedfon…
309 XftDrawStringUtf8(d, &drw->scheme[invert…
310 usedfont->xfont, x, ty…
311 }
312 x += ew;
313 w -= ew;
314 }
315 if (utf8err && (!render || invalid_width < w)) {
316 if (render)
317 drw_text(drw, x, y, w, h, 0, invalid, in…
318 x += invalid_width;
319 w -= invalid_width;
320 }
321 if (render && overflow)
322 drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "…
323
324 if (!*text || overflow) {
325 break;
326 } else if (nextfont) {
327 charexists = 0;
328 usedfont = nextfont;
329 } else {
330 /* Regardless of whether or not a fallback font …
331 * character must be drawn. */
332 charexists = 1;
333
334 hash = (unsigned int)utf8codepoint;
335 hash = ((hash >> 16) ^ hash) * 0x21F0AAAD;
336 hash = ((hash >> 15) ^ hash) * 0xD35A2D97;
337 h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches);
338 h1 = (hash >> 17) % LENGTH(nomatches);
339 /* avoid expensive XftFontMatch call when we kno…
340 if (nomatches[h0] == utf8codepoint || nomatches[…
341 goto no_match;
342
343 fccharset = FcCharSetCreate();
344 FcCharSetAddChar(fccharset, utf8codepoint);
345
346 if (!drw->fonts->pattern) {
347 /* Refer to the comment in xfont_create …
348 die("the first font in the cache must be…
349 }
350
351 fcpattern = FcPatternDuplicate(drw->fonts->patte…
352 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccha…
353 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
354
355 FcConfigSubstitute(NULL, fcpattern, FcMatchPatte…
356 FcDefaultSubstitute(fcpattern);
357 match = XftFontMatch(drw->dpy, drw->screen, fcpa…
358
359 FcCharSetDestroy(fccharset);
360 FcPatternDestroy(fcpattern);
361
362 if (match) {
363 usedfont = xfont_create(drw, NULL, match…
364 if (usedfont && XftCharExists(drw->dpy, …
365 for (curfont = drw->fonts; curfo…
366 ; /* NOP */
367 curfont->next = usedfont;
368 } else {
369 xfont_free(usedfont);
370 nomatches[nomatches[h0] ? h1 : h…
371 no_match:
372 usedfont = drw->fonts;
373 }
374 }
375 }
376 }
377 if (d)
378 XftDrawDestroy(d);
379
380 return x + (render ? w : 0);
381 }
382
383 void
384 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int…
385 {
386 if (!drw)
387 return;
388
389 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, …
390 XSync(drw->dpy, False);
391 }
392
393 unsigned int
394 drw_fontset_getwidth(Drw *drw, const char *text)
395 {
396 if (!drw || !drw->fonts || !text)
397 return 0;
398 return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
399 }
400
401 unsigned int
402 drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
403 {
404 unsigned int tmp = 0;
405 if (drw && drw->fonts && text && n)
406 tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
407 return MIN(n, tmp);
408 }
409
410 void
411 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned…
412 {
413 XGlyphInfo ext;
414
415 if (!font || !text)
416 return;
417
418 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len…
419 if (w)
420 *w = ext.xOff;
421 if (h)
422 *h = font->h;
423 }
424
425 Cur *
426 drw_cur_create(Drw *drw, int shape)
427 {
428 Cur *cur;
429
430 if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
431 return NULL;
432
433 cur->cursor = XCreateFontCursor(drw->dpy, shape);
434
435 return cur;
436 }
437
438 void
439 drw_cur_free(Drw *drw, Cur *cursor)
440 {
441 if (!cursor)
442 return;
443
444 XFreeCursor(drw->dpy, cursor->cursor);
445 free(cursor);
446 }
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.