commit c8ee269e7344f7e1deeaa8c4ce1b4a16c6f5b26b
parent 915b95b03d33e960e477fbdbe9d108ffc90aaacf
Author: Maarten van Gompel <proycon@anaproy.nl>
Date: Sun, 2 Aug 2020 15:46:12 +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>
Diffstat:
M | LICENSE | | | 1 | + |
M | Makefile | | | 13 | +++---------- |
M | config.def.h | | | 18 | ++++++++++-------- |
M | config.mk | | | 12 | ++++++++---- |
A | drw.c | | | 417 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | drw.h | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | layout.sxmo.h | | | 38 | +++++++++++++++++++------------------- |
M | svkbd.c | | | 202 | ++++++++++++++++++++++++------------------------------------------------------- |
A | util.c | | | 35 | +++++++++++++++++++++++++++++++++++ |
A | util.h | | | 8 | ++++++++ |
10 files changed, 613 insertions(+), 182 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -2,6 +2,7 @@ MIT/X Consortium License
© 2011 Christoph Lohmann <20h@r-36.net>
© 2008-2011 Enno Boland <g # s01 ' de>
+© 2020 Maarten van Gompel <proycon@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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -13,16 +13,24 @@
#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 */
@@ -30,22 +38,6 @@ 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;
uint width;
@@ -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
@@ -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
@@ -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);