home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xautolk.zip / XAUTOLK / xautolock / xautolock.c < prev    next >
C/C++ Source or Header  |  1993-01-28  |  38KB  |  1,390 lines

  1. /***************************************************************************
  2.  *
  3.  * xautolock
  4.  * =========
  5.  *
  6.  * Authors   :  S. De Troch (SDT)
  7.  *              M. Eyckmans (MCE)
  8.  *
  9.  * Date      :  22/07/90
  10.  *
  11.  * Comments  :
  12.  *
  13.  * Review    :  - 12/02/92 (MCE) :
  14.  *                . Hacked around a dxcalendar problem.
  15.  *              - 21/02/92 (MCE) :
  16.  *                . Major rewrite.
  17.  *              - 24/02/92 (MCE) :
  18.  *                . Removed an initialization bug.
  19.  *              - 25/02/92 (MCE) :
  20.  *                . Added code to detect multiple invocations.
  21.  *              - 06/03/92 (MCE) :
  22.  *                . Re-arranged the event loop in order to detect defunct
  23.  *                  children as soon as possible.
  24.  *              - 10/03/92 (SDT & MCE) :
  25.  *                . Added code to detect broken server connections.
  26.  *              - 24/03/92 (MCE) :
  27.  *                . Don't reset the time-out counter after receiving a
  28.  *                  synthetic or otherwise unexpected event.
  29.  *              - 15/04/92 (MCE) :
  30.  *                . Changed the default locker to "xlock 2>&- 1>&-".
  31.  *                . Fixed a couple of event mask bugs. (Thanks to
  32.  *                  jwz@lucid.com for running into these.)
  33.  *                . Corrected a property type bug in CheckConnection ().
  34.  *              - 20/04/92 (MCE) :
  35.  *                . Cut Main () into more managable pieces.
  36.  *                . Periodically call XQueryPointer ().
  37.  *              - 25/04/92 (MCE) :
  38.  *                . Added the `corners' feature. (Suggested by
  39.  *                  weisen@alw.nih.gov.)
  40.  *                . Fixed a problem with pseudo-root windows. (Thanks to
  41.  *                  sherman@unx.sas.com, nedwards@titan.trl.OZ.AU,
  42.  *                  dave@elxr.jpl.Nasa.Gov and tmcconne@sedona.intel.com
  43.  *                  for pointing out the problem and testing the patch.)
  44.  *                . Added `disable/enable on SIGHUP'. (Suggested by
  45.  *                  paul_smith@dg.com.)
  46.  *                . Added support for multiheaded displays. 
  47.  *              - 28/04/92 (MCE) :
  48.  *                . Use the X resource manager.
  49.  *              - 06/05/92 (MCE) :
  50.  *                . Fixed a few potential portability problems. (Thanks
  51.  *                  to paul_smith@dg.com again.)
  52.  *                . CheckConnection () now works properly on multiheaded
  53.  *                  displays. (Thanks to brian@natinst.com for testing
  54.  *                  the `multiheaded' feature.)
  55.  *                . Better version of Sleep().
  56.  *                . Recognize X resources for class "Xautolock".
  57.  *                . Don't update timer while sighupped.
  58.  *                . Switched to vfork () and execl ().
  59.  *                . New copyright notice.
  60.  *              - 11/05/92 (MCE) :
  61.  *                . Close stdout and stderr in stead of using "2>&- 1>&-".
  62.  *                  (Suggested by sinkwitz@ifi.unizh.ch.)
  63.  *                . Added "-noclose" for debugging. 
  64.  *
  65.  * -------------------------------------------------------------------------
  66.  *
  67.  * Please send bug reports to detroch@imec.be or eyckmans@imec.be.
  68.  *
  69.  * -------------------------------------------------------------------------
  70.  *
  71.  * Copyright 1990, 1992 by S. De Troch and MCE.
  72.  *
  73.  * Permission to use, copy, modify and distribute this software and the
  74.  * supporting documentation without fee is hereby granted, provided that :
  75.  *
  76.  *  1 : Both the above copyright notice and this permission notice
  77.  *      appear in all copies of both the software and the supporting
  78.  *      documentation.
  79.  *  2 : You don't make a profit out of it.
  80.  *
  81.  * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  82.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
  83.  * EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  84.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
  85.  * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  86.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  87.  * PERFORMANCE OF THIS SOFTWARE.
  88.  *
  89.  ***************************************************************************/
  90.  
  91.  
  92.  
  93. /*
  94.  *  Have a guess what this does...
  95.  *  ==============================
  96.  *
  97.  *  Warning for swm & tvtwm users : xautolock should *not* be compiled
  98.  *  with vroot.h, because it needs to know the real root window.
  99.  */
  100. #include <stdio.h>
  101. #include <strings.h>
  102. #include <X11/Xlib.h>
  103. #include <X11/Xatom.h>
  104. #include <X11/Xresource.h>
  105. #include <sys/types.h>
  106. #include <sys/wait.h>
  107. #include <signal.h>
  108. #include <memory.h>
  109. #include <math.h>
  110.  
  111. #ifdef AIXV3    
  112. #include <sys/m_wait.h>
  113. #endif /* AIXV3 */
  114.  
  115. #if !defined (news1800) && !defined (sun386)
  116.  
  117. #include <stdlib.h>
  118.  
  119. #ifndef apollo
  120. #include <malloc.h>
  121. #include <unistd.h>
  122. #endif /* apollo */
  123.  
  124. #endif /* !news1800 && !sun386 */
  125.  
  126. #include "patchlevel.h"
  127.  
  128.  
  129.  
  130.  
  131. /*
  132.  *  Usefull macros and customization stuff
  133.  *  ======================================
  134.  */
  135. #ifdef HasPrototypes
  136. #define PP(x)                      x
  137. #else /* HasPrototypes */
  138. #define PP(x)                      ()
  139. #endif /* HasPrototypes */
  140.  
  141.  
  142. #define FALSE                      0       /* as it says                   */
  143. #define TRUE                       1       /* as it says                   */
  144.  
  145. #define ALL_OK                     0       /* for use by exit ()           */
  146. #define PROBLEMS                   1       /* for use by exit ()           */
  147. #define BELL_PERCENT               40      /* as is says                   */
  148. #define MIN_MINUTES                1       /* minimum number of minutes
  149.                           before firing up the locker  */
  150. #define MINUTES                    10      /* default ...                  */
  151. #define MAX_MINUTES                60      /* maximum ...                  */
  152. #define INITIAL_SLEEP              20      /* for machines on which the
  153.                              login sequence takes forever */
  154. #define INCREMENTAL_SLEEP          1       /* time step in seconds         */
  155. #define CREATION_DELAY             30      /* should be > 10 and
  156.                            < min (45,(MIN_MINUTES*30))  */
  157. #define CORNER_SIZE                10      /* size in pixels of the
  158.                             force-lock areas             */
  159. #define CORNER_DELAY               5       /* number of seconds to wait
  160.                           before forcing a lock        */
  161. #define LOCKER                     "xlock" /* NEVER use the -root option!  */
  162. #define CLASS                      "Xautolock"
  163.                             /* as it says                   */
  164.  
  165. #if SystemV == YES
  166. #define vfork                      fork
  167. #endif /* SystemV == YES */
  168.  
  169. #define Main                       main
  170. #define Min(a,b)                   (a < b ? a : b)
  171. #define forever                    for (;;)
  172. #define Output0(str)               (Void) fprintf (stdout, str)
  173. #define Output1(str,arg1)          (Void) fprintf (stdout, str, arg1)
  174. #define Output2(str,arg1,arg2)     (Void) fprintf (stdout, str, arg1, arg2)
  175. #define Error0(str)                (Void) fprintf (stderr, str)
  176. #define Error1(str,arg1)           (Void) fprintf (stderr, str, arg1)
  177. #define Error2(str,arg1,arg2)      (Void) fprintf (stderr, str, arg1, arg2)
  178. #define UpdateTimer(new_val)       if (!sighupped) timer = new_val
  179.  
  180. static void*                       ch_ptr;  /* this is dirty */
  181. #define Skeleton(t,s)              (ch_ptr = (Void*) malloc ((unsigned) s), \
  182.                        ch_ptr == (Void*) NULL                \
  183.                        ?   (Error0 ("Out of memory.\n"),       \
  184.                         (Void) exit (PROBLEMS),              \
  185.                         (t*) NULL                            \
  186.                        )                                     \
  187.                         : (t*) ch_ptr                           \
  188.                                )                                        \
  189.  
  190. #define New(type)                  Skeleton (type, sizeof (type))
  191. #define NewArray(type,nof_elems)   Skeleton (type, sizeof (type) * nof_elems)
  192.  
  193.  
  194.  
  195.  
  196. /*
  197.  *  New types
  198.  *  =========
  199.  */
  200. #if defined (apollo) || defined (news1800)
  201. typedef int                        (*XErrorHandler) PP((Display*,
  202.                                XErrorEvent*));
  203. #endif /* apollo || news1800 */
  204.  
  205. #if defined (news1800) || defined (sun386)
  206. typedef int                        pid_t;
  207. #endif /* news1800  || sun386 */
  208.  
  209. #define Void                       void     /* no typedef because of VAX */
  210. typedef int                        Int;
  211. typedef char                       Char;
  212. typedef char*                      String;
  213. typedef int                        Boolean;
  214. typedef caddr_t                    Caddrt;
  215. typedef unsigned long              Huge;
  216.  
  217. #ifdef HasVoidSignalReturn
  218. #define SigRet                     Void     /* no typedef because of VAX */
  219. #else /* HasVoidSignalReturn */
  220. typedef Int                        SigRet;
  221. #endif /* HasVoidSignalReturn */
  222.  
  223. typedef SigRet                     (*SigHandler) PP((/* OS dependent */));
  224. typedef Boolean                    (*OptAction)  PP((Display*, String,
  225.                              String));
  226. typedef Void                       (*OptChecker) PP((Display*));
  227.  
  228. typedef enum
  229.     {
  230.       IGNORE,                                 /* ignore this corner  */
  231.       DONT_LOCK,                              /* never lock          */
  232.       FORCE_LOCK,                             /* lock immediately    */
  233.     } CornerAction;
  234.  
  235. typedef struct QueueItem_
  236.     {
  237.       Window                   window;        /* as it says          */
  238.       Time                     creationtime;  /* as it says          */
  239.       struct QueueItem_*       next;          /* as it says          */
  240.       struct QueueItem_*       prev;          /* as it says          */
  241.     } aQueueItem, *QueueItem;
  242.  
  243. typedef struct Queue_
  244.     {
  245.       struct QueueItem_*       head;          /* as it says          */
  246.       struct QueueItem_*       tail;          /* as it says          */
  247.     } aQueue, *Queue;
  248.  
  249. typedef struct Opt_
  250.     {
  251.       String                   name;          /* as it says          */
  252.       XrmOptionKind            kind;          /* as it says          */
  253.       Caddrt                   value;         /* XrmOptionNoArg only */
  254.       OptAction                action;        /* as it says          */
  255.       OptChecker               checker;       /* as it says          */
  256.     } anOpt, *Opt;
  257.  
  258.  
  259.  
  260.  
  261. /*
  262.  *  Function declarations
  263.  *  =====================
  264.  */
  265. #ifdef news1800
  266. extern Void*    malloc             PP((unsigned int));
  267. #endif /* news1800 */
  268.  
  269. static Void     Usage              PP((String, Int));
  270. static Void     Sleep              PP((Void));
  271. static Void     EvaluateCounter    PP((Display*));
  272. static Void     QueryPointer       PP((Display*));
  273. static Void     ProcessEvents      PP((Display*, Queue));
  274. static Queue    NewQueue           PP((Void));
  275. static Void     AddToQueue         PP((Queue, Window));
  276. static Void     ProcessQueue       PP((Queue, Display*, Time));
  277. static Void     SelectEvents       PP((Display*, Window, Boolean));
  278. static Void     CheckConnection    PP((Display*, String));
  279. static Int      FetchFalseAlarm    PP((Display*, XEvent));
  280. static Void     ProcessOpts        PP((Display*, Int, String*));
  281. static Boolean  TimeAction         PP((Display*, String, String));
  282. static Boolean  LockerAction       PP((Display*, String, String));
  283. static Boolean  CornersAction      PP((Display*, String, String));
  284. static Boolean  CornerSizeAction   PP((Display*, String, String));
  285. static Boolean  CornerDelayAction  PP((Display*, String, String));
  286. static Boolean  NotifyAction       PP((Display*, String, String));
  287. static Boolean  BellAction         PP((Display*, String, String));
  288. static Boolean  NoCloseAction      PP((Display*, String, String));
  289. static Boolean  HelpAction         PP((Display*, String, String));
  290. static Boolean  VersionAction      PP((Display*, String, String));
  291. static Boolean  GetPositive        PP((String, Int*));
  292. static Void     TimeChecker        PP((Display*));
  293. static Void     NotifyChecker      PP((Display*));
  294. static Void     CornerSizeChecker  PP((Display*));
  295. static Void     BellChecker        PP((Display*));
  296. static SigRet   DisableBySignal    PP((Void));
  297.  
  298.  
  299.  
  300.  
  301. /*
  302.  *  Global variables
  303.  *  ================
  304.  */
  305. static Time          now = 0;               /* number of sleeps since we
  306.                                started (not `Int')        */
  307. static Int           timer = 0;             /* as it says (not `Time')    */
  308. static String        locker = LOCKER;       /* as it says                 */
  309. static Int           time_limit = MINUTES;  /* as it says (not `Time')    */
  310. static Int           notify_margin;         /* as it says (not `Time')    */
  311. static Int           bell_percent = BELL_PERCENT;
  312.                         /* as it says                 */
  313. static Int           corner_size = CORNER_SIZE;
  314.                         /* as it says                 */
  315. static Int           corner_delay = CORNER_DELAY;
  316.                         /* as it says (not `Time')    */
  317. static Boolean       sighupped = FALSE;     /* whether to ignore all
  318.                            time-outs                  */
  319. static Boolean       notify_lock = FALSE;   /* whether to notify the user
  320.                                before locking             */
  321. static CornerAction  corners[4] = { IGNORE, IGNORE, IGNORE, IGNORE };
  322.                                         /* default CornerActions      */
  323. static Boolean       close_output = TRUE;   /* whether to close stdout
  324.                                                and stderr                 */
  325. static anOpt         options[] = 
  326.                   {
  327.                       {"help"       , XrmoptionNoArg   ,
  328.                     (Caddrt) ""  , HelpAction       , (OptChecker) NULL},
  329.                       {"version"    , XrmoptionNoArg   ,
  330.                     (Caddrt) ""  , VersionAction    , (OptChecker) NULL},
  331.                       {"locker"     , XrmoptionSepArg  ,
  332.                     (Caddrt) NULL, LockerAction     , (OptChecker) NULL},
  333.                       {"corners"    , XrmoptionSepArg  ,
  334.                     (Caddrt) NULL, CornersAction    , (OptChecker) NULL},
  335.                       {"cornersize" , XrmoptionSepArg  ,
  336.                     (Caddrt) NULL, CornerSizeAction , CornerSizeChecker},
  337.                       {"cornerdelay", XrmoptionSepArg  ,
  338.                     (Caddrt) NULL, CornerDelayAction, (OptChecker) NULL},
  339.                       {"time"       , XrmoptionSepArg  ,
  340.                     (Caddrt) NULL, TimeAction       , TimeChecker      },
  341.                       {"notify"     , XrmoptionSepArg  ,
  342.                     (Caddrt) NULL, NotifyAction     , NotifyChecker    },
  343.                       {"bell"       , XrmoptionSepArg  ,
  344.                     (Caddrt) NULL, BellAction       , BellChecker      },
  345.                       {"noclose"    , XrmoptionNoArg   ,
  346.                     (Caddrt) ""  , NoCloseAction    , (OptChecker) NULL},
  347.                   };                     /* as it says, the order is
  348.                            important                  */
  349.  
  350.  
  351.  
  352.  
  353. /*
  354.  *  Command line argument related functions
  355.  *  =======================================
  356.  *
  357.  *  Support functions
  358.  *  -----------------
  359.  */
  360. static Boolean  GetPositive (arg, pos)
  361. String  arg;  /* string to scan                  */
  362. Int*    pos;  /* adress where to store the stuff */
  363.  
  364. {
  365.   Char  c;           /* dummy            */
  366.   Int   old = *pos;  /* backup old value */
  367.  
  368.  
  369.   if (   sscanf (arg, "%d%c", pos, &c) == 1
  370.       && *pos >= 0
  371.      )
  372.   {
  373.     return TRUE;
  374.   }
  375.   else
  376.   {
  377.     *pos = old;
  378.     return FALSE;
  379.   }
  380. }
  381.  
  382.  
  383.  
  384. /*
  385.  *  Action functions
  386.  *  ----------------
  387.  */
  388. /*ARGSUSED*/
  389. static Boolean  HelpAction (d, name, arg)
  390. Display*  d;     /* display pointer */
  391. String    name;  /* program name    */
  392. String    arg;   /* argument value  */
  393.  
  394. {
  395.   Usage (name, ALL_OK);
  396.  
  397.   return TRUE;  /* for lint and gcc */
  398. }
  399.  
  400.  
  401. /*ARGSUSED*/
  402. static Boolean  VersionAction (d, name, arg)
  403. Display*  d;     /* display pointer */
  404. String    name;  /* program name    */
  405. String    arg;   /* argument value  */
  406.  
  407. {
  408.   Error2 ("%s : patchlevel %d\n", name, PATCHLEVEL);
  409.   (Void) exit (ALL_OK);
  410.  
  411.   return TRUE;  /* for lint and gcc */
  412. }
  413.  
  414.  
  415. /*ARGSUSED*/
  416. static Boolean  CornerSizeAction (d, name, arg)
  417. Display*  d;     /* display pointer */
  418. String    name;  /* program name    */
  419. String    arg;   /* argument value  */
  420.  
  421. {
  422.   return GetPositive (arg, &corner_size);
  423. }
  424.  
  425.  
  426. /*ARGSUSED*/
  427. static Boolean  CornerDelayAction (d, name, arg)
  428. Display*  d;     /* display pointer */
  429. String    name;  /* program name    */
  430. String    arg;   /* argument value  */
  431.  
  432. {
  433.   return GetPositive (arg, &corner_delay);
  434. }
  435.  
  436.  
  437. /*ARGSUSED*/
  438. static Boolean  TimeAction (d, name, arg)
  439. Display*  d;     /* display pointer */
  440. String    name;  /* program name    */
  441. String    arg;   /* argument value  */
  442.  
  443. {
  444.   return GetPositive (arg, &time_limit);
  445. }
  446.  
  447.  
  448. /*ARGSUSED*/
  449. static Boolean  NotifyAction (d, name, arg)
  450. Display*  d;     /* display pointer */
  451. String    name;  /* program name    */
  452. String    arg;   /* argument value  */
  453.  
  454. {
  455.   return notify_lock = GetPositive (arg, ¬ify_margin);
  456. }
  457.  
  458.  
  459. /*ARGSUSED*/
  460. static Boolean  BellAction (d, name, arg)
  461. Display*  d;     /* display pointer */
  462. String    name;  /* program name    */
  463. String    arg;   /* argument value  */
  464.  
  465. {
  466.   return GetPositive (arg, &bell_percent);
  467. }
  468.  
  469.  
  470. /*ARGSUSED*/
  471. static Boolean  NoCloseAction (d, name, arg)
  472. Display*  d;     /* display pointer */
  473. String    name;  /* program name    */
  474. String    arg;   /* argument value  */
  475.  
  476. {
  477.   close_output = FALSE;
  478.   return TRUE;
  479. }
  480.  
  481.  
  482. /*ARGSUSED*/
  483. static Boolean  LockerAction (d, name, arg)
  484. Display*  d;     /* display pointer */
  485. String    name;  /* program name    */
  486. String    arg;   /* argument value  */
  487.  
  488. {
  489.   locker = arg;
  490.   return TRUE;
  491. }
  492.  
  493.  
  494. /*ARGSUSED*/
  495. static Boolean  CornersAction (d, name, arg)
  496. Display*  d;     /* display pointer */
  497. String    name;  /* program name    */
  498. String    arg;   /* argument value  */
  499.  
  500. {
  501.   Int  c;  /* loop counter */
  502.  
  503.  
  504.   if (strlen (arg) == 4)
  505.   {
  506.     for (c = -1; ++c < 4; )
  507.     {
  508.       switch (arg[c])
  509.       {
  510.     case '0' :
  511.       corners[c] = IGNORE;
  512.       continue;
  513.  
  514.     case '-' :
  515.       corners[c] = DONT_LOCK;
  516.       continue;
  517.  
  518.     case '+' :
  519.       corners[c] = FORCE_LOCK;
  520.       continue;
  521.  
  522.     default :
  523.       return FALSE;
  524.       }
  525.     }
  526.  
  527.     return TRUE;
  528.   }
  529.   else
  530.   {
  531.     return FALSE;
  532.   }
  533. }
  534.  
  535.  
  536.  
  537. /*
  538.  *  Consistency checkers
  539.  *  --------------------
  540.  */
  541. /*ARGSUSED*/
  542. static Void  TimeChecker (d)
  543. Display*  d;  /* display pointer */
  544.  
  545. {
  546.   if (time_limit < MIN_MINUTES)
  547.   {
  548.     Error1 ("Setting time to minimum value of %d minute(s).\n",
  549.             time_limit = MIN_MINUTES);
  550.   }
  551.   else if (time_limit > MAX_MINUTES)
  552.   {
  553.     Error1 ("Setting time to maximum value of %d minute(s).\n",
  554.             time_limit = MAX_MINUTES);
  555.   }
  556.  
  557.   time_limit *= 60; /* convert to seconds */
  558. }
  559.  
  560.  
  561. /*ARGSUSED*/
  562. static Void  NotifyChecker (d)
  563. Display*  d;  /* display pointer */
  564.  
  565. {
  566.   if (   notify_lock
  567.       && notify_margin >= time_limit / 2
  568.      )
  569.   {
  570.     Error1 ("Notification time set to %d seconds.\n",
  571.             notify_margin = time_limit / 2);
  572.   }
  573. }
  574.  
  575.  
  576. /*ARGSUSED*/
  577. static Void  BellChecker (d)
  578. Display*  d;  /* display pointer */
  579.  
  580. {
  581.   if (   bell_percent < 1
  582.       || bell_percent > 100
  583.      )
  584.   {
  585.     Error1 ("Bell percentage set to %d%%.\n",
  586.         bell_percent = BELL_PERCENT);
  587.   }
  588. }
  589.  
  590.  
  591. /*ARGSUSED*/
  592. static Void  CornerSizeChecker (d)
  593. Display*  d;  /* display pointer */
  594.  
  595. {
  596.   Int      s;                /* screen index   */
  597.   Screen*  scr;              /* screen pointer */
  598.   Int      max_corner_size;  /* as it says     */
  599.   
  600.  
  601.   for (max_corner_size = 32000, s = -1; ++s < ScreenCount (d); )
  602.   {
  603.     scr = ScreenOfDisplay (d, s);
  604.  
  605.     if (   max_corner_size > WidthOfScreen (scr) / 4
  606.     || max_corner_size > HeightOfScreen (scr) / 4
  607.        )
  608.     {
  609.       max_corner_size = Min (WidthOfScreen (scr), HeightOfScreen (scr)) / 4;
  610.     }
  611.   }
  612.  
  613.   if (corner_size > max_corner_size)
  614.   {
  615.     Error1 ("Corner size set to %d pixels.\n",
  616.         corner_size = max_corner_size);
  617.   }
  618. }
  619.  
  620.  
  621.  
  622. /*
  623.  *  Function for informing the user about syntax errors
  624.  *  ---------------------------------------------------
  625.  */
  626. static Void  Usage (prog_name, exit_code)
  627. String  prog_name;  /* as it says */
  628. Int     exit_code;  /* as it says */
  629.  
  630. {
  631.   String  blanks;  /* string full of blanks */
  632.   size_t  len;     /* number of blanks      */
  633.  
  634.  
  635.  /*
  636.   *  The relative overhead is enormous here, but who cares.
  637.   *  I'm a perfectionist and Usage () doesn't return anyway.
  638.   */
  639.   len = strlen ("Usage : ") + strlen (prog_name) + 1;
  640.   (Void) memset (blanks = NewArray (Char, len + 1), ' ', len);
  641.   blanks[len] = '\0';
  642.  
  643.  
  644.  /*
  645.   *  This is where the actual work gets done...
  646.   */
  647.   Error0 ("\n");
  648.   Error1 ("Usage : %s ", prog_name);
  649.   Error0 ("[-help][-version][-time minutes][-locker locker]\n");
  650.   Error0 (blanks);
  651.   Error0 ("[-notify margin][-bell percent][-corners xxxx]\n");
  652.   Error0 (blanks);
  653.   Error0 ("[-cornerdelay secs][-cornersize pixels][-noclose]\n");
  654.  
  655.   Error0 ("\n");
  656.   Error0 (" -help              : print this message and exit.\n");
  657.   Error0 (" -version           : print version number and exit.\n");
  658.   Error2 (" -time minutes      : time to lock screen [%d < minutes < %d].\n",
  659.                              MIN_MINUTES, MAX_MINUTES);
  660.   Error0 (" -locker locker     : program used to lock.\n");
  661.   Error0 (" -notify margin     : beep this many seconds before locking.\n");
  662.   Error0 (" -bell percent      : loudness of the beep.\n");
  663.   Error0 (" -corners xxxx      : corner actions (0, +, -) in this order :\n");
  664.   Error0 ("                      topleft topright bottomleft bottomright\n");
  665.   Error0 (" -cornerdelay secs  : time to lock screen in a `+' corner.\n");
  666.   Error0 (" -cornersize pixels : size of corner areas.\n");
  667.   Error0 (" -noclose           : do not close stdout and stderr.\n");
  668.  
  669.   Error0 ("\n");
  670.   Error0 ("Defaults :\n");
  671.  
  672.   Error0 ("\n");
  673.   Error1 ("  time        : %d minutes\n"  , MINUTES     );
  674.   Error1 ("  locker      : %s\n"          , LOCKER      );
  675.   Error0 ("  notify      : don't beep\n"                );
  676.   Error0 ("  bell        : 40%%\n"                      );
  677.   Error0 ("  corners     : 0000\n"                      );
  678.   Error1 ("  cornerdelay : %d seconds\n"  , CORNER_DELAY);
  679.   Error1 ("  cornersize  : %d pixels\n"   , CORNER_SIZE );
  680.  
  681.   Error0 ("\n");
  682.  
  683.   exit (exit_code);
  684. }
  685.  
  686.  
  687.  
  688. /*
  689.  *  Function for processing command line arguments
  690.  *  ----------------------------------------------
  691.  */
  692. static Void  ProcessOpts (d, argc, argv)
  693. Display*  d;       /* display pointer     */
  694. Int       argc;    /* number of arguments */
  695. String    argv[];  /* array of arguments  */
  696.  
  697. {
  698.   Int                nof_options = sizeof (options) / sizeof (anOpt);
  699.                               /* number of supported options   */
  700.   Int                j;           /* loop counter                  */
  701.   Int                l;           /* temporary storage             */
  702.   Char*              ptr;         /* temporary storage             */
  703.   Char               buffer[80];  /* as it says                    */
  704.   Char*              dummy;       /* as it says                    */
  705.   XrmValue           value;       /* resource value container      */
  706.   XrmOptionDescList  xoptions;    /* optionslist in Xlib format    */
  707.   XrmDatabase        db = (XrmDatabase) NULL;
  708.                   /* command line options database */
  709.  
  710.  
  711.  /*
  712.   *  Beautify argv[0].
  713.   */
  714.   for (ptr = argv[0] + strlen (argv[0]) - 1; ptr >= argv[0]; ptr--)
  715.   {
  716.     if (*ptr == '/')
  717.     {
  718.       break;
  719.     }
  720.   }
  721.  
  722.   argv[0] = ptr + 1;
  723.  
  724.  
  725.  /*
  726.   *  Calling XGetDefault () on a dummy resource is the easiest 
  727.   *  way to get both Xrm and d->db initialized.
  728.   */
  729.   (Void) XGetDefault (d, argv[0], "dummy");
  730.  
  731.  
  732.  /*
  733.   *  Parse the command line options into a resource database. (The
  734.   *  command line database and the resource file database are not
  735.   *  merged, because we want to know where exactly each resource
  736.   *  value came from.)
  737.   */
  738.   xoptions = NewArray (XrmOptionDescRec, nof_options);
  739.  
  740.   for (j = -1; ++j < nof_options; )
  741.   {
  742.     l = strlen (options[j].name);
  743.  
  744.     (Void) sprintf (xoptions[j].option = NewArray (Char, l + 2),
  745.                 "-%s", options[j].name);
  746.     (Void) sprintf (xoptions[j].specifier = NewArray (Char, l + 2),
  747.                 ".%s", options[j].name);
  748.     xoptions[j].argKind = options[j].kind;
  749.     xoptions[j].value = options[j].value;
  750.   }
  751.  
  752.   XrmParseCommand (&db, xoptions, nof_options, argv[0], &argc, argv);
  753.  
  754.   if (--argc)
  755.   {
  756.     Usage (argv[0], PROBLEMS);
  757.   }
  758.  
  759.   for (j = -1; ++j < nof_options; )
  760.   {
  761.     free (xoptions[j].option);
  762.     free (xoptions[j].specifier);
  763.   }
  764.  
  765.   free (xoptions);
  766.  
  767.  
  768.  /*
  769.   *  Call the action functions.
  770.   */
  771.   for (j = -1; ++j < nof_options; )
  772.   {
  773.     (Void) sprintf (buffer, "%s%s", argv[0], xoptions[j].specifier);
  774.  
  775.     if (XrmGetResource (db, buffer, (String) NULL, &dummy, &value))
  776.     {
  777.       if (!(*(options[j].action)) (d, argv[0], value.addr))
  778.       {
  779.         Usage (argv[0], PROBLEMS); 
  780.       }
  781.     }
  782.     else if (XrmGetResource (d->db, buffer, (String) NULL, &dummy, &value))
  783.     {
  784.       if (!(*(options[j].action)) (d, argv[0], value.addr))
  785.       {
  786.         Error2 ("Can't interprete \"%s\" for \"%s\", using default.\n", 
  787.             value.addr, buffer);
  788.       }
  789.     }
  790.     else
  791.     {
  792.       (Void) sprintf (buffer, "%s%s", CLASS, xoptions[j].specifier);
  793.  
  794.       if (   XrmGetResource (d->db, buffer, (String) NULL, &dummy, &value)
  795.           && !(*(options[j].action)) (d, argv[0], value.addr)
  796.          )
  797.       {
  798.         Error2 ("Can't interprete \"%s\" for \"%s\", using default.\n", 
  799.             value.addr, buffer);
  800.       }
  801.     }
  802.   }
  803.  
  804.  
  805.  
  806.  /*
  807.   *  Call the consistency checkers.
  808.   */
  809.   for (j = -1; ++j < nof_options; )
  810.   {
  811.     if (options[j].checker != (OptChecker) NULL)
  812.     {
  813.       (*(options[j].checker)) (d);
  814.     }
  815.   }
  816. }
  817.  
  818.  
  819.  
  820.  
  821. /*
  822.  *  Functions related to the window queue
  823.  *  =====================================
  824.  *
  825.  *  Function for creating a new queue
  826.  *  ---------------------------------
  827.  */
  828. static Queue  NewQueue ()
  829.  
  830. {
  831.   Queue  queue;  /* return value */
  832.  
  833.  
  834.   queue = New (aQueue);
  835.   queue->tail = New (aQueueItem);
  836.   queue->head = New (aQueueItem);
  837.  
  838.   queue->tail->next = queue->head;
  839.   queue->head->prev = queue->tail;
  840.   queue->tail->prev = queue->head->next = (QueueItem) NULL;
  841.  
  842.   return queue;
  843. }
  844.  
  845.  
  846.  
  847. /*
  848.  *  Function for adding an item to a queue
  849.  *  --------------------------------------
  850.  */
  851. static Void  AddToQueue (queue, window)
  852. Queue   queue;   /* as it says */
  853. Window  window;  /* as it says */
  854.  
  855. {
  856.   QueueItem  new;  /* new item */
  857.  
  858.  
  859.   new = New (aQueueItem);
  860.  
  861.   new->window = window;
  862.   new->creationtime = now;
  863.   new->next = queue->tail->next;
  864.   new->prev = queue->tail;
  865.   queue->tail->next->prev = new;
  866.   queue->tail->next = new;
  867. }
  868.  
  869.  
  870.  
  871. /*
  872.  *  Function for processing those entries that are old enough
  873.  *  ---------------------------------------------------------
  874.  */
  875. static Void  ProcessQueue (queue, d, age)
  876. Queue     queue;  /* as it says      */
  877. Display*  d;      /* display pointer */
  878. Time      age;    /* required age    */
  879.  
  880. {
  881.   QueueItem  current;  /* as it says */
  882.  
  883.  
  884.   if (now > age)
  885.   {
  886.     current = queue->head->prev;
  887.  
  888.     while (   current->prev
  889.        && current->creationtime + age < now
  890.       )
  891.     {
  892.       SelectEvents (d, current->window, False);
  893.       current = current->prev;
  894.       free (current->next);
  895.     }
  896.  
  897.     current->next = queue->head;
  898.     queue->head->prev = current;
  899.   }
  900. }
  901.  
  902.  
  903.  
  904.  
  905. /*
  906.  *  Functions related to (the lack of) user activity
  907.  *  ================================================
  908.  *
  909.  *  Function for processing the event queue
  910.  *  ---------------------------------------
  911.  */
  912. static Void  ProcessEvents (d, queue)
  913. Display*  d;      /* display pointer */
  914. Queue     queue;  /* as it says      */
  915.  
  916. {
  917.   XEvent  event;  /* as it says */
  918.  
  919.  
  920.  /*
  921.   *  Read whatever is available for reading.
  922.   */
  923.   while (XPending (d))
  924.   {
  925.     if (XCheckMaskEvent (d, SubstructureNotifyMask, &event))
  926.     {
  927.       if (event.type == CreateNotify)
  928.       {
  929.     AddToQueue (queue, event.xcreatewindow.window);
  930.       }
  931.     }
  932.     else
  933.     {
  934.       XNextEvent (d, &event);
  935.     }
  936.  
  937.  
  938.    /*
  939.     *  Reset the counter if and only if the event is of one of
  940.     *  the types we are expecting to get *and* was not generated by
  941.     *  XSendEvent ().
  942.     */
  943.     if (   event.type == KeyPress
  944.     && !event.xany.send_event
  945.        )
  946.     {
  947.       UpdateTimer (0);
  948.     }
  949.   }
  950.  
  951.  
  952.  /*
  953.   *  Check the window queue for entries that are older than
  954.   *  CREATION_DELAY seconds.
  955.   */
  956.   ProcessQueue (queue, d, (Time) CREATION_DELAY);
  957. }
  958.  
  959.  
  960.  
  961. /*
  962.  *  Function for monitoring pointer movements
  963.  *  -----------------------------------------
  964.  */
  965. static Void  QueryPointer (d)
  966. Display*  d;  /* display pointer */
  967.  
  968. {
  969.   Window          dummy_w;            /* as it says                    */
  970.   Int             dummy_c;            /* as it says                    */
  971.   Mask            dummy_m;            /* as it says                    */
  972.   Int             root_x;             /* as it says                    */
  973.   Int             root_y;             /* as it says                    */
  974.   Int             corner;             /* corner index                  */
  975.   Int             i;                  /* loop counter                  */
  976.   static Window   root;               /* root window the pointer is on */
  977.   static Screen*  screen;             /* screen the pointer is on      */
  978.   static Int      prev_root_x = -1;   /* as it says                    */
  979.   static Int      prev_root_y = -1;   /* as it says                    */
  980.   static Boolean  first_call = TRUE;  /* as it says                    */
  981.  
  982.  
  983.  /*
  984.   *  Have a guess...
  985.   */
  986.   if (first_call)
  987.   {
  988.     first_call = FALSE;
  989.     root = DefaultRootWindow (d);
  990.     screen = ScreenOfDisplay (d, DefaultScreen (d));
  991.   }
  992.  
  993.  
  994.  /*
  995.   *  Find out whether the pointer has moved. Using XQueryPointer for this
  996.   *  is gross, but it also is the only way never to mess up propagation
  997.   *  of pointer events.
  998.   *
  999.   *  Remark : Unlike XNextEvent(), XPending () doesn't notice if the
  1000.   *           connection to the server is lost. For this reason, earlier
  1001.   *           versions of xautolock periodically called XNoOp (). But
  1002.   *           why not let XQueryPointer () do the job for us, since
  1003.   *           we now call it every INCREMENTAL_SLEEP seconds anyway?
  1004.   */
  1005.   if (!XQueryPointer (d, root, &root, &dummy_w, &root_x, &root_y,
  1006.               &dummy_c, &dummy_c, &dummy_m))
  1007.   {
  1008.    /*
  1009.     *  Pointer has moved to another screen, so let's find out which one.
  1010.     */
  1011.     for (i = -1; ++i < ScreenCount (d); ) 
  1012.     {
  1013.       if (root == RootWindow (d, i)) 
  1014.       {
  1015.         screen = ScreenOfDisplay (d, i);
  1016.     break;
  1017.       }
  1018.     }
  1019.   }
  1020.  
  1021.   if (   root_x == prev_root_x
  1022.       && root_y == prev_root_y
  1023.      )
  1024.   {
  1025.    /*
  1026.     *  If the pointer has not moved since the previous call and 
  1027.     *  is inside one of the 4 corners, we act according to the
  1028.     *  contents of the "corners" array.
  1029.     */
  1030.     if (   (corner = 0,
  1031.            root_x <= corner_size
  1032.         && root_y <= corner_size
  1033.        )
  1034.     || (corner++,
  1035.            root_x >= WidthOfScreen  (screen) - corner_size - 1
  1036.         && root_y <= corner_size
  1037.        )
  1038.     || (corner++,
  1039.            root_x <= corner_size
  1040.         && root_y >= HeightOfScreen (screen) - corner_size - 1
  1041.        )
  1042.     || (corner++,
  1043.            root_x >= WidthOfScreen  (screen) - corner_size - 1
  1044.         && root_y >= HeightOfScreen (screen) - corner_size - 1
  1045.        )
  1046.        )
  1047.     {
  1048.       switch (corners[corner])
  1049.       {
  1050.     case FORCE_LOCK :
  1051.       if (timer < time_limit - corner_delay + 2)
  1052.       {
  1053.         UpdateTimer (time_limit - corner_delay + 2);
  1054.       }
  1055.       break;
  1056.  
  1057.     case DONT_LOCK :
  1058.       UpdateTimer (0);
  1059.       }
  1060.     }
  1061.   }
  1062.   else
  1063.   {
  1064.     prev_root_x = root_x;
  1065.     prev_root_y = root_y;
  1066.     UpdateTimer (0);
  1067.   }
  1068. }
  1069.  
  1070.  
  1071.  
  1072. /*
  1073.  *  Function for deciding whether to lock
  1074.  *  -------------------------------------
  1075.  */
  1076. static Void  EvaluateCounter (d)
  1077. Display*  d;  /* display pointer */
  1078.  
  1079. {
  1080.   static pid_t  locker_pid = 0;  /* child pid  */
  1081.   static Time   prev_bell = 0;   /* as it says */
  1082.  
  1083.  
  1084.  /*
  1085.   *  Find out whether we should do something special. This can
  1086.   *  be one (or more) of the following :
  1087.   *
  1088.   *   - Wait for the previous locker (if any).
  1089.   *   - Ring the bell, if we were asked to and are about to lock.
  1090.   *   - Start up a new locker if the time limit has been reached.
  1091.   */
  1092.   if (locker_pid)
  1093.   {
  1094.     union wait  status;  /* childs process status */
  1095.  
  1096.  
  1097.     if (!wait3 (&status, WNOHANG, (struct rusage*) NULL))
  1098.     {
  1099.       UpdateTimer (0);
  1100.     }
  1101.     else
  1102.     {
  1103.       locker_pid = 0;
  1104.     }
  1105.   }
  1106.  
  1107.   if (   notify_lock
  1108.       && timer + notify_margin > time_limit
  1109.       && prev_bell < now - notify_margin - 1
  1110.      )
  1111.   {
  1112.     prev_bell = now;
  1113.     XBell (d, bell_percent);
  1114.     XSync (d, 0);
  1115.   }
  1116.  
  1117.   if (timer > time_limit)
  1118.   {
  1119.     if (!locker_pid)
  1120.     {
  1121.       switch (locker_pid = vfork ())
  1122.       {
  1123.     case -1 :
  1124.       locker_pid = 0;
  1125.       break;
  1126.  
  1127.     case 0 :
  1128.       (Void) close (ConnectionNumber (d));
  1129.       (Void) execl ("/bin/sh", "sh", "-c", locker, (String) NULL);
  1130.       (Void) _exit (PROBLEMS);
  1131.  
  1132.     default :
  1133.       UpdateTimer (0);
  1134.       }
  1135.     }
  1136.   }
  1137. }
  1138.  
  1139.  
  1140.  
  1141.  
  1142. /*
  1143.  *  Miscellaneous functions
  1144.  *  =======================
  1145.  *
  1146.  *  X Error handler
  1147.  *  ---------------
  1148.  */
  1149. /*ARGSUSED*/
  1150. static Int  FetchFalseAlarm (d, event)
  1151. Display*  d;      /* display pointer */
  1152. XEvent    event;  /* error event     */
  1153.  
  1154. {
  1155.   return 0;
  1156. }
  1157.  
  1158.  
  1159.  
  1160. /*
  1161.  *  SIGHUP signal handler
  1162.  *  ---------------------
  1163.  */
  1164. static SigRet  DisableBySignal ()
  1165.  
  1166. {
  1167.  /*
  1168.   *  The order in which things are done is rather important here.
  1169.   */
  1170.   UpdateTimer (0);
  1171.   sighupped = !sighupped;
  1172.   (Void) signal (SIGHUP, (SigHandler) DisableBySignal);
  1173.  
  1174. #ifndef HasVoidSignalReturn 
  1175.   return 0;
  1176. #endif /* HasVoidSignalReturn */
  1177. }
  1178.  
  1179.  
  1180.  
  1181. /*
  1182.  *  Lazy function
  1183.  *  -------------
  1184.  */
  1185. static Void  Sleep ()
  1186.  
  1187. {
  1188.   Int  i;  /* loop counter */
  1189.  
  1190.  
  1191.   for (i = -1; ++i < INCREMENTAL_SLEEP; )
  1192.   {
  1193.     (Void) sleep (1);
  1194.     UpdateTimer (timer + 1);
  1195.     now++;
  1196.   }
  1197. }
  1198.  
  1199.  
  1200.  
  1201. /*
  1202.  *  Function for finding out whether another xautolock is already running
  1203.  *  ---------------------------------------------------------------------
  1204.  */
  1205. static Void  CheckConnection (d, prog_name)
  1206. Display*  d;          /* display pointer */
  1207. String    prog_name;  /* as it says      */
  1208.  
  1209. {
  1210.   pid_t   pid;        /* as it says              */
  1211.   Int     kill_val;   /* return value of kill () */
  1212.   Window  r;          /* root window             */
  1213.   Atom    property;   /* property atom           */
  1214.   Atom    type;       /* property type atom      */
  1215.   Int     format;     /* property format         */
  1216.   Huge    nof_items;  /* actual number of items  */
  1217.   Huge    after;      /* dummy                   */
  1218.   pid_t*  contents;   /* actual property value   */
  1219.  
  1220.  
  1221.   r = RootWindowOfScreen (ScreenOfDisplay (d, 0));
  1222.   property = XInternAtom (d, "XAUTOLOCK_SEMAPHORE_PID", False);
  1223.  
  1224.   XGrabServer (d);
  1225.   XGetWindowProperty (d, r, property, 0L, 2L, False, AnyPropertyType,
  1226.               &type, &format, &nof_items, &after,
  1227.               (unsigned char**) &contents);
  1228.  
  1229.   if (type == XA_INTEGER)
  1230.   {
  1231.    /*
  1232.     *  This breaks if the other xautolock is not 
  1233.     *  running on the same machine.
  1234.     */
  1235.     kill_val = kill (*contents, 0);
  1236.  
  1237.     if (kill_val == 0)
  1238.     {
  1239.       Error2 ("%s is already running (PID %d).\n",
  1240.           prog_name, *contents);
  1241.       (Void) exit (PROBLEMS);
  1242.     }
  1243.   }
  1244.  
  1245.   pid = getpid ();
  1246.   XChangeProperty (d, r, property, XA_INTEGER, 8,
  1247.                PropModeReplace, (Char*) &pid, sizeof (pid));
  1248.   XUngrabServer (d);
  1249.  
  1250.   XFree ((Char*) contents);
  1251. }
  1252.  
  1253.  
  1254.  
  1255. /*
  1256.  *  Function for selecting events on a tree of windows
  1257.  *  --------------------------------------------------
  1258.  */
  1259. static Void  SelectEvents (d, window, substructure_only)
  1260. Display*  d;                  /* display pointer   */
  1261. Window    window;             /* window            */
  1262. Boolean   substructure_only;  /* as it says        */
  1263.  
  1264. {
  1265.   Window             root;              /* root window of this window */
  1266.   Window             parent;            /* parent of this window      */
  1267.   Window*            children;          /* children of this window    */
  1268.   Int                nof_children = 0;  /* number of children         */
  1269.   Int                i;                 /* loop counter               */
  1270.   XWindowAttributes  attribs;           /* attributes of the window   */
  1271.  
  1272.  
  1273.  /*
  1274.   *  Start by querying the server about parent and child windows.
  1275.   */
  1276.   if (!XQueryTree (d, window, &root, &parent, &children, &nof_children))
  1277.   {
  1278.     return;
  1279.   }
  1280.  
  1281.  
  1282.  /*
  1283.   *  Build the appropriate event mask. The basic idea is that we don't
  1284.   *  want to interfere with the normal event propagation mechanism if
  1285.   *  we don't have to.
  1286.   */
  1287.   if (substructure_only)
  1288.   {
  1289.     XSelectInput (d, window, SubstructureNotifyMask);
  1290.   }
  1291.   else
  1292.   {
  1293.     if (parent == None)  /* the *real* rootwindow */
  1294.     {
  1295.       attribs.all_event_masks = 
  1296.       attribs.do_not_propagate_mask = KeyPressMask;
  1297.     }
  1298.     else if (XGetWindowAttributes (d, window, &attribs) == 0)
  1299.     {
  1300.       return;
  1301.     }
  1302.  
  1303.     XSelectInput (d, window,   SubstructureNotifyMask
  1304.                      | (  (  attribs.all_event_masks
  1305.                    | attribs.do_not_propagate_mask)
  1306.                 & KeyPressMask));
  1307.   }
  1308.  
  1309.  
  1310.  /*
  1311.   *  Now do the same thing for all children.
  1312.   */
  1313.   for (i = -1; ++i < nof_children; )
  1314.   {
  1315.     SelectEvents (d, children[i], substructure_only);
  1316.   }
  1317.  
  1318.   if (nof_children != 0)
  1319.   {
  1320.     XFree ((Char*) children);
  1321.   }
  1322. }
  1323.  
  1324.  
  1325.  
  1326. /*
  1327.  *  Main function
  1328.  *  -------------
  1329.  */
  1330. Int  Main (argc, argv)
  1331. Int     argc;    /* number of arguments */
  1332. String  argv[];  /* array of arguments  */
  1333.  
  1334. {
  1335.   Display*  d;      /* display pointer */
  1336.   Window    r;      /* root window     */
  1337.   Int       s;      /* screen index    */
  1338.   Queue     queue;  /* as it says      */
  1339.  
  1340.  
  1341.  /*
  1342.   *  Find out whether there actually is a server on the other side...
  1343.   */
  1344.   if (   (d = XOpenDisplay ((String) NULL))
  1345.       == (Display*) NULL
  1346.      )
  1347.   {
  1348.     (Void) exit (PROBLEMS);
  1349.   }
  1350.  
  1351.  
  1352.  /*
  1353.   *  Some initializations.
  1354.   */
  1355.   ProcessOpts (d, argc, argv);
  1356.  
  1357.   XSetErrorHandler ((XErrorHandler) FetchFalseAlarm);
  1358.   CheckConnection (d, argv[0]);
  1359.   (Void) signal (SIGHUP, (SigHandler) DisableBySignal);
  1360.  
  1361.   XSync (d, 0);
  1362.   (Void) sleep (INITIAL_SLEEP);
  1363.  
  1364.   queue = NewQueue ();
  1365.  
  1366.   for (s = -1; ++s < ScreenCount (d); )
  1367.   {
  1368.     AddToQueue (queue, r = RootWindowOfScreen (ScreenOfDisplay (d, s)));
  1369.     SelectEvents (d, r, True);
  1370.   }
  1371.  
  1372.   if (close_output)
  1373.   {
  1374.     (Void) fclose (stdout);
  1375.     (Void) fclose (stderr);
  1376.   }
  1377.  
  1378.  
  1379.  /*
  1380.   *  Main event loop.
  1381.   */
  1382.   forever
  1383.   {
  1384.     Sleep ();
  1385.     ProcessEvents (d, queue);
  1386.     QueryPointer (d);
  1387.     EvaluateCounter (d);
  1388.   }
  1389. }
  1390.