1 /*
2 * astime is an analogue clock utility for X Windows.
3 *
4 * Copyright (c) 1998-2000 Albert Dorofeev <albert@tigr.net>
5 * Copyright (c) 1999 William Kostis <kostis@ee.cornell.edu>
6 *
7 * For the updates see http://www.tigr.net/afterstep/as-apps/
8 *
9 * This software is distributed under GPL. For details see LICENSE file.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <math.h>
15 #include <time.h>
16
17 #include <X11/Xlib.h>
18 #include <X11/xpm.h>
19 #include <X11/Xatom.h>
20
21 #include "x_color.h"
22 #include "state.h"
23 struct astime_state state;
24
25 #include "dof.xpm"
26 #include "months.xpm"
27 #include "digits.xpm"
28 #include "ampm.xpm"
29
30 /* nice idea from ascd */
31 typedef struct _XpmIcon {
32 Pixmap pixmap;
33 Pixmap mask;
34 XpmAttributes attributes;
35 } XpmIcon;
36
37 XpmIcon dofXpm;
38 XpmIcon ampmXpm;
39 XpmIcon monthsXpm;
40 XpmIcon digitsXpm;
41
42 /* X windows related global variables */
43 Display *mainDisplay = 0; /* The display we are working on */
44 Window Root; /* The root window of X11 */
45 Pixmap backgroundWindow; /* Window for drawing */
46 Pixmap drawWindow; /* Window for drawing */
47 Window mainWindow; /* Application window */
48 Window iconWindow; /* Icon window */
49 XGCValues mainGCV; /* graphics context values */
50 GC mainGC; /* Graphics context */
51 Atom wm_delete_window;
52 Atom wm_protocols;
53 Font label_font;
54 XFontStruct * label_fnstruct;
55
56 /* the label position and color */
57 int label_x, label_y;
58 Pixel label_pix;
59
60 /* background, digits, months etc pixmap colors */
61 char bgpixmap_color[4][32];
62 char dof_pixmap_color[2][32];
63 char ampm_pixmap_color[2][32];
64 char digits_pixmap_color[2][32];
65 char months_pixmap_color[2][32];
66
67 Pixel back_pix, fore_pix;
68
69 /* The center of the clock */
70 struct coordinates center;
71 /* The half-size of the watch drawable area
72 * (2 more pixels are given to the frame */
73 struct coordinates watch_size;
74
75 /* calculated values in pixels */
76 int pixelLength[3];
77 struct line_struct {
78 int x1, y1;
79 int x2, y2;
80 } lines[3];
81
82 /* polygons for the hands */
83 XPoint hand[3][4];
84
85 /* pixels we need */
86 Pixel pix[9];
87
88 /* last time we updated */
89 time_t last_time = 0;
90 time_t curTime;
91
92 /* current time in nice format */
93 struct tm *loc_time;
94
95 /* requests for update */
96 int update_request = 0;
97
98 /* float pi = 3.14159265359; */
99
draw_window(Window win)100 void draw_window(Window win)
101 {
102 int i;
103
104 XCopyArea(
105 mainDisplay,
106 backgroundWindow,
107 win,
108 mainGC,
109 0,
110 0,
111 state.total_size.x,
112 state.total_size.y,
113 0,
114 0
115 );
116 if (state.draw_ampm)
117 XCopyArea(
118 mainDisplay,
119 ampmXpm.pixmap,
120 win,
121 mainGC,
122 0,
123 (loc_time->tm_hour > 11 ? 6 : 0),
124 13,
125 7,
126 state.total_size.x - 14,
127 1
128 );
129 if (state.draw_date) {
130 XCopyArea(
131 mainDisplay,
132 dofXpm.pixmap,
133 win,
134 mainGC,
135 0,
136 loc_time->tm_wday * 6,
137 13,
138 7,
139 1,
140 1
141 );
142 XCopyArea(
143 mainDisplay,
144 digitsXpm.pixmap,
145 win,
146 mainGC,
147 0,
148 (loc_time->tm_mday / 10) * 7,
149 7,
150 8,
151 1,
152 state.total_size.y - 9
153 );
154 XCopyArea(
155 mainDisplay,
156 digitsXpm.pixmap,
157 win,
158 mainGC,
159 0,
160 (loc_time->tm_mday % 10) * 7,
161 7,
162 8,
163 8,
164 state.total_size.y - 9
165 );
166 XCopyArea(
167 mainDisplay,
168 monthsXpm.pixmap,
169 win,
170 mainGC,
171 0,
172 loc_time->tm_mon * 6,
173 19,
174 7,
175 18,
176 state.total_size.y - 8
177 );
178 /* The year won't fit in smaller displays */
179 if (state.total_size.x > 51) {
180 XCopyArea(
181 mainDisplay,
182 digitsXpm.pixmap,
183 win,
184 mainGC,
185 0,
186 (loc_time->tm_year % 100 / 10) * 7,
187 7,
188 8,
189 38,
190 state.total_size.y - 9
191 );
192 XCopyArea(
193 mainDisplay,
194 digitsXpm.pixmap,
195 win,
196 mainGC,
197 0,
198 (loc_time->tm_year % 10) * 7,
199 7,
200 8,
201 45,
202 state.total_size.y - 9
203 );
204 }
205 }
206 #ifdef DEBUG
207 mainGCV.foreground = pix[2];
208 XChangeGC(
209 mainDisplay,
210 mainGC,
211 GCForeground,
212 &mainGCV
213 );
214 XDrawLine(
215 mainDisplay,
216 win,
217 mainGC,
218 center.x - watch_size.x,
219 center.y - watch_size.y,
220 center.x + watch_size.x,
221 center.y - watch_size.y
222 );
223 XDrawLine(
224 mainDisplay,
225 win,
226 mainGC,
227 center.x + watch_size.x,
228 center.y - watch_size.y,
229 center.x + watch_size.x,
230 center.y + watch_size.y
231 );
232 XDrawLine(
233 mainDisplay,
234 win,
235 mainGC,
236 center.x + watch_size.x,
237 center.y + watch_size.y,
238 center.x - watch_size.x,
239 center.y + watch_size.y
240 );
241 XDrawLine(
242 mainDisplay,
243 win,
244 mainGC,
245 center.x - watch_size.x,
246 center.y + watch_size.y,
247 center.x - watch_size.x,
248 center.y - watch_size.y
249 );
250 #endif
251
252
253 /* draw filled polygonal hands */
254 for (i = 2; i >= 0; i--) {
255 if ((i == 0) && (state.draw_seconds == 0))
256 break;
257
258 if (state.hprop[i][HFILL]) {
259 mainGCV.foreground = pix[i + 6];
260 XChangeGC(
261 mainDisplay,
262 mainGC,
263 GCForeground | GCLineWidth,
264 &mainGCV
265 );
266
267 XFillPolygon(mainDisplay, win, mainGC, hand[i], 3, Convex, CoordModeOrigin);
268 }
269 /* draw line-rendered hands */
270 if (state.hprop[i][HCLINE]) {
271 mainGCV.foreground = pix[i];
272
273 if ((i == 0) && state.thin_seconds) {
274 mainGCV.line_width = 1;
275 } else {
276 /* scale line thickness by window size */
277 mainGCV.line_width = rint((1 + (0.5 * i)) * (((watch_size.x + watch_size.y) / 2.0) *
278 (state.hthick / 100.0)));
279 }
280
281 XChangeGC(
282 mainDisplay,
283 mainGC,
284 GCForeground | GCLineWidth,
285 &mainGCV
286 );
287 XDrawLine(
288 mainDisplay,
289 win,
290 mainGC,
291 lines[i].x1,
292 lines[i].y1,
293 lines[i].x2,
294 lines[i].y2
295 );
296 }
297 /* draw outlines of hands */
298 if (state.hprop[i][HOLINE]) {
299 mainGCV.foreground = pix[i + 3];
300 mainGCV.line_width = rint((1 + (0.5 * i)) * (((watch_size.x + watch_size.y) / 2.0) *
301 (state.othick / 1000.0)));
302 XChangeGC(
303 mainDisplay,
304 mainGC,
305 GCForeground | GCLineWidth,
306 &mainGCV
307 );
308 XDrawLines(mainDisplay, win, mainGC, hand[i], 4, CoordModeOrigin);
309
310 }
311 }
312
313 if ( state.show_label ) {
314 mainGCV.foreground = label_pix;
315 XChangeGC(
316 mainDisplay,
317 mainGC,
318 GCForeground,
319 &mainGCV
320 );
321 XDrawString(
322 mainDisplay,
323 win,
324 mainGC,
325 label_x,
326 label_y,
327 state.label,
328 strlen(state.label)
329 );
330 }
331 }
332
333 /* convert the position on 0-60 scale into xy coordinates */
convert2x(int tim)334 inline float convert2x(int tim)
335 {
336 return cos(M_PI * (((float) (tim - 15)) * 6) / 180);
337 }
convert2y(int tim)338 inline float convert2y(int tim)
339 {
340 return sin(M_PI * (((float) (tim - 15)) * 6) / 180);
341 }
342
343 float hwidth[3];
344 float hlength[3];
345 float hback[3];
346 float hscale;
347
348 /* calculate some rendering constants */
constants()349 void constants()
350 {
351 hscale = (state.hthick / 4.0);
352
353 hwidth[0] = 0.02 * hscale;
354 hwidth[1] = 0.05 * hscale;
355 hwidth[2] = 0.07 * hscale;
356
357 hlength[0] = 1.0;
358 hlength[1] = 0.9;
359 hlength[2] = 0.6;
360 hback[0] = 0.02;
361 hback[1] = 0.05;
362 hback[2] = 0.07;
363
364 if (state.float_seconds)
365 hback[0] = -0.8;
366 }
367
368
369
370 /* calculate rendering parameters for hands */
calculate_hands()371 void calculate_hands()
372 {
373 int i;
374 float xrate[3], yrate[3];
375
376 loc_time = localtime(&curTime);
377 if (state.shift) {
378 loc_time->tm_hour += state.shift;
379 while (loc_time->tm_hour > 23)
380 loc_time->tm_hour %= 24;
381 while (loc_time->tm_hour < 0)
382 loc_time->tm_hour += 24;
383 }
384 /* seconds */
385 xrate[0] = convert2x(loc_time->tm_sec);
386 yrate[0] = convert2y(loc_time->tm_sec);
387
388 /* minutes */
389 xrate[1] = convert2x(loc_time->tm_min + (float) (loc_time->tm_sec) / 60.0);
390 yrate[1] = convert2y(loc_time->tm_min + (float) (loc_time->tm_sec) / 60.0);
391
392 /* hours */
393 xrate[2] = convert2x(((loc_time->tm_hour % 12) * 5) + (loc_time->tm_min / 12.0));
394 yrate[2] = convert2y(((loc_time->tm_hour % 12) * 5) + (loc_time->tm_min / 12.0));
395
396 for (i = 0; i < 3; i++) {
397 lines[i].x1 = center.x - rint(hback[i] * watch_size.x * xrate[i]);
398 lines[i].y1 = center.y - rint(hback[i] * watch_size.y * yrate[i]);
399 lines[i].x2 = rint(hlength[i] * watch_size.x * xrate[i]) + center.x;
400 lines[i].y2 = rint(hlength[i] * watch_size.y * yrate[i]) + center.y;
401
402 #ifdef DEBUG
403 if (i == 0)
404 printf("%d sec = %d %d -> %d %d, xrate = %f, yrate = %f\n",
405 loc_time->tm_sec, lines[0].x1, lines[0].y1,
406 lines[0].x2, lines[0].y2, xrate[0], yrate[0]);
407 #endif
408
409 /* generate polygons */
410 hand[i][0].x = rint((hwidth[i] * watch_size.x) * yrate[i]) + center.x
411 - rint(hback[i] * watch_size.x * xrate[i]);
412 hand[i][0].y = rint((hwidth[i] * watch_size.y) * (-xrate[i])) + center.y
413 - rint(hback[i] * watch_size.y * yrate[i]);
414 hand[i][1].x = rint((hwidth[i] * watch_size.x) * (-yrate[i])) + center.x
415 - rint(hback[i] * watch_size.x * xrate[i]);
416 hand[i][1].y = rint((hwidth[i] * watch_size.y) * xrate[i]) + center.y
417 - rint(hback[i] * watch_size.y * yrate[i]);
418 hand[i][2].x = lines[i].x2;
419 hand[i][2].y = lines[i].y2;
420 hand[i][3].x = hand[i][0].x;
421 hand[i][3].y = hand[i][0].y;
422 }
423 }
424
425 /*
426 * Calculate and redraw the lines corresponding to the
427 * time.
428 */
refresh()429 void refresh()
430 {
431 constants();
432 calculate_hands();
433 draw_window(drawWindow);
434 ++update_request;
435 }
436
437 /*
438 * This function clears up all X related
439 * stuff and exits. It is called in case
440 * of emergencies too.
441 */
x_cleanup()442 void x_cleanup()
443 {
444 if (mainDisplay) {
445 XCloseDisplay(mainDisplay);
446 }
447 exit(0);
448 }
449
450 /*
451 * This checks for X11 events. We distinguish the following:
452 * - request to repaint the window
453 * - request to quit (Close button)
454 */
CheckX11Events()455 void CheckX11Events()
456 {
457 XEvent Event;
458 while (XPending(mainDisplay)) {
459 XNextEvent(mainDisplay, &Event);
460 switch (Event.type) {
461 case Expose:
462 #ifdef DEBUG
463 printf("Expose event caught: (%d %d) (%d x %d)\n",
464 ((XExposeEvent *) & Event)->x,
465 ((XExposeEvent *) & Event)->y,
466 ((XExposeEvent *) & Event)->width,
467 ((XExposeEvent *) & Event)->height);
468 #endif
469 if (Event.xexpose.count == 0) {
470 ++update_request;
471 }
472 break;
473 case ButtonPress:
474 system(state.program_name);
475 break;
476 case ClientMessage:
477 if ((Event.xclient.message_type == wm_protocols)
478 && (Event.xclient.data.l[0] == wm_delete_window)) {
479 #ifdef DEBUG
480 printf("caught wm_delete_window, closing\n");
481 #endif
482 x_cleanup();
483 }
484 break;
485 }
486 }
487 }
488
489 /*
490 * Flush the changes that were done in the hidden window
491 * onto the visible windows.
492 */
redraw()493 void redraw()
494 {
495 XCopyArea(mainDisplay, drawWindow, mainWindow, mainGC, 0, 0,
496 state.total_size.x, state.total_size.y, 0, 0);
497
498 XCopyArea(mainDisplay, drawWindow, iconWindow, mainGC, 0, 0,
499 state.total_size.x, state.total_size.y, 0, 0);
500
501 update_request = 0;
502 }
503
504 /*
505 * This routine checks if the current time is equal to the time
506 * specified in the configuration file and executes the given
507 * command.
508 */
croncheck()509 void croncheck()
510 {
511 int i;
512
513 for (i = 0; i < state.nprogs; i++) {
514 if (loc_time->tm_hour == state.PInf[i]->time[0]) {
515 if (loc_time->tm_min == state.PInf[i]->time[1]) {
516 if ((loc_time->tm_sec == state.PInf[i]->time[2])) {
517 if (!state.PInf[i]->done) {
518 state.PInf[i]->done = 1;
519 system(state.PInf[i]->name);
520 }
521 } else {
522 state.PInf[i]->done = 0;
523 }
524 }
525 }
526 }
527 }
528
529 /*
530 * This function triggers checks for updates of the clock
531 * every second and checks if any X11 events were passed
532 * to us. If one of the functions triggers the flag an
533 * update is flushed to the screen.
534 */
update()535 void update()
536 {
537 curTime = time(0);
538
539 if ( curTime != last_time ) {
540 if ( abs(curTime - last_time) >= state.update_interval) {
541 last_time = curTime;
542 refresh();
543 }
544 if (state.cron_program)
545 croncheck();
546 }
547
548 CheckX11Events();
549 if (update_request) {
550 redraw();
551 }
552 }
553
554 /*
555 * Draw those little points every 5 secs on the background pixmap
556 * that usually are marked 1,2,3,4,5,6,7 etc.
557 * And those triangles that mark 3,6,9,12 o'clock
558 */
draw_dial()559 void draw_dial()
560 {
561 int tmp, tinc;
562 struct coordinates tmp_coord;
563 float xrate, yrate;
564
565 mainGCV.foreground = fore_pix;
566 XChangeGC(mainDisplay, mainGC, GCForeground, &mainGCV);
567
568 switch (state.tprop) {
569 case 2:
570 tinc = 1;
571 break;
572 case 1:
573 tinc = 5;
574 break;
575 case 0:
576 tinc = 60;
577 break;
578 default:
579 tinc = 1;
580 break;
581 }
582
583 if (state.tprop) {
584 for (tmp = 0; tmp < 60; tmp += tinc) {
585 xrate = convert2x(tmp);
586 yrate = convert2y(tmp);
587 tmp_coord.x = rint((watch_size.x + 1) * xrate) + center.x;
588 tmp_coord.y = rint((watch_size.y + 1) * yrate) + center.y;
589 #ifdef DEBUG
590 printf("dot at %d %d\n", tmp_coord.x, tmp_coord.y);
591 #endif
592 XDrawPoint(mainDisplay, backgroundWindow, mainGC, tmp_coord.x, tmp_coord.y);
593 if (state.tprop == 2) {
594 if (!(tmp % 5)) {
595 XDrawPoint(mainDisplay, backgroundWindow, mainGC, tmp_coord.x, tmp_coord.y + 1);
596 XDrawPoint(mainDisplay, backgroundWindow, mainGC, tmp_coord.x + 1, tmp_coord.y);
597 XDrawPoint(mainDisplay, backgroundWindow, mainGC, tmp_coord.x, tmp_coord.y - 1);
598 XDrawPoint(mainDisplay, backgroundWindow, mainGC, tmp_coord.x - 1, tmp_coord.y);
599 }
600 }
601 }
602
603 if (state.tprop == 1) {
604 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x - watch_size.x - 1, center.y - 1);
605 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x - watch_size.x - 1, center.y + 1);
606 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x - watch_size.x, center.y);
607 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x + watch_size.x + 1, center.y - 1);
608 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x + watch_size.x + 1, center.y + 1);
609 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x + watch_size.x, center.y);
610 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x - 1, center.y - watch_size.y - 1);
611 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x + 1, center.y - watch_size.y - 1);
612 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x, center.y - watch_size.y);
613 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x - 1, center.y + watch_size.y + 1);
614 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x + 1, center.y + watch_size.y + 1);
615 XDrawPoint(mainDisplay, backgroundWindow, mainGC, center.x, center.y + watch_size.y);
616 }
617 }
618 }
619
initialize(int argc,char ** argv,char * window_name,char * display_name,char * mainGeometry,int withdrawn,int iconic,int pushed_in,int no_border)620 void initialize(int argc, char **argv,
621 char *window_name,
622 char *display_name,
623 char *mainGeometry,
624 int withdrawn,
625 int iconic,
626 int pushed_in,
627 int no_border)
628 {
629 int screen;
630 Status status;
631 XWindowAttributes winAttr;
632 XSizeHints SizeHints;
633 XTextProperty title;
634 XClassHint classHint;
635 int gravity;
636 XWMHints WmHints;
637 XEvent Event;
638 int color_depth;
639 Pixel tmp_pix;
640 int result;
641 int x_negative = 0;
642 int y_negative = 0;
643 int x_size_forced = 0;
644 int y_size_forced = 0;
645 int label_w = 0;
646 int label_h = 0;
647
648 mainDisplay = XOpenDisplay(display_name);
649 if (!mainDisplay) {
650 printf("astime : grrrr... can't open display %s. Sorry ...\n",
651 XDisplayName(display_name));
652 exit(1);
653 }
654 screen = DefaultScreen(mainDisplay);
655 Root = RootWindow(mainDisplay, screen);
656 back_pix = GetColor(state.bgcolor, mainDisplay, Root);
657 fore_pix = GetColor(state.fgcolor, mainDisplay, Root);
658 color_depth = DefaultDepth(mainDisplay, screen);
659 #ifdef DEBUG
660 printf("astime : detected color depth %d bpp, using %d bpp\n",
661 color_depth, color_depth);
662 #endif
663 /* Set up the font for the label */
664 if ( state.show_label ) {
665 label_fnstruct = XLoadQueryFont( mainDisplay, state.font_name );
666 if ( ! label_fnstruct ) {
667 printf("astime : failed to load font %s\n",
668 state.font_name);
669 printf("astime : warning : the label will not be drawn\n");
670 state.show_label = 0;
671 } else {
672 label_font = label_fnstruct->fid;
673 label_w = XTextWidth(
674 label_fnstruct,
675 state.label,
676 strlen(state.label)
677 );
678 label_h = label_fnstruct->max_bounds.ascent +
679 label_fnstruct->max_bounds.descent;
680 #ifdef DEBUG
681 printf("astime : loaded font %s\n", state.font_name);
682 printf("astime : label width is %d, height is %d [label \"%s\"]\n",
683 label_w, label_h, state.label);
684 #endif
685 }
686 }
687
688 if (strlen(mainGeometry)) {
689 /* Check the user-specified size */
690 result = XParseGeometry(mainGeometry,
691 &SizeHints.x,
692 &SizeHints.y,
693 &SizeHints.width,
694 &SizeHints.height);
695 if (result & WidthValue) {
696 state.total_size.x = SizeHints.width;
697 x_size_forced = 1;
698 }
699 if (result & HeightValue) {
700 state.total_size.y = SizeHints.height;
701 y_size_forced = 1;
702 }
703 if (result & XNegative)
704 x_negative = 1;
705 if (result & YNegative)
706 y_negative = 1;
707 #ifdef DEBUG
708 printf("User size: %d x %d position: %d %d (negative %d %d)\n",
709 state.total_size.x, state.total_size.y,
710 SizeHints.x, SizeHints.y, x_negative, y_negative);
711 #endif
712 }
713 /* adjust the coordinate/size for the date */
714 if (state.draw_date) {
715 center.x = state.total_size.x / 2;
716 center.y = state.total_size.y / 2 - 4;
717 watch_size.x = center.x - 3;
718 watch_size.y = state.total_size.y / 2 - 7;
719 } else {
720 center.x = state.total_size.x / 2;
721 center.y = state.total_size.y / 2;
722 watch_size.x = center.x - 3;
723 watch_size.y = center.y - 3;
724 }
725 /* adjust the coordinates/size for the label */
726 if ( state.show_label ) {
727 if ( state.label_top )
728 center.y += label_h/2 + 1;
729 else
730 center.y -= label_h/2;
731 watch_size.y -= label_h/2 + 1;
732 label_x = state.total_size.x / 2 - label_w / 2;
733 if ( state.label_top )
734 label_y = label_h;
735 else {
736 if ( state.draw_date )
737 label_y = state.total_size.y - 10;
738 else
739 label_y = state.total_size.y - 3;
740 }
741 }
742
743 /* The day-of-week pixmap */
744 sprintf(dof_pixmap_color[0], "c c %s", state.bgcolor);
745 sprintf(dof_pixmap_color[1], "l c %s", state.daycolor);
746 dof[1] = dof_pixmap_color[0];
747 dof[2] = dof_pixmap_color[1];
748 dofXpm.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
749 status = XpmCreatePixmapFromData(
750 mainDisplay, /* display */
751 Root, /* window */
752 dof, /* xpm */
753 &dofXpm.pixmap, /* resulting pixmap */
754 &dofXpm.mask,
755 &dofXpm.attributes);
756 if (status != XpmSuccess) {
757 printf("astime : (%d) not enough free color cells for day_of_week.\n", status);
758 x_cleanup();
759 }
760 /* The AM/PM pixmap */
761 sprintf(ampm_pixmap_color[0], "c c %s", state.bgcolor);
762 sprintf(ampm_pixmap_color[1], "l c %s", state.ampmcolor);
763 ampm[1] = ampm_pixmap_color[0];
764 ampm[2] = ampm_pixmap_color[1];
765 ampmXpm.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
766 status = XpmCreatePixmapFromData(
767 mainDisplay, /* display */
768 Root, /* window */
769 ampm, /* xpm */
770 &mXpm.pixmap, /* resulting pixmap */
771 &mXpm.mask,
772 &mXpm.attributes);
773 if (status != XpmSuccess) {
774 printf("astime : (%d) not enough free color cells for AM/PM indicator.\n", status);
775 x_cleanup();
776 }
777 /* The digits pixmap */
778 sprintf(digits_pixmap_color[0], "c c %s", state.bgcolor);
779 sprintf(digits_pixmap_color[1], ". c %s", state.datecolor);
780 digits[1] = digits_pixmap_color[0];
781 digits[2] = digits_pixmap_color[1];
782 digitsXpm.attributes.valuemask |=
783 (XpmReturnPixels | XpmReturnExtensions);
784 status = XpmCreatePixmapFromData(
785 mainDisplay, /* display */
786 Root, /* window */
787 digits, /* xpm */
788 &digitsXpm.pixmap, /* resulting pixmap */
789 &digitsXpm.mask,
790 &digitsXpm.attributes);
791 if (status != XpmSuccess) {
792 printf("astime : (%d) not enough free color cells for digits.\n", status);
793 x_cleanup();
794 }
795 /* The months pixmap */
796 sprintf(months_pixmap_color[0], ". c %s", state.bgcolor);
797 sprintf(months_pixmap_color[1], "o c %s", state.datecolor);
798 months[1] = months_pixmap_color[0];
799 months[2] = months_pixmap_color[1];
800 monthsXpm.attributes.valuemask |=
801 (XpmReturnPixels | XpmReturnExtensions);
802 status = XpmCreatePixmapFromData(
803 mainDisplay, /* display */
804 Root, /* window */
805 months, /* xpm */
806 &monthsXpm.pixmap, /* resulting pixmap */
807 &monthsXpm.mask,
808 &monthsXpm.attributes);
809 if (status != XpmSuccess) {
810 printf("astime : (%d) not enough free color cells for months.\n", status);
811 x_cleanup();
812 }
813 SizeHints.flags = USSize | USPosition;
814 SizeHints.x = 0;
815 SizeHints.y = 0;
816 SizeHints.min_width =
817 SizeHints.max_width =
818 SizeHints.width = state.total_size.x;
819 SizeHints.min_height =
820 SizeHints.max_height =
821 SizeHints.height = state.total_size.y;
822 SizeHints.flags |= PMinSize | PMaxSize;
823 /*
824 * The forth parameter is the window border width.
825 * Set to 0 it makes astime look really queer in
826 * AS when using -0-0 geometry. I have no idea why.
827 * When the border is 1, everything is fine, but
828 * the window is off by 1, of course.
829 * It is probably a bug in AS.
830 */
831 XWMGeometry(mainDisplay, screen, mainGeometry, NULL, 0,
832 &SizeHints, &SizeHints.x, &SizeHints.y,
833 &SizeHints.width, &SizeHints.height, &gravity);
834 #ifdef DEBUG
835 printf("SizeHints were: %d x %d, setting to %d x %d, position %d %d\n",
836 SizeHints.width, SizeHints.height,
837 state.total_size.x, state.total_size.y,
838 SizeHints.x, SizeHints.y);
839 #endif
840
841 /* Correct the offsets if the X/Y are negative */
842 SizeHints.win_gravity = NorthWestGravity;
843 if (x_negative) {
844 SizeHints.win_gravity = NorthEastGravity;
845 }
846 if (y_negative) {
847 if (x_negative)
848 SizeHints.win_gravity = SouthEastGravity;
849 else
850 SizeHints.win_gravity = SouthWestGravity;
851 }
852 SizeHints.flags |= PWinGravity;
853
854 backgroundWindow = XCreatePixmap(
855 mainDisplay,
856 Root,
857 state.total_size.x,
858 state.total_size.y,
859 color_depth
860 );
861
862 drawWindow = XCreatePixmap(
863 mainDisplay, /* display */
864 Root, /* parent */
865 state.total_size.x, /* width */
866 state.total_size.y, /* height */
867 color_depth /* color depth */
868 );
869
870 mainWindow = XCreateSimpleWindow(
871 mainDisplay, /* display */
872 Root, /* parent */
873 SizeHints.x, /* x */
874 SizeHints.y, /* y */
875 SizeHints.width, /* width */
876 SizeHints.height, /* height */
877 0, /* border_width */
878 fore_pix, /* border */
879 back_pix /* background */
880 );
881
882 iconWindow = XCreateSimpleWindow(
883 mainDisplay, /* display */
884 Root, /* parent */
885 SizeHints.x, /* x */
886 SizeHints.y, /* y */
887 SizeHints.width, /* width */
888 SizeHints.height, /* height */
889 0, /* border_width */
890 fore_pix, /* border */
891 back_pix /* background */
892 );
893
894 XSetWMNormalHints(mainDisplay, mainWindow, &SizeHints);
895 XSetWMNormalHints(mainDisplay, iconWindow, &SizeHints);
896 status = XClearWindow(mainDisplay, mainWindow);
897 status = XClearWindow(mainDisplay, iconWindow);
898
899 status = XGetWindowAttributes(
900 mainDisplay, /* display */
901 mainWindow, /* window */
902 &winAttr /* window_attributes_return */
903 );
904 #ifdef DEBUG
905 printf("Window Attributes: %d x %d at %d %d border %d\n",
906 winAttr.width, winAttr.height, winAttr.x, winAttr.y,
907 winAttr.border_width);
908 #endif
909
910 status = XStringListToTextProperty(&window_name, 1, &title);
911 XSetWMName(mainDisplay, mainWindow, &title);
912 XSetWMName(mainDisplay, iconWindow, &title);
913
914 classHint.res_name = "astime";
915 classHint.res_class = "ASTIME";
916 XSetClassHint(mainDisplay, mainWindow, &classHint);
917 XStoreName(mainDisplay, mainWindow, window_name);
918 XSetIconName(mainDisplay, mainWindow, window_name);
919
920 /*
921 * If the user did not specify a program to run
922 * we do not intercept mouse clicks in our window.
923 */
924 if (state.run_program)
925 status = XSelectInput(
926 mainDisplay, /* display */
927 mainWindow, /* window */
928 ExposureMask | ButtonPressMask /* event_mask */
929 );
930 else
931 status = XSelectInput(
932 mainDisplay, /* display */
933 mainWindow, /* window */
934 ExposureMask /* event_mask */
935 );
936
937 /* Make sure WindowMaker users can click happily away ... */
938 if ( withdrawn )
939 status = XSelectInput(
940 mainDisplay, /* display */
941 iconWindow, /* window */
942 ExposureMask | ButtonPressMask /* event_mask */
943 );
944 else
945 status = XSelectInput(
946 mainDisplay, /* display */
947 iconWindow, /* window */
948 ExposureMask /* event_mask */
949 );
950
951 /* Creating Graphics context */
952 mainGCV.foreground = fore_pix;
953 mainGCV.background = back_pix;
954 mainGCV.graphics_exposures = False;
955 mainGCV.line_style = LineSolid;
956 mainGCV.fill_style = FillSolid;
957 mainGCV.line_width = 1;
958 if ( state.show_label ) {
959 mainGCV.font = label_font;
960 mainGC = XCreateGC(mainDisplay,
961 mainWindow,
962 GCForeground | GCBackground | GCLineWidth |
963 GCLineStyle | GCFillStyle | GCFont,
964 &mainGCV
965 );
966 } else {
967 mainGC = XCreateGC(mainDisplay,
968 mainWindow,
969 GCForeground | GCBackground | GCLineWidth |
970 GCLineStyle | GCFillStyle,
971 &mainGCV
972 );
973 }
974
975 /* Draw the background */
976 mainGCV.foreground = back_pix;
977 XChangeGC(mainDisplay,
978 mainGC,
979 GCForeground,
980 &mainGCV
981 );
982 XFillRectangle(mainDisplay,
983 backgroundWindow,
984 mainGC,
985 0,
986 0,
987 state.total_size.x,
988 state.total_size.y
989 );
990
991 if (!no_border) {
992
993 /* The shadow on the sides */
994 if (pushed_in) {
995 tmp_pix = DarkenColor(state.bgcolor, 1.6, mainDisplay, Root);
996 } else {
997 tmp_pix = LightenColor(state.bgcolor, 2.0, mainDisplay, Root);
998 }
999 mainGCV.foreground = tmp_pix;
1000 XChangeGC(mainDisplay,
1001 mainGC,
1002 GCForeground,
1003 &mainGCV
1004 );
1005 XDrawLine(mainDisplay,
1006 backgroundWindow,
1007 mainGC,
1008 0,
1009 0,
1010 state.total_size.x - 1,
1011 0
1012 );
1013 XDrawLine(mainDisplay,
1014 backgroundWindow,
1015 mainGC,
1016 0,
1017 0,
1018 0,
1019 state.total_size.y - 1
1020 );
1021 if (!pushed_in) {
1022 tmp_pix = DarkenColor(state.bgcolor, 1.6, mainDisplay, Root);
1023 } else {
1024 tmp_pix = LightenColor(state.bgcolor, 2.0, mainDisplay, Root);
1025 }
1026 mainGCV.foreground = tmp_pix;
1027 XChangeGC(mainDisplay,
1028 mainGC,
1029 GCForeground,
1030 &mainGCV
1031 );
1032 XDrawLine(mainDisplay,
1033 backgroundWindow,
1034 mainGC,
1035 state.total_size.x - 1,
1036 state.total_size.y,
1037 state.total_size.x - 1,
1038 0
1039 );
1040 XDrawLine(mainDisplay,
1041 backgroundWindow,
1042 mainGC,
1043 state.total_size.x,
1044 state.total_size.y - 1,
1045 0,
1046 state.total_size.y - 1
1047 );
1048 }
1049
1050 /* Finish up the background (the dial) */
1051 draw_dial();
1052
1053 status = XSetCommand(mainDisplay, mainWindow, argv, argc);
1054
1055 /* Set up the event for quitting the window */
1056 wm_delete_window = XInternAtom(mainDisplay,
1057 "WM_DELETE_WINDOW", /* atom_name */
1058 False /* only_if_exists */
1059 );
1060 wm_protocols = XInternAtom(mainDisplay,
1061 "WM_PROTOCOLS", /* atom_name */
1062 False /* only_if_exists */
1063 );
1064 status = XSetWMProtocols(mainDisplay,
1065 mainWindow,
1066 &wm_delete_window,
1067 1
1068 );
1069 status = XSetWMProtocols(mainDisplay,
1070 iconWindow,
1071 &wm_delete_window,
1072 1
1073 );
1074
1075 WmHints.flags = StateHint | IconWindowHint;
1076 WmHints.initial_state =
1077 withdrawn ? WithdrawnState :
1078 iconic ? IconicState : NormalState;
1079 WmHints.icon_window = iconWindow;
1080 if (withdrawn) {
1081 WmHints.window_group = mainWindow;
1082 WmHints.flags |= WindowGroupHint;
1083 }
1084 if (iconic || withdrawn) {
1085 WmHints.icon_x = SizeHints.x;
1086 WmHints.icon_y = SizeHints.y;
1087 WmHints.flags |= IconPositionHint;
1088 }
1089 XSetWMHints(mainDisplay,
1090 mainWindow,
1091 &WmHints);
1092
1093 /* Finally show the window */
1094 status = XMapWindow(mainDisplay, mainWindow);
1095
1096 /* Get colors while waiting for Expose */
1097 if (state.neon) {
1098 pix[0] = DarkenColor(state.seccolor, 1.8, mainDisplay, Root);
1099 pix[1] = DarkenColor(state.mincolor, 1.8, mainDisplay, Root);
1100 pix[2] = DarkenColor(state.hourcolor, 1.8, mainDisplay, Root);
1101 } else {
1102 pix[0] = GetColor(state.seccolor, mainDisplay, Root);
1103 pix[1] = GetColor(state.mincolor, mainDisplay, Root);
1104 pix[2] = GetColor(state.hourcolor, mainDisplay, Root);
1105 }
1106
1107 /* Get outline colors */
1108 if (state.neon) {
1109 pix[3] = GetColor(state.seccolor, mainDisplay, Root);
1110 pix[4] = GetColor(state.mincolor, mainDisplay, Root);
1111 pix[5] = GetColor(state.hourcolor, mainDisplay, Root);
1112 } else {
1113 pix[3] = LightenColor(state.seccolor, 1.8, mainDisplay, Root);
1114 pix[4] = LightenColor(state.mincolor, 1.8, mainDisplay, Root);
1115 pix[5] = LightenColor(state.hourcolor, 1.8, mainDisplay, Root);
1116 }
1117
1118 /* allow user to override outline colors */
1119 if (strcmp(state.secocolor, "<>"))
1120 pix[3] = GetColor(state.secocolor, mainDisplay, Root);
1121 if (strcmp(state.minocolor, "<>"))
1122 pix[4] = GetColor(state.minocolor, mainDisplay, Root);
1123 if (strcmp(state.hourocolor, "<>"))
1124 pix[5] = GetColor(state.hourocolor, mainDisplay, Root);
1125
1126 /* Get fill colors */
1127 pix[6] = pix[0];
1128 pix[7] = pix[1];
1129 pix[8] = pix[2];
1130
1131 /* allow user to override fill colors */
1132 if (strcmp(state.secfillcolor, "<>"))
1133 pix[6] = GetColor(state.secfillcolor, mainDisplay, Root);
1134 if (strcmp(state.minfillcolor, "<>"))
1135 pix[7] = GetColor(state.minfillcolor, mainDisplay, Root);
1136 if (strcmp(state.hourfillcolor, "<>"))
1137 pix[8] = GetColor(state.hourfillcolor, mainDisplay, Root);
1138
1139 /* Get the label color */
1140 label_pix = GetColor(state.label_color, mainDisplay, Root);
1141
1142 /* try to read the time */
1143 curTime = time(0);
1144 last_time = curTime;
1145 refresh();
1146
1147 /* wait for the Expose event now */
1148 XNextEvent(mainDisplay, &Event);
1149 /* We've got Expose -> draw the parts of the window. */
1150 redraw();
1151 XFlush(mainDisplay);
1152 }
1153