Introduction
Introduction Statistics Contact Development Disclaimer Help
drw.c - sent - simple plaintext presentation tool
git clone git://git.suckless.org/sent
Log
Files
Refs
README
LICENSE
---
drw.c (9896B)
---
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 free(drw);
99 }
100
101 /* This function is an implementation detail. Library users should use
102 * drw_fontset_create instead.
103 */
104 static Fnt *
105 xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
106 {
107 Fnt *font;
108 XftFont *xfont = NULL;
109 FcPattern *pattern = NULL;
110
111 if (fontname) {
112 /* Using the pattern found at font->xfont->pattern does …
113 * same substitution results as using the pattern return…
114 * FcNameParse; using the latter results in the desired …
115 * behaviour whereas the former just results in missing-…
116 * rectangles being drawn, at least with some fonts. */
117 if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fon…
118 fprintf(stderr, "error, cannot load font from na…
119 return NULL;
120 }
121 if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
122 fprintf(stderr, "error, cannot parse font name t…
123 XftFontClose(drw->dpy, xfont);
124 return NULL;
125 }
126 } else if (fontpattern) {
127 if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))…
128 fprintf(stderr, "error, cannot load font from pa…
129 return NULL;
130 }
131 } else {
132 die("no font specified.");
133 }
134
135 font = ecalloc(1, sizeof(Fnt));
136 font->xfont = xfont;
137 font->pattern = pattern;
138 font->h = xfont->ascent + xfont->descent;
139 font->dpy = drw->dpy;
140
141 return font;
142 }
143
144 static void
145 xfont_free(Fnt *font)
146 {
147 if (!font)
148 return;
149 if (font->pattern)
150 FcPatternDestroy(font->pattern);
151 XftFontClose(font->dpy, font->xfont);
152 free(font);
153 }
154
155 Fnt*
156 drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
157 {
158 Fnt *cur, *ret = NULL;
159 size_t i;
160
161 if (!drw || !fonts)
162 return NULL;
163
164 for (i = 1; i <= fontcount; i++) {
165 if ((cur = xfont_create(drw, fonts[fontcount - i], NULL)…
166 cur->next = ret;
167 ret = cur;
168 }
169 }
170 return (drw->fonts = ret);
171 }
172
173 void
174 drw_fontset_free(Fnt *font)
175 {
176 if (font) {
177 drw_fontset_free(font->next);
178 xfont_free(font);
179 }
180 }
181
182 void
183 drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
184 {
185 if (!drw || !dest || !clrname)
186 return;
187
188 if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->sc…
189 DefaultColormap(drw->dpy, drw->screen),
190 clrname, dest))
191 die("error, cannot allocate color '%s'", clrname);
192 }
193
194 /* Wrapper to create color schemes. The caller has to call free(3) on the
195 * returned color scheme when done using it. */
196 Clr *
197 drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
198 {
199 size_t i;
200 Clr *ret;
201
202 /* need at least two colors for a scheme */
203 if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcoun…
204 return NULL;
205
206 for (i = 0; i < clrcount; i++)
207 drw_clr_create(drw, &ret[i], clrnames[i]);
208 return ret;
209 }
210
211 void
212 drw_setfontset(Drw *drw, Fnt *set)
213 {
214 if (drw)
215 drw->fonts = set;
216 }
217
218 void
219 drw_setscheme(Drw *drw, Clr *scm)
220 {
221 if (drw)
222 drw->scheme = scm;
223 }
224
225 void
226 drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int fil…
227 {
228 if (!drw || !drw->scheme)
229 return;
230 XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pi…
231 if (filled)
232 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w…
233 else
234 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w…
235 }
236
237 int
238 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigne…
239 {
240 char buf[1024];
241 int ty;
242 unsigned int ew;
243 XftDraw *d = NULL;
244 Fnt *usedfont, *curfont, *nextfont;
245 size_t i, len;
246 int utf8strlen, utf8charlen, render = x || y || w || h;
247 long utf8codepoint = 0;
248 const char *utf8str;
249 FcCharSet *fccharset;
250 FcPattern *fcpattern;
251 FcPattern *match;
252 XftResult result;
253 int charexists = 0;
254
255 if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
256 return 0;
257
258 if (!render) {
259 w = ~w;
260 } else {
261 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? C…
262 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w…
263 d = XftDrawCreate(drw->dpy, drw->drawable,
264 DefaultVisual(drw->dpy, drw->screen),
265 DefaultColormap(drw->dpy, drw->screen)…
266 x += lpad;
267 w -= lpad;
268 }
269
270 usedfont = drw->fonts;
271 while (1) {
272 utf8strlen = 0;
273 utf8str = text;
274 nextfont = NULL;
275 while (*text) {
276 utf8charlen = utf8decode(text, &utf8codepoint, U…
277 for (curfont = drw->fonts; curfont; curfont = cu…
278 charexists = charexists || XftCharExists…
279 if (charexists) {
280 if (curfont == usedfont) {
281 utf8strlen += utf8charle…
282 text += utf8charlen;
283 } else {
284 nextfont = curfont;
285 }
286 break;
287 }
288 }
289
290 if (!charexists || nextfont)
291 break;
292 else
293 charexists = 0;
294 }
295
296 if (utf8strlen) {
297 drw_font_getexts(usedfont, utf8str, utf8strlen, …
298 /* shorten text if necessary */
299 for (len = MIN(utf8strlen, sizeof(buf) - 1); len…
300 drw_font_getexts(usedfont, utf8str, len,…
301
302 if (len) {
303 memcpy(buf, utf8str, len);
304 buf[len] = '\0';
305 if (len < utf8strlen)
306 for (i = len; i && i > len - 3; …
307 ; /* NOP */
308
309 if (render) {
310 ty = y + (h - usedfont->h) / 2 +…
311 XftDrawStringUtf8(d, &drw->schem…
312 usedfont->xfon…
313 }
314 x += ew;
315 w -= ew;
316 }
317 }
318
319 if (!*text) {
320 break;
321 } else if (nextfont) {
322 charexists = 0;
323 usedfont = nextfont;
324 } else {
325 /* Regardless of whether or not a fallback font …
326 * character must be drawn. */
327 charexists = 1;
328
329 fccharset = FcCharSetCreate();
330 FcCharSetAddChar(fccharset, utf8codepoint);
331
332 if (!drw->fonts->pattern) {
333 /* Refer to the comment in xfont_create …
334 die("the first font in the cache must be…
335 }
336
337 fcpattern = FcPatternDuplicate(drw->fonts->patte…
338 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccha…
339 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
340
341 FcConfigSubstitute(NULL, fcpattern, FcMatchPatte…
342 FcDefaultSubstitute(fcpattern);
343 match = XftFontMatch(drw->dpy, drw->screen, fcpa…
344
345 FcCharSetDestroy(fccharset);
346 FcPatternDestroy(fcpattern);
347
348 if (match) {
349 usedfont = xfont_create(drw, NULL, match…
350 if (usedfont && XftCharExists(drw->dpy, …
351 for (curfont = drw->fonts; curfo…
352 ; /* NOP */
353 curfont->next = usedfont;
354 } else {
355 xfont_free(usedfont);
356 usedfont = drw->fonts;
357 }
358 }
359 }
360 }
361 if (d)
362 XftDrawDestroy(d);
363
364 return x + (render ? w : 0);
365 }
366
367 void
368 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int…
369 {
370 if (!drw)
371 return;
372
373 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, …
374 XSync(drw->dpy, False);
375 }
376
377 unsigned int
378 drw_fontset_getwidth(Drw *drw, const char *text)
379 {
380 if (!drw || !drw->fonts || !text)
381 return 0;
382 return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
383 }
384
385 void
386 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned…
387 {
388 XGlyphInfo ext;
389
390 if (!font || !text)
391 return;
392
393 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len…
394 if (w)
395 *w = ext.xOff;
396 if (h)
397 *h = font->h;
398 }
399
400 Cur *
401 drw_cur_create(Drw *drw, int shape)
402 {
403 Cur *cur;
404
405 if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
406 return NULL;
407
408 cur->cursor = XCreateFontCursor(drw->dpy, shape);
409
410 return cur;
411 }
412
413 void
414 drw_cur_free(Drw *drw, Cur *cursor)
415 {
416 if (!cursor)
417 return;
418
419 XFreeCursor(drw->dpy, cursor->cursor);
420 free(cursor);
421 }
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.