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