commit c8ee269e7344f7e1deeaa8c4ce1b4a16c6f5b26b
Author:     Maarten van Gompel <proy...@anaproy.nl>
AuthorDate: Sun Aug 2 15:46:12 2020 +0200
Commit:     Hiltjo Posthuma <hil...@codemadness.org>
CommitDate: Sun Aug 2 18:00:00 2020 +0200

    Added Xft support (in the same fashion as done in dmenu by Hiltjo 
Posthuma), Xinerama support, changed colors and key layout
    
    Signed-off-by: Miles Alan <m...@milesalan.com>

diff --git a/LICENSE b/LICENSE
index 51864d7..0ccc34f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,6 +2,7 @@ MIT/X Consortium License
 
 © 2011 Christoph Lohmann <2...@r-36.net>
 © 2008-2011 Enno Boland <g # s01 ' de>
+© 2020 Maarten van Gompel <proy...@anaproy.nl>
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
diff --git a/Makefile b/Makefile
index f719e1e..3e4f23e 100644
--- a/Makefile
+++ b/Makefile
@@ -3,12 +3,12 @@
 .POSIX:
 
 NAME = svkbd
-VERSION = 0.1
+VERSION = 0.2
 
 include config.mk
 
 BIN = ${NAME}-${LAYOUT}
-SRC = ${NAME}.c
+SRC = drw.c ${NAME}.c util.c
 OBJ = ${NAME}-${LAYOUT}.o
 MAN1 = ${NAME}.1
 
@@ -24,15 +24,8 @@ options:
 config.h:
        cp config.def.h $@
 
-${BIN}: config.h ${OBJ}
-
-${OBJ}: config.h
-
-${OBJ}:
-       ${CC} -o $@ -c ${SRC} ${SVKBD_CFLAGS} ${SVKBD_CPPFLAGS}
-
 ${BIN}:
-       ${CC} -o ${BIN} ${OBJ} ${SVKBD_LDFLAGS}
+       ${CC} -o $@ ${SRC} ${SVKBD_CFLAGS} ${SVKBD_CPPFLAGS} ${SVKBD_LDFLAGS}
 
 clean:
        rm -f ${NAME}-?? ${NAME}-??.o ${OBJ}
diff --git a/config.def.h b/config.def.h
index b332a8f..0d4172d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,9 +1,11 @@
 static const Bool wmborder = True;
-static const char font[] = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*";
-static const char normbgcolor[] = "#cccccc";
-static const char normfgcolor[] = "#000000";
-static const char pressbgcolor[] = "#0000cc";
-static const char pressfgcolor[] = "#ffffff";
-static const char highlightbgcolor[] = "#0000cc";
-static const char highlightfgcolor[] = "#ffffff";
-
+static int fontsize = 16;
+static const char *fonts[] = {
+       "monospace:size=16"
+};
+static const char *colors[SchemeLast][2] = {
+       /*     fg         bg       */
+       [SchemeNorm] = { "#58a7c6", "#14313d" },
+       [SchemePress] = { "#ffffff", "#005577" },
+       [SchemeHighlight] = { "#58a7c6", "#005577" },
+};
diff --git a/config.mk b/config.mk
index 507d1cb..f64c515 100644
--- a/config.mk
+++ b/config.mk
@@ -1,4 +1,4 @@
-LAYOUT = en
+LAYOUT = sxmo
 
 # paths
 PREFIX = /usr/local
@@ -7,11 +7,15 @@ MANPREFIX = ${PREFIX}/share/man
 X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
 
+# Xinerama, comment if you don't want it
+XINERAMALIBS = -L${X11LIB} -lXinerama
+XINERAMAFLAGS = -DXINERAMA
+
 # includes and libs
-INCS = -I. -I./layouts -I${X11INC}
-LIBS = -L${X11LIB} -lX11 -lXtst
+INCS = -I. -I./layouts -I${X11INC} -I/usr/include/freetype2
+LIBS = -L${X11LIB} -lX11 -lXtst -lfontconfig -lXft ${XINERAMALIBS}
 
 # use system flags
 SVKBD_CFLAGS = ${CFLAGS}
 SVKBD_LDFLAGS = ${LDFLAGS} ${LIBS}
-SVKBD_CPPFLAGS = ${CPPFLAGS} ${INCS} -DVERSION=\"VERSION\" 
-DLAYOUT=\"layout.${LAYOUT}.h\"
+SVKBD_CPPFLAGS = ${CPPFLAGS} ${INCS} -DVERSION=\"VERSION\" ${XINERAMAFLAGS} 
-DLAYOUT=\"layout.${LAYOUT}.h\"
diff --git a/drw.c b/drw.c
new file mode 100644
index 0000000..963cca7
--- /dev/null
+++ b/drw.c
@@ -0,0 +1,417 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+
+#include "drw.h"
+#include "util.h"
+
+#define UTF_INVALID 0xFFFD
+#define UTF_SIZ     4
+
+static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 
0xF0};
+static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 
0xF8};
+static const long utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  
0x10000};
+static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 
0x10FFFF};
+
+static long
+utf8decodebyte(const char c, size_t *i)
+{
+       for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
+               if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
+                       return (unsigned char)c & ~utfmask[*i];
+       return 0;
+}
+
+static size_t
+utf8validate(long *u, size_t i)
+{
+       if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
+               *u = UTF_INVALID;
+       for (i = 1; *u > utfmax[i]; ++i)
+               ;
+       return i;
+}
+
+static size_t
+utf8decode(const char *c, long *u, size_t clen)
+{
+       size_t i, j, len, type;
+       long udecoded;
+
+       *u = UTF_INVALID;
+       if (!clen)
+               return 0;
+       udecoded = utf8decodebyte(c[0], &len);
+       if (!BETWEEN(len, 1, UTF_SIZ))
+               return 1;
+       for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
+               udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
+               if (type)
+                       return j;
+       }
+       if (j < len)
+               return 0;
+       *u = udecoded;
+       utf8validate(u, len);
+
+       return len;
+}
+
+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_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, 
DefaultDepth(drw->dpy, drw->screen));
+}
+
+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 {
+               die("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))
+               die("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))))
+               die("error, cannot create color scheme (drw=%d) (clrcount=%d)", 
drw, clrcount);
+
+       for (i = 0; i < clrcount; i++)
+               drw_clr_create(drw, &ret[i], clrnames[i]);
+       return ret;
+}
+
+void
+drw_setfontset(Drw *drw, Fnt *set)
+{
+       if (drw)
+               drw->fonts = set;
+}
+
+void
+drw_setscheme(Drw *drw, Clr *scm)
+{
+       if (drw)
+               drw->scheme = scm;
+}
+
+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);
+}
+
+int
+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int 
lpad, const char *text, int invert)
+{
+       char buf[1024];
+       int ty;
+       unsigned int ew;
+       XftDraw *d = NULL;
+       Fnt *usedfont, *curfont, *nextfont;
+       size_t i, len;
+       int utf8strlen, utf8charlen, render = x || y || w || h;
+       long utf8codepoint = 0;
+       const char *utf8str;
+       FcCharSet *fccharset;
+       FcPattern *fcpattern;
+       FcPattern *match;
+       XftResult result;
+       int charexists = 0;
+
+       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,
+                                 DefaultVisual(drw->dpy, drw->screen),
+                                 DefaultColormap(drw->dpy, drw->screen));
+               x += lpad;
+               w -= lpad;
+       }
+
+       usedfont = drw->fonts;
+       while (1) {
+               utf8strlen = 0;
+               utf8str = text;
+               nextfont = NULL;
+               while (*text) {
+                       utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
+                       for (curfont = drw->fonts; curfont; curfont = 
curfont->next) {
+                               charexists = charexists || 
XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
+                               if (charexists) {
+                                       if (curfont == usedfont) {
+                                               utf8strlen += utf8charlen;
+                                               text += utf8charlen;
+                                       } else {
+                                               nextfont = curfont;
+                                       }
+                                       break;
+                               }
+                       }
+
+                       if (!charexists || nextfont)
+                               break;
+                       else
+                               charexists = 0;
+               }
+
+               if (utf8strlen) {
+                       drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, 
NULL);
+                       /* shorten text if necessary */
+                       for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew 
> w; len--)
+                               drw_font_getexts(usedfont, utf8str, len, &ew, 
NULL);
+
+                       if (len) {
+                               memcpy(buf, utf8str, len);
+                               buf[len] = '\0';
+                               if (len < utf8strlen)
+                                       for (i = len; i && i > len - 3; 
buf[--i] = '.')
+                                               ; /* NOP */
+
+                               if (render) {
+                                       ty = y + (h - usedfont->h) / 2 + 
usedfont->xfont->ascent;
+                                       XftDrawStringUtf8(d, 
&drw->scheme[invert ? ColBg : ColFg],
+                                                         usedfont->xfont, x, 
ty, (XftChar8 *)buf, len);
+                               }
+                               x += ew;
+                               w -= ew;
+                       }
+               }
+
+               if (!*text) {
+                       break;
+               } else if (nextfont) {
+                       charexists = 0;
+                       usedfont = nextfont;
+               } else {
+                       /* Regardless of whether or not a fallback font is 
found, the
+                        * character must be drawn. */
+                       charexists = 1;
+
+                       fccharset = FcCharSetCreate();
+                       FcCharSetAddChar(fccharset, utf8codepoint);
+
+                       if (!drw->fonts->pattern) {
+                               /* Refer to the comment in xfont_create for 
more information. */
+                               die("the first font in the cache must be loaded 
from a font string.");
+                       }
+
+                       fcpattern = FcPatternDuplicate(drw->fonts->pattern);
+                       FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
+                       FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
+                       FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
+
+                       FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
+                       FcDefaultSubstitute(fcpattern);
+                       match = XftFontMatch(drw->dpy, drw->screen, fcpattern, 
&result);
+
+                       FcCharSetDestroy(fccharset);
+                       FcPatternDestroy(fcpattern);
+
+                       if (match) {
+                               usedfont = xfont_create(drw, NULL, match);
+                               if (usedfont && XftCharExists(drw->dpy, 
usedfont->xfont, utf8codepoint)) {
+                                       for (curfont = drw->fonts; 
curfont->next; curfont = curfont->next)
+                                               ; /* NOP */
+                                       curfont->next = usedfont;
+                               } else {
+                                       xfont_free(usedfont);
+                                       usedfont = drw->fonts;
+                               }
+                       }
+               }
+       }
+       if (d)
+               XftDrawDestroy(d);
+
+       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);
+}
+
+void
+drw_sync(Drw *drw) {
+    XSync(drw->dpy, False);
+}
+
+unsigned int
+drw_fontset_getwidth(Drw *drw, const char *text)
+{
+       if (!drw || !drw->fonts || !text)
+               return 0;
+       return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
+}
+
+void
+drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int 
*w, unsigned int *h)
+{
+       XGlyphInfo ext;
+
+       if (!font || !text)
+               return;
+
+       XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
+       if (w)
+               *w = ext.xOff;
+       if (h)
+               *h = font->h;
+}
diff --git a/drw.h b/drw.h
new file mode 100644
index 0000000..50d9208
--- /dev/null
+++ b/drw.h
@@ -0,0 +1,51 @@
+/* See LICENSE file for copyright and license details. */
+
+typedef struct Fnt {
+       Display *dpy;
+       unsigned int h;
+       XftFont *xfont;
+       FcPattern *pattern;
+       struct Fnt *next;
+} Fnt;
+
+enum { ColFg, ColBg }; /* Clr scheme index */
+typedef XftColor Clr;
+
+typedef struct {
+       unsigned int w, h;
+       Display *dpy;
+       int screen;
+       Window root;
+       Drawable drawable;
+       GC gc;
+       Clr *scheme;
+       Fnt *fonts;
+} Drw;
+
+/* Drawable abstraction */
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned 
int h);
+void drw_resize(Drw *drw, unsigned int w, unsigned int h);
+void drw_free(Drw *drw);
+
+/* Fnt abstraction */
+Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
+void drw_fontset_free(Fnt* set);
+unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
+void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned 
int *w, unsigned int *h);
+
+/* Colorscheme abstraction */
+void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
+Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
+
+
+/* Drawing context manipulation */
+void drw_setfontset(Drw *drw, Fnt *set);
+void drw_setscheme(Drw *drw, Clr *scm);
+
+/* Drawing functions */
+void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int 
filled, int invert);
+int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned 
int lpad, const char *text, int invert);
+
+/* Map functions */
+void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int 
h);
+void drw_sync(Drw *drw);
diff --git a/layout.sxmo.h b/layout.sxmo.h
index 52ce781..1ee74bc 100644
--- a/layout.sxmo.h
+++ b/layout.sxmo.h
@@ -37,20 +37,20 @@ static Key keys_en[40] = {
         { 0, XK_m, 1 },
         /*{ "/?", XK_slash, 1 },*/
         { "Tab", XK_Tab, 1 },
-        { "<-", XK_BackSpace, 2 },
+        { "⇍ Bksp", XK_BackSpace, 2 },
 
         { 0 }, /* New row */
-        { "Layer 2", XK_Cancel, 1},
-        { "Shift", XK_Shift_L, 1 },
+        { "↺", XK_Cancel, 1},
+        { "Shft", XK_Shift_L, 1 },
         /*{ "L", XK_Left, 1 },*/
-        { "D", XK_Down, 1 },
-        { "U", XK_Up, 1 },
+        { "↓", XK_Down, 1 },
+        { "↑", XK_Up, 1 },
         /*{ "R", XK_Right, 1 },*/
         { "", XK_space, 2 },
         { "Esc", XK_Escape, 1 },
         { "Ctrl", XK_Control_L, 1 },
         /*{ "Alt", XK_Alt_L, 1 },*/
-        { "Enter", XK_Return, 2 },
+        { "↲ Enter", XK_Return, 2 },
 };
 
 static Key keys_symbols[40] = {
@@ -80,28 +80,28 @@ static Key keys_symbols[40] = {
 
   { 0 }, /* New row */
 
-  { " ", XK_Shift_L|XK_bar, 1 },
-  { " ", XK_Shift_L|XK_bar, 1 },
-  { "L", XK_Left, 1 },
-  { "R", XK_Right, 1 },
-  { " ", XK_Shift_L|XK_bar, 1 },
-  { " ", XK_Shift_L|XK_bar, 1 },
-  { " ", XK_Shift_L|XK_bar, 1 },
+  { "", XK_Shift_L|XK_bar, 1 },
+  { "⇤", XK_Home, 1 },
+  { "←", XK_Left, 1 },
+  { "→", XK_Right, 1 },
+  { "⇥", XK_End, 1 },
+  { "⇊", XK_Next, 1 },
+  { "⇈", XK_Prior, 1 },
   { "Tab", XK_Tab, 1 },
-  { "<-", XK_BackSpace, 2 },
+  { "⇍ Bksp", XK_BackSpace, 2 },
 
   { 0 }, /* New row */
-  { "Layer 1", XK_Cancel, 1},
-  { "Shift", XK_Shift_L, 1 },
+  { "↺", XK_Cancel, 1},
+  { "Shft", XK_Shift_L, 1 },
   /*{ "L", XK_Left, 1 },*/
-  { "D", XK_Down, 1 },
-  { "U", XK_Up, 1 },
+  { "↓", XK_Down, 1 },
+  { "↑", XK_Up, 1 },
   /*{ "R", XK_Right, 1 },*/
   { "", XK_space, 2 },
   { "Esc", XK_Escape, 1 },
   { "Ctrl", XK_Control_L, 1 },
   /*{ "Alt", XK_Alt_L, 1 },*/
-  { "Enter", XK_Return, 2 },
+  { "↲ Enter", XK_Return, 2 },
 };
 
 Buttonmod buttonmods[] = {
diff --git a/svkbd.c b/svkbd.c
index 7d93d78..e5319e1 100644
--- a/svkbd.c
+++ b/svkbd.c
@@ -13,38 +13,30 @@
 #include <X11/Xutil.h>
 #include <X11/Xproto.h>
 #include <X11/extensions/XTest.h>
+#include <X11/Xft/Xft.h>
+#ifdef XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
 #include <signal.h>
 #include <sys/select.h>
 
+#include "drw.h"
+#include "util.h"
+
+
 
 /* macros */
-#define MAX(a, b)       ((a) > (b) ? (a) : (b))
 #define LENGTH(x)       (sizeof x / sizeof x[0])
+#define TEXTW(X)        (drw_fontset_getwidth(drw, (X)))
 
 /* enums */
-enum { ColFG, ColBG, ColLast };
+enum { SchemeNorm, SchemePress, SchemeHighlight, SchemeLast };
 enum { NetWMWindowType, NetLast };
 
 /* typedefs */
 typedef unsigned int uint;
 typedef unsigned long ulong;
 
-typedef struct {
-       ulong norm[ColLast];
-       ulong press[ColLast];
-       ulong high[ColLast];
-
-       Drawable drawable;
-       GC gc;
-       struct {
-               int ascent;
-               int descent;
-               int height;
-               XFontSet set;
-               XFontStruct *xfont;
-       } font;
-} DC; /* draw context */
-
 typedef struct {
        char *label;
        KeySym keysym;
@@ -66,18 +58,15 @@ static void buttonrelease(XEvent *e);
 static void cleanup(void);
 static void configurenotify(XEvent *e);
 static void countrows();
-static void die(const char *errstr, ...);
 static void drawkeyboard(void);
 static void drawkey(Key *k);
 static void expose(XEvent *e);
 static Key *findkey(int x, int y);
-static ulong getcolor(const char *colstr);
-static void initfont(const char *fontstr);
 static void leavenotify(XEvent *e);
 static void press(Key *k, KeySym mod);
 static void run(void);
 static void setup(void);
-static int textnw(const char *text, uint len);
+static void togglelayer();
 static void unpress(Key *k, KeySym mod);
 static void updatekeys();
 
@@ -93,8 +82,9 @@ static void (*handler[LASTEvent]) (XEvent *) = {
 };
 static Atom netatom[NetLast];
 static Display *dpy;
-static DC dc;
+static Drw *drw;
 static Window root, win;
+static Clr* scheme[SchemeLast];
 static Bool running = True, isdock = False;
 static KeySym pressedmod = 0;
 static int rows = 0, ww = 0, wh = 0, wx = 0, wy = 0;
@@ -203,14 +193,12 @@ cleanup(void) {
                        XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, 
keys[i].keysym), False, 0);
                }
        }
-       XSync(dpy, False);
 
-       if(dc.font.set)
-               XFreeFontSet(dpy, dc.font.set);
-       else
-               XFreeFont(dpy, dc.font.xfont);
-       XFreePixmap(dpy, dc.drawable);
-       XFreeGC(dpy, dc.gc);
+       for (i = 0; i < SchemeLast; i++)
+               free(scheme[i]);
+       drw_free(drw);
+       drw_sync(drw);
+       XSync(dpy, False);
        XDestroyWindow(dpy, win);
        XSync(dpy, False);
        XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
@@ -223,9 +211,7 @@ configurenotify(XEvent *e) {
        if(ev->window == win && (ev->width != ww || ev->height != wh)) {
                ww = ev->width;
                wh = ev->height;
-               XFreePixmap(dpy, dc.drawable);
-               dc.drawable = XCreatePixmap(dpy, root, ww, wh,
-                               DefaultDepth(dpy, screen));
+               drw_resize(drw, ww, wh);
                updatekeys();
        }
 }
@@ -240,15 +226,6 @@ countrows() {
        }
 }
 
-void
-die(const char *errstr, ...) {
-       va_list ap;
-
-       va_start(ap, errstr);
-       vfprintf(stderr, errstr, ap);
-       va_end(ap);
-       exit(EXIT_FAILURE);
-}
 
 void
 drawkeyboard(void) {
@@ -262,42 +239,29 @@ drawkeyboard(void) {
 
 void
 drawkey(Key *k) {
-       int x, y, h, len;
-       XRectangle r = { k->x, k->y, k->w, k->h};
+       int x, y, w, h;
        const char *l;
-       ulong *col;
 
        if(k->pressed)
-               col = dc.press;
+               drw_setscheme(drw, scheme[SchemePress]);
        else if(k->highlighted)
-               col = dc.high;
+               drw_setscheme(drw, scheme[SchemeHighlight]);
        else
-               col = dc.norm;
-
-       XSetForeground(dpy, dc.gc, col[ColBG]);
-       XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
-       XSetForeground(dpy, dc.gc, dc.norm[ColFG]);
-       r.height -= 1;
-       r.width -= 1;
-       XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
-       XSetForeground(dpy, dc.gc, col[ColFG]);
+               drw_setscheme(drw, scheme[SchemeNorm]);
+       drw_rect(drw, k->x, k->y, k->w, k->h, 1, 1);
+       drw_rect(drw, k->x, k->y, k->w, k->h, 0, 0);
+
        if(k->label) {
                l = k->label;
        } else {
                l = XKeysymToString(k->keysym);
        }
-       len = strlen(l);
-       h = dc.font.ascent + dc.font.descent;
-       y = k->y + (k->h / 2) - (h / 2) + dc.font.ascent;
-       x = k->x + (k->w / 2) - (textnw(l, len) / 2);
-       if(dc.font.set) {
-               XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, l,
-                               len);
-       } else {
-               XDrawString(dpy, dc.drawable, dc.gc, x, y, l, len);
-       }
-       XCopyArea(dpy, dc.drawable, win, dc.gc, k->x, k->y, k->w, k->h,
-                       k->x, k->y);
+       h = fontsize * 2;
+       y = k->y + (k->h / 2) - (h / 2);
+       w = TEXTW(l);
+       x = k->x + (k->w / 2) - (w / 2);
+       drw_text(drw, x, y, w, h, 0, l, 0);
+       drw_map(drw, win, k->x, k->y, k->w, k->h);
 }
 
 void
@@ -322,52 +286,7 @@ findkey(int x, int y) {
        return NULL;
 }
 
-ulong
-getcolor(const char *colstr) {
-       Colormap cmap = DefaultColormap(dpy, screen);
-       XColor color;
 
-       if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
-               die("error, cannot allocate color '%s'\n", colstr);
-       return color.pixel;
-}
-
-void
-initfont(const char *fontstr) {
-       char *def, **missing;
-       int i, n;
-
-       missing = NULL;
-       if(dc.font.set)
-               XFreeFontSet(dpy, dc.font.set);
-       dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
-       if(missing) {
-               while(n--)
-                       fprintf(stderr, "svkbd: missing fontset: %s\n", 
missing[n]);
-               XFreeStringList(missing);
-       }
-       if(dc.font.set) {
-               XFontStruct **xfonts;
-               char **font_names;
-               dc.font.ascent = dc.font.descent = 0;
-               n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
-               for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) 
{
-                       dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
-                       dc.font.descent = 
MAX(dc.font.descent,(*xfonts)->descent);
-                       xfonts++;
-               }
-       } else {
-               if(dc.font.xfont)
-                       XFreeFont(dpy, dc.font.xfont);
-               dc.font.xfont = NULL;
-               if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
-               && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
-                       die("error, cannot load font: '%s'\n", fontstr);
-               dc.font.ascent = dc.font.xfont->ascent;
-               dc.font.descent = dc.font.xfont->descent;
-       }
-       dc.font.height = dc.font.ascent + dc.font.descent;
-}
 
 void
 leavenotify(XEvent *e) {
@@ -487,15 +406,36 @@ setup(void) {
        XSizeHints *sizeh = NULL;
        XClassHint *ch;
        Atom atype = -1;
-       int i, sh, sw;
+       int i, j, sh, sw;
        XWMHints *wmh;
 
+       #if XINERAMA
+       XineramaScreenInfo *info = NULL;
+       #endif
+
        /* init screen */
        screen = DefaultScreen(dpy);
        root = RootWindow(dpy, screen);
-       sw = DisplayWidth(dpy, screen);
-       sh = DisplayHeight(dpy, screen);
-       initfont(font);
+       #if XINERAMA
+       if(XineramaIsActive(dpy)) {
+               info = XineramaQueryScreens(dpy, &i);
+               sw = info[0].width;
+               sh = info[0].height;
+               XFree(info);
+       } else
+       #endif
+       {
+               sw = DisplayWidth(dpy, screen);
+               sh = DisplayHeight(dpy, screen);
+       }
+    drw = drw_create(dpy, screen, root, sw, sh);
+       if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
+               die("no fonts could be loaded.");
+    drw_setscheme(drw, scheme[SchemeNorm]);
+
+       /* init appearance */
+       for (j = 0; j < SchemeLast; j++)
+               scheme[j] = drw_scm_create(drw, colors[j], 2);
 
        /* init atoms */
        if(isdock) {
@@ -520,23 +460,12 @@ setup(void) {
        if(wy < 0)
                wy = sh + wy - wh;
 
-       dc.norm[ColBG] = getcolor(normbgcolor);
-       dc.norm[ColFG] = getcolor(normfgcolor);
-       dc.press[ColBG] = getcolor(pressbgcolor);
-       dc.press[ColFG] = getcolor(pressfgcolor);
-       dc.high[ColBG] = getcolor(highlightbgcolor);
-       dc.high[ColFG] = getcolor(highlightfgcolor);
-       dc.drawable = XCreatePixmap(dpy, root, ww, wh,
-                       DefaultDepth(dpy, screen));
-       dc.gc = XCreateGC(dpy, root, 0, 0);
-       if(!dc.font.set)
-               XSetFont(dpy, dc.gc, dc.font.xfont->fid);
        for(i = 0; i < LENGTH(keys); i++)
                keys[i].pressed = 0;
 
        wa.override_redirect = !wmborder;
-       wa.border_pixel = dc.norm[ColFG];
-       wa.background_pixel = dc.norm[ColBG];
+       wa.border_pixel = scheme[SchemeNorm][ColFg].pixel;
+       wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
        win = XCreateWindow(dpy, root, wx, wy, ww, wh, 0,
                            CopyFromParent, CopyFromParent, CopyFromParent,
                            CWOverrideRedirect | CWBorderPixel |
@@ -575,20 +504,11 @@ setup(void) {
        }
 
        XMapRaised(dpy, win);
+       drw_resize(drw, ww, wh);
        updatekeys();
        drawkeyboard();
 }
 
-int
-textnw(const char *text, uint len) {
-       XRectangle r;
-
-       if(dc.font.set) {
-               XmbTextExtents(dc.font.set, text, len, NULL, &r);
-               return r.width;
-       }
-       return XTextWidth(dc.font.xfont, text, len);
-}
 
 void
 updatekeys() {
@@ -642,7 +562,7 @@ main(int argc, char *argv[]) {
        signal(SIGTERM, sigterm);
        for (i = 1; argv[i]; i++) {
                if(!strcmp(argv[i], "-v")) {
-                       die("svkbd-"VERSION", © 2006-2016 svkbd engineers,"
+                       die("svkbd-"VERSION", © 2006-2020 svkbd engineers,"
                                       " see LICENSE for details\n");
                } else if(!strcmp(argv[i], "-d")) {
                        isdock = True;
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..fe044fc
--- /dev/null
+++ b/util.c
@@ -0,0 +1,35 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+void *
+ecalloc(size_t nmemb, size_t size)
+{
+       void *p;
+
+       if (!(p = calloc(nmemb, size)))
+               die("calloc:");
+       return p;
+}
+
+void
+die(const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+
+       if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+               fputc(' ', stderr);
+               perror(NULL);
+       } else {
+               fputc('\n', stderr);
+       }
+
+       exit(1);
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..f633b51
--- /dev/null
+++ b/util.h
@@ -0,0 +1,8 @@
+/* See LICENSE file for copyright and license details. */
+
+#define MAX(A, B)               ((A) > (B) ? (A) : (B))
+#define MIN(A, B)               ((A) < (B) ? (A) : (B))
+#define BETWEEN(X, A, B)        ((A) <= (X) && (X) <= (B))
+
+void die(const char *fmt, ...);
+void *ecalloc(size_t nmemb, size_t size);

Reply via email to