ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rclock.C
Revision: 1.2
Committed: Mon May 10 00:36:58 2021 UTC (3 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +97 -39 lines
Log Message:
debian patches

File Contents

# Content
1 /*--------------------------------*-C-*---------------------------------*
2 * Copyright 1997 1998 Oezguer Kesim <kesim@math.fu-berlin.de>
3 * Copyright 1992, 1993 Robert Nation <nation@rocket.sanders.lockheed.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------*/
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #else
22 /* # define STDC_HEADERS */
23 # define HAVE_UNISTD_H
24 # define TIME_WITH_SYS_TIME
25 # define HAVE_SYS_TIME_H
26 # ifdef _AIX
27 # define HAVE_SYS_SELECT_H
28 # endif
29 #endif
30
31 #include "../src/version.h"
32 #include "feature.h"
33
34 #include <ctype.h>
35 /* #ifdef STDC_HEADERS */
36 # include <stdarg.h>
37 # include <stdio.h>
38 # include <stdlib.h>
39 # include <string.h>
40 /* #endif */
41
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45
46 #ifdef TIME_WITH_SYS_TIME
47 # include <sys/time.h>
48 # include <time.h>
49 #else
50 # ifdef HAVE_SYS_TIME_H
51 # include <sys/time.h>
52 # else
53 # include <time.h>
54 # endif
55 #endif
56
57 #if defined (__svr4__)
58 # include <sys/resource.h> /* for struct rlimit */
59 #endif
60
61 #ifdef HAVE_SYS_SELECT_H
62 # include <sys/select.h>
63 #endif
64 #include <sys/stat.h>
65
66 #ifdef MAIL
67 #include <dirent.h>
68 #endif
69
70 #include <X11/Intrinsic.h> /* Xlib, Xutil, Xresource, Xfuncproto */
71
72 #define APL_CLASS "Clock"
73 #define APL_NAME "rclock"
74 #define MSG_CLASS "Appointment"
75 #define MSG_NAME "Appointment"
76 #define CONFIG_FILE ".rclock"
77
78 #ifndef EXIT_SUCCESS /* missed from <stdlib.h> ? */
79 # define EXIT_SUCCESS 0
80 # define EXIT_FAILURE 1
81 #endif
82
83 /*----------------------------------------------------------------------*/
84
85 static Display* Xdisplay; /* X display */
86 static int Xfd; /* file descriptor of server connection */
87 static GC Xgc, Xrvgc; /* normal, reverse video GC */
88
89 #define Xscreen DefaultScreen (Xdisplay)
90 #define Xcmap DefaultColormap (Xdisplay, Xscreen)
91 #define Xroot DefaultRootWindow (Xdisplay)
92
93 /* windows and their sizes */
94 typedef struct {
95 Window win;
96 int width, height;
97 } mywindow_t;
98
99 static mywindow_t Clock = {None, 80, 80}; /* parent window */
100
101 #define fgColor 0
102 #define bgColor 1
103 static const char * rs_color [2] = { FG_COLOR_NAME, BG_COLOR_NAME };
104 static Pixel PixColors [2];
105 static const char * rs_geometry = NULL;
106
107 #ifdef ICONWIN
108 static const char * rs_iconGeometry = NULL;
109 static mywindow_t Icon = {None, 65, 65}; /* icon window */
110 static int iconic_state = NormalState; /* iconic startup? */
111 #endif
112
113 #ifdef REMINDERS
114 static mywindow_t Msg = {0, 0, 0}; /* message window */
115 static struct {
116 Window
117 # ifndef NO_REMINDER_EXEC
118 Start,
119 # endif
120 Dismiss,
121 Defer;
122 int width, height;
123 } msgButton;
124
125 static XFontStruct * Xfont;
126 #define FontHeight() (Xfont->ascent + Xfont->descent)
127 static int Msg_Mapped = 0; /* message window mapped? */
128 static int reminderTime = -1;
129 static char message [256] = "";
130 #ifndef NO_REMINDER_EXEC
131 static char execPrgm [256] = "";
132 #endif
133 static const char * reminders_file = NULL; /* name of ~/.rclock file */
134 #ifdef DATE_ON_CLOCK_FACE
135 static int show_date = 1; /* show date on face of clock */
136 #endif
137 #endif
138
139 #ifdef ADJUST_TIME
140 static int adjustTime = 0;
141 #else
142 # define adjustTime 0
143 #endif
144
145 #ifdef CENTURY
146 # if (CENTURY < 1900)
147 Error, Cenury incorrectly set.
148 # endif
149 #else
150 # define CENTURY 1900
151 #endif
152
153 static int clockUpdate = CLOCKUPDATE;
154
155 #ifdef MAIL
156 static int mailUpdate = MAILUPDATE;
157 static char * mail_file = NULL;
158 #ifndef MAIL_SPAWN
159 static char * mail_spawn = NULL;
160 #endif
161 static int is_maildir = 0;
162 #endif
163
164 static XSizeHints szHint = {
165 PMinSize | PResizeInc | PBaseSize | PWinGravity,
166 0, 0, 80, 80, /* x, y, width and height */
167 1, 1, /* Min width and height */
168 0, 0, /* Max width and height */
169 1, 1, /* Width and height increments */
170 {1, 1}, /* x, y increments */
171 {1, 1}, /* Aspect ratio - not used */
172 0, 0, /* base size */
173 NorthWestGravity /* gravity */
174 };
175
176 /* subroutine declarations */
177 static void geometry2sizehint (mywindow_t * /* win */,
178 const char * /* geom */);
179 static void Create_Windows (int /* argc */,
180 char * /* argv */ []);
181 static void getXevent (void);
182 static void print_error (const char * /* fmt */, ...);
183
184 static void Draw_Window (mywindow_t * /* this_win */,
185 int /* full_redraw */);
186 static void Reminder (void);
187 static void Next_Reminder (int /* update_only */);
188
189 /* Arguments for Next_Reminder() */
190 #define REPLACE 0
191 #define UPDATE 1
192
193 /*----------------------------------------------------------------------*/
194
195 static void
196 usage (void)
197 {
198 int i;
199 struct {
200 const char * const opt;
201 const char * const desc;
202 } optList[] = {
203 #define optList_size() (sizeof(optList)/sizeof(optList[0]))
204 { "-display displayname", "X server to contact" },
205 { "-geometry geom", "size (in pixels) and position" },
206 { "-bg color", "background color" },
207 { "-fg color", "foreground color" },
208 #ifdef REMINDERS
209 { "-fn fontname", "normal font for messages" },
210 #ifdef DATE_ON_CLOCK_FACE
211 { "-nodate", "do not display date on the clock face" },
212 #endif
213 #endif
214 #ifdef ICONWIN
215 { "-iconic", "start iconic" },
216 #endif
217 #ifdef ADJUST_TIME
218 { "-adjust +/-ddhhmm", "adjust clock time" },
219 #endif
220 { "-update seconds", "clock update interval" },
221 #ifdef MAIL
222 { "-mail seconds", "check $MAIL interval" },
223 { "-mailfile file", "file to use for mail checking" },
224 #ifndef MAIL_SPAWN
225 { "-mailspawn cmd", "execute `cmd` when clock is clicked" },
226 #endif
227 #endif
228 { "#geom", "icon window geometry" }
229 };
230
231 fprintf (stderr, "\nUsage v" VERSION ":\n " APL_NAME " [options]\n\n"
232 "where options include:\n");
233
234 for (i = 0; i < optList_size(); i++)
235 fprintf (stderr, " %-29s%s\n", optList[i].opt, optList[i].desc);
236 }
237
238
239 /****************
240 * Check out if we are using a maildir drop (qmail)
241 * Note: this changes mail_dir to hold the "new" diretory
242 */
243 #ifdef MAIL
244 static void
245 CheckMaildir()
246 {
247 struct stat st;
248 char *buf, *p;
249
250 if( !*mail_file || stat(mail_file, &st) || !S_ISDIR(st.st_mode) )
251 return; /* no */
252
253 if( !(buf = malloc(strlen(mail_file)+5)) ) {
254 print_error ("malloc error");
255 exit( EXIT_FAILURE );
256 }
257 strcpy(buf,mail_file);
258 p = buf+strlen(buf);
259 if( p[-1] != '/' )
260 *p++ = '/';
261
262 strcpy(p, "tmp" );
263 if( stat(buf, &st) || !S_ISDIR(st.st_mode ) )
264 goto leave;
265 strcpy(p, "cur" );
266 if( stat(buf, &st) || !S_ISDIR(st.st_mode ) )
267 goto leave;
268 strcpy(p, "new" );
269 if( stat(buf, &st) || !S_ISDIR(st.st_mode ) )
270 goto leave;
271
272 mail_file = buf;
273 is_maildir = 1;
274 return;
275 leave:
276 free(buf);
277 }
278 #endif
279
280 /*----------------------------------------------------------------------*
281 * rclock - Rob's clock
282 * simple X windows clock with appointment reminder
283 *----------------------------------------------------------------------*/
284 int
285 main (int argc, char * argv [])
286 {
287 int i;
288 char * opt, * val;
289 const char * display_name = NULL;
290 XGCValues gcv;
291
292 #ifdef REMINDERS
293 const char * rs_font = FONT_NAME;
294
295 /* find the ~/.rclock file */
296 if ((val = getenv ("HOME")) != NULL)
297 {
298 char * p = malloc (strlen (CONFIG_FILE) + strlen (val) + 2);
299 if (p == NULL)
300 goto Malloc_Error;
301
302 strcpy (p, val);
303 strcat (p, "/" CONFIG_FILE);
304
305 reminders_file = p;
306 }
307 #endif
308 #ifdef MAIL
309 val = getenv ("MAIL"); /* get the mail spool file name */
310 #ifdef MAIL_SPOOL
311 if (val == NULL) /* csh doesn't set $MAIL */
312 {
313 const char * spool = MAIL_SPOOL;
314 char * user = getenv ("USER"); /* assume this works */
315 if (user != NULL) {
316 val = malloc (strlen (spool) + strlen (user) + 1);
317 if (val == NULL)
318 goto Malloc_Error;
319 strcpy (val, spool);
320 strcat (val, user);
321 }
322 }
323 #endif
324 mail_file = val;
325 if( mail_file )
326 CheckMaildir();
327 #endif
328
329 /* parse the command line */
330 for (i = 1; i < argc; i += 2)
331 {
332 opt = argv [i];
333 val = argv [i+1];
334
335 switch (*opt++) {
336 case '-':
337 break;
338
339 case '#':
340 #ifdef ICONWIN
341 rs_iconGeometry = opt; /* drop */
342 #endif
343 default:
344 continue;
345 break;
346 }
347
348 if (*opt == 'd' && val) display_name = val; /* "d", "display" */
349 else if (*opt == 'g' && val) rs_geometry = val; /* "g", "geometry" */
350 #ifdef ICONWIN
351 else if (*opt == 'i') /* "ic", "iconic" */
352 {
353 iconic_state = IconicState;
354 i--; /* no argument */
355 }
356 #endif
357 else if (!strcmp (opt, "fg") && val) rs_color [fgColor] = val;
358 else if (!strcmp (opt, "bg") && val) rs_color [bgColor] = val;
359 #ifdef REMINDERS
360 else if (!strcmp (opt, "fn") && val) rs_font = val;
361 #ifdef DATE_ON_CLOCK_FACE
362 else if (!strcmp (opt, "nodate"))
363 {
364 show_date = 0;
365 i--; /* no argument */
366 }
367 #endif
368 #endif
369 else if (!strcmp (opt, "update") && val)
370 {
371 int x = atoi (val);
372 if (x < 1 || x > 60)
373 print_error ("update: %d sec", clockUpdate);
374 else
375 clockUpdate = x;
376 }
377 #ifdef MAIL
378 else if (!strcmp (opt, "mail") && val)
379 {
380 int x = atoi (val);
381 if (x < 1)
382 print_error ("mail update: %d sec", mailUpdate);
383 else
384 mailUpdate = x;
385 }
386 else if (!strcmp (opt, "mailfile") && val)
387 {
388 /* If the mail environment is not set, then mail_file was created
389 * with a malloc. We need to free it.
390 */
391 if( getenv ("MAIL") == NULL)
392 free( mail_file);
393 /* assume user knows what he's doing, don't check that file is valid...*/
394 mail_file = val;
395 }
396 #ifndef MAIL_SPAWN
397 else if (!strcmp (opt, "mailspawn") && val)
398 {
399 mail_spawn = val;
400 }
401 #endif
402 #endif /* MAIL */
403 #ifdef ADJUST_TIME
404 else if (!strcmp (opt, "adjust") && val)
405 {
406 /* convert ddhhmm to seconds, minimal error checking */
407 int x = atoi (val);
408 adjustTime = ((((abs (x) / 10000) % 100) * 24 /* days */
409 + ((abs (x) / 100) % 100)) * 60 /* hours */
410 + (abs (x) % 100)) * 60; /* minutes */
411 if (x < 0)
412 adjustTime = -adjustTime;
413 }
414 #endif /* ADJUST_TIME */
415 else
416 {
417 usage ();
418 goto Abort;
419 }
420 }
421
422 /* open display */
423 Xdisplay = XOpenDisplay (display_name);
424 if (!Xdisplay)
425 {
426 print_error ("can't open display %s", display_name?display_name:
427 getenv("DISPLAY")?getenv("DISPLAY"):
428 "as no -d given and DISPLAY not set");
429 goto Abort;
430 }
431
432 /* get display info */
433 Xfd = XConnectionNumber (Xdisplay);
434 {
435 const char * const color_msg = "can't load color \"%s\"";
436 XColor xcol;
437
438 /* allocate foreground/background colors */
439 if (!XParseColor (Xdisplay, Xcmap, rs_color [fgColor], &xcol) ||
440 !XAllocColor (Xdisplay, Xcmap, &xcol))
441 {
442 print_error (color_msg, rs_color [fgColor]);
443 goto Abort;
444 }
445 PixColors [fgColor] = xcol.pixel;
446
447 if (!XParseColor (Xdisplay, Xcmap, rs_color [bgColor], &xcol) ||
448 !XAllocColor (Xdisplay, Xcmap, &xcol))
449 {
450 print_error (color_msg, rs_color [bgColor]);
451 goto Abort;
452 }
453 PixColors [bgColor] = xcol.pixel;
454 }
455
456 #ifdef REMINDERS
457 /* load the font for messages */
458 if ((Xfont = XLoadQueryFont (Xdisplay, rs_font)) == NULL)
459 {
460 print_error ("can't load font \"%s\"", rs_font);
461 goto Abort;
462 }
463 gcv.font = Xfont->fid;
464 #endif
465
466 Create_Windows (argc, argv);
467 /* Create the graphics contexts */
468 gcv.foreground = PixColors [fgColor];
469 gcv.background = PixColors [bgColor];
470
471 Xgc = XCreateGC (Xdisplay, Clock.win,
472 #ifdef REMINDERS
473 GCFont |
474 #endif
475 GCForeground | GCBackground, &gcv);
476
477 gcv.foreground = PixColors [bgColor];
478 gcv.background = PixColors [fgColor];
479 Xrvgc = XCreateGC (Xdisplay, Clock.win,
480 #ifdef REMINDERS
481 GCFont |
482 #endif
483 GCForeground | GCBackground, &gcv);
484
485 getXevent ();
486 return EXIT_SUCCESS;
487
488 Malloc_Error:
489 print_error ("malloc error");
490 Abort:
491 print_error ("aborting");
492 return EXIT_FAILURE;
493 }
494
495 /*
496 * translate geometry string to appropriate sizehint
497 */
498 static void
499 geometry2sizehint (mywindow_t * win, const char * geom)
500 {
501 int x, y, flags;
502 unsigned int width, height;
503
504 /* copy in values */
505 szHint.width = win->width;
506 szHint.height = win->height;
507
508 if (geom == NULL)
509 return;
510
511 flags = XParseGeometry (geom, &x, &y, &width, &height);
512
513 if (flags & WidthValue)
514 {
515 szHint.width = width + szHint.base_width;
516 szHint.flags |= USSize;
517 }
518 if (flags & HeightValue)
519 {
520 szHint.height = height + szHint.base_height;
521 szHint.flags |= USSize;
522 }
523
524 if (flags & XValue)
525 {
526 if (flags & XNegative)
527 {
528 x += (DisplayWidth (Xdisplay, Xscreen) - szHint.width);
529 szHint.win_gravity = NorthEastGravity;
530 }
531 szHint.x = x;
532 szHint.flags |= USPosition;
533 }
534 if (flags & YValue)
535 {
536 if (flags & YNegative)
537 {
538 y += (DisplayHeight (Xdisplay, Xscreen) - szHint.height);
539 szHint.win_gravity = (szHint.win_gravity == NorthEastGravity ?
540 SouthEastGravity : SouthWestGravity);
541 }
542 szHint.y = y;
543 szHint.flags |= USPosition;
544 }
545
546 /* copy out values */
547 win->width = szHint.width;
548 win->height = szHint.height;
549 }
550
551 /*
552 * Open and map the windows
553 */
554 static void
555 Create_Windows (int argc, char * argv [])
556 {
557 XClassHint classHint;
558 XWMHints wmHint;
559
560 geometry2sizehint (&Clock, rs_geometry);
561 Clock.win = XCreateSimpleWindow (Xdisplay, Xroot,
562 szHint.x, szHint.y,
563 Clock.width, Clock.height,
564 0,
565 PixColors [fgColor],
566 PixColors [bgColor]);
567
568 #ifdef ICONWIN
569 geometry2sizehint (&Icon, rs_iconGeometry);
570 Icon.win = XCreateSimpleWindow (Xdisplay, Xroot,
571 szHint.x, szHint.y,
572 Icon.width, Icon.height,
573 0,
574 PixColors [fgColor],
575 PixColors [bgColor]);
576 wmHint.initial_state = iconic_state;
577 wmHint.icon_window = Icon.win;
578 wmHint.flags = InputHint | StateHint | IconWindowHint;
579 #else
580 wmHint.flags = InputHint;
581 #endif
582 wmHint.input = True;
583
584 /* ignore warning about discarded `const' */
585 classHint.res_name = APL_NAME;
586 classHint.res_class = APL_CLASS;
587 XSetWMProperties (Xdisplay, Clock.win, NULL, NULL, argv, argc,
588 &szHint, &wmHint, &classHint);
589
590 XSelectInput (Xdisplay, Clock.win,
591 (ExposureMask|StructureNotifyMask|ButtonPressMask));
592
593 #ifdef ICONWIN
594 XSelectInput (Xdisplay, Icon.win,
595 (ExposureMask|ButtonPressMask));
596 #endif
597 XMapWindow (Xdisplay, Clock.win);
598
599 /* create, but don't map a window for appointment reminders */
600 #ifdef REMINDERS
601 Msg.win = XCreateSimpleWindow (Xdisplay, Xroot,
602 szHint.x, szHint.y,
603 szHint.width, szHint.height,
604 0,
605 PixColors [fgColor],
606 PixColors [bgColor]);
607
608 szHint.flags |= USPosition;
609 /* ignore warning about discarded `const' */
610 classHint.res_name = MSG_NAME;
611 classHint.res_class = MSG_CLASS;
612 wmHint.input = True;
613 wmHint.flags = InputHint;
614
615 XSetWMProperties (Xdisplay, Msg.win, NULL, NULL, argv, argc,
616 &szHint, &wmHint, &classHint);
617 {
618 char * str = MSG_NAME;
619 XStoreName (Xdisplay, Msg.win, str);
620 XSetIconName (Xdisplay, Msg.win, str);
621 }
622
623 XSelectInput (Xdisplay, Msg.win,
624 (ExposureMask|ButtonPressMask|KeyPressMask));
625
626 /* font already loaded */
627
628 msgButton.width = 4 + 5 * XTextWidth (Xfont, "M", 1);
629 msgButton.height = 4 + FontHeight ();
630
631 msgButton.Dismiss = XCreateSimpleWindow (Xdisplay, Msg.win,
632 0, 0,
633 msgButton.width, msgButton.height,
634 0,
635 PixColors [bgColor],
636 PixColors [fgColor]);
637
638 XMapWindow (Xdisplay, msgButton.Dismiss);
639
640 msgButton.Defer = XCreateSimpleWindow (Xdisplay, Msg.win,
641 0, 0,
642 msgButton.width, msgButton.height,
643 0,
644 PixColors [bgColor],
645 PixColors [fgColor]);
646 XMapWindow (Xdisplay, msgButton.Defer);
647
648 #ifndef NO_REMINDER_EXEC
649 msgButton.Start = XCreateSimpleWindow (Xdisplay, Msg.win,
650 0, 0,
651 msgButton.width, msgButton.height,
652 0,
653 PixColors [bgColor],
654 PixColors [fgColor]);
655 XMapWindow (Xdisplay, msgButton.Start);
656 #endif /* NO_REMINDER_EXEC */
657 #endif
658 }
659
660 static time_t
661 mk_time (struct tm * tmval)
662 {
663 return (tmval->tm_min
664 + 60 * (tmval->tm_hour
665 + 24 * (tmval->tm_mday
666 + 31 * ((tmval->tm_mon+1)
667 + 12 * tmval->tm_year))));
668 }
669
670
671 #ifdef MAIL
672 static int
673 MailAvailable()
674 {
675 struct stat st;
676
677 if( is_maildir ) {
678 DIR *dirp;
679 struct dirent *d;
680
681 if( (dirp=opendir( mail_file )) ) {
682 while( (d=readdir(dirp)) ) {
683 if( *d->d_name == '.' )
684 continue;
685 if( isdigit(*d->d_name) ) {
686 closedir(dirp);
687 return 1;
688 }
689 }
690 closedir(dirp);
691 }
692 return 0;
693 }
694 else
695 return !stat(mail_file, &st) &&
696 (st.st_size > 0) && (st.st_mtime >= st.st_atime);
697 }
698 #endif
699
700 /*----------------------------------------------------------------------*
701 * Redraw the whole window after an exposure or size change.
702 * After a timeout, only redraw the hands.
703 * Provide reminder if needed.
704 *----------------------------------------------------------------------*/
705 static void
706 Draw_Window (mywindow_t * W, int full_redraw)
707 {
708 /* pre-computed values for sin() x1000, to avoid using floats */
709 static const short Sin [720] = {
710 0,
711 9, 17, 26, 35, 44, 52, 61, 70, 78, 87, 96, 105,
712 113, 122, 131, 139, 148, 156, 165, 174, 182, 191, 199, 208,
713 216, 225, 233, 242, 250, 259, 267, 276, 284, 292, 301, 309,
714 317, 326, 334, 342, 350, 358, 367, 375, 383, 391, 399, 407,
715 415, 423, 431, 438, 446, 454, 462, 469, 477, 485, 492, 500,
716 508, 515, 522, 530, 537, 545, 552, 559, 566, 574, 581, 588,
717 595, 602, 609, 616, 623, 629, 636, 643, 649, 656, 663, 669,
718 676, 682, 688, 695, 701, 707, 713, 719, 725, 731, 737, 743,
719 749, 755, 760, 766, 772, 777, 783, 788, 793, 799, 804, 809,
720 814, 819, 824, 829, 834, 839, 843, 848, 853, 857, 862, 866,
721 870, 875, 879, 883, 887, 891, 895, 899, 903, 906, 910, 914,
722 917, 921, 924, 927, 930, 934, 937, 940, 943, 946, 948, 951,
723 954, 956, 959, 961, 964, 966, 968, 970, 972, 974, 976, 978,
724 980, 982, 983, 985, 986, 988, 989, 990, 991, 993, 994, 995,
725 995, 996, 997, 998, 998, 999, 999, 999, 1000, 1000, 1000, 1000,
726 1000, 1000, 1000, 999, 999, 999, 998, 998, 997, 996, 995, 995,
727 994, 993, 991, 990, 989, 988, 986, 985, 983, 982, 980, 978,
728 976, 974, 972, 970, 968, 966, 964, 961, 959, 956, 954, 951,
729 948, 946, 943, 940, 937, 934, 930, 927, 924, 921, 917, 914,
730 910, 906, 903, 899, 895, 891, 887, 883, 879, 875, 870, 866,
731 862, 857, 853, 848, 843, 839, 834, 829, 824, 819, 814, 809,
732 804, 799, 793, 788, 783, 777, 772, 766, 760, 755, 749, 743,
733 737, 731, 725, 719, 713, 707, 701, 695, 688, 682, 676, 669,
734 663, 656, 649, 643, 636, 629, 623, 616, 609, 602, 595, 588,
735 581, 574, 566, 559, 552, 545, 537, 530, 523, 515, 508, 500,
736 492, 485, 477, 469, 462, 454, 446, 438, 431, 423, 415, 407,
737 399, 391, 383, 375, 367, 358, 350, 342, 334, 326, 317, 309,
738 301, 292, 284, 276, 267, 259, 250, 242, 233, 225, 216, 208,
739 199, 191, 182, 174, 165, 156, 148, 139, 131, 122, 113, 105,
740 96, 87, 78, 70, 61, 52, 44, 35, 26, 17, 9, 0,
741 -9, -17, -26, -35, -44, -52, -61, -70, -78, -87, -96, -105,
742 -113, -122, -131, -139, -148, -156, -165, -174, -182, -191, -199, -208,
743 -216, -225, -233, -242, -250, -259, -267, -276, -284, -292, -301, -309,
744 -317, -326, -334, -342, -350, -358, -366, -375, -383, -391, -399, -407,
745 -415, -423, -431, -438, -446, -454, -462, -469, -477, -485, -492, -500,
746 -508, -515, -522, -530, -537, -545, -552, -559, -566, -574, -581, -588,
747 -595, -602, -609, -616, -623, -629, -636, -643, -649, -656, -663, -669,
748 -676, -682, -688, -695, -701, -707, -713, -719, -725, -731, -737, -743,
749 -749, -755, -760, -766, -772, -777, -783, -788, -793, -799, -804, -809,
750 -814, -819, -824, -829, -834, -839, -843, -848, -853, -857, -862, -866,
751 -870, -875, -879, -883, -887, -891, -895, -899, -903, -906, -910, -914,
752 -917, -921, -924, -927, -930, -934, -937, -940, -943, -946, -948, -951,
753 -954, -956, -959, -961, -964, -966, -968, -970, -972, -974, -976, -978,
754 -980, -982, -983, -985, -986, -988, -989, -990, -991, -993, -994, -995,
755 -995, -996, -997, -998, -998, -999, -999, -999, -1000, -1000, -1000, -1000,
756 -1000, -1000, -1000, -999, -999, -999, -998, -998, -997, -996, -995, -995,
757 -994, -993, -991, -990, -989, -988, -986, -985, -983, -982, -980, -978,
758 -976, -974, -972, -970, -968, -966, -964, -961, -959, -956, -954, -951,
759 -948, -946, -943, -940, -937, -934, -930, -927, -924, -921, -917, -914,
760 -910, -906, -903, -899, -895, -891, -887, -883, -879, -875, -870, -866,
761 -862, -857, -853, -848, -843, -839, -834, -829, -824, -819, -814, -809,
762 -804, -799, -793, -788, -783, -777, -772, -766, -760, -755, -749, -743,
763 -737, -731, -725, -719, -713, -707, -701, -695, -688, -682, -676, -669,
764 -663, -656, -649, -643, -636, -629, -623, -616, -609, -602, -595, -588,
765 -581, -574, -566, -559, -552, -545, -537, -530, -523, -515, -508, -500,
766 -492, -485, -477, -469, -462, -454, -446, -438, -431, -423, -415, -407,
767 -399, -391, -383, -375, -367, -358, -350, -342, -334, -326, -317, -309,
768 -301, -292, -284, -276, -267, -259, -250, -242, -233, -225, -216, -208,
769 -199, -191, -182, -174, -165, -156, -148, -139, -131, -122, -113, -105,
770 -96, -87, -78, -70, -61, -52, -44, -35, -26, -17, -9,
771 };
772
773 static int savedDay = -1;
774
775 time_t currentTime;
776 struct tm * tmval;
777 int ctr_x, ctr_y;
778
779 typedef struct {
780 int h_x, h_y; /* hour */
781 int m_x, m_y; /* minute */
782 int s_x, s_y; /* second */
783 } hands_t; /* hand positions (x,y) */
784
785 hands_t HandsNow, * pHandsOld;
786
787 GC X_gc, X_rvgc;
788
789 static hands_t HandsOld = { -1 };
790 #ifdef ICONWIN
791 static hands_t HandsOld_icon = { -1 };
792 #endif
793 #ifdef REMINDERS
794 static int lastUpdateTime = -10;
795 #endif
796
797 #ifdef MAIL
798 static time_t mailTime = 0;
799 static int MailUp = 0, MailUp_rvideo = 0;
800 #ifdef ICONWIN
801 static int MailUp_icon = 0;
802 #endif
803 #endif /* MAIL */
804
805 currentTime = time (NULL) + adjustTime; /* get the current time */
806 tmval = localtime (&currentTime);
807
808 #ifdef MAIL
809 #ifdef REMINDERS
810 if (W->win != Msg.win)
811 #endif
812 {
813 int * pMailUp = (
814 #ifdef ICONWIN
815 W->win == Icon.win ? &MailUp_icon :
816 #endif
817 &MailUp);
818
819 if ((currentTime - mailTime) >= mailUpdate)
820 {
821 struct stat st;
822
823 if (
824 #ifdef ICONWIN
825 MailUp != MailUp_icon ? MailUp :
826 #endif
827 ((mail_file != NULL) && MailAvailable() ) )
828 {
829 if (!*pMailUp)
830 {
831 *pMailUp = 1;
832 full_redraw = 1;
833 XSetWindowBackground (Xdisplay, W->win,
834 PixColors [fgColor]);
835 #ifdef MAIL_BELL
836 XBell (Xdisplay, 0);
837 #endif
838 }
839 }
840 else
841 {
842 if (*pMailUp)
843 {
844 *pMailUp = 0;
845 full_redraw = 1;
846 XSetWindowBackground (Xdisplay, W->win,
847 PixColors [bgColor]);
848 }
849 }
850 #ifdef ICONWIN
851 if (MailUp == MailUp_icon)
852 #endif
853 mailTime = currentTime;
854
855 MailUp_rvideo = *pMailUp;
856 }
857 }
858 #endif /* MAIL */
859
860 /* once every day, update the window and icon name */
861 if (tmval->tm_yday != savedDay)
862 {
863 char str [20];
864
865 savedDay = tmval->tm_yday;
866 strftime (str, sizeof(str), "%a %h %d", tmval);
867 XStoreName (Xdisplay, Clock.win, str);
868 XSetIconName (Xdisplay, Clock.win, str);
869 }
870
871 if (full_redraw)
872 XClearWindow (Xdisplay, W->win);
873
874 #ifdef REMINDERS
875 /* for a message window, just re-draw the message */
876 if (W->win == Msg.win)
877 {
878 char * beg, * next;
879 int lines;
880
881 for (beg = message, lines = 0; beg; beg = next, lines++)
882 {
883 char * end;
884
885 if ((end = strstr (beg, "\\n")) == NULL)
886 {
887 end = beg + strlen (beg);
888 next = NULL;
889 }
890 else
891 {
892 next = end + 2;
893 }
894
895 XDrawString (Xdisplay, Msg.win,
896 Xgc,
897 (Msg.width -
898 XTextWidth (Xfont, beg, (end-beg))) / 2,
899 10 + Xfont->ascent + FontHeight () * lines,
900 beg, (end-beg));
901 }
902
903 XDrawString (Xdisplay, msgButton.Dismiss,
904 Xrvgc,
905 (msgButton.width - XTextWidth (Xfont, "Done", 4)) / 2,
906 Xfont->ascent + 2,
907 "Done", 4);
908
909 XDrawString (Xdisplay, msgButton.Defer,
910 Xrvgc,
911 (msgButton.width - XTextWidth (Xfont, "Defer", 5)) / 2,
912 Xfont->ascent + 2,
913 "Defer", 5);
914
915 # ifndef NO_REMINDER_EXEC
916 XDrawString (Xdisplay, msgButton.Start,
917 Xrvgc,
918 (msgButton.width - XTextWidth (Xfont, "Start", 5)) / 2,
919 Xfont->ascent + 2,
920 "Start", 5);
921
922 if (strlen (execPrgm) > 1)
923 XMapWindow (Xdisplay, msgButton.Start);
924 else
925 XUnmapWindow (Xdisplay, msgButton.Start);
926 # endif /* NO_REMINDER_EXEC */
927 return;
928 }
929
930 /*
931 * Convert multi-field time info to a single integer with a resolution
932 * in minutes.
933 */
934 currentTime = mk_time (tmval);
935
936 /* is there a reminder pending? */
937 if (reminderTime >= 0 && currentTime >= reminderTime)
938 Reminder ();
939
940 /* every 10 minutes, or at start of day, check for revised entries */
941 if (!Msg_Mapped &&
942 (currentTime > lastUpdateTime + REMINDERS_TIME ||
943 (currentTime != lastUpdateTime &&
944 tmval->tm_hour == 0 && tmval->tm_min == 0)))
945 {
946 Next_Reminder (UPDATE);
947 lastUpdateTime = currentTime;
948 }
949 #endif
950
951 /*
952 * draw clock
953 */
954
955 ctr_x = (W->width / 2);
956 ctr_y = (W->height / 2);
957
958 #define XPOS(i,val) (ctr_x + (W->width * Sin[i%720] * (val) + 100000) / 200000)
959 #define YPOS(i,val) (ctr_y - (W->height * Sin[(i+180)%720] * (val) + 100000) / 200000)
960 /*
961 * how to draw the clock face
962 */
963
964 /* calculate the positions of the hands */
965 {
966 int angle = (tmval->tm_hour % 12) * 60 + tmval->tm_min;
967 HandsNow.h_x = XPOS (angle, 60);
968 HandsNow.h_y = YPOS (angle, 60);
969 }
970 {
971 int angle = (tmval->tm_min * 12);
972 HandsNow.m_x = XPOS (angle, 80);
973 HandsNow.m_y = YPOS (angle, 80);
974 }
975 if (clockUpdate == 1)
976 {
977 int angle = (tmval->tm_sec * 12);
978 HandsNow.s_x = XPOS (angle, 85);
979 HandsNow.s_y = YPOS (angle, 85);
980 }
981
982 pHandsOld = (
983 #ifdef ICONWIN
984 W->win == Icon.win ? &HandsOld_icon :
985 #endif
986 &HandsOld);
987
988 #ifdef MAIL
989 if (MailUp_rvideo)
990 {
991 X_gc = Xrvgc;
992 X_rvgc = Xgc;
993 }
994 else
995 #endif
996 {
997 X_gc = Xgc;
998 X_rvgc = Xrvgc;
999 }
1000
1001 /*
1002 * Draw the date in the lower half of the clock window.
1003 * The code is enclosed in REMINDERS because it uses the same
1004 * font as the reminders code.
1005 * I believe this should be drawn always so it does not get
1006 * "swept away" by the minute hand.
1007 */
1008 #if defined(REMINDERS) && defined(DATE_ON_CLOCK_FACE)
1009 if( show_date)
1010 {
1011 char date[10];
1012 currentTime = time (NULL) + adjustTime; /* get the current time */
1013 tmval = localtime (&currentTime);
1014 strftime (date, sizeof(date), "%d", tmval);
1015 XDrawString (Xdisplay, W->win, X_gc,
1016 ctr_x - XTextWidth(Xfont, date, strlen(date))/2,
1017 ctr_y + FontHeight() + (ctr_y - FontHeight())/2,
1018 date, strlen(date));
1019 }
1020 #endif
1021
1022 if (full_redraw)
1023 {
1024 int mintick;
1025 /*
1026 * draw clock face
1027 */
1028 #ifdef SUBTICKS
1029 for (mintick = 0; mintick < 60; mintick++)
1030 XDrawPoint (Xdisplay, W->win, X_gc,
1031 XPOS ((mintick * 12), 95),
1032 YPOS ((mintick * 12), 95));
1033 #endif
1034 for (mintick = 0; mintick < 60; mintick += 5)
1035 XDrawLine (Xdisplay, W->win, X_gc,
1036 XPOS ((mintick * 12), 90),
1037 YPOS ((mintick * 12), 90),
1038 XPOS ((mintick * 12), 100),
1039 YPOS ((mintick * 12), 100));
1040 }
1041 else if (memcmp (pHandsOld, &HandsNow, sizeof(hands_t)))
1042 {
1043 int i, j;
1044 /*
1045 * erase old hands
1046 */
1047 for (i = -1; i < 2; i++) for (j = -1; j < 2; j++)
1048 {
1049 /* hour/minute hands */
1050 XDrawLine (Xdisplay, W->win, X_rvgc,
1051 ctr_x + i,
1052 ctr_y + j,
1053 pHandsOld->h_x, pHandsOld->h_y);
1054 XDrawLine (Xdisplay, W->win, X_rvgc,
1055 ctr_x + i,
1056 ctr_y + j,
1057 pHandsOld->m_x, pHandsOld->m_y);
1058 }
1059
1060 if (clockUpdate == 1) /* seconds hand */
1061 XDrawLine (Xdisplay,
1062 W->win, X_rvgc,
1063 ctr_x,
1064 ctr_y,
1065 pHandsOld->s_x, pHandsOld->s_y);
1066 }
1067
1068 if (full_redraw || memcmp (pHandsOld, &HandsNow, sizeof(hands_t)))
1069 {
1070 int i, j;
1071 /*
1072 * draw new hands
1073 */
1074 for (i = -1; i < 2; i++) for (j = -1; j < 2; j++)
1075 {
1076 /* hour/minute hands */
1077 XDrawLine (Xdisplay, W->win, X_gc,
1078 ctr_x + i,
1079 ctr_y + j,
1080 HandsNow.h_x, HandsNow.h_y);
1081
1082 XDrawLine (Xdisplay, W->win, X_gc,
1083 ctr_x + i,
1084 ctr_y + j,
1085 HandsNow.m_x, HandsNow.m_y);
1086 }
1087 if (clockUpdate == 1) /* seconds hand */
1088 XDrawLine (Xdisplay, W->win, X_gc,
1089 ctr_x,
1090 ctr_y,
1091 HandsNow.s_x, HandsNow.s_y);
1092
1093 *pHandsOld = HandsNow;
1094 }
1095 }
1096
1097 #ifdef REMINDERS
1098 /*
1099 * Read a single integer from *pstr, returns default value if it finds "*"
1100 * DELIM = trailing delimiter to skip
1101 */
1102 static int
1103 GetOneNum (char ** pstr, int def)
1104 {
1105 int num, hit = 0;
1106
1107 for (num = 0; isdigit (**pstr); (*pstr)++)
1108 {
1109 num = num * 10 + (**pstr - '0');
1110 hit = 1;
1111 }
1112 if (!hit)
1113 {
1114 num = def;
1115 while (**pstr == '*') (*pstr)++;
1116 }
1117 return num;
1118 }
1119
1120 /*
1121 * find if TODAY is found in PSTR
1122 */
1123 static int
1124 isToday (char ** pstr, int wday)
1125 {
1126 const char * dayNames = DAY_NAMES;
1127 int rval, today;
1128
1129 today = dayNames [wday];
1130 /* no day specified is same as wildcard */
1131 if (!strchr (dayNames, tolower (**pstr)))
1132 return 1;
1133
1134 for (rval = 0; strchr (dayNames, tolower (**pstr)); (*pstr)++)
1135 {
1136 if (today == tolower (**pstr) || **pstr == '*')
1137 rval = 1; /* found it */
1138 }
1139 return rval;
1140 }
1141
1142 static char *
1143 trim_string (char * str)
1144 {
1145 if (str && *str)
1146 {
1147 int n;
1148 while (*str && isspace (*str)) str++;
1149
1150 n = strlen (str) - 1;
1151 while (n > 0 && isspace (str [n])) n--;
1152 str [n+1] = '\0';
1153 }
1154 return str;
1155 }
1156
1157 # ifndef NO_REMINDER_EXEC
1158 static char *
1159 extract_program (char * text)
1160 {
1161 char * prgm = text;
1162 while ((prgm = strchr (prgm, ';')) != NULL)
1163 {
1164 if (*(prgm-1) == '\\') /* backslash escaped */
1165 {
1166 /* remove backslash - avoid memmove() */
1167 int i, n = strlen (prgm);
1168 for (i = 0; i <= n; i++)
1169 prgm [i - 1] = prgm [i];
1170 }
1171 else
1172 {
1173 *prgm++ = '\0';
1174 /* remove leading/trailing space */
1175 prgm = trim_string (prgm);
1176 break;
1177 }
1178 }
1179 return prgm;
1180 }
1181 # endif /* NO_REMINDER_EXEC */
1182
1183 /*
1184 * Read the ~/.rclock file and find the next reminder
1185 *
1186 * update_only = 1
1187 * look for a reminder whose time is greater than the current time,
1188 * but less than the currently set reminder time
1189 *
1190 * update_only = 0
1191 * look for a reminder whose time is greater than the reminder that
1192 * just went off
1193 */
1194 static void
1195 Next_Reminder (int update_only)
1196 {
1197 struct tm * tmval;
1198 char buffer [256];
1199 #ifndef INT_MAX
1200 # define INT_MAX 1e8
1201 #endif
1202 time_t currentTime;
1203 int savedTime = INT_MAX;
1204 FILE * fd;
1205
1206 if (reminders_file == NULL || (fd = fopen (reminders_file, "r")) == NULL)
1207 {
1208 reminderTime = -1; /* no config file, no reminders */
1209 return;
1210 }
1211
1212 currentTime = time (NULL) + adjustTime; /* get the current time */
1213 tmval = localtime (&currentTime);
1214 currentTime = mk_time (tmval);
1215
1216 /* initial startup*/
1217 if (reminderTime < 0)
1218 {
1219 /* ignore reminders that have already occurred */
1220 reminderTime = currentTime;
1221 # ifndef NO_REMINDER_EXEC
1222 /* scan for programs run on start-up */
1223 while (fgets (buffer, sizeof(buffer), fd))
1224 {
1225 char * prgm, * text;
1226
1227 text = trim_string (buffer);
1228 if (*text != ';') continue;
1229
1230 prgm = extract_program (text);
1231 if (prgm != NULL && strlen (prgm) > 1)
1232 system (prgm);
1233 }
1234 rewind (fd);
1235 # endif /* NO_REMINDER_EXEC */
1236 }
1237
1238 /* now scan for next reminder */
1239 while (fgets (buffer, sizeof(buffer), fd))
1240 {
1241 int testTime, hh, mm, mo, dd, yy;
1242 char * text;
1243
1244 text = trim_string (buffer);
1245 if (*text == '#') continue; /* comment */
1246 if (*text == ';') continue; /* program run on startup */
1247 /*
1248 * parse the line, format is hh:mm mo/dd/yr message; program
1249 * any of hh, mm, mo, dd, yr could be a wildcard `*'
1250 */
1251 hh = GetOneNum (&text, tmval->tm_hour); if (*text == ':') text++;
1252 mm = GetOneNum (&text, 0);
1253
1254 while (isspace (*text)) text++;
1255 if (!isToday (&text, tmval->tm_wday)) continue;
1256 while (isspace (*text)) text++;
1257
1258 mo = GetOneNum (&text, tmval->tm_mon+1); if (*text == '/') text++;
1259 dd = GetOneNum (&text, tmval->tm_mday); if (*text == '/') text++;
1260 yy = GetOneNum (&text, tmval->tm_year);
1261
1262 /* handle 20th/21st centuries */
1263 if (yy > CENTURY)
1264 yy -= 1900;
1265 else if (yy < CENTURY)
1266 yy += (CENTURY - 1900);
1267
1268 while (isspace (*text)) text++;
1269 if (!*text) continue;
1270
1271 testTime = (mm + 60 * (hh + 24 * (dd + 31 * (mo + 12 * yy))));
1272
1273 if (testTime > (update_only ? currentTime : reminderTime))
1274 {
1275 #ifndef NO_REMINDER_EXEC
1276 char * prgm = extract_program (text);
1277 #endif /* NO_REMINDER_EXEC */
1278 /* trim leading/trailing space */
1279 text = trim_string (text);
1280
1281 /*
1282 * have a reminder whose time is greater than the last
1283 * reminder, now make sure it is the smallest available
1284 */
1285 if (testTime < savedTime)
1286 {
1287 savedTime = testTime;
1288 strncpy (message, text, sizeof(message));
1289 #ifndef NO_REMINDER_EXEC
1290 strncpy (execPrgm, (prgm ? prgm : ""), sizeof(execPrgm));
1291 #endif
1292 }
1293 else if (testTime == savedTime)
1294 {
1295 if (strlen (text))
1296 {
1297 int n = (sizeof(message) - strlen (message) - 3);
1298 if (n > 0)
1299 {
1300 /* for co-occurring events */
1301 strcat (message, "\\n");
1302 strncat (message, text, n);
1303 }
1304 }
1305 #ifndef NO_REMINDER_EXEC
1306 if (prgm != NULL)
1307 {
1308 int n = (sizeof(execPrgm) - strlen (execPrgm) - 2);
1309 if ((n > 0) && (n >= strlen (prgm)))
1310 {
1311 /* for co-occurring programs */
1312 switch (execPrgm[strlen (execPrgm)-1])
1313 {
1314 case '&':
1315 case ';':
1316 break;
1317 default:
1318 strcat (execPrgm, ";");
1319 break;
1320 }
1321 strncat (execPrgm, prgm, n);
1322 }
1323 }
1324 #endif /* NO_REMINDER_EXEC */
1325 }
1326 }
1327 }
1328
1329 reminderTime = (savedTime < INT_MAX) ? savedTime : -1;
1330 fclose (fd);
1331 }
1332
1333 /*
1334 * Provide reminder by mapping the message window
1335 */
1336 static void
1337 Reminder (void)
1338 {
1339 char * beg, * next;
1340 int lines;
1341
1342 if (Msg_Mapped)
1343 return;
1344
1345 #ifndef NO_REMINDER_EXEC
1346 if (strlen (message) == 0)
1347 {
1348 if (strlen (execPrgm) > 1)
1349 {
1350 system (execPrgm);
1351 Next_Reminder (REPLACE);
1352 }
1353 return; /* some sort of error */
1354 }
1355 #endif
1356
1357 /* compute the window size */
1358 #ifdef NO_REMINDER_EXEC
1359 Msg.width = 10 * XTextWidth (Xfont, "M", 1);
1360 #else
1361 Msg.width = 18 * XTextWidth (Xfont, "M", 1);
1362 #endif
1363
1364 for (beg = message, lines = 1; beg; beg = next, lines++)
1365 {
1366 int width;
1367 char * end;
1368
1369 if ((end = strstr (beg, "\\n")) == NULL)
1370 {
1371 end = beg + strlen (beg);
1372 next = NULL;
1373 }
1374 else
1375 {
1376 next = end + 2;
1377 }
1378
1379 width = XTextWidth (Xfont, beg, (end-beg));
1380 if (Msg.width < width)
1381 Msg.width = width;
1382 }
1383
1384 Msg.width += 30;
1385 Msg.height = (lines+1) * FontHeight () + 30;
1386
1387 /* resize and centre the window */
1388 XMoveResizeWindow (Xdisplay, Msg.win,
1389 (DisplayWidth (Xdisplay, Xscreen) - Msg.width ) / 2,
1390 (DisplayHeight (Xdisplay, Xscreen) - Msg.height) / 2,
1391 Msg.width, Msg.height);
1392
1393 #define BUTTON_MARGIN 8
1394
1395 XMoveWindow (Xdisplay, msgButton.Dismiss,
1396 BUTTON_MARGIN,
1397 (Msg.height - msgButton.height - BUTTON_MARGIN));
1398 XMoveWindow (Xdisplay, msgButton.Defer,
1399 (Msg.width - msgButton.width - BUTTON_MARGIN),
1400 (Msg.height - msgButton.height - BUTTON_MARGIN));
1401 #ifndef NO_REMINDER_EXEC
1402 XMoveWindow (Xdisplay, msgButton.Start,
1403 (Msg.width - msgButton.width) / 2,
1404 (Msg.height - msgButton.height - BUTTON_MARGIN));
1405 #endif
1406
1407 XMapRaised (Xdisplay, Msg.win);
1408 XBell (Xdisplay, 0);
1409 Msg_Mapped = 1;
1410 }
1411 #endif /* REMINDERS */
1412
1413 #ifndef _POSIX_VERSION
1414 # if defined (__svr4__)
1415 static int
1416 getdtablesize (void)
1417 {
1418 struct rlimit rlim;
1419 getrlimit (RLIMIT_NOFILE, &rlim);
1420 return rlim.rlim_cur;
1421 }
1422 # endif
1423 #endif
1424
1425 /*
1426 * Loops forever, looking for stuff to do. Sleeps 1 minute if nothing to do
1427 */
1428 static void
1429 getXevent (void)
1430 {
1431 XEvent ev;
1432 int num_fds; /* number of file descriptors being used */
1433 struct timeval tm;
1434 struct tm * tmval;
1435 Atom wmDeleteWindow;
1436 fd_set in_fdset;
1437
1438 /* Enable delete window protocol */
1439 wmDeleteWindow = XInternAtom (Xdisplay, "WM_DELETE_WINDOW", False);
1440 XSetWMProtocols (Xdisplay, Clock.win, &wmDeleteWindow, 1);
1441 #ifdef ICONWIN
1442 XSetWMProtocols (Xdisplay, Icon.win, &wmDeleteWindow, 1);
1443 #endif
1444 #ifdef REMINDERS
1445 XSetWMProtocols (Xdisplay, Msg.win, &wmDeleteWindow, 1);
1446 #endif
1447
1448 #ifdef _POSIX_VERSION
1449 num_fds = sysconf (_SC_OPEN_MAX);
1450 #else
1451 num_fds = getdtablesize ();
1452 #endif
1453 #ifdef FD_SETSIZE
1454 if (num_fds > FD_SETSIZE)
1455 num_fds = FD_SETSIZE;
1456 #endif
1457
1458 while (1) {
1459 /* take care of all pending X events */
1460 while (XPending (Xdisplay)) {
1461 XNextEvent (Xdisplay, &ev);
1462 switch (ev.type) {
1463 case ClientMessage:
1464 /* check for delete window requests */
1465 if ((ev.xclient.format == 32) &&
1466 (ev.xclient.data.l[0] == wmDeleteWindow))
1467 {
1468 #ifdef REMINDERS
1469 if (ev.xany.window == Msg.win)
1470 {
1471 XUnmapWindow (Xdisplay, Msg.win);
1472 Msg_Mapped = 0;
1473 Next_Reminder (REPLACE);
1474 }
1475 else
1476 #endif
1477 return; /* delete window is how this terminates */
1478 }
1479 break;
1480
1481 case Expose:
1482 case GraphicsExpose:
1483 /* need to re-draw a window */
1484 if (ev.xany.window == Clock.win)
1485 Draw_Window (&Clock, 1);
1486 #ifdef ICONWIN
1487 else if (ev.xany.window == Icon.win)
1488 Draw_Window (&Icon, 1);
1489 #endif
1490 #ifdef REMINDERS
1491 else
1492 Draw_Window (&Msg, 1);
1493 #endif
1494 break;
1495
1496 case ConfigureNotify:
1497 /* window has been re-sized */
1498 if (ev.xany.window == Clock.win)
1499 {
1500 Clock.width = ev.xconfigure.width;
1501 Clock.height = ev.xconfigure.height;
1502 }
1503 break;
1504
1505 #ifdef REMINDERS
1506 case KeyPress:
1507 /* any key press to dismiss message window */
1508 if (ev.xany.window == Msg.win)
1509 {
1510 Next_Reminder (REPLACE);
1511 Msg_Mapped = 0;
1512 XUnmapWindow (Xdisplay, Msg.win);
1513 }
1514 break;
1515 #endif
1516
1517 case ButtonPress:
1518 #ifdef REMINDERS
1519 /* button press to dismiss message window */
1520 if (ev.xany.window == Msg.win)
1521 {
1522 if (ev.xbutton.subwindow == msgButton.Dismiss)
1523 {
1524 Next_Reminder (REPLACE);
1525 Msg_Mapped = 0;
1526 XUnmapWindow (Xdisplay, Msg.win);
1527 }
1528 else if (ev.xbutton.subwindow == msgButton.Defer)
1529 {
1530 time_t t = time (NULL) + adjustTime;
1531 tmval = localtime (&t);
1532 reminderTime = mk_time (tmval) + DEFER_TIME;
1533 Msg_Mapped = 0;
1534 XUnmapWindow (Xdisplay, Msg.win);
1535 }
1536 #ifndef NO_REMINDER_EXEC
1537 else if (ev.xbutton.subwindow == msgButton.Start)
1538 {
1539 system (execPrgm);
1540 Next_Reminder (REPLACE);
1541 Msg_Mapped = 0;
1542 XUnmapWindow (Xdisplay, Msg.win);
1543 }
1544 #endif /* NO_REMINDER_EXEC */
1545 }
1546 #endif
1547 #ifdef MAIL
1548 if (ev.xany.window == Clock.win)
1549 {
1550 #ifdef MAIL_SPAWN
1551 /* left button action - spawn a mail reader */
1552 if (ev.xbutton.button == Button1)
1553 system (MAIL_SPAWN);
1554 #else
1555 if ( (ev.xbutton.button == Button1) && (mail_spawn != NULL) )
1556 system(mail_spawn);
1557 #endif
1558 /* redraw the window */
1559 Draw_Window (&Clock, 1);
1560 }
1561 #endif
1562 break;
1563 }
1564 }
1565
1566 /* Now wait for time out or new X event */
1567 FD_ZERO (&in_fdset);
1568 FD_SET (Xfd, &in_fdset);
1569 tm.tv_sec = clockUpdate;
1570 tm.tv_usec = 0;
1571 select (num_fds, &in_fdset, NULL, NULL, &tm);
1572
1573 Draw_Window (&Clock, 0);
1574 #ifdef ICONWIN
1575 Draw_Window (&Icon, 0);
1576 #endif
1577 }
1578 }
1579
1580 /*
1581 * Print an error message.
1582 */
1583 static void
1584 print_error (const char * fmt, ...)
1585 {
1586 va_list arg_ptr;
1587
1588 va_start (arg_ptr, fmt);
1589 fprintf (stderr, APL_NAME ": ");
1590 vfprintf (stderr, fmt, arg_ptr);
1591 fprintf (stderr,"\n");
1592 va_end (arg_ptr);
1593 }
1594 /*----------------------- end-of-file (C source) -----------------------*/