dwm-speedie/drw.c

343 lines
7.3 KiB
C
Raw Normal View History

2023-07-02 01:39:07 +02:00
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
2023-09-13 10:57:58 +02:00
#include <X11/Xft/Xft.h>
2023-07-02 01:39:07 +02:00
#include "drw.h"
#include "util.h"
2023-09-13 10:57:58 +02:00
Clr transcheme[3];
2023-07-02 01:39:07 +02:00
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
{
2023-09-13 10:57:58 +02:00
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;
2023-07-02 01:39:07 +02:00
}
void
drw_resize(Drw *drw, unsigned int w, unsigned int h)
{
2023-09-13 10:57:58 +02:00
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);
2023-07-02 01:39:07 +02:00
}
void
drw_free(Drw *drw)
{
2023-09-13 10:57:58 +02:00
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
drw_fontset_free(drw->fonts);
free(drw);
2023-07-02 01:39:07 +02:00
}
2023-09-13 10:57:58 +02:00
/* This function is an implementation detail. Library users should use
* drw_font_create instead.
*/
2023-07-02 01:39:07 +02:00
static Fnt *
2023-09-13 10:57:58 +02:00
xfont_create(Drw *drw, const char *fontname)
{
Fnt *font;
PangoFontMap *fontmap;
PangoContext *context;
PangoFontDescription *desc;
PangoFontMetrics *metrics;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
if (!fontname) {
die("no font specified.");
}
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
font = ecalloc(1, sizeof(Fnt));
font->dpy = drw->dpy;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
fontmap = pango_xft_get_font_map(drw->dpy, drw->screen);
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);
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us"));
font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
pango_font_metrics_unref(metrics);
g_object_unref(context);
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
return font;
2023-07-02 01:39:07 +02:00
}
2023-09-13 10:57:58 +02:00
static void
xfont_free(Fnt *font)
2023-07-02 01:39:07 +02:00
{
2023-09-13 10:57:58 +02:00
if (!font)
return;
if (font->layout)
g_object_unref(font->layout);
free(font);
2023-07-02 01:39:07 +02:00
}
2023-09-13 10:57:58 +02:00
Fnt*
drw_font_create(Drw* drw, const char font[])
2023-07-02 01:39:07 +02:00
{
2023-09-13 10:57:58 +02:00
Fnt *fnt = NULL;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
if (!drw || !font)
return NULL;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
fnt = xfont_create(drw, font);
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
return (drw->fonts = fnt);
2023-07-02 01:39:07 +02:00
}
void
2023-09-13 10:57:58 +02:00
drw_fontset_free(Fnt *font)
2023-07-02 01:39:07 +02:00
{
2023-09-13 10:57:58 +02:00
if (font) {
xfont_free(font);
}
2023-07-02 01:39:07 +02:00
}
void
2023-09-13 10:57:58 +02:00
drw_clr_create(
Drw *drw,
Clr *dest,
const char *clrname
, unsigned int alpha
) {
if (!drw || !dest || !clrname)
return;
if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
clrname, dest))
die("error, cannot allocate color '%s'", clrname);
dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
}
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
/* 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,
char *clrnames[],
const unsigned int alphas[],
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], alphas[i]);
return ret;
}
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
void
drw_setscheme(Drw *drw, Clr *scm)
{
if (drw)
drw->scheme = scm;
}
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
void
drw_settrans(Drw *drw, Clr *psc, Clr *nsc)
{
if (drw) {
transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColBorder];
drw->scheme = transcheme;
}
}
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
{
if (!drw || !drw->scheme)
return;
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
if (filled)
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
else
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
2023-07-02 01:39:07 +02:00
}
int
2023-09-13 10:57:58 +02:00
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 buf[1024];
int ty;
unsigned int ew;
XftDraw *d = NULL;
size_t i, len;
int render = x || y || w || h;
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
return 0;
if (!render) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
x += lpad;
w -= lpad;
}
len = strlen(text);
if (len) {
drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup);
/* shorten text if necessary */
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--)
drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup);
if (len) {
memcpy(buf, text, len);
buf[len] = '\0';
if (len < strlen(text))
for (i = len; i && i > len - 3; buf[--i] = '.')
; /* NOP */
if (render) {
ty = y + (h - drw->fonts->h) / 2;
if (markup)
pango_layout_set_markup(drw->fonts->layout, buf, len);
else
pango_layout_set_text(drw->fonts->layout, buf, len);
pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg],
drw->fonts->layout, x * PANGO_SCALE, ty * PANGO_SCALE);
if (markup) /* clear markup attributes */
pango_layout_set_attributes(drw->fonts->layout, NULL);
}
x += ew;
w -= ew;
}
}
if (d)
XftDrawDestroy(d);
return x + (render ? w : 0);
}
void
drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash)
2023-07-02 01:39:07 +02:00
{
2023-09-13 10:57:58 +02:00
if (!drw || !drw->scheme)
return;
/* direction=1 draws right arrow */
x = direction ? x : x + w;
w = direction ? w : -w;
/* slash=1 draws slash instead of arrow */
unsigned int hh = slash ? (direction ? 0 : h) : h/2;
XPoint points[] = {
{x , y },
{x + w, y + hh },
{x , y + h },
};
XPoint bg[] = {
{x , y },
{x + w, y },
{x + w, y + h},
{x , y + h},
};
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin);
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel);
XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin);
2023-07-02 01:39:07 +02:00
}
void
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
{
2023-09-13 10:57:58 +02:00
if (!drw)
return;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
XSync(drw->dpy, False);
2023-07-02 01:39:07 +02:00
}
unsigned int
2023-09-13 10:57:58 +02:00
drw_fontset_getwidth(Drw *drw, const char *text, Bool markup)
2023-07-02 01:39:07 +02:00
{
2023-09-13 10:57:58 +02:00
if (!drw || !drw->fonts || !text)
return 0;
return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup);
2023-07-02 01:39:07 +02:00
}
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup)
{
2023-09-13 10:57:58 +02:00
if (!font || !text)
return;
PangoRectangle r;
if (markup)
pango_layout_set_markup(font->layout, text, len);
else
pango_layout_set_text(font->layout, text, 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;
2023-07-02 01:39:07 +02:00
}
Cur *
drw_cur_create(Drw *drw, int shape)
{
2023-09-13 10:57:58 +02:00
Cur *cur;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
return NULL;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
cur->cursor = XCreateFontCursor(drw->dpy, shape);
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
return cur;
2023-07-02 01:39:07 +02:00
}
void
drw_cur_free(Drw *drw, Cur *cursor)
{
2023-09-13 10:57:58 +02:00
if (!cursor)
return;
2023-07-02 01:39:07 +02:00
2023-09-13 10:57:58 +02:00
XFreeCursor(drw->dpy, cursor->cursor);
free(cursor);
2023-07-02 01:39:07 +02:00
}
2023-09-13 10:57:58 +02:00