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