libsl

shared code master of various suckless projects
git clone git://git.suckless.org/libsl
Log | Files | Refs | 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 }