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 >
Wrap
C/C++ Source or Header
|
1993-01-28
|
38KB
|
1,390 lines
/***************************************************************************
*
* xautolock
* =========
*
* Authors : S. De Troch (SDT)
* M. Eyckmans (MCE)
*
* Date : 22/07/90
*
* Comments :
*
* Review : - 12/02/92 (MCE) :
* . Hacked around a dxcalendar problem.
* - 21/02/92 (MCE) :
* . Major rewrite.
* - 24/02/92 (MCE) :
* . Removed an initialization bug.
* - 25/02/92 (MCE) :
* . Added code to detect multiple invocations.
* - 06/03/92 (MCE) :
* . Re-arranged the event loop in order to detect defunct
* children as soon as possible.
* - 10/03/92 (SDT & MCE) :
* . Added code to detect broken server connections.
* - 24/03/92 (MCE) :
* . Don't reset the time-out counter after receiving a
* synthetic or otherwise unexpected event.
* - 15/04/92 (MCE) :
* . Changed the default locker to "xlock 2>&- 1>&-".
* . Fixed a couple of event mask bugs. (Thanks to
* jwz@lucid.com for running into these.)
* . Corrected a property type bug in CheckConnection ().
* - 20/04/92 (MCE) :
* . Cut Main () into more managable pieces.
* . Periodically call XQueryPointer ().
* - 25/04/92 (MCE) :
* . Added the `corners' feature. (Suggested by
* weisen@alw.nih.gov.)
* . Fixed a problem with pseudo-root windows. (Thanks to
* sherman@unx.sas.com, nedwards@titan.trl.OZ.AU,
* dave@elxr.jpl.Nasa.Gov and tmcconne@sedona.intel.com
* for pointing out the problem and testing the patch.)
* . Added `disable/enable on SIGHUP'. (Suggested by
* paul_smith@dg.com.)
* . Added support for multiheaded displays.
* - 28/04/92 (MCE) :
* . Use the X resource manager.
* - 06/05/92 (MCE) :
* . Fixed a few potential portability problems. (Thanks
* to paul_smith@dg.com again.)
* . CheckConnection () now works properly on multiheaded
* displays. (Thanks to brian@natinst.com for testing
* the `multiheaded' feature.)
* . Better version of Sleep().
* . Recognize X resources for class "Xautolock".
* . Don't update timer while sighupped.
* . Switched to vfork () and execl ().
* . New copyright notice.
* - 11/05/92 (MCE) :
* . Close stdout and stderr in stead of using "2>&- 1>&-".
* (Suggested by sinkwitz@ifi.unizh.ch.)
* . Added "-noclose" for debugging.
*
* -------------------------------------------------------------------------
*
* Please send bug reports to detroch@imec.be or eyckmans@imec.be.
*
* -------------------------------------------------------------------------
*
* Copyright 1990, 1992 by S. De Troch and MCE.
*
* Permission to use, copy, modify and distribute this software and the
* supporting documentation without fee is hereby granted, provided that :
*
* 1 : Both the above copyright notice and this permission notice
* appear in all copies of both the software and the supporting
* documentation.
* 2 : You don't make a profit out of it.
*
* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
***************************************************************************/
/*
* Have a guess what this does...
* ==============================
*
* Warning for swm & tvtwm users : xautolock should *not* be compiled
* with vroot.h, because it needs to know the real root window.
*/
#include <stdio.h>
#include <strings.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <memory.h>
#include <math.h>
#ifdef AIXV3
#include <sys/m_wait.h>
#endif /* AIXV3 */
#if !defined (news1800) && !defined (sun386)
#include <stdlib.h>
#ifndef apollo
#include <malloc.h>
#include <unistd.h>
#endif /* apollo */
#endif /* !news1800 && !sun386 */
#include "patchlevel.h"
/*
* Usefull macros and customization stuff
* ======================================
*/
#ifdef HasPrototypes
#define PP(x) x
#else /* HasPrototypes */
#define PP(x) ()
#endif /* HasPrototypes */
#define FALSE 0 /* as it says */
#define TRUE 1 /* as it says */
#define ALL_OK 0 /* for use by exit () */
#define PROBLEMS 1 /* for use by exit () */
#define BELL_PERCENT 40 /* as is says */
#define MIN_MINUTES 1 /* minimum number of minutes
before firing up the locker */
#define MINUTES 10 /* default ... */
#define MAX_MINUTES 60 /* maximum ... */
#define INITIAL_SLEEP 20 /* for machines on which the
login sequence takes forever */
#define INCREMENTAL_SLEEP 1 /* time step in seconds */
#define CREATION_DELAY 30 /* should be > 10 and
< min (45,(MIN_MINUTES*30)) */
#define CORNER_SIZE 10 /* size in pixels of the
force-lock areas */
#define CORNER_DELAY 5 /* number of seconds to wait
before forcing a lock */
#define LOCKER "xlock" /* NEVER use the -root option! */
#define CLASS "Xautolock"
/* as it says */
#if SystemV == YES
#define vfork fork
#endif /* SystemV == YES */
#define Main main
#define Min(a,b) (a < b ? a : b)
#define forever for (;;)
#define Output0(str) (Void) fprintf (stdout, str)
#define Output1(str,arg1) (Void) fprintf (stdout, str, arg1)
#define Output2(str,arg1,arg2) (Void) fprintf (stdout, str, arg1, arg2)
#define Error0(str) (Void) fprintf (stderr, str)
#define Error1(str,arg1) (Void) fprintf (stderr, str, arg1)
#define Error2(str,arg1,arg2) (Void) fprintf (stderr, str, arg1, arg2)
#define UpdateTimer(new_val) if (!sighupped) timer = new_val
static void* ch_ptr; /* this is dirty */
#define Skeleton(t,s) (ch_ptr = (Void*) malloc ((unsigned) s), \
ch_ptr == (Void*) NULL \
? (Error0 ("Out of memory.\n"), \
(Void) exit (PROBLEMS), \
(t*) NULL \
) \
: (t*) ch_ptr \
) \
#define New(type) Skeleton (type, sizeof (type))
#define NewArray(type,nof_elems) Skeleton (type, sizeof (type) * nof_elems)
/*
* New types
* =========
*/
#if defined (apollo) || defined (news1800)
typedef int (*XErrorHandler) PP((Display*,
XErrorEvent*));
#endif /* apollo || news1800 */
#if defined (news1800) || defined (sun386)
typedef int pid_t;
#endif /* news1800 || sun386 */
#define Void void /* no typedef because of VAX */
typedef int Int;
typedef char Char;
typedef char* String;
typedef int Boolean;
typedef caddr_t Caddrt;
typedef unsigned long Huge;
#ifdef HasVoidSignalReturn
#define SigRet Void /* no typedef because of VAX */
#else /* HasVoidSignalReturn */
typedef Int SigRet;
#endif /* HasVoidSignalReturn */
typedef SigRet (*SigHandler) PP((/* OS dependent */));
typedef Boolean (*OptAction) PP((Display*, String,
String));
typedef Void (*OptChecker) PP((Display*));
typedef enum
{
IGNORE, /* ignore this corner */
DONT_LOCK, /* never lock */
FORCE_LOCK, /* lock immediately */
} CornerAction;
typedef struct QueueItem_
{
Window window; /* as it says */
Time creationtime; /* as it says */
struct QueueItem_* next; /* as it says */
struct QueueItem_* prev; /* as it says */
} aQueueItem, *QueueItem;
typedef struct Queue_
{
struct QueueItem_* head; /* as it says */
struct QueueItem_* tail; /* as it says */
} aQueue, *Queue;
typedef struct Opt_
{
String name; /* as it says */
XrmOptionKind kind; /* as it says */
Caddrt value; /* XrmOptionNoArg only */
OptAction action; /* as it says */
OptChecker checker; /* as it says */
} anOpt, *Opt;
/*
* Function declarations
* =====================
*/
#ifdef news1800
extern Void* malloc PP((unsigned int));
#endif /* news1800 */
static Void Usage PP((String, Int));
static Void Sleep PP((Void));
static Void EvaluateCounter PP((Display*));
static Void QueryPointer PP((Display*));
static Void ProcessEvents PP((Display*, Queue));
static Queue NewQueue PP((Void));
static Void AddToQueue PP((Queue, Window));
static Void ProcessQueue PP((Queue, Display*, Time));
static Void SelectEvents PP((Display*, Window, Boolean));
static Void CheckConnection PP((Display*, String));
static Int FetchFalseAlarm PP((Display*, XEvent));
static Void ProcessOpts PP((Display*, Int, String*));
static Boolean TimeAction PP((Display*, String, String));
static Boolean LockerAction PP((Display*, String, String));
static Boolean CornersAction PP((Display*, String, String));
static Boolean CornerSizeAction PP((Display*, String, String));
static Boolean CornerDelayAction PP((Display*, String, String));
static Boolean NotifyAction PP((Display*, String, String));
static Boolean BellAction PP((Display*, String, String));
static Boolean NoCloseAction PP((Display*, String, String));
static Boolean HelpAction PP((Display*, String, String));
static Boolean VersionAction PP((Display*, String, String));
static Boolean GetPositive PP((String, Int*));
static Void TimeChecker PP((Display*));
static Void NotifyChecker PP((Display*));
static Void CornerSizeChecker PP((Display*));
static Void BellChecker PP((Display*));
static SigRet DisableBySignal PP((Void));
/*
* Global variables
* ================
*/
static Time now = 0; /* number of sleeps since we
started (not `Int') */
static Int timer = 0; /* as it says (not `Time') */
static String locker = LOCKER; /* as it says */
static Int time_limit = MINUTES; /* as it says (not `Time') */
static Int notify_margin; /* as it says (not `Time') */
static Int bell_percent = BELL_PERCENT;
/* as it says */
static Int corner_size = CORNER_SIZE;
/* as it says */
static Int corner_delay = CORNER_DELAY;
/* as it says (not `Time') */
static Boolean sighupped = FALSE; /* whether to ignore all
time-outs */
static Boolean notify_lock = FALSE; /* whether to notify the user
before locking */
static CornerAction corners[4] = { IGNORE, IGNORE, IGNORE, IGNORE };
/* default CornerActions */
static Boolean close_output = TRUE; /* whether to close stdout
and stderr */
static anOpt options[] =
{
{"help" , XrmoptionNoArg ,
(Caddrt) "" , HelpAction , (OptChecker) NULL},
{"version" , XrmoptionNoArg ,
(Caddrt) "" , VersionAction , (OptChecker) NULL},
{"locker" , XrmoptionSepArg ,
(Caddrt) NULL, LockerAction , (OptChecker) NULL},
{"corners" , XrmoptionSepArg ,
(Caddrt) NULL, CornersAction , (OptChecker) NULL},
{"cornersize" , XrmoptionSepArg ,
(Caddrt) NULL, CornerSizeAction , CornerSizeChecker},
{"cornerdelay", XrmoptionSepArg ,
(Caddrt) NULL, CornerDelayAction, (OptChecker) NULL},
{"time" , XrmoptionSepArg ,
(Caddrt) NULL, TimeAction , TimeChecker },
{"notify" , XrmoptionSepArg ,
(Caddrt) NULL, NotifyAction , NotifyChecker },
{"bell" , XrmoptionSepArg ,
(Caddrt) NULL, BellAction , BellChecker },
{"noclose" , XrmoptionNoArg ,
(Caddrt) "" , NoCloseAction , (OptChecker) NULL},
}; /* as it says, the order is
important */
/*
* Command line argument related functions
* =======================================
*
* Support functions
* -----------------
*/
static Boolean GetPositive (arg, pos)
String arg; /* string to scan */
Int* pos; /* adress where to store the stuff */
{
Char c; /* dummy */
Int old = *pos; /* backup old value */
if ( sscanf (arg, "%d%c", pos, &c) == 1
&& *pos >= 0
)
{
return TRUE;
}
else
{
*pos = old;
return FALSE;
}
}
/*
* Action functions
* ----------------
*/
/*ARGSUSED*/
static Boolean HelpAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
Usage (name, ALL_OK);
return TRUE; /* for lint and gcc */
}
/*ARGSUSED*/
static Boolean VersionAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
Error2 ("%s : patchlevel %d\n", name, PATCHLEVEL);
(Void) exit (ALL_OK);
return TRUE; /* for lint and gcc */
}
/*ARGSUSED*/
static Boolean CornerSizeAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
return GetPositive (arg, &corner_size);
}
/*ARGSUSED*/
static Boolean CornerDelayAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
return GetPositive (arg, &corner_delay);
}
/*ARGSUSED*/
static Boolean TimeAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
return GetPositive (arg, &time_limit);
}
/*ARGSUSED*/
static Boolean NotifyAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
return notify_lock = GetPositive (arg, ¬ify_margin);
}
/*ARGSUSED*/
static Boolean BellAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
return GetPositive (arg, &bell_percent);
}
/*ARGSUSED*/
static Boolean NoCloseAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
close_output = FALSE;
return TRUE;
}
/*ARGSUSED*/
static Boolean LockerAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
locker = arg;
return TRUE;
}
/*ARGSUSED*/
static Boolean CornersAction (d, name, arg)
Display* d; /* display pointer */
String name; /* program name */
String arg; /* argument value */
{
Int c; /* loop counter */
if (strlen (arg) == 4)
{
for (c = -1; ++c < 4; )
{
switch (arg[c])
{
case '0' :
corners[c] = IGNORE;
continue;
case '-' :
corners[c] = DONT_LOCK;
continue;
case '+' :
corners[c] = FORCE_LOCK;
continue;
default :
return FALSE;
}
}
return TRUE;
}
else
{
return FALSE;
}
}
/*
* Consistency checkers
* --------------------
*/
/*ARGSUSED*/
static Void TimeChecker (d)
Display* d; /* display pointer */
{
if (time_limit < MIN_MINUTES)
{
Error1 ("Setting time to minimum value of %d minute(s).\n",
time_limit = MIN_MINUTES);
}
else if (time_limit > MAX_MINUTES)
{
Error1 ("Setting time to maximum value of %d minute(s).\n",
time_limit = MAX_MINUTES);
}
time_limit *= 60; /* convert to seconds */
}
/*ARGSUSED*/
static Void NotifyChecker (d)
Display* d; /* display pointer */
{
if ( notify_lock
&& notify_margin >= time_limit / 2
)
{
Error1 ("Notification time set to %d seconds.\n",
notify_margin = time_limit / 2);
}
}
/*ARGSUSED*/
static Void BellChecker (d)
Display* d; /* display pointer */
{
if ( bell_percent < 1
|| bell_percent > 100
)
{
Error1 ("Bell percentage set to %d%%.\n",
bell_percent = BELL_PERCENT);
}
}
/*ARGSUSED*/
static Void CornerSizeChecker (d)
Display* d; /* display pointer */
{
Int s; /* screen index */
Screen* scr; /* screen pointer */
Int max_corner_size; /* as it says */
for (max_corner_size = 32000, s = -1; ++s < ScreenCount (d); )
{
scr = ScreenOfDisplay (d, s);
if ( max_corner_size > WidthOfScreen (scr) / 4
|| max_corner_size > HeightOfScreen (scr) / 4
)
{
max_corner_size = Min (WidthOfScreen (scr), HeightOfScreen (scr)) / 4;
}
}
if (corner_size > max_corner_size)
{
Error1 ("Corner size set to %d pixels.\n",
corner_size = max_corner_size);
}
}
/*
* Function for informing the user about syntax errors
* ---------------------------------------------------
*/
static Void Usage (prog_name, exit_code)
String prog_name; /* as it says */
Int exit_code; /* as it says */
{
String blanks; /* string full of blanks */
size_t len; /* number of blanks */
/*
* The relative overhead is enormous here, but who cares.
* I'm a perfectionist and Usage () doesn't return anyway.
*/
len = strlen ("Usage : ") + strlen (prog_name) + 1;
(Void) memset (blanks = NewArray (Char, len + 1), ' ', len);
blanks[len] = '\0';
/*
* This is where the actual work gets done...
*/
Error0 ("\n");
Error1 ("Usage : %s ", prog_name);
Error0 ("[-help][-version][-time minutes][-locker locker]\n");
Error0 (blanks);
Error0 ("[-notify margin][-bell percent][-corners xxxx]\n");
Error0 (blanks);
Error0 ("[-cornerdelay secs][-cornersize pixels][-noclose]\n");
Error0 ("\n");
Error0 (" -help : print this message and exit.\n");
Error0 (" -version : print version number and exit.\n");
Error2 (" -time minutes : time to lock screen [%d < minutes < %d].\n",
MIN_MINUTES, MAX_MINUTES);
Error0 (" -locker locker : program used to lock.\n");
Error0 (" -notify margin : beep this many seconds before locking.\n");
Error0 (" -bell percent : loudness of the beep.\n");
Error0 (" -corners xxxx : corner actions (0, +, -) in this order :\n");
Error0 (" topleft topright bottomleft bottomright\n");
Error0 (" -cornerdelay secs : time to lock screen in a `+' corner.\n");
Error0 (" -cornersize pixels : size of corner areas.\n");
Error0 (" -noclose : do not close stdout and stderr.\n");
Error0 ("\n");
Error0 ("Defaults :\n");
Error0 ("\n");
Error1 (" time : %d minutes\n" , MINUTES );
Error1 (" locker : %s\n" , LOCKER );
Error0 (" notify : don't beep\n" );
Error0 (" bell : 40%%\n" );
Error0 (" corners : 0000\n" );
Error1 (" cornerdelay : %d seconds\n" , CORNER_DELAY);
Error1 (" cornersize : %d pixels\n" , CORNER_SIZE );
Error0 ("\n");
exit (exit_code);
}
/*
* Function for processing command line arguments
* ----------------------------------------------
*/
static Void ProcessOpts (d, argc, argv)
Display* d; /* display pointer */
Int argc; /* number of arguments */
String argv[]; /* array of arguments */
{
Int nof_options = sizeof (options) / sizeof (anOpt);
/* number of supported options */
Int j; /* loop counter */
Int l; /* temporary storage */
Char* ptr; /* temporary storage */
Char buffer[80]; /* as it says */
Char* dummy; /* as it says */
XrmValue value; /* resource value container */
XrmOptionDescList xoptions; /* optionslist in Xlib format */
XrmDatabase db = (XrmDatabase) NULL;
/* command line options database */
/*
* Beautify argv[0].
*/
for (ptr = argv[0] + strlen (argv[0]) - 1; ptr >= argv[0]; ptr--)
{
if (*ptr == '/')
{
break;
}
}
argv[0] = ptr + 1;
/*
* Calling XGetDefault () on a dummy resource is the easiest
* way to get both Xrm and d->db initialized.
*/
(Void) XGetDefault (d, argv[0], "dummy");
/*
* Parse the command line options into a resource database. (The
* command line database and the resource file database are not
* merged, because we want to know where exactly each resource
* value came from.)
*/
xoptions = NewArray (XrmOptionDescRec, nof_options);
for (j = -1; ++j < nof_options; )
{
l = strlen (options[j].name);
(Void) sprintf (xoptions[j].option = NewArray (Char, l + 2),
"-%s", options[j].name);
(Void) sprintf (xoptions[j].specifier = NewArray (Char, l + 2),
".%s", options[j].name);
xoptions[j].argKind = options[j].kind;
xoptions[j].value = options[j].value;
}
XrmParseCommand (&db, xoptions, nof_options, argv[0], &argc, argv);
if (--argc)
{
Usage (argv[0], PROBLEMS);
}
for (j = -1; ++j < nof_options; )
{
free (xoptions[j].option);
free (xoptions[j].specifier);
}
free (xoptions);
/*
* Call the action functions.
*/
for (j = -1; ++j < nof_options; )
{
(Void) sprintf (buffer, "%s%s", argv[0], xoptions[j].specifier);
if (XrmGetResource (db, buffer, (String) NULL, &dummy, &value))
{
if (!(*(options[j].action)) (d, argv[0], value.addr))
{
Usage (argv[0], PROBLEMS);
}
}
else if (XrmGetResource (d->db, buffer, (String) NULL, &dummy, &value))
{
if (!(*(options[j].action)) (d, argv[0], value.addr))
{
Error2 ("Can't interprete \"%s\" for \"%s\", using default.\n",
value.addr, buffer);
}
}
else
{
(Void) sprintf (buffer, "%s%s", CLASS, xoptions[j].specifier);
if ( XrmGetResource (d->db, buffer, (String) NULL, &dummy, &value)
&& !(*(options[j].action)) (d, argv[0], value.addr)
)
{
Error2 ("Can't interprete \"%s\" for \"%s\", using default.\n",
value.addr, buffer);
}
}
}
/*
* Call the consistency checkers.
*/
for (j = -1; ++j < nof_options; )
{
if (options[j].checker != (OptChecker) NULL)
{
(*(options[j].checker)) (d);
}
}
}
/*
* Functions related to the window queue
* =====================================
*
* Function for creating a new queue
* ---------------------------------
*/
static Queue NewQueue ()
{
Queue queue; /* return value */
queue = New (aQueue);
queue->tail = New (aQueueItem);
queue->head = New (aQueueItem);
queue->tail->next = queue->head;
queue->head->prev = queue->tail;
queue->tail->prev = queue->head->next = (QueueItem) NULL;
return queue;
}
/*
* Function for adding an item to a queue
* --------------------------------------
*/
static Void AddToQueue (queue, window)
Queue queue; /* as it says */
Window window; /* as it says */
{
QueueItem new; /* new item */
new = New (aQueueItem);
new->window = window;
new->creationtime = now;
new->next = queue->tail->next;
new->prev = queue->tail;
queue->tail->next->prev = new;
queue->tail->next = new;
}
/*
* Function for processing those entries that are old enough
* ---------------------------------------------------------
*/
static Void ProcessQueue (queue, d, age)
Queue queue; /* as it says */
Display* d; /* display pointer */
Time age; /* required age */
{
QueueItem current; /* as it says */
if (now > age)
{
current = queue->head->prev;
while ( current->prev
&& current->creationtime + age < now
)
{
SelectEvents (d, current->window, False);
current = current->prev;
free (current->next);
}
current->next = queue->head;
queue->head->prev = current;
}
}
/*
* Functions related to (the lack of) user activity
* ================================================
*
* Function for processing the event queue
* ---------------------------------------
*/
static Void ProcessEvents (d, queue)
Display* d; /* display pointer */
Queue queue; /* as it says */
{
XEvent event; /* as it says */
/*
* Read whatever is available for reading.
*/
while (XPending (d))
{
if (XCheckMaskEvent (d, SubstructureNotifyMask, &event))
{
if (event.type == CreateNotify)
{
AddToQueue (queue, event.xcreatewindow.window);
}
}
else
{
XNextEvent (d, &event);
}
/*
* Reset the counter if and only if the event is of one of
* the types we are expecting to get *and* was not generated by
* XSendEvent ().
*/
if ( event.type == KeyPress
&& !event.xany.send_event
)
{
UpdateTimer (0);
}
}
/*
* Check the window queue for entries that are older than
* CREATION_DELAY seconds.
*/
ProcessQueue (queue, d, (Time) CREATION_DELAY);
}
/*
* Function for monitoring pointer movements
* -----------------------------------------
*/
static Void QueryPointer (d)
Display* d; /* display pointer */
{
Window dummy_w; /* as it says */
Int dummy_c; /* as it says */
Mask dummy_m; /* as it says */
Int root_x; /* as it says */
Int root_y; /* as it says */
Int corner; /* corner index */
Int i; /* loop counter */
static Window root; /* root window the pointer is on */
static Screen* screen; /* screen the pointer is on */
static Int prev_root_x = -1; /* as it says */
static Int prev_root_y = -1; /* as it says */
static Boolean first_call = TRUE; /* as it says */
/*
* Have a guess...
*/
if (first_call)
{
first_call = FALSE;
root = DefaultRootWindow (d);
screen = ScreenOfDisplay (d, DefaultScreen (d));
}
/*
* Find out whether the pointer has moved. Using XQueryPointer for this
* is gross, but it also is the only way never to mess up propagation
* of pointer events.
*
* Remark : Unlike XNextEvent(), XPending () doesn't notice if the
* connection to the server is lost. For this reason, earlier
* versions of xautolock periodically called XNoOp (). But
* why not let XQueryPointer () do the job for us, since
* we now call it every INCREMENTAL_SLEEP seconds anyway?
*/
if (!XQueryPointer (d, root, &root, &dummy_w, &root_x, &root_y,
&dummy_c, &dummy_c, &dummy_m))
{
/*
* Pointer has moved to another screen, so let's find out which one.
*/
for (i = -1; ++i < ScreenCount (d); )
{
if (root == RootWindow (d, i))
{
screen = ScreenOfDisplay (d, i);
break;
}
}
}
if ( root_x == prev_root_x
&& root_y == prev_root_y
)
{
/*
* If the pointer has not moved since the previous call and
* is inside one of the 4 corners, we act according to the
* contents of the "corners" array.
*/
if ( (corner = 0,
root_x <= corner_size
&& root_y <= corner_size
)
|| (corner++,
root_x >= WidthOfScreen (screen) - corner_size - 1
&& root_y <= corner_size
)
|| (corner++,
root_x <= corner_size
&& root_y >= HeightOfScreen (screen) - corner_size - 1
)
|| (corner++,
root_x >= WidthOfScreen (screen) - corner_size - 1
&& root_y >= HeightOfScreen (screen) - corner_size - 1
)
)
{
switch (corners[corner])
{
case FORCE_LOCK :
if (timer < time_limit - corner_delay + 2)
{
UpdateTimer (time_limit - corner_delay + 2);
}
break;
case DONT_LOCK :
UpdateTimer (0);
}
}
}
else
{
prev_root_x = root_x;
prev_root_y = root_y;
UpdateTimer (0);
}
}
/*
* Function for deciding whether to lock
* -------------------------------------
*/
static Void EvaluateCounter (d)
Display* d; /* display pointer */
{
static pid_t locker_pid = 0; /* child pid */
static Time prev_bell = 0; /* as it says */
/*
* Find out whether we should do something special. This can
* be one (or more) of the following :
*
* - Wait for the previous locker (if any).
* - Ring the bell, if we were asked to and are about to lock.
* - Start up a new locker if the time limit has been reached.
*/
if (locker_pid)
{
union wait status; /* childs process status */
if (!wait3 (&status, WNOHANG, (struct rusage*) NULL))
{
UpdateTimer (0);
}
else
{
locker_pid = 0;
}
}
if ( notify_lock
&& timer + notify_margin > time_limit
&& prev_bell < now - notify_margin - 1
)
{
prev_bell = now;
XBell (d, bell_percent);
XSync (d, 0);
}
if (timer > time_limit)
{
if (!locker_pid)
{
switch (locker_pid = vfork ())
{
case -1 :
locker_pid = 0;
break;
case 0 :
(Void) close (ConnectionNumber (d));
(Void) execl ("/bin/sh", "sh", "-c", locker, (String) NULL);
(Void) _exit (PROBLEMS);
default :
UpdateTimer (0);
}
}
}
}
/*
* Miscellaneous functions
* =======================
*
* X Error handler
* ---------------
*/
/*ARGSUSED*/
static Int FetchFalseAlarm (d, event)
Display* d; /* display pointer */
XEvent event; /* error event */
{
return 0;
}
/*
* SIGHUP signal handler
* ---------------------
*/
static SigRet DisableBySignal ()
{
/*
* The order in which things are done is rather important here.
*/
UpdateTimer (0);
sighupped = !sighupped;
(Void) signal (SIGHUP, (SigHandler) DisableBySignal);
#ifndef HasVoidSignalReturn
return 0;
#endif /* HasVoidSignalReturn */
}
/*
* Lazy function
* -------------
*/
static Void Sleep ()
{
Int i; /* loop counter */
for (i = -1; ++i < INCREMENTAL_SLEEP; )
{
(Void) sleep (1);
UpdateTimer (timer + 1);
now++;
}
}
/*
* Function for finding out whether another xautolock is already running
* ---------------------------------------------------------------------
*/
static Void CheckConnection (d, prog_name)
Display* d; /* display pointer */
String prog_name; /* as it says */
{
pid_t pid; /* as it says */
Int kill_val; /* return value of kill () */
Window r; /* root window */
Atom property; /* property atom */
Atom type; /* property type atom */
Int format; /* property format */
Huge nof_items; /* actual number of items */
Huge after; /* dummy */
pid_t* contents; /* actual property value */
r = RootWindowOfScreen (ScreenOfDisplay (d, 0));
property = XInternAtom (d, "XAUTOLOCK_SEMAPHORE_PID", False);
XGrabServer (d);
XGetWindowProperty (d, r, property, 0L, 2L, False, AnyPropertyType,
&type, &format, &nof_items, &after,
(unsigned char**) &contents);
if (type == XA_INTEGER)
{
/*
* This breaks if the other xautolock is not
* running on the same machine.
*/
kill_val = kill (*contents, 0);
if (kill_val == 0)
{
Error2 ("%s is already running (PID %d).\n",
prog_name, *contents);
(Void) exit (PROBLEMS);
}
}
pid = getpid ();
XChangeProperty (d, r, property, XA_INTEGER, 8,
PropModeReplace, (Char*) &pid, sizeof (pid));
XUngrabServer (d);
XFree ((Char*) contents);
}
/*
* Function for selecting events on a tree of windows
* --------------------------------------------------
*/
static Void SelectEvents (d, window, substructure_only)
Display* d; /* display pointer */
Window window; /* window */
Boolean substructure_only; /* as it says */
{
Window root; /* root window of this window */
Window parent; /* parent of this window */
Window* children; /* children of this window */
Int nof_children = 0; /* number of children */
Int i; /* loop counter */
XWindowAttributes attribs; /* attributes of the window */
/*
* Start by querying the server about parent and child windows.
*/
if (!XQueryTree (d, window, &root, &parent, &children, &nof_children))
{
return;
}
/*
* Build the appropriate event mask. The basic idea is that we don't
* want to interfere with the normal event propagation mechanism if
* we don't have to.
*/
if (substructure_only)
{
XSelectInput (d, window, SubstructureNotifyMask);
}
else
{
if (parent == None) /* the *real* rootwindow */
{
attribs.all_event_masks =
attribs.do_not_propagate_mask = KeyPressMask;
}
else if (XGetWindowAttributes (d, window, &attribs) == 0)
{
return;
}
XSelectInput (d, window, SubstructureNotifyMask
| ( ( attribs.all_event_masks
| attribs.do_not_propagate_mask)
& KeyPressMask));
}
/*
* Now do the same thing for all children.
*/
for (i = -1; ++i < nof_children; )
{
SelectEvents (d, children[i], substructure_only);
}
if (nof_children != 0)
{
XFree ((Char*) children);
}
}
/*
* Main function
* -------------
*/
Int Main (argc, argv)
Int argc; /* number of arguments */
String argv[]; /* array of arguments */
{
Display* d; /* display pointer */
Window r; /* root window */
Int s; /* screen index */
Queue queue; /* as it says */
/*
* Find out whether there actually is a server on the other side...
*/
if ( (d = XOpenDisplay ((String) NULL))
== (Display*) NULL
)
{
(Void) exit (PROBLEMS);
}
/*
* Some initializations.
*/
ProcessOpts (d, argc, argv);
XSetErrorHandler ((XErrorHandler) FetchFalseAlarm);
CheckConnection (d, argv[0]);
(Void) signal (SIGHUP, (SigHandler) DisableBySignal);
XSync (d, 0);
(Void) sleep (INITIAL_SLEEP);
queue = NewQueue ();
for (s = -1; ++s < ScreenCount (d); )
{
AddToQueue (queue, r = RootWindowOfScreen (ScreenOfDisplay (d, s)));
SelectEvents (d, r, True);
}
if (close_output)
{
(Void) fclose (stdout);
(Void) fclose (stderr);
}
/*
* Main event loop.
*/
forever
{
Sleep ();
ProcessEvents (d, queue);
QueryPointer (d);
EvaluateCounter (d);
}
}