drw.c - libsl - draw back-ends for dwm, dmenu, etc
 (HTM) git clone git://git.codemadness.org/libsl
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       drw.c (6233B)
       ---
            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 }
          155 
          156 void
          157 drw_setfontset(Drw *drw, Fnt *set)
          158 {
          159         drw->fonts = set;
          160 }
          161 
          162 void
          163 drw_setscheme(Drw *drw, Clr *scheme)
          164 {
          165         drw->scheme = scheme;
          166 }
          167 
          168 void
          169 drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled,
          170         int invert)
          171 {
          172         XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColBg : ColFg].pixel);
          173         if (filled)
          174                 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1);
          175         else
          176                 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
          177 }
          178 
          179 int
          180 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad,
          181         const char *text, int invert)
          182 {
          183         char buf[256];
          184         int i, tx, ty, th, len, olen, render = x || y || w || h;
          185         unsigned int texw, texh;
          186 
          187         if (!render) {
          188                 w = ~w;
          189         } else {
          190                 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
          191                 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
          192                 x += lpad;
          193                 w -= lpad;
          194         }
          195 
          196         olen = strlen(text);
          197         drw_font_getexts(drw->fonts, text, olen, &texw, &texh);
          198         th = drw->fonts->ascent + drw->fonts->descent;
          199         ty = y + (h / 2) - (th / 2) + drw->fonts->ascent;
          200         tx = x;
          201         /* shorten text if necessary */
          202         for (len = MIN(olen, sizeof buf); len && texw > w; len--)
          203                 drw_font_getexts(drw->fonts, text, len, &texw, &texh);
          204         if (!len)
          205                 return x;
          206         memcpy(buf, text, len);
          207         if (len < olen)
          208                 for (i = len; i && i > len - 3; buf[--i] = '.')
          209                         ;
          210         XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
          211         if (drw->fonts->set)
          212                 XmbDrawString(drw->dpy, drw->drawable, drw->fonts->set, drw->gc, tx, ty, buf, len);
          213         else
          214                 XDrawString(drw->dpy, drw->drawable, drw->gc, tx, ty, buf, len);
          215 
          216         x += texw;
          217         w -= texw;
          218 
          219         return x + (render ? w : 0);
          220 }
          221 
          222 void
          223 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
          224 {
          225         XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
          226         XSync(drw->dpy, False);
          227 }
          228 
          229 static unsigned int
          230 drw_font_getexts_width(Fnt *font, const char *text, unsigned int len)
          231 {
          232         unsigned int w;
          233 
          234         drw_font_getexts(font, text, len, &w, NULL);
          235 
          236         return w;
          237 }
          238 
          239 unsigned int
          240 drw_fontset_getwidth(Drw *drw, const char *text)
          241 {
          242         return drw_font_getexts_width(drw->fonts, text, strlen(text));
          243 }
          244 
          245 unsigned int
          246 drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
          247 {
          248         unsigned int tmp = 0;
          249         if (drw && drw->fonts && text && n)
          250                 tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
          251         return MIN(n, tmp);
          252 }
          253 
          254 void
          255 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
          256 {
          257         XRectangle r;
          258 
          259         if (font->set) {
          260                 XmbTextExtents(font->set, text, len, NULL, &r);
          261                 if (w)
          262                         *w = r.width;
          263                 if (h)
          264                         *h = r.height;
          265         } else {
          266                 if (w)
          267                         *w = XTextWidth(font->xfont, text, len);
          268                 if (h)
          269                         *h = font->ascent + font->descent;
          270         }
          271 }
          272 
          273 Cur *
          274 drw_cur_create(Drw *drw, int shape)
          275 {
          276         Cur *cur;
          277 
          278         cur = ecalloc(1, sizeof(Cur));
          279         cur->cursor = XCreateFontCursor(drw->dpy, shape);
          280 
          281         return cur;
          282 }
          283 
          284 void
          285 drw_cur_free(Drw *drw, Cur *cursor)
          286 {
          287         XFreeCursor(drw->dpy, cursor->cursor);
          288         free(cursor);
          289 }