187 lines
4.3 KiB
C
187 lines
4.3 KiB
C
#include "logger.h"
|
|
#include "util.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xft/Xft.h>
|
|
|
|
// TODO: Include necessary headers in this header.
|
|
#include "drw.h"
|
|
|
|
static void drw_fontset_free(Fnt* set);
|
|
static void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
|
|
|
|
Drw *
|
|
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
|
{
|
|
Drw *drw = ecalloc(1, sizeof(Drw));
|
|
|
|
drw->dpy = dpy;
|
|
drw->screen = screen;
|
|
drw->root = root;
|
|
drw->w = w;
|
|
drw->h = h;
|
|
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
|
|
drw->gc = XCreateGC(dpy, root, 0, NULL);
|
|
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
|
|
|
return drw;
|
|
}
|
|
|
|
void
|
|
drw_free(Drw *drw)
|
|
{
|
|
XFreePixmap(drw->dpy, drw->drawable);
|
|
XFreeGC(drw->dpy, drw->gc);
|
|
drw_fontset_free(drw->fonts);
|
|
free(drw);
|
|
}
|
|
|
|
/* This function is an implementation detail. Library users should use
|
|
* drw_fontset_create instead.
|
|
*/
|
|
static Fnt *
|
|
xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
|
{
|
|
Fnt *font;
|
|
XftFont *xfont = NULL;
|
|
FcPattern *pattern = NULL;
|
|
|
|
if (fontname) {
|
|
/* Using the pattern found at font->xfont->pattern does not yield the
|
|
* same substitution results as using the pattern returned by
|
|
* FcNameParse; using the latter results in the desired fallback
|
|
* behaviour whereas the former just results in missing-character
|
|
* rectangles being drawn, at least with some fonts. */
|
|
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
|
|
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
|
|
return NULL;
|
|
}
|
|
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
|
|
fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
|
|
XftFontClose(drw->dpy, xfont);
|
|
return NULL;
|
|
}
|
|
} else if (fontpattern) {
|
|
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
|
|
fprintf(stderr, "error, cannot load font from pattern.\n");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
fatal("no font specified.");
|
|
}
|
|
|
|
/* Do not allow using color fonts. This is a workaround for a BadLength
|
|
* error from Xft with color glyphs. Modelled on the Xterm workaround. See
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1498269
|
|
* https://lists.suckless.org/dev/1701/30932.html
|
|
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
|
|
* and lots more all over the internet.
|
|
*/
|
|
FcBool iscol;
|
|
if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
|
|
XftFontClose(drw->dpy, xfont);
|
|
return NULL;
|
|
}
|
|
|
|
font = ecalloc(1, sizeof(Fnt));
|
|
font->xfont = xfont;
|
|
font->pattern = pattern;
|
|
font->h = xfont->ascent + xfont->descent;
|
|
font->dpy = drw->dpy;
|
|
|
|
return font;
|
|
}
|
|
|
|
static void
|
|
xfont_free(Fnt *font)
|
|
{
|
|
if (!font)
|
|
return;
|
|
if (font->pattern)
|
|
FcPatternDestroy(font->pattern);
|
|
XftFontClose(font->dpy, font->xfont);
|
|
free(font);
|
|
}
|
|
|
|
Fnt*
|
|
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
|
|
{
|
|
Fnt *cur, *ret = NULL;
|
|
size_t i;
|
|
|
|
if (!drw || !fonts)
|
|
return NULL;
|
|
|
|
for (i = 1; i <= fontcount; i++) {
|
|
if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
|
|
cur->next = ret;
|
|
ret = cur;
|
|
}
|
|
}
|
|
return (drw->fonts = ret);
|
|
}
|
|
|
|
void
|
|
drw_fontset_free(Fnt *font)
|
|
{
|
|
if (font) {
|
|
drw_fontset_free(font->next);
|
|
xfont_free(font);
|
|
}
|
|
}
|
|
|
|
void
|
|
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
|
{
|
|
if (!drw || !dest || !clrname)
|
|
return;
|
|
|
|
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
|
DefaultColormap(drw->dpy, drw->screen),
|
|
clrname, dest))
|
|
fatal("error, cannot allocate color '%s'", clrname);
|
|
}
|
|
|
|
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
|
* returned color scheme when done using it. */
|
|
Clr *
|
|
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
|
{
|
|
size_t i;
|
|
Clr *ret;
|
|
|
|
/* need at least two colors for a scheme */
|
|
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
|
|
return NULL;
|
|
|
|
for (i = 0; i < clrcount; i++)
|
|
drw_clr_create(drw, &ret[i], clrnames[i]);
|
|
return ret;
|
|
}
|
|
|
|
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);
|
|
}
|