1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <X11/Xlib.h>
6 #include <X11/xpm.h>
7 #include <X11/extensions/shape.h>
8 #include <time.h>
9 #include <X11/Xatom.h>
10
11 #include "tztime.h"
12
13 #include "clk.xpm"
14 #include "led.xpm"
15 #include "month.xpm"
16 #include "date.xpm"
17 #include "weekday.xpm"
18 #include "xpm/mask.xbm"
19 #include "xpm/mask.xpm"
20
21 int SHOWAMPM=0; /* default value is 24h format */
22 int ONLYSHAPE=0; /* default value is noshape */
23 int ITBLINKS=1; /* default is blinking */
24 int ICONIFIED=0; /* default is not iconified */
25 /* led positions *************************************************************/
26 int twelve[5] = {5, 14, 24, 28, 37};
27 int twfour[5] = {4, 8, 17, 22, 31};
28 /* with shape */
29 int ws_posx[11] = {0,0,0,0,0,40, 17, 17, 22, 27, 15};
30 int ws_posy[4] = {3, 21, 30, 45};
31
32 /* no shape */
33 int ns_posx[11] = {5,5,5,5,5,45, 21, 21, 26, 31, 19};
34 int ns_posy[4] = {7, 25, 34, 49};
35
36 int posx[11];
37 int posy[4];
38
39 /* X11 Variablen *************************************************************/
40 Display *dpy; /* welches DISPLAY */
41 Window Root; /* Hintergrund-Drawable */
42 int screen;
43 int x_fd;
44 int d_depth;
45 XSizeHints mysizehints;
46 XWMHints mywmhints;
47 Pixel back_pix, fore_pix;
48 GC NormalGC;
49 Window iconwin, win; /* My home is my window */
50 char *ProgName;
51 char *Geometry;
52 char *LedColor = "LightSeaGreen";
53 char Execute[] = "echo no program has been specified >/dev/console";
54 char *ERR_colorcells = "not enough free color cells\n";
55 char *ampers = " &";
56 /* XPM Variablen *************************************************************/
57 typedef struct _XpmIcon {
58 Pixmap pixmap;
59 Pixmap mask;
60 XpmAttributes attributes;
61 } XpmIcon;
62
63 XpmIcon asclock, led, month, date, weekday;
64 XpmIcon visible;
65 time_t actualtime;
66 long actualmin;
67 struct tm* (*timefunc)(const time_t*);
68
69 /* lokale Funktionen *********************************************************/
70 #define MW_EVENTS (ExposureMask | ButtonPressMask | StructureNotifyMask)
71 #define FALSE 0
72 void GetXPM(void);
73 Pixel GetColor(char *name);
74 void RedrawWindow( XpmIcon *v);
75 void InsertTime();
76 /*****************************************************************************/
77 /*****************************************************************************/
78 static char *help_message[] = {
79 "where options include:",
80 " -12 12 hour format",
81 " -24 24 hour format",
82 " -exe <program> program to start on click",
83 " -led <color> color of the led",
84 " -position [+|-]x[+|-]y position of asclock",
85 " -shape without groundplate",
86 " -noblink don't blink",
87 " -iconic start up as icon",
88 " -timezone <zone> use the specified timezone",
89 NULL
90 };
91
usage()92 void usage()
93 {
94 char **cpp;
95
96 fprintf(stderr,"usage: %s [-options ...] \n", ProgName);
97 for (cpp = help_message; *cpp; cpp++) {
98 fprintf(stderr, "%s\n", *cpp);
99 }
100 fprintf(stderr,"\n");
101 exit(1);
102 }
103
main(int argc,char * argv[])104 int main(int argc,char *argv[])
105 {
106 int i;
107 unsigned int borderwidth ;
108 char *display_name = NULL;
109 char *wname = "astzclock";
110 XGCValues gcv;
111 unsigned long gcm;
112 XEvent Event;
113 XTextProperty name;
114 XClassHint classHint;
115 Pixmap pixmask;
116 ProgName = argv[0];
117 Geometry = "";
118 timefunc = &localtime;
119
120 /* Parse command line options */
121 ProgName = argv[0];
122
123 for(i=1;i<argc;i++) {
124 char *arg= argv[i];
125
126 if (arg[0] == '-') {
127 switch(arg[1]) {
128 case '1':
129 SHOWAMPM=1;
130 continue;
131 case '2':
132 SHOWAMPM=0;
133 continue;
134 case 'e':
135 if(++i >=argc) usage();
136 strcpy(&Execute[0], argv[i]);
137 strcat(&Execute[0], " &");
138 continue;
139 case 's':
140 ONLYSHAPE=1;
141 continue;
142 case 'p':
143 if(++i >=argc) usage();
144 Geometry = argv[i];
145 continue;
146 case 'i':
147 ICONIFIED=1;
148 continue;
149 case 'l':
150 if(++i >=argc) usage();
151 LedColor = argv[i];
152 continue;
153 case 'n':
154 ITBLINKS = 0;
155 continue;
156 case 't':
157 if(++i >=argc) usage();
158 settz(argv[i]);
159 timefunc = &tztime;
160 continue;
161 default:
162 usage();
163 }
164 }
165 }
166 /* init led position */
167 for(i=0;i<4;i++)
168 posy[i] = ONLYSHAPE ? ws_posy[i] : ns_posy[i];
169 for(i=0;i<11;i++)
170 posx[i] = ONLYSHAPE ? ws_posx[i] : ns_posx[i];
171 for(i=0;i<5;i++)
172 posx[i] += SHOWAMPM ? twfour[i] : twelve[i];
173
174 /* Open the display */
175 if (!(dpy = XOpenDisplay(display_name)))
176 {
177 fprintf(stderr,"asclock: can't open display %s\n",
178 XDisplayName(display_name));
179 exit (1);
180 }
181 screen= DefaultScreen(dpy);
182 Root = RootWindow(dpy, screen);
183 d_depth = DefaultDepth(dpy, screen);
184 x_fd = XConnectionNumber(dpy);
185
186 /* Icon Daten nach XImage konvertieren */
187 GetXPM();
188
189 /* Create a window to hold the banner */
190 mysizehints.flags= USSize|USPosition;
191 mysizehints.x = 0;
192 mysizehints.y = 0;
193
194 back_pix = GetColor("white");
195 fore_pix = GetColor("black");
196
197 XWMGeometry(dpy, screen, Geometry, NULL, (borderwidth =1), &mysizehints,
198 &mysizehints.x,&mysizehints.y,&mysizehints.width,&mysizehints.height, &i);
199
200 mysizehints.width = asclock.attributes.width;
201 mysizehints.height= asclock.attributes.height;
202
203 win = XCreateSimpleWindow(dpy,Root,mysizehints.x,mysizehints.y,
204 mysizehints.width,mysizehints.height,
205 borderwidth,fore_pix,back_pix);
206 iconwin = XCreateSimpleWindow(dpy,win,mysizehints.x,mysizehints.y,
207 mysizehints.width,mysizehints.height,
208 borderwidth,fore_pix,back_pix);
209
210
211
212 /* Hints aktivieren */
213 XSetWMNormalHints(dpy, win, &mysizehints);
214 classHint.res_name = "asclock";
215 classHint.res_class = " ASClock";
216 XSetClassHint(dpy, win, &classHint);
217
218 XSelectInput(dpy,win,MW_EVENTS);
219 XSelectInput(dpy,iconwin,MW_EVENTS);
220
221 if (XStringListToTextProperty(&wname, 1, &name) ==0) {
222 fprintf(stderr, "asclock: can't allocate window name\n");
223 exit(-1);
224 }
225 XSetWMName(dpy, win, &name);
226
227 /* Create a GC for drawing */
228 gcm = GCForeground|GCBackground|GCGraphicsExposures;
229 gcv.foreground = fore_pix;
230 gcv.background = back_pix;
231 gcv.graphics_exposures = FALSE;
232 NormalGC = XCreateGC(dpy, Root, gcm, &gcv);
233
234 if (ONLYSHAPE) { /* try to make shaped window here */
235 pixmask = XCreateBitmapFromData(dpy, win, mask_bits, mask_width,
236 mask_height);
237 XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
238 XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
239 }
240
241 mywmhints.initial_state = (ICONIFIED ? IconicState : NormalState);
242 mywmhints.icon_window = iconwin;
243 mywmhints.icon_x = mysizehints.x;
244 mywmhints.icon_y = mysizehints.y;
245 mywmhints.flags = StateHint | IconWindowHint | IconPositionHint;
246 XSetWMHints(dpy, win, &mywmhints);
247
248 XMapWindow(dpy,win);
249
250 InsertTime();
251 RedrawWindow(&visible);
252 while(1)
253 {
254 if (actualtime != time(0))
255 {
256 actualtime = time(0);
257 if(actualmin != actualtime / 60)
258 {
259 InsertTime();
260 }
261 if (ITBLINKS)
262 if (actualtime % 2)
263 {
264 /* Sekunden Doppelpunkt ein */
265 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
266 90,0,3,11,posx[2], posy[0]);
267 }
268 else
269 {
270 /* Sekunden Doppelpunkt aus */
271 XCopyArea(dpy, asclock.pixmap, visible.pixmap, NormalGC,
272 27,6,3,11,posx[2], posy[0]);
273 }
274
275 RedrawWindow(&visible);
276
277 }
278
279 /* read a packet */
280 while (XPending(dpy))
281 {
282 XNextEvent(dpy,&Event);
283 switch(Event.type)
284 {
285 case Expose:
286 if(Event.xexpose.count == 0 )
287 RedrawWindow(&visible);
288 break;
289 case ButtonPress:
290 system(Execute);
291 break;
292 case DestroyNotify:
293 XFreeGC(dpy, NormalGC);
294 XDestroyWindow(dpy, win);
295 XDestroyWindow(dpy, iconwin);
296 XCloseDisplay(dpy);
297 exit(0);
298 default:
299 break;
300 }
301 }
302 XFlush(dpy);
303 #ifdef SYSV
304 poll((struct poll *) 0, (size_t) 0, 50);
305 #else
306 usleep(50000L); /* 5/100 sec */
307 #endif
308 }
309 return 0;
310 }
311 /****************************************************************************/
nocolor(char * a,char * b)312 void nocolor(char *a, char *b)
313 {
314 fprintf(stderr,"asclock: can't %s %s\n", a,b);
315 }
316 /****************************************************************************/
317 /* Konvertiere XPMIcons nach XImage */
GetXPM(void)318 void GetXPM(void)
319 {
320 static char **clock_xpm;
321 XColor col;
322 XWindowAttributes attributes;
323 char led1[64];
324 char led2[64];
325 int ret;
326
327 clock_xpm =ONLYSHAPE ? mask_xpm : clk_xpm;
328
329 /* for the colormap */
330 XGetWindowAttributes(dpy,Root,&attributes);
331
332 /* get user-defined color */
333 if (!XParseColor (dpy, attributes.colormap, LedColor, &col))
334 {
335 nocolor("parse",LedColor);
336 }
337
338 sprintf(led1, ". c #%04X%04X%04X", col.red, col.green, col.blue);
339 led_xpm[2] = led1;
340
341 col.red = (col.red /10) *3;
342 col.green = (col.green/10) *3;
343 col.blue = (col.blue /10) *3;
344 sprintf(led2, "X c #%04X%04X%04X", col.red, col.green, col.blue);
345 led_xpm[3] = led2;
346
347 asclock.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
348 ret = XpmCreatePixmapFromData(dpy, Root, clock_xpm, &asclock.pixmap,
349 &asclock.mask, &asclock.attributes);
350 if(ret != XpmSuccess)
351 {fprintf(stderr, "1: %s\n", XpmGetErrorString(ret));exit(1);}
352 visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
353 ret = XpmCreatePixmapFromData(dpy, Root, clk_xpm, &visible.pixmap,
354 &visible.mask, &visible.attributes);
355 if(ret != XpmSuccess)
356 {fprintf(stderr, "2: %s\n", XpmGetErrorString(ret));exit(1);}
357
358 led.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
359 ret = XpmCreatePixmapFromData(dpy, Root, led_xpm, &led.pixmap,
360 &led.mask, &led.attributes);
361 if(ret != XpmSuccess)
362 {fprintf(stderr, "3: %s\n", XpmGetErrorString(ret));exit(1);}
363
364 month.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
365 ret = XpmCreatePixmapFromData(dpy, Root, month_xpm, &month.pixmap,
366 &month.mask, &month.attributes);
367 if(ret != XpmSuccess)
368 {fprintf(stderr, "4: %s\n", XpmGetErrorString(ret));exit(1);}
369
370 date.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
371 ret = XpmCreatePixmapFromData(dpy, Root, date_xpm, &date.pixmap,
372 &date.mask, &date.attributes);
373 if(ret != XpmSuccess)
374 {fprintf(stderr, "5: %s\n", XpmGetErrorString(ret));exit(1);}
375
376 weekday.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
377 ret = XpmCreatePixmapFromData(dpy, Root, weekday_xpm, &weekday.pixmap,
378 &weekday.mask, &weekday.attributes);
379 if(ret != XpmSuccess)
380 {fprintf(stderr, "6: %s\n", XpmGetErrorString(ret));exit(1);}
381 }
382 /****************************************************************************/
383 /* Removes expose events for a specific window from the queue */
flush_expose(Window w)384 int flush_expose (Window w)
385 {
386 XEvent dummy;
387 int i=0;
388
389 while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy))i++;
390 return i;
391 }
392
393 /****************************************************************************/
394 /* Draws the icon window */
RedrawWindow(XpmIcon * v)395 void RedrawWindow( XpmIcon *v)
396 {
397 flush_expose (iconwin);
398 XCopyArea(dpy,v->pixmap,iconwin,NormalGC,
399 0,0,v->attributes.width, v->attributes.height,0,0);
400 flush_expose (win);
401 XCopyArea(dpy,v->pixmap,win,NormalGC,
402 0,0,v->attributes.width, v->attributes.height,0,0);
403
404 }
405 /****************************************************************************/
GetColor(char * name)406 Pixel GetColor(char *name)
407 {
408 XColor color;
409 XWindowAttributes attributes;
410
411 XGetWindowAttributes(dpy,Root,&attributes);
412 color.pixel = 0;
413 if (!XParseColor (dpy, attributes.colormap, name, &color))
414 {
415 nocolor("parse",name);
416 }
417 else if(!XAllocColor (dpy, attributes.colormap, &color))
418 {
419 nocolor("alloc",name);
420 }
421 return color.pixel;
422 }
423 /****************************************************************************/
424 static struct tm *clk;
425
Twelve()426 void Twelve()
427 {
428 int thishour;
429 /* Stunde ohne am/pm */
430 thishour = clk->tm_hour % 12;
431 if (thishour == 0 )
432 thishour = 12;
433
434 if (clk->tm_hour >= 12)
435 {
436 /* PM */
437 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
438 107,5,11,6,posx[5],posy[0]+5);
439 }
440 else
441 /* AM */
442 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
443 94,5,12,6,posx[5],posy[0]+5);
444
445 if (thishour>9)
446 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
447 13,0,5,11,posx[0], posy[0]);
448
449 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
450 9*(thishour % 10),0,9,11,posx[1], posy[0]);
451
452 /* Minute, drawn first, so am/pm won't be overwritten */
453 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
454 9*(clk->tm_min / 10),0,9,11,posx[3],posy[0]);
455 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
456 9*(clk->tm_min % 10),0,9,11,posx[4],posy[0]);
457
458
459 }
460
TwentyFour()461 void TwentyFour()
462 {
463 /* Stunde ohne am/pm */
464 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
465 9*(clk->tm_hour / 10),0,9,11,posx[0],posy[0]);
466 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
467 9*(clk->tm_hour % 10),0,9,11,posx[1], posy[0]);
468
469 /* Minute */
470 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
471 9*(clk->tm_min / 10),0,9,11,posx[3],posy[0]);
472 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
473 9*(clk->tm_min % 10),0,9,11,posx[4],posy[0]);
474
475 }
476 /****************************************************************************/
InsertTime()477 void InsertTime()
478 {
479 /* Zeit auslesen */
480 actualtime = time(0);
481 actualmin = actualtime / 60;
482
483 clk = (*timefunc)(&actualtime);
484
485 /* leere asclock holen */
486 XCopyArea(dpy, asclock.pixmap, visible.pixmap, NormalGC,
487 0,0,mysizehints.width,mysizehints.height,0,0);
488
489 if (SHOWAMPM)
490 {
491 Twelve();
492 }
493 else
494 TwentyFour();
495
496 /* Monat */
497 XCopyArea(dpy, month.pixmap, visible.pixmap, NormalGC,
498 0,6*(clk->tm_mon ),22,6,posx[10],posy[3]);
499
500 /* Datum */
501 if (clk->tm_mday>9)
502 {
503 XCopyArea(dpy, date.pixmap, visible.pixmap, NormalGC,
504 9*((clk->tm_mday / 10 +9) % 10),0,9,13,posx[7],posy[2]);
505 XCopyArea(dpy, date.pixmap, visible.pixmap, NormalGC,
506 9*((clk->tm_mday % 10 +9) % 10),0,9,13,posx[9],posy[2]);
507 }
508 else
509 XCopyArea(dpy, date.pixmap, visible.pixmap, NormalGC,
510 9*(clk->tm_mday -1),0,9,13,posx[8], posy[2]);
511
512 /* Wochentag */
513 XCopyArea(dpy, weekday.pixmap, visible.pixmap, NormalGC,
514 0,6*((clk->tm_wday +6) % 7),21,7,posx[6], posy[1]);
515
516 if (! ITBLINKS )
517 /* Sekunden Doppelpunkt ein */
518 XCopyArea(dpy, led.pixmap, visible.pixmap, NormalGC,
519 90,0,3,11,posx[2], posy[0]);
520
521 }
522
523
524
525
526
527
528
529
530
531
532
533
534
535