1 #include <math.h>
2 #include <time.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <X11/X.h>
6 #include <X11/Xlib.h>
7 #include <X11/Xutil.h>
8 #include <X11/extensions/shape.h>
9
10 #define DEFAULT_RADIUS 70
11
12 struct stuff {
13 Display *disp;
14 Pixmap bound, clip;
15 Pixmap hbound, hclip;
16 GC gc, cgc, copygc;
17 XFontStruct *font;
18 int x, y, orbit, radius, width;
19 Window window;
20 };
21
vector(int xo,int yo,double angle,double radius,int * x,int * y)22 void vector(int xo, int yo, double angle, double radius, int *x, int *y)
23 {
24 *x = (int) (xo + radius * cos(angle) + 0.5);
25 *y = (int) (yo - radius * sin(angle) + 0.5);
26 }
27
28
drawface(struct stuff * st)29 void drawface(struct stuff *st)
30 {
31 int h, radius, xo, yo, mg;
32 char buf[5];
33 XCharStruct cs;
34
35 xo = st->x / 2;
36 yo = st->y / 2;
37 mg = (st->font->ascent + st->font->descent) / 2;
38 h = XTextWidth(st->font, "3", 1) / 2;
39 mg = h > mg ? h : mg;
40 h = XTextWidth(st->font, "9", 1) / 2;
41 mg = h > mg ? h : mg;
42 radius = (st->x < st->y ? st->x : st->y) / 2 - mg - 1;
43 st->radius = radius;
44
45 XFillRectangle(st->disp, st->bound, st->cgc, 0, 0, st->x, st->y);
46 XFillRectangle(st->disp, st->clip, st->cgc, 0, 0, st->x, st->y);
47 for (h = 0; h < 12; ++h) {
48 double angle;
49 int x, y, i, j;
50
51 sprintf(buf, "%d", (14 - h) % 12 + 1);
52 angle = h * M_PI * 2.0 / 12.0;
53 vector(xo, yo, angle, (double) radius, &x, &y);
54 x -= XTextWidth(st->font, buf, strlen(buf)) / 2;
55 y += (st->font->ascent - st->font->descent) / 2;
56
57 for (i = -(st->orbit); i <= st->orbit; ++i) {
58 for (j = -(st->orbit); j <= st->orbit; ++j) {
59 XDrawString(st->disp, st->bound, st->gc, x + i, y + j,
60 buf, strlen(buf));
61 }
62 }
63 XDrawString(st->disp, st->clip, st->gc, x, y, buf, strlen(buf));
64 }
65 }
66
67
drawline(struct stuff * st,int x1,int y1,int x2,int y2,int width)68 void drawline(struct stuff *st, int x1, int y1, int x2, int y2, int width)
69 {
70 XSetLineAttributes(st->disp, st->gc, width + st->orbit * 2,
71 LineSolid, CapRound, JoinMiter);
72 XDrawLine(st->disp, st->hbound, st->gc, x1, y1, x2, y2);
73
74 XSetLineAttributes(st->disp, st->gc, width,
75 LineSolid, CapRound, JoinMiter);
76 XDrawLine(st->disp, st->hclip, st->gc, x1, y1, x2, y2);
77 }
78
79
drawhands(struct stuff * st)80 void drawhands(struct stuff *st)
81 {
82 double hangle, mangle;
83 time_t t;
84 struct tm *lt;
85 int m, dm, qdm, xo, yo, x, y;
86
87 dm = 60 * 12;
88 qdm = 60 * 3;
89
90 /* get time, figure hand positions */
91 time(&t);
92 lt = localtime(&t);
93
94 m = ((lt->tm_hour % 12) * 60 + lt->tm_min);
95 m = (dm - m + qdm - 1) % dm;
96 hangle = (double) m / dm * 2 * M_PI;
97
98 m = lt->tm_min;
99 m = (60 - m + 15 - 1) % 60;
100 mangle = (double) m / 60 * 2 * M_PI;
101
102 /* copy over face pixmaps */
103 XCopyArea(st->disp, st->bound, st->hbound, st->copygc,
104 0, 0, st->x, st->y, 0, 0);
105 XCopyArea(st->disp, st->clip, st->hclip, st->copygc,
106 0, 0, st->x, st->y, 0, 0);
107
108 /* draw hands */
109 xo = st->x / 2;
110 yo = st->y / 2;
111 vector(xo, yo, mangle, st->radius * .75, &x, &y);
112 drawline(st, xo, yo, x, y, st->width);
113
114 vector(xo, yo, hangle, st->radius * .5, &x, &y);
115 drawline(st, xo, yo, x, y, st->width * 2);
116
117 /* re-shape window */
118 XShapeCombineMask(st->disp, st->window, ShapeBounding, 0, 0, st->hbound,
119 ShapeSet);
120 XShapeCombineMask(st->disp, st->window, ShapeClip, 0, 0, st->hclip,
121 ShapeSet);
122 XSync(st->disp, True);
123 }
124
125
resizepm(struct stuff * st,Pixmap * p)126 void resizepm(struct stuff *st, Pixmap *p)
127 {
128 Display *d = st->disp;
129
130 if (*p != None)
131 XFreePixmap(d, *p);
132
133 *p = XCreatePixmap(d, RootWindow(d, DefaultScreen(d)), st->x, st->y, 1);
134 }
135
136
resize(struct stuff * st,int x,int y)137 void resize(struct stuff *st, int x, int y)
138 {
139 if (st->x == x && st->y == y)
140 return;
141
142 st->x = x;
143 st->y = y;
144
145 resizepm(st, &(st->bound));
146 resizepm(st, &(st->clip));
147 resizepm(st, &(st->hbound));
148 resizepm(st, &(st->hclip));
149
150 drawface(st);
151 drawhands(st);
152 }
153
basename(char * s)154 static char *basename(char *s)
155 {
156 char *t;
157
158 if (t = strrchr(s, '/'))
159 return ++t;
160
161 return s;
162 }
163
main(int argc,char ** argv)164 main(int argc, char **argv)
165 {
166 Display *disp;
167 XFontStruct *font;
168 int screen, orbit;
169 Window rw, w;
170 Pixmap sp;
171 GC gc, cgc, copygc;
172 struct stuff st;
173 XClassHint xch = { "lmclock", "Lmclock" };
174 int i, x, y, err;
175 int radius;
176 char *geom, *dstr;
177 XSizeHints xsh = {
178 PMinSize | PMaxSize | PResizeInc | PAspect | PBaseSize | PWinGravity,
179 0, 0, 0, 0,
180 0, 0, 0, 0, 0, 0,
181 {1, 1}, {1, 1},
182 0, 0,
183 NorthWestGravity
184 };
185
186 radius = DEFAULT_RADIUS;
187 xsh.min_width = xsh.min_height = xsh.max_width = xsh.max_height =
188 xsh.base_width = xsh.base_height = 2 * radius;
189 geom = 0;
190 dstr = 0;
191 orbit = 2;
192 err = 0;
193 for (i = 1; i < argc && '-' == argv[i][0]; ++i) {
194 if ('-' != argv[i][0])
195 break;
196
197 if (!strcmp(argv[i], "-") || !strcmp(argv[i], "--")) {
198 ++i;
199 break;
200 }
201
202 if (!strncmp(argv[i], "-display", 2)) {
203 ++i;
204 if (i >= argc) {
205 ++err;
206 break;
207 }
208
209 dstr = argv[i];
210 } else if (!strncmp(argv[i], "-geometry", 2)) {
211 ++i;
212 if (i >= argc) {
213 ++err;
214 break;
215 }
216
217 geom = argv[i];
218 }
219 }
220
221 if (err || i < argc) {
222 fprintf(stderr, "usage: %s [-display <display>] [-geometry <geometry>]\n",
223 argv[0] ? basename(argv[0]) : "lmclock");
224 exit(2);
225 }
226
227 disp = XOpenDisplay(dstr);
228 if (!disp) {
229 fprintf(stderr, "Cannot open display: %s\n", dstr ? dstr : "");
230 exit(1);
231 }
232 screen = DefaultScreen(disp);
233 rw = RootWindow(disp, screen);
234
235 x = y = 0;
236 if (geom) {
237 char pgeom[256];
238 int w, h, g;
239
240 sprintf(pgeom, "%dx%d", 2 * radius, 2 * radius);
241 XWMGeometry(disp, screen, geom, pgeom, 0, &xsh, &x, &y,
242 &w, &h, &g);
243 xsh.flags = USPosition;
244 }
245
246 /* open font */
247 font = XLoadQueryFont(disp, "-adobe-courier-*-r-*-*-18-*");
248
249 w = XCreateWindow(disp, rw, x, y, radius * 2, radius * 2, 0,
250 CopyFromParent, InputOutput, CopyFromParent,
251 0L, (XSetWindowAttributes *) 0);
252 XSetWindowBackground(disp, w, BlackPixel(disp, screen));
253 XSetWindowBorder(disp, w, WhitePixel(disp, screen));
254 XmbSetWMProperties(disp, w, "lmclock",
255 "lmclock", argv, argc, &xsh, NULL, &xch);
256 XMapWindow(disp, w);
257
258 /* create GCs */
259 sp = XCreatePixmap(disp, w, 1, 1, 1);
260
261 gc = XCreateGC(disp, sp, 0L, (XGCValues *) 0);
262 XSetFont(disp, gc, font->fid);
263 XSetLineAttributes(disp, gc, 5, LineSolid, CapRound, JoinMiter);
264 XSetFunction(disp, gc, GXset);
265
266 cgc = XCreateGC(disp, sp, 0L, (XGCValues *) 0);
267 XSetFunction(disp, cgc, GXclear);
268
269 copygc = XCreateGC(disp, sp, 0L, (XGCValues *) 0);
270 XSetFunction(disp, copygc, GXcopy);
271
272 XFreePixmap(disp, sp);
273
274 st.disp = disp;
275 st.bound = st.hbound = st.clip = st.hclip = None;
276 st.gc = gc;
277 st.cgc = cgc;
278 st.copygc = copygc;
279 st.font = font;
280 st.x = st.y = 0;
281 st.orbit = st.width = orbit;
282 st.window = w;
283
284 resize(&st, radius * 2, radius * 2);
285 for (;;) {
286 sleep(30);
287 drawhands(&st);
288 }
289 }
290