/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #include "drw.h" #include "util.h" void cairo_set_source_hex(cairo_t* cr, const char *col, int alpha) { unsigned int hex; sscanf(col, "#%x", &hex); double r = ((hex >> 16) & 0xFF) / 255.0; double g = ((hex >> 8) & 0xFF) / 255.0; double b = (hex & 0xFF) / 255.0; cairo_set_source_rgba(cr, r, g, b, alpha / 255.0); } Drw * drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap) { Drw *drw = ecalloc(1, sizeof(Drw)); drw->dpy = dpy; drw->screen = screen; drw->root = root; drw->w = w; drw->h = h; drw->visual = visual; drw->depth = depth; drw->cmap = cmap; drw->drawable = XCreatePixmap(dpy, root, w, h, depth); drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL); XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); return drw; } void drw_resize(Drw *drw, unsigned int w, unsigned int h) { if (!drw) return; drw->w = w; drw->h = h; if (drw->drawable) XFreePixmap(drw->dpy, drw->drawable); drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth); } void drw_free(Drw *drw) { XFreePixmap(drw->dpy, drw->drawable); XFreeGC(drw->dpy, drw->gc); drw_font_free(drw->font); free(drw); } static Fnt * font_create(Drw *drw, const char *fontname) { Fnt *font; PangoFontMap *fontmap; PangoContext *context; PangoFontDescription *desc; PangoFontMetrics *metrics; if (!fontname) { die("dwm: no font specified."); } font = ecalloc(1, sizeof(Fnt)); font->dpy = drw->dpy; fontmap = pango_cairo_font_map_new(); context = pango_font_map_create_context(fontmap); desc = pango_font_description_from_string(fontname); font->layout = pango_layout_new(context); pango_layout_set_font_description(font->layout, desc); metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us")); font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE; pango_font_metrics_unref(metrics); g_object_unref(context); return font; } void font_free(Fnt *font) { if (!font) return; if (font->layout) g_object_unref(font->layout); free(font); } Fnt * drw_font_create(Drw* drw, char *font[], size_t fontcount) { if (!drw || !font) return NULL; Fnt *fnt = NULL; fnt = font_create(drw, *font); return (drw->font = fnt); } void drw_font_free(Fnt *font) { if (font) { font_free(font); } } void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert, char *fgcol, char *bgcol, int fgalpha, int bgalpha) { if (!drw) { return; } cairo_surface_t *sf; sf = cairo_xlib_surface_create(drw->dpy, drw->drawable, drw->visual, drw->w, drw->h); cairo_t *cr = cairo_create(sf); if (!cr) { die("failed to create cairo context"); } cairo_set_source_hex(cr, invert ? bgcol : fgcol, invert ? bgalpha : fgalpha); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); if (filled) { cairo_rectangle(cr, x, y, w, h); cairo_fill(cr); } else { cairo_rectangle(cr, x, y, w - 1, h - 1); cairo_stroke(cr); } cairo_destroy(cr); cairo_surface_destroy(sf); } int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup, char *fgcol, char *bgcol, int fgalpha, int bgalpha) { char buf[1024]; unsigned int ew = 0; size_t i, len; int render = x || y || w || h; char *t; if (!drw || !text || !drw->font) { return 0; } if (!render) { w = ~w; } else { x += lpad; w -= lpad; drw->surface = cairo_xlib_surface_create(drw->dpy, drw->drawable, drw->visual, drw->w, drw->h); drw->d = cairo_create(drw->surface); /* draw bg */ cairo_set_source_hex(drw->d, invert ? fgcol : bgcol, invert ? fgalpha : bgalpha); cairo_set_operator(drw->d, CAIRO_OPERATOR_SOURCE); cairo_rectangle(drw->d, x - lpad, y, w + lpad, h); cairo_fill(drw->d); } t = strdup(text); len = strlen(t); if (len) { drw_font_getexts(drw->font, t, len, &ew, NULL, markup); /* shorten text if necessary */ for (len = MIN(len, sizeof(buf) - 1); len && ew > w; drw_font_getexts(drw->font, t, len, &ew, NULL, markup)) len--; if (len) { memcpy(buf, t, len); buf[len] = '\0'; if (len < strlen(t)) for (i = len; i && i > len - 3; buf[--i] = '.') ; // NOP if (!strstr(buf, "font->layout, buf, len); } else { pango_layout_set_text(drw->font->layout, buf, len); } pango_layout_set_single_paragraph_mode(drw->font->layout, True); /* draw fg */ cairo_set_source_hex(drw->d, fgcol, fgalpha); cairo_move_to(drw->d, x, y + (h - drw->font->h) / 2); /* update and show layout */ pango_cairo_update_layout(drw->d, drw->font->layout); pango_cairo_show_layout(drw->d, drw->font->layout); cairo_set_operator(drw->d, CAIRO_OPERATOR_SOURCE); if (markup) /* clear markup attributes */ pango_layout_set_attributes(drw->font->layout, NULL); } x += ew; w -= ew; } } return x + (render ? w : 0); } void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) { if (!drw) return; XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); XSync(drw->dpy, False); } unsigned int drw_font_getwidth(Drw *drw, const char *text, Bool markup) { if (!drw || !drw->font || !text) return 0; return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup, "#000000", "#000000", 255, 255); } void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup) { if (!font || !text) return; char *t = strdup(text); if (!strstr(t, "layout, t, len); else pango_layout_set_text(font->layout, t, len); pango_layout_get_extents(font->layout, 0, &r); if (markup) /* clear markup attributes */ pango_layout_set_attributes(font->layout, NULL); if (w) *w = r.width / PANGO_SCALE; if (h) *h = font->h; } Cur * drw_cur_create(Drw *drw, int shape) { Cur *cur; if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) return NULL; cur->cursor = XCreateFontCursor(drw->dpy, shape); return cur; } void drw_cur_free(Drw *drw, Cur *cursor) { if (!cursor) return; XFreeCursor(drw->dpy, cursor->cursor); free(cursor); }