Blob


1 /* See LICENSE file for copyright and license details.
2 *
3 * X background color daemon is really simple. It just uses interpolation
4 * between steps to get the new background color. If the substep reaches 1.0f,
5 * it resets it, and starts the next step.
6 */
7 #include <X11/Xlib.h>
8 #include <unistd.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
14 struct MyColor {
15 float r, g, b;
16 };
18 #include "config.h"
20 const size_t num_steps = (sizeof steps) / (sizeof *steps);
22 static Display *dpy;
23 static int screen;
24 static Window root;
26 static unsigned long MyColorToPixel (const struct MyColor *color);
27 static unsigned long NameToPixel (const char *color);
28 static void FillBackground (const struct MyColor *color);
29 static void die (const char *s);
31 int
32 main(int argc, char *argv[])
33 {
34 if (argc == 2 && !strcmp (argv[1], "-v")) {
35 die ("xkbcd-" VERSION);
36 } else if (argc != 1) {
37 die ("usage: xbcd [-v]");
38 }
40 dpy = XOpenDisplay (NULL);
41 if (!dpy)
42 die ("xkbcd: unable to open display");
44 #ifdef __OpenBSD__
45 if (pledge ("stdio", NULL) == -1)
46 die ("pledge");
47 #endif // __OpenBSD__
49 screen = DefaultScreen (dpy);
50 root = RootWindow (dpy, screen);
52 size_t step = 0;
53 float sub_step = 0.0f;
54 struct MyColor prev = initial_color;
56 while (1) {
57 const struct MyColor cur = steps[step];
58 const struct MyColor c = {
59 .r = prev.r + (cur.r - prev.r) * sub_step,
60 .g = prev.g + (cur.g - prev.g) * sub_step,
61 .b = prev.b + (cur.b - prev.b) * sub_step,
62 };
64 FillBackground (&c);
66 sub_step += sub_step_inc;
68 if (sub_step > 1.0f) {
69 step = (step + 1) % num_steps;
70 prev = cur;
71 sub_step -= 1.0f;
72 }
73 usleep (delay * 1000);
74 }
75 XCloseDisplay (dpy);
76 return 0;
77 }
79 static unsigned long
80 MyColorToPixel (const struct MyColor *color)
81 {
82 char str[8];
83 const int r = (int)(color->r * 255.0f);
84 const int g = (int)(color->g * 255.0f);
85 const int b = (int)(color->b * 255.0f);
87 snprintf (str, sizeof str, "#%02X%02X%02X", r, g, b);
89 return NameToPixel (str);
90 }
92 // This function is taken from xsetroot: https://github.com/freedesktop/xorg-xsetroot/blob/master/xsetroot.c
93 static unsigned long
94 NameToPixel (const char *name)
95 {
96 XColor ecolor;
98 if (!name || !*name)
99 return BlackPixel (dpy, screen);
101 Colormap colormap = DefaultColormap (dpy, screen);
103 if (!XParseColor (dpy, colormap, name, &ecolor)) {
104 fprintf (stderr, "xbgcd: unknown color '%s'\n", name);
105 return BlackPixel (dpy, screen);
108 if (!XAllocColor (dpy, colormap, &ecolor)) {
109 fprintf (stderr, "xbgcd: unable to allocate color for '%s'\n", name);
110 return BlackPixel (dpy, screen);
113 return ecolor.pixel;
116 static void
117 FillBackground (const struct MyColor *color)
119 unsigned long pixel = MyColorToPixel (color);
120 XSetWindowBackground (dpy, root, pixel);
121 XClearWindow (dpy, root);
122 XFlush (dpy);
125 static void
126 die (const char *s)
128 fprintf (stderr, "%s\n", s);
129 exit (1);