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

# User Rev Content
1 root 1.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 root 1.2 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 root 1.1 }
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 root 1.2 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 root 1.1 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 root 1.2 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 root 1.1 };
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 root 1.2 #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 root 1.1 /*
961     * how to draw the clock face
962     */
963    
964     /* calculate the positions of the hands */
965     {
966 root 1.2 int angle = (tmval->tm_hour % 12) * 60 + tmval->tm_min;
967 root 1.1 HandsNow.h_x = XPOS (angle, 60);
968     HandsNow.h_y = YPOS (angle, 60);
969     }
970     {
971 root 1.2 int angle = (tmval->tm_min * 12);
972 root 1.1 HandsNow.m_x = XPOS (angle, 80);
973     HandsNow.m_y = YPOS (angle, 80);
974     }
975     if (clockUpdate == 1)
976     {
977 root 1.2 int angle = (tmval->tm_sec * 12);
978 root 1.1 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 root 1.2 #if defined(REMINDERS) && defined(DATE_ON_CLOCK_FACE)
1009 root 1.1 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 root 1.2 int mintick;
1025 root 1.1 /*
1026     * draw clock face
1027     */
1028     #ifdef SUBTICKS
1029 root 1.2 for (mintick = 0; mintick < 60; mintick++)
1030 root 1.1 XDrawPoint (Xdisplay, W->win, X_gc,
1031 root 1.2 XPOS ((mintick * 12), 95),
1032     YPOS ((mintick * 12), 95));
1033 root 1.1 #endif
1034 root 1.2 for (mintick = 0; mintick < 60; mintick += 5)
1035 root 1.1 XDrawLine (Xdisplay, W->win, X_gc,
1036 root 1.2 XPOS ((mintick * 12), 90),
1037     YPOS ((mintick * 12), 90),
1038     XPOS ((mintick * 12), 100),
1039     YPOS ((mintick * 12), 100));
1040 root 1.1 }
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 root 1.2 /* 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 root 1.1 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) -----------------------*/