aboutsummaryrefslogtreecommitdiffstats
path: root/drw.c~
diff options
context:
space:
mode:
authorphilw <dscr@duck.com>2025-04-15 01:41:05 +0200
committerphilw <dscr@duck.com>2025-04-15 01:41:05 +0200
commit8146021a2ea4130cfb0d2bf846b451ec538b1bb6 (patch)
tree3a946ef5ee4769bf4eae89b4e77858cc67b8060b /drw.c~
parent515b7f3b4f048b29325e3e38f0f4a2ef898e8daa (diff)
downloaddwm-8146021a2ea4130cfb0d2bf846b451ec538b1bb6.tar.gz
dwm-8146021a2ea4130cfb0d2bf846b451ec538b1bb6.zip
Refactor the project
Refactored core logic to improve readability and maintainability. Documented the 'transient.c' file to provide clear explanations of its purpose and functions. Updated the 'util.c' file with necessary comments and improvements to existing code. Documented the 'util.h' header file to clarify function prototypes and usage. This update should improve the overall code quality and make it easier for future development. Signed-off-by: philw <dscr@duck.com>
Diffstat (limited to 'drw.c~')
-rw-r--r--drw.c~450
1 files changed, 0 insertions, 450 deletions
diff --git a/drw.c~ b/drw.c~
deleted file mode 100644
index a58a2b4..0000000
--- a/drw.c~
+++ /dev/null
@@ -1,450 +0,0 @@
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
14static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
15static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
16static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
17static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
18
19static long
20utf8decodebyte(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
28static size_t
29utf8validate(long *u, size_t i)
30{
31 if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
32 *u = UTF_INVALID;
33 for (i = 1; *u > utfmax[i]; ++i)
34 ;
35 return i;
36}
37
38static size_t
39utf8decode(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
63Drw *
64drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
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, screen));
74 drw->gc = XCreateGC(dpy, root, 0, NULL);
75 XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
76
77 return drw;
78}
79
80void
81drw_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, DefaultDepth(drw->dpy, drw->screen));
91}
92
93void
94drw_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 */
105static Fnt *
106xfont_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 not yield the
114 * same substitution results as using the pattern returned by
115 * FcNameParse; using the latter results in the desired fallback
116 * behaviour whereas the former just results in missing-character
117 * rectangles being drawn, at least with some fonts. */
118 if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
119 fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
120 return NULL;
121 }
122 if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
123 fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
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 pattern.\n");
130 return NULL;
131 }
132 } else {
133 die("no font specified.");
134 }
135
136 font = ecalloc(1, sizeof(Fnt));
137 font->xfont = xfont;
138 font->pattern = pattern;
139 font->h = xfont->ascent + xfont->descent;
140 font->dpy = drw->dpy;
141
142 return font;
143}
144
145static void
146xfont_free(Fnt *font)
147{
148 if (!font)
149 return;
150 if (font->pattern)
151 FcPatternDestroy(font->pattern);
152 XftFontClose(font->dpy, font->xfont);
153 free(font);
154}
155
156Fnt*
157drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
158{
159 Fnt *cur, *ret = NULL;
160 size_t i;
161
162 if (!drw || !fonts)
163 return NULL;
164
165 for (i = 1; i <= fontcount; i++) {
166 if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
167 cur->next = ret;
168 ret = cur;
169 }
170 }
171 return (drw->fonts = ret);
172}
173
174void
175drw_fontset_free(Fnt *font)
176{
177 if (font) {
178 drw_fontset_free(font->next);
179 xfont_free(font);
180 }
181}
182
183void
184drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
185{
186 if (!drw || !dest || !clrname)
187 return;
188
189 if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
190 DefaultColormap(drw->dpy, drw->screen),
191 clrname, dest))
192 die("error, cannot allocate color '%s'", clrname);
193}
194
195/* Wrapper to create color schemes. The caller has to call free(3) on the
196 * returned color scheme when done using it. */
197Clr *
198drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
199{
200 size_t i;
201 Clr *ret;
202
203 /* need at least two colors for a scheme */
204 if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
205 return NULL;
206
207 for (i = 0; i < clrcount; i++)
208 drw_clr_create(drw, &ret[i], clrnames[i]);
209 return ret;
210}
211
212void
213drw_setfontset(Drw *drw, Fnt *set)
214{
215 if (drw)
216 drw->fonts = set;
217}
218
219void
220drw_setscheme(Drw *drw, Clr *scm)
221{
222 if (drw)
223 drw->scheme = scm;
224}
225
226void
227drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
228{
229 if (!drw || !drw->scheme)
230 return;
231 XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
232 if (filled)
233 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
234 else
235 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
236}
237
238int
239drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
240{
241 int i, ty, ellipsis_x = 0;
242 unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
243 XftDraw *d = NULL;
244 Fnt *usedfont, *curfont, *nextfont;
245 int utf8strlen, utf8charlen, render = x || y || w || h;
246 long utf8codepoint = 0;
247 const char *utf8str;
248 FcCharSet *fccharset;
249 FcPattern *fcpattern;
250 FcPattern *match;
251 XftResult result;
252 int charexists = 0, overflow = 0;
253 /* keep track of a couple codepoints for which we have no match. */
254 enum { nomatches_len = 64 };
255 static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
256 static unsigned int ellipsis_width = 0;
257
258 if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
259 return 0;
260
261 if (!render) {
262 w = invert ? invert : ~invert;
263 } else {
264 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
265 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
266 d = XftDrawCreate(drw->dpy, drw->drawable,
267 DefaultVisual(drw->dpy, drw->screen),
268 DefaultColormap(drw->dpy, drw->screen));
269 x += lpad;
270 w -= lpad;
271 }
272
273 usedfont = drw->fonts;
274 if (!ellipsis_width && render)
275 ellipsis_width = drw_fontset_getwidth(drw, "...");
276 while (1) {
277 ew = ellipsis_len = utf8strlen = 0;
278 utf8str = text;
279 nextfont = NULL;
280 while (*text) {
281 utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
282 for (curfont = drw->fonts; curfont; curfont = curfont->next) {
283 charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
284 if (charexists) {
285 drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
286 if (ew + ellipsis_width <= w) {
287 /* keep track where the ellipsis still fits */
288 ellipsis_x = x + ew;
289 ellipsis_w = w - ew;
290 ellipsis_len = utf8strlen;
291 }
292
293 if (ew + tmpw > w) {
294 overflow = 1;
295 /* called from drw_fontset_getwidth_clamp():
296 * it wants the width AFTER the overflow
297 */
298 if (!render)
299 x += tmpw;
300 else
301 utf8strlen = ellipsis_len;
302 } else if (curfont == usedfont) {
303 utf8strlen += utf8charlen;
304 text += utf8charlen;
305 ew += tmpw;
306 } else {
307 nextfont = curfont;
308 }
309 break;
310 }
311 }
312
313 if (overflow || !charexists || nextfont)
314 break;
315 else
316 charexists = 0;
317 }
318
319 if (utf8strlen) {
320 if (render) {
321 ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
322 XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
323 usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
324 }
325 x += ew;
326 w -= ew;
327 }
328 if (render && overflow)
329 drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
330
331 if (!*text || overflow) {
332 break;
333 } else if (nextfont) {
334 charexists = 0;
335 usedfont = nextfont;
336 } else {
337 /* Regardless of whether or not a fallback font is found, the
338 * character must be drawn. */
339 charexists = 1;
340
341 for (i = 0; i < nomatches_len; ++i) {
342 /* avoid calling XftFontMatch if we know we won't find a match */
343 if (utf8codepoint == nomatches.codepoint[i])
344 goto no_match;
345 }
346
347 fccharset = FcCharSetCreate();
348 FcCharSetAddChar(fccharset, utf8codepoint);
349
350 if (!drw->fonts->pattern) {
351 /* Refer to the comment in xfont_create for more information. */
352 die("the first font in the cache must be loaded from a font string.");
353 }
354
355 fcpattern = FcPatternDuplicate(drw->fonts->pattern);
356 FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
357 FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
358
359 FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
360 FcDefaultSubstitute(fcpattern);
361 match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
362
363 FcCharSetDestroy(fccharset);
364 FcPatternDestroy(fcpattern);
365
366 if (match) {
367 usedfont = xfont_create(drw, NULL, match);
368 if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
369 for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
370 ; /* NOP */
371 curfont->next = usedfont;
372 } else {
373 xfont_free(usedfont);
374 nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
375no_match:
376 usedfont = drw->fonts;
377 }
378 }
379 }
380 }
381 if (d)
382 XftDrawDestroy(d);
383
384 return x + (render ? w : 0);
385}
386
387void
388drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
389{
390 if (!drw)
391 return;
392
393 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
394 XSync(drw->dpy, False);
395}
396
397unsigned int
398drw_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
405unsigned int
406drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
407{
408 unsigned int tmp = 0;
409 if (drw && drw->fonts && text && n)
410 tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
411 return MIN(n, tmp);
412}
413
414void
415drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
416{
417 XGlyphInfo ext;
418
419 if (!font || !text)
420 return;
421
422 XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
423 if (w)
424 *w = ext.xOff;
425 if (h)
426 *h = font->h;
427}
428
429Cur *
430drw_cur_create(Drw *drw, int shape)
431{
432 Cur *cur;
433
434 if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
435 return NULL;
436
437 cur->cursor = XCreateFontCursor(drw->dpy, shape);
438
439 return cur;
440}
441
442void
443drw_cur_free(Drw *drw, Cur *cursor)
444{
445 if (!cursor)
446 return;
447
448 XFreeCursor(drw->dpy, cursor->cursor);
449 free(cursor);
450}