Introduction
Introduction Statistics Contact Development Disclaimer Help
drw.c - svkbd - simple virtual keyboard
git clone git://git.suckless.org/svkbd
Log
Files
Refs
README
LICENSE
---
drw.c (10278B)
---
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 die("error, cannot create color scheme (drw=%d) (clrcoun…
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 char buf[1024];
255 int ty;
256 unsigned int ew;
257 XftDraw *d = NULL;
258 Fnt *usedfont, *curfont, *nextfont;
259 size_t i, len;
260 int utf8strlen, utf8charlen, render = x || y || w || h;
261 long utf8codepoint = 0;
262 const char *utf8str;
263 FcCharSet *fccharset;
264 FcPattern *fcpattern;
265 FcPattern *match;
266 XftResult result;
267 int charexists = 0;
268
269 if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
270 return 0;
271
272 if (!render) {
273 w = ~w;
274 } else {
275 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? C…
276 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w…
277 d = XftDrawCreate(drw->dpy, drw->drawable,
278 DefaultVisual(drw->dpy, drw->screen),
279 DefaultColormap(drw->dpy, drw->screen)…
280 x += lpad;
281 w -= lpad;
282 }
283
284 usedfont = drw->fonts;
285 while (1) {
286 utf8strlen = 0;
287 utf8str = text;
288 nextfont = NULL;
289 while (*text) {
290 utf8charlen = utf8decode(text, &utf8codepoint, U…
291 for (curfont = drw->fonts; curfont; curfont = cu…
292 charexists = charexists || XftCharExists…
293 if (charexists) {
294 if (curfont == usedfont) {
295 utf8strlen += utf8charle…
296 text += utf8charlen;
297 } else {
298 nextfont = curfont;
299 }
300 break;
301 }
302 }
303
304 if (!charexists || nextfont)
305 break;
306 else
307 charexists = 0;
308 }
309
310 if (utf8strlen) {
311 drw_font_getexts(usedfont, utf8str, utf8strlen, …
312 /* shorten text if necessary */
313 for (len = MIN(utf8strlen, sizeof(buf) - 1); len…
314 drw_font_getexts(usedfont, utf8str, len,…
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; …
321 ; /* NOP */
322
323 if (render) {
324 ty = y + (h - usedfont->h) / 2 +…
325 XftDrawStringUtf8(d, &drw->schem…
326 usedfont->xfon…
327 }
328 x += ew;
329 w -= ew;
330 }
331 }
332
333 if (!*text) {
334 break;
335 } else if (nextfont) {
336 charexists = 0;
337 usedfont = nextfont;
338 } else {
339 /* Regardless of whether or not a fallback font …
340 * character must be drawn. */
341 charexists = 1;
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 FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
355
356 FcConfigSubstitute(NULL, fcpattern, FcMatchPatte…
357 FcDefaultSubstitute(fcpattern);
358 match = XftFontMatch(drw->dpy, drw->screen, fcpa…
359
360 FcCharSetDestroy(fccharset);
361 FcPatternDestroy(fcpattern);
362
363 if (match) {
364 usedfont = xfont_create(drw, NULL, match…
365 if (usedfont && XftCharExists(drw->dpy, …
366 for (curfont = drw->fonts; curfo…
367 ; /* NOP */
368 curfont->next = usedfont;
369 } else {
370 xfont_free(usedfont);
371 usedfont = drw->fonts;
372 }
373 }
374 }
375 }
376 if (d)
377 XftDrawDestroy(d);
378
379 return x + (render ? w : 0);
380 }
381
382 void
383 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int…
384 {
385 if (!drw)
386 return;
387
388 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, …
389 }
390
391 void
392 drw_sync(Drw *drw)
393 {
394 XSync(drw->dpy, False);
395 }
396
397 unsigned int
398 drw_fontset_getwidth(Drw *drw, const char *text)
399 {
400 if (!drw || !drw->fonts || !text)
401 return 0;
402 return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
403 }
404
405 void
406 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned…
407 {
408 XGlyphInfo ext;
409
410 if (!font || !text)
411 return;
412
413 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len…
414 if (w)
415 *w = ext.xOff;
416 if (h)
417 *h = font->h;
418 }
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.