Commit Diff


commit - 15f3a3a2f5fe4fb609bf560f1cd26ac8907a24c8
commit + 8917670ecee53ffd46e89f1ac22ffe9ecf5090e1
blob - cbfb9ef599eeff12bd160d287b1a825a53164915
blob + bededa2e85204ddaa587830d57929b26e88f6a40
--- Makefile
+++ Makefile
@@ -14,7 +14,7 @@ HDR_STEST	= ${HDR_DMENU}
 
 MAN		= dwm/dwm.1 st/st.1 dmenu/dmenu.1 dmenu/stest.1
 
-all: bin/dwm bin/st bin/bedstatus bin/dmenu bin/stest
+all: bin/dwm bin/st bin/bedstatus bin/dmenu bin/stest bin/xbgcd
 
 clean:
 	rm -rf bin
@@ -55,4 +55,8 @@ bin/stest: ${SRC_STEST} ${HDR_STEST}
 	@mkdir -p bin
 	${CC} -o $@ ${SRC_STEST} ${CFLAGS}
 
+bin/xbgcd: xbgcd/xbgcd.c
+	@mkdir -p bin
+	${CC} -o $@ xbgcd/xbgcd.c ${CFLAGS} `pkg-config --cflags --libs x11`
+
 .PHONY: all clean install
blob - 424ce83fa920781beb8cd499a0f309d9818bcf88
blob + b45a56b765d53dd6b0f39145b3f8774bf4e88fab
--- TODO
+++ TODO
@@ -1,7 +1,6 @@
 # Import
 - surf
 - tabbed
-- xbgcd
 - slock
 - nsxiv
 
blob - /dev/null
blob + 1b12b24364134eaa04e79f3b3384c3405190386d (mode 644)
--- /dev/null
+++ xbgcd/LICENSE
@@ -0,0 +1,22 @@
+MIT/X Consortium License
+
+© 2022 Benjamin Stürz <benni@stuerz.xyz>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
blob - /dev/null
blob + d9731410f1b432c39c46631480e57c66dcc3b0ca (mode 644)
--- /dev/null
+++ xbgcd/config.h
@@ -0,0 +1,16 @@
+
+// Define the color steps.
+static const struct MyColor steps[] = {
+	{ 1.0, 0.0, 0.0 },
+	{ 0.0, 1.0, 0.0 },
+	{ 0.0, 0.0, 1.0 },
+};
+
+// The initial background color.
+static const struct MyColor initial_color = { 0.5, 0.5, 0.5 };
+
+// Interpolation increent per substep.
+static const float sub_step_inc = 0.01f;
+
+// Delay (in milliseconds) between substeps.
+static const unsigned delay = 100;
blob - /dev/null
blob + d36d9c8c5fde5ad200f4e2a9f61d9ffa16ae67a9 (mode 644)
--- /dev/null
+++ xbgcd/xbgcd.c
@@ -0,0 +1,130 @@
+/* See LICENSE file for copyright and license details.
+ *
+ * X background color daemon is really simple. It just uses interpolation
+ * between steps to get the new background color. If the substep reaches 1.0f,
+ * it resets it, and starts the next step.
+ */
+#include <X11/Xlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+struct MyColor {
+	float r, g, b;
+};
+
+#include "config.h"
+
+const size_t num_steps = (sizeof steps) / (sizeof *steps);
+
+static Display *dpy;
+static int screen;
+static Window root;
+
+static unsigned long MyColorToPixel (const struct MyColor *color);
+static unsigned long NameToPixel (const char *color);
+static void FillBackground (const struct MyColor *color);
+static void die (const char *s);
+
+int
+main(int argc, char *argv[])
+{
+	if (argc == 2 && !strcmp (argv[1], "-v")) {
+		die ("xkbcd-" VERSION);
+	} else if (argc != 1) {
+		die ("usage: xbcd [-v]");
+	}
+
+	dpy = XOpenDisplay (NULL);
+	if (!dpy)
+		die ("xkbcd: unable to open display");
+
+#ifdef __OpenBSD__
+	if (pledge ("stdio", NULL) == -1)
+		die ("pledge");
+#endif // __OpenBSD__
+
+	screen = DefaultScreen (dpy);
+	root = RootWindow (dpy, screen);
+ 
+	size_t step = 0;
+	float sub_step = 0.0f;
+	struct MyColor prev = initial_color;
+
+	while (1) {
+		const struct MyColor cur = steps[step];
+		const struct MyColor c = {
+			.r = prev.r + (cur.r - prev.r) * sub_step,
+			.g = prev.g + (cur.g - prev.g) * sub_step,
+			.b = prev.b + (cur.b - prev.b) * sub_step,
+		};
+
+		FillBackground (&c);
+
+		sub_step += sub_step_inc;
+
+		if (sub_step > 1.0f) {
+			step = (step + 1) % num_steps;
+			prev = cur;
+			sub_step -= 1.0f;
+		}
+		usleep (delay * 1000);
+	}
+	XCloseDisplay (dpy);
+	return 0;
+}
+
+static unsigned long
+MyColorToPixel (const struct MyColor *color)
+{
+	char str[8];
+	const int r = (int)(color->r * 255.0f);
+	const int g = (int)(color->g * 255.0f);
+	const int b = (int)(color->b * 255.0f);
+
+	snprintf (str, sizeof str, "#%02X%02X%02X", r, g, b);
+
+	return NameToPixel (str);
+}
+
+// This function is taken from xsetroot: https://github.com/freedesktop/xorg-xsetroot/blob/master/xsetroot.c
+static unsigned long
+NameToPixel (const char *name)
+{
+	XColor ecolor;
+
+	if (!name || !*name)
+		return BlackPixel (dpy, screen);
+
+	Colormap colormap = DefaultColormap (dpy, screen);
+
+	if (!XParseColor (dpy, colormap, name, &ecolor)) {
+		fprintf (stderr, "xbgcd: unknown color '%s'\n", name);
+		return BlackPixel (dpy, screen);
+	}
+
+	if (!XAllocColor (dpy, colormap, &ecolor)) {
+		fprintf (stderr, "xbgcd: unable to allocate color for '%s'\n", name);
+		return BlackPixel (dpy, screen);
+	}
+
+	return ecolor.pixel;
+}
+
+static void
+FillBackground (const struct MyColor *color)
+{
+	unsigned long pixel = MyColorToPixel (color);
+	XSetWindowBackground (dpy, root, pixel);
+	XClearWindow (dpy, root);
+	XFlush (dpy);
+}
+
+static void
+die (const char *s)
+{
+	fprintf (stderr, "%s\n", s);
+	exit (1);
+}