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 }