a small clock for X11 that displays time as pixels
1/* vim:ts=8
2 * $Id: pixelclock.c,v 1.2 2005/06/28 21:07:37 jcs Exp $
3 *
4 * pixelclock
5 * a different way of looking at time
6 *
7 * Copyright (c) 2005 joshua stein <jcs@jcs.org>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <err.h>
34#include <getopt.h>
35#include <signal.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <time.h>
40#include <unistd.h>
41#include <sys/types.h>
42
43#include <X11/Xlib.h>
44#include <X11/Xutil.h>
45
46/* default clock width */
47#define DEFWIDTH 3
48
49/* so our window manager knows us */
50char* win_name = "pixelclock";
51
52/* hours to highlight (start work, lunch, etc.) */
53int hihours[] = { 9, 12, 17 };
54
55struct xinfo {
56 Display* dpy;
57 int dpy_width, dpy_height;
58
59 int screen;
60
61 Window win;
62
63 int width;
64
65 GC gc;
66
67 Colormap win_colormap;
68} x;
69
70const struct option longopts[] = {
71 { "display", required_argument, NULL, 'd' },
72 { "width", required_argument, NULL, 'w' },
73
74 { NULL, 0, NULL, 0 }
75};
76
77extern char *__progname;
78
79long getcolor(const char *);
80void handler(int sig);
81void init_x(const char *);
82void usage(void);
83
84int
85main(int argc, char* argv[])
86{
87 char *display = NULL, *p;
88 int c, hi, y, z;
89 int hourtick, lastpos = -1, newpos = 0;
90 struct timeval tv[2];
91 time_t now;
92 struct tm *t;
93
94 bzero(&x, sizeof(struct xinfo));
95
96 x.width = DEFWIDTH;
97
98 while ((c = getopt_long_only(argc, argv, "", longopts, NULL)) != -1) {
99 switch (c) {
100 case 'd':
101 display = optarg;
102 break;
103
104 case 'w':
105 x.width = strtol(optarg, &p, 10);
106 if (*p || x.width < 1)
107 errx(1, "illegal value -- %s", optarg);
108 /* NOTREACHED */
109 break;
110
111 default:
112 usage();
113 /* NOTREACHED */
114 }
115 }
116
117 init_x(display);
118
119 signal(SIGINT, handler);
120 signal(SIGTERM, handler);
121
122 /* each hour will be this many pixels away */
123 hourtick = x.dpy_height / 24;
124
125 for (;;) {
126 if (gettimeofday(&tv[0], NULL))
127 errx(1, "gettimeofday");
128 /* NOTREACHED */
129
130 now = tv[0].tv_sec;
131 if ((t = localtime(&now)) == NULL)
132 errx(1, "localtime");
133 /* NOTREACHED */
134
135 newpos = (hourtick * t->tm_hour) +
136 (float)(((float)t->tm_min / 60.0) * hourtick) - 3;
137
138 if (newpos != lastpos) {
139 XClearWindow(x.dpy, x.win);
140
141 XSetForeground(x.dpy, x.gc, getcolor("yellow"));
142 XFillRectangle(x.dpy, x.win, x.gc,
143 0, newpos,
144 x.width, 6);
145
146 /* draw the hour marks */
147 for (y = 1; y <= 23; y++) {
148 hi = 0;
149 for (z = 0; z < sizeof(&hihours); z++)
150 if (y == hihours[z]) {
151 hi = 1;
152 break;
153 }
154
155 if (hi)
156 XSetForeground(x.dpy, x.gc,
157 getcolor("green"));
158 else
159 XSetForeground(x.dpy, x.gc,
160 getcolor("blue"));
161
162 XFillRectangle(x.dpy, x.win, x.gc,
163 0, (y * hourtick),
164 x.width, 2);
165 }
166
167 lastpos = newpos;
168
169 XFlush(x.dpy);
170 }
171
172 sleep(1);
173 }
174
175 exit(1);
176}
177
178void
179init_x(const char *display)
180{
181 int rc;
182 XGCValues values;
183 XTextProperty win_name_prop;
184
185 if (!(x.dpy = XOpenDisplay(display)))
186 errx(1, "Unable to open display %s", XDisplayName(display));
187 /* NOTREACHED */
188
189 x.screen = DefaultScreen(x.dpy);
190
191 x.dpy_width = DisplayWidth(x.dpy, x.screen);
192 x.dpy_height = DisplayHeight(x.dpy, x.screen);
193
194 x.win_colormap = DefaultColormap(x.dpy, DefaultScreen(x.dpy));
195
196 x.win = XCreateSimpleWindow(x.dpy, RootWindow(x.dpy, x.screen),
197 x.dpy_width - x.width, 0,
198 x.width, x.dpy_height,
199 0,
200 BlackPixel(x.dpy, x.screen),
201 BlackPixel(x.dpy, x.screen));
202
203 if (!(x.gc = XCreateGC(x.dpy, x.win, 0, &values)))
204 errx(1, "XCreateGC");
205 /* NOTREACHED */
206
207 if (!(rc = XStringListToTextProperty(&win_name, 1, &win_name_prop)))
208 errx(1, "XStringListToTextProperty");
209 /* NOTREACHED */
210
211 XSetWMName(x.dpy, x.win, &win_name_prop);
212
213 XMapWindow(x.dpy, x.win);
214
215 XFlush(x.dpy);
216 XSync(x.dpy, False);
217}
218
219long
220getcolor(const char *color)
221{
222 int rc;
223
224 XColor tcolor;
225
226 if (!(rc = XAllocNamedColor(x.dpy, x.win_colormap, color, &tcolor,
227 &tcolor)))
228 errx(1, "can't allocate %s", color);
229
230 return tcolor.pixel;
231}
232
233void
234handler(int sig)
235{
236 XCloseDisplay(x.dpy);
237
238 exit(0);
239 /* NOTREACHED */
240}
241
242void
243usage(void)
244{
245 fprintf(stderr, "usage: %s %s\n", __progname,
246 "[-display host:dpy] [-width]");
247 exit(1);
248}