rclock.c 35 KB

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