drw.c - libsl - shared code master of various suckless projects
(HTM) git clone git://git.suckless.org/libsl
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
drw.c (6245B)
---
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
7 #include "drw.h"
8 #include "util.h"
9
10 Drw *
11 drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
12 {
13 Drw *drw;
14
15 drw = ecalloc(1, sizeof(Drw));
16 drw->dpy = dpy;
17 drw->screen = screen;
18 drw->root = root;
19 drw->w = w;
20 drw->h = h;
21 drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
22 drw->gc = XCreateGC(dpy, root, 0, NULL);
23 XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
24
25 return drw;
26 }
27
28 void
29 drw_resize(Drw *drw, unsigned int w, unsigned int h)
30 {
31 drw->w = w;
32 drw->h = h;
33 if (drw->drawable)
34 XFreePixmap(drw->dpy, drw->drawable);
35 drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
36 }
37
38 void
39 drw_free(Drw *drw)
40 {
41 XFreePixmap(drw->dpy, drw->drawable);
42 XFreeGC(drw->dpy, drw->gc);
43 free(drw);
44 }
45
46 static Fnt *
47 xfont_create(Display *dpy, const char *fontname)
48 {
49 Fnt *font;
50 XFontStruct **xfonts;
51 char **font_names;
52 char *def, **missing;
53 int n;
54
55 font = ecalloc(1, sizeof(Fnt));
56 font->dpy = dpy;
57 font->set = XCreateFontSet(dpy, fontname, &missing, &n, &def);
58 if (missing) {
59 while (n--)
60 fprintf(stderr, "drw: missing fontset: %s\n", missing[n]);
61 XFreeStringList(missing);
62 }
63 if (font->set) {
64 XExtentsOfFontSet(font->set);
65 n = XFontsOfFontSet(font->set, &xfonts, &font_names);
66 while (n--) {
67 font->ascent = MAX(font->ascent, (*xfonts)->ascent);
68 font->descent = MAX(font->descent,(*xfonts)->descent);
69 xfonts++;
70 }
71 } else {
72 if (!(font->xfont = XLoadQueryFont(dpy, fontname))
73 && !(font->xfont = XLoadQueryFont(dpy, "fixed")))
74 die("error, cannot load font: '%s'\n", fontname);
75 font->ascent = font->xfont->ascent;
76 font->descent = font->xfont->descent;
77 }
78 font->h = font->ascent + font->descent;
79
80 return font;
81 }
82
83 void
84 xfont_free(Display *dpy, Fnt *font)
85 {
86 if (font->set)
87 XFreeFontSet(dpy, font->set);
88 else
89 XFreeFont(dpy, font->xfont);
90 free(font);
91 }
92
93 Fnt *
94 drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
95 {
96 /* just create using first font */
97 /* TODO: more? */
98 drw->fonts = xfont_create(drw->dpy, fonts[0]);
99 return drw->fonts;
100 }
101
102 void
103 drw_fontset_free(Fnt *font)
104 {
105 xfont_free(font->dpy, font);
106 }
107
108 void
109 drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
110 {
111 Colormap cmap;
112 XColor ecolor;
113
114 cmap = DefaultColormap(drw->dpy, drw->screen);
115 if (!XAllocNamedColor(drw->dpy, cmap, clrname, dest, &ecolor))
116 die("error, cannot allocate color '%s'\n", clrname);
117 }
118
119 /* Wrapper to create color schemes. The caller has to call free(3) on the
120 * returned color scheme when done using it. */
121 Clr *
122 drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
123 {
124 size_t i;
125 Clr *ret;
126
127 ret = ecalloc(clrcount, sizeof(Clr));
128 for (i = 0; i < clrcount; i++)
129 drw_clr_create(drw, &ret[i], clrnames[i]);
130
131 return ret;
132 }
133
134 void
135 drw_clr_free(Drw *drw, Clr *c)
136 {
137 if (!drw || !c)
138 return;
139
140 /* c is typedef XColor Clr */
141 /* TODO: free XColor? */
142 }
143
144 void
145 drw_scm_free(Drw *drw, Clr *scm, size_t clrcount)
146 {
147 size_t i;
148
149 if (!drw || !scm)
150 return;
151
152 for (i = 0; i < clrcount; i++)
153 drw_clr_free(drw, &scm[i]);
154 free(scm);
155 }
156
157 void
158 drw_setfontset(Drw *drw, Fnt *set)
159 {
160 drw->fonts = set;
161 }
162
163 void
164 drw_setscheme(Drw *drw, Clr *scheme)
165 {
166 drw->scheme = scheme;
167 }
168
169 void
170 drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled,
171 int invert)
172 {
173 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColBg : ColFg].pixel);
174 if (filled)
175 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1);
176 else
177 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
178 }
179
180 int
181 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad,
182 const char *text, int invert)
183 {
184 char buf[256];
185 int i, tx, ty, th, len, olen, render = x || y || w || h;
186 unsigned int texw, texh;
187
188 if (!render) {
189 w = ~w;
190 } else {
191 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
192 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
193 x += lpad;
194 w -= lpad;
195 }
196
197 olen = strlen(text);
198 drw_font_getexts(drw->fonts, text, olen, &texw, &texh);
199 th = drw->fonts->ascent + drw->fonts->descent;
200 ty = y + (h / 2) - (th / 2) + drw->fonts->ascent;
201 tx = x;
202 /* shorten text if necessary */
203 for (len = MIN(olen, sizeof buf); len && texw > w; len--)
204 drw_font_getexts(drw->fonts, text, len, &texw, &texh);
205 if (!len)
206 return x;
207 memcpy(buf, text, len);
208 if (len < olen)
209 for (i = len; i && i > len - 3; buf[--i] = '.')
210 ;
211 XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
212 if (drw->fonts->set)
213 XmbDrawString(drw->dpy, drw->drawable, drw->fonts->set, drw->gc, tx, ty, buf, len);
214 else
215 XDrawString(drw->dpy, drw->drawable, drw->gc, tx, ty, buf, len);
216
217 x += texw;
218 w -= texw;
219
220 return x + (render ? w : 0);
221 }
222
223 void
224 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
225 {
226 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
227 XSync(drw->dpy, False);
228 }
229
230 static unsigned int
231 drw_font_getexts_width(Fnt *font, const char *text, unsigned int len)
232 {
233 unsigned int w;
234
235 drw_font_getexts(font, text, len, &w, NULL);
236
237 return w;
238 }
239
240 unsigned int
241 drw_fontset_getwidth(Drw *drw, const char *text)
242 {
243 return drw_font_getexts_width(drw->fonts, text, strlen(text));
244 }
245
246 unsigned int
247 drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
248 {
249 unsigned int tmp = 0;
250 if (drw && drw->fonts && text && n)
251 tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
252 return MIN(n, tmp);
253 }
254
255 void
256 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
257 {
258 XRectangle r;
259
260 if (font->set) {
261 XmbTextExtents(font->set, text, len, NULL, &r);
262 if (w)
263 *w = r.width;
264 if (h)
265 *h = r.height;
266 } else {
267 if (w)
268 *w = XTextWidth(font->xfont, text, len);
269 if (h)
270 *h = font->ascent + font->descent;
271 }
272 }
273
274 Cur *
275 drw_cur_create(Drw *drw, int shape)
276 {
277 Cur *cur;
278
279 cur = ecalloc(1, sizeof(Cur));
280 cur->cursor = XCreateFontCursor(drw->dpy, shape);
281
282 return cur;
283 }
284
285 void
286 drw_cur_free(Drw *drw, Cur *cursor)
287 {
288 XFreeCursor(drw->dpy, cursor->cursor);
289 free(cursor);
290 }