drw.c (6440B)
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 #include <pango/pango.h> 8 #include <pango/pangoxft.h> 9 10 #include "drw.h" 11 #include "util.h" 12 13 Drw * 14 drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) 15 { 16 Drw *drw = ecalloc(1, sizeof(Drw)); 17 18 drw->dpy = dpy; 19 drw->screen = screen; 20 drw->root = root; 21 drw->w = w; 22 drw->h = h; 23 drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); 24 drw->gc = XCreateGC(dpy, root, 0, NULL); 25 XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); 26 27 return drw; 28 } 29 30 void 31 drw_resize(Drw *drw, unsigned int w, unsigned int h) 32 { 33 if (!drw) 34 return; 35 36 drw->w = w; 37 drw->h = h; 38 if (drw->drawable) 39 XFreePixmap(drw->dpy, drw->drawable); 40 drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); 41 } 42 43 void 44 drw_free(Drw *drw) 45 { 46 XFreePixmap(drw->dpy, drw->drawable); 47 XFreeGC(drw->dpy, drw->gc); 48 drw_font_free(drw->font); 49 free(drw); 50 } 51 52 /* This function is an implementation detail. Library users should use 53 * drw_font_create instead. 54 */ 55 static Fnt * 56 xfont_create(Drw *drw, const char *fontname) 57 { 58 Fnt *font; 59 PangoFontMap *fontmap; 60 PangoContext *context; 61 PangoFontDescription *desc; 62 PangoFontMetrics *metrics; 63 64 if (!fontname) { 65 die("no font specified."); 66 } 67 68 font = ecalloc(1, sizeof(Fnt)); 69 font->dpy = drw->dpy; 70 71 fontmap = pango_xft_get_font_map(drw->dpy, drw->screen); 72 context = pango_font_map_create_context(fontmap); 73 desc = pango_font_description_from_string(fontname); 74 font->layout = pango_layout_new(context); 75 pango_layout_set_font_description(font->layout, desc); 76 77 metrics = pango_context_get_metrics(context, desc, NULL); 78 font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE; 79 80 pango_font_metrics_unref(metrics); 81 g_object_unref(context); 82 83 return font; 84 } 85 86 static void 87 xfont_free(Fnt *font) 88 { 89 if (!font) 90 return; 91 if (font->layout) 92 g_object_unref(font->layout); 93 free(font); 94 } 95 96 Fnt* 97 drw_font_create(Drw* drw, const char font[]) 98 { 99 Fnt *fnt = NULL; 100 101 if (!drw || !font) 102 return NULL; 103 104 fnt = xfont_create(drw, font); 105 106 return (drw->font = fnt); 107 } 108 109 void 110 drw_font_free(Fnt *font) 111 { 112 if (font) { 113 xfont_free(font); 114 } 115 } 116 117 void 118 drw_clr_create(Drw *drw, Clr *dest, const char *clrname) 119 { 120 if (!drw || !dest || !clrname) 121 return; 122 123 if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), 124 DefaultColormap(drw->dpy, drw->screen), 125 clrname, dest)) 126 die("error, cannot allocate color '%s'", clrname); 127 } 128 129 /* Wrapper to create color schemes. The caller has to call free(3) on the 130 * returned color scheme when done using it. */ 131 Clr * 132 drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) 133 { 134 size_t i; 135 Clr *ret; 136 137 /* need at least two colors for a scheme */ 138 if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) 139 return NULL; 140 141 for (i = 0; i < clrcount; i++) 142 drw_clr_create(drw, &ret[i], clrnames[i]); 143 return ret; 144 } 145 146 void 147 drw_setscheme(Drw *drw, Clr *scm) 148 { 149 if (drw) 150 drw->scheme = scm; 151 } 152 153 void 154 drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) 155 { 156 if (!drw || !drw->scheme) 157 return; 158 XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); 159 if (filled) 160 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); 161 else 162 XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); 163 } 164 165 int 166 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup) 167 { 168 char buf[1024]; 169 int ty, th; 170 unsigned int ew, eh; 171 XftDraw *d = NULL; 172 size_t i, len; 173 174 int render = x || y || w || h; 175 176 if (!drw || (render && !drw->scheme) || !text || !drw->font) 177 return 0; 178 179 if (!render) { 180 w = ~w; 181 } else { 182 XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); 183 XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); 184 d = XftDrawCreate(drw->dpy, drw->drawable, 185 DefaultVisual(drw->dpy, drw->screen), 186 DefaultColormap(drw->dpy, drw->screen)); 187 x += lpad; 188 w -= lpad; 189 } 190 191 len = strlen(text); 192 193 if (len) { 194 drw_font_getexts(drw->font, text, len, &ew, &eh, markup); 195 th = eh; 196 /* shorten text if necessary */ 197 for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) { 198 drw_font_getexts(drw->font, text, len, &ew, &eh, markup); 199 if (eh > th) 200 th = eh; 201 } 202 203 if (len) { 204 memcpy(buf, text, len); 205 buf[len] = '\0'; 206 if (len < strlen(text)) 207 for (i = len; i && i > len - 3; buf[--i] = '.') 208 ; /* NOP */ 209 210 if (render) { 211 ty = y + (h - th) / 2; 212 if(markup) 213 pango_layout_set_markup(drw->font->layout, buf, len); 214 else 215 pango_layout_set_text(drw->font->layout, buf, len); 216 pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg], 217 drw->font->layout, x * PANGO_SCALE, ty * PANGO_SCALE); 218 if(markup) /* clear markup attributes */ 219 pango_layout_set_attributes(drw->font->layout, NULL); 220 } 221 x += ew; 222 w -= ew; 223 } 224 } 225 226 if (d) 227 XftDrawDestroy(d); 228 229 return x + (render ? w : 0); 230 } 231 232 void 233 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) 234 { 235 if (!drw) 236 return; 237 238 XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); 239 XSync(drw->dpy, False); 240 } 241 242 unsigned int 243 drw_font_getwidth(Drw *drw, const char *text, Bool markup) 244 { 245 if (!drw || !drw->font || !text) 246 return 0; 247 return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup); 248 } 249 250 void 251 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup) 252 { 253 if (!font || !text) 254 return; 255 256 PangoRectangle r; 257 if(markup) 258 pango_layout_set_markup(font->layout, text, len); 259 else 260 pango_layout_set_text(font->layout, text, len); 261 pango_layout_get_extents(font->layout, 0, &r); 262 if(markup) /* clear markup attributes */ 263 pango_layout_set_attributes(font->layout, NULL); 264 if (w) 265 *w = r.width / PANGO_SCALE; 266 if (h) 267 *h = r.height / PANGO_SCALE; 268 } 269 270 Cur * 271 drw_cur_create(Drw *drw, int shape) 272 { 273 Cur *cur; 274 275 if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) 276 return NULL; 277 278 cur->cursor = XCreateFontCursor(drw->dpy, shape); 279 280 return cur; 281 } 282 283 void 284 drw_cur_free(Drw *drw, Cur *cursor) 285 { 286 if (!cursor) 287 return; 288 289 XFreeCursor(drw->dpy, cursor->cursor); 290 free(cursor); 291 }