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