You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kdesktop/xautolock_engine.c

420 lines
12 KiB

/*****************************************************************************
*
* Authors: Michel Eyckmans (MCE) & Stefan De Troch (SDT)
*
* Content: This file is part of version 2.x of xautolock. It implements
* the program's core functions.
*
* Please send bug reports etc. to eyckmans@imec.be.
*
* --------------------------------------------------------------------------
*
* Copyright 1990,1992-1999,2001-2002 by Stefan De Troch and Michel Eyckmans.
*
* Versions 2.0 and above of xautolock are available under version 2 of the
* GNU GPL. Earlier versions are available under other conditions. For more
* information, see the License file.
*
*****************************************************************************/
#include <X11/Xlib.h>
#include <time.h>
#include "xautolock_c.h"
/*
* Function for querying the idle time from the server.
* Only used if either the Xidle or the Xscreensaver
* extension is present.
*/
void
xautolock_queryIdleTime (Display* d)
{
Time idleTime = 0; /* millisecs since last input event */
#ifdef HasXidle
if (xautolock_useXidle)
{
XGetIdleTime (d, &idleTime);
}
else
#endif /* HasXIdle */
{
#ifdef HasScreenSaver
if( xautolock_useMit )
{
static XScreenSaverInfo* mitInfo = 0;
if (!mitInfo) mitInfo = XScreenSaverAllocInfo ();
XScreenSaverQueryInfo (d, DefaultRootWindow (d), mitInfo);
idleTime = mitInfo->idle;
}
else
#endif /* HasScreenSaver */
{
d = d; /* shut up */
return; /* DIY */
}
}
if (idleTime < CHECK_INTERVAL )
{
xautolock_resetTriggers ();
}
}
/*
* Function for monitoring pointer movements. This implements the
* `corners' feature and as a side effect also tracks pointer
* related user activity. The latter actually is only needed when
* we're using the DIY mode of operations, but it's much simpler
* to do it unconditionally.
*/
void
xautolock_queryPointer (Display* d)
{
Window dummyWin; /* as it says */
int dummyInt; /* as it says */
unsigned tqmask; /* modifier tqmask */
int rootX; /* as it says */
int rootY; /* as it says */
int corner; /* corner index */
time_t now; /* as it says */
time_t newTrigger; /* temporary storage */
int i; /* loop counter */
static Window root; /* root window the pointer is on */
static Screen* screen; /* screen the pointer is on */
static unsigned prevMask = 0; /* as it says */
static int prevRootX = -1; /* as it says */
static int prevRootY = -1; /* as it says */
static Bool firstCall = True; /* as it says */
/*
* Have a guess...
*/
if (firstCall)
{
firstCall = 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.
*/
if (!XQueryPointer (d, root, &root, &dummyWin, &rootX, &rootY,
&dummyInt, &dummyInt, &tqmask))
{
/*
* 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 ( rootX == prevRootX
&& rootY == prevRootY
&& tqmask == prevMask)
{
xautolock_corner_t* corners = xautolock_corners;
/*
* 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 rootX and rootY are less than zero, don't lock even if
* ca_forceLock is set in the upper-left corner. Why? 'cause
* on initial server startup, if (and only if) the pointer is
* never moved, XQueryPointer() can return values less than
* zero (only some servers, Openwindows 2.0 and 3.0 in
* particular).
*/
if ( (corner = 0,
rootX <= cornerSize && rootX >= 0
&& rootY <= cornerSize && rootY >= 0)
|| (corner++,
rootX >= WidthOfScreen (screen) - cornerSize - 1
&& rootY <= cornerSize)
|| (corner++,
rootX <= cornerSize
&& rootY >= HeightOfScreen (screen) - cornerSize - 1)
|| (corner++,
rootX >= WidthOfScreen (screen) - cornerSize - 1
&& rootY >= HeightOfScreen (screen) - cornerSize - 1))
{
now = time (0);
switch (corners[corner])
{
case ca_forceLock:
#if 0
newTrigger = now + (useRedelay ? cornerRedelay : cornerDelay) - 1;
#else
newTrigger = now;
#endif
#if 0
if (newTrigger < lockTrigger)
{
setLockTrigger (newTrigger - now);
}
#else
xautolock_setTrigger( newTrigger );
#endif
break;
case ca_dontLock:
xautolock_resetTriggers ();
#ifdef __GNUC__
default: ; /* Makes gcc -Wall shut up. */
#endif /* __GNUC__ */
}
}
}
else
{
#if 0
useRedelay = False;
#endif
prevRootX = rootX;
prevRootY = rootY;
prevMask = tqmask;
xautolock_resetTriggers ();
}
}
#if 0
/*
* Support for deciding whether to lock or kill.
*/
void
evaluateTriggers (Display* d)
{
static time_t prevNotification = 0;
time_t now = 0;
/*
* Obvious things first.
*
* The triggers are being moved all the time while in disabled
* mode in order to make absolutely sure we cannot run into
* trouble by an enable message coming in at an odd moment.
* Otherwise we possibly might lock or kill too soon.
*/
if (disabled)
{
resetTriggers ();
}
/*
* Next, wait for (or kill, if we were so told) the previous
* locker (if any). Note that this must also be done while in
* disabled mode. Not only to avoid a potential zombie proces
* hanging around until we are re-enabled, but also to prevent
* us from incorrectly setting a kill trigger at the moment
* when we are finally re-enabled.
*/
#ifdef VMS
if (vmstqStatus == 0)
{
#else /* VMS */
if (lockerPid)
{
#if !defined (UTEKV) && !defined (SYSV) && !defined (SVR4)
union wait status; /* childs process status */
#else /* !UTEKV && !SYSV && !SVR4 */
int status = 0; /* childs process status */
#endif /* !UTEKV && !SYSV && !SVR4 */
if (unlockNow && !disabled)
{
(void) kill (lockerPid, SIGTERM);
}
#if !defined (UTEKV) && !defined (SYSV) && !defined (SVR4)
if (wait3 (&status, WNOHANG, 0))
#else /* !UTEKV && !SYSV && !SVR4 */
if (waitpid (-1, &status, WNOHANG))
#endif /* !UTEKV && !SYSV && !SVR4 */
{
/*
* If the locker exited normally, we disable any pending kill
* trigger. Otherwise, we assume that it either has crashed or
* was not able to lock the display because of an existing
* locker (which may have been started manually). In both of
* the later cases, disabling the kill trigger would open a
* loop hole.
*/
if ( WIFEXITED (status)
&& WEXITSTATUS (status) == EXIT_SUCCESS)
{
disableKillTrigger ();
}
useRedelay = True;
lockerPid = 0;
}
#endif /* VMS */
setLockTrigger (lockTime);
/*
* No return here! The pointer may be sitting in a corner, while
* parameter settings may be such that we need to start another
* locker without further delay. If you think this cannot happen,
* consider the case in which the locker simply crashed.
*/
}
unlockNow = False;
/*
* Note that the above lot needs to be done even when we're in
* disabled mode, since we may have entered said mode with an
* active locker around.
*/
if (disabled) return;
/*
* Is it time to run the killer command?
*/
now = time (0);
if (killTrigger && now >= killTrigger)
{
/*
* There is a dirty trick here. On the one hand, we don't want
* to block until the killer returns, but on the other one
* we don't want to have it interfere with the wait() stuff we
* do to keep track of the locker. To obtain both, the killer
* command has already been patched by KillerChecker() so that
* it gets backgrounded by the shell started by system().
*
* For the time being, VMS users are out of luck: their xautolock
* will indeed block until the killer returns.
*/
(void) system (killer);
setKillTrigger (killTime);
}
/*
* Now trigger the notifier if required.
*/
if ( notifyLock
&& now + notifyMargin >= lockTrigger
&& prevNotification < now - notifyMargin - 1)
{
if (notifierSpecified)
{
/*
* Here we use the same dirty trick as for the killer command.
*/
(void) system (notifier);
}
else
{
(void) XBell (d, bellPercent);
(void) XSync (d, 0);
}
prevNotification = now;
}
/*
* Finally fire up the locker if time has somehow come.
*/
if ( lockNow
|| now >= lockTrigger)
{
#ifdef VMS
if (vmstqStatus != 0)
#else /* VMS */
if (!lockerPid)
#endif /* VMS */
{
switch (lockerPid = vfork ())
{
case -1:
lockerPid = 0;
break;
case 0:
(void) close (ConnectionNumber (d));
#ifdef VMS
vmstqStatus = 0;
lockerPid = lib$spawn ((lockNow ? &nowLockerDescr : &lockerDescr),
0, 0, &1, 0, 0, &vmstqStatus);
if (!(lockerPid & 1)) exit (lockerPid);
#ifdef SLOW_VMS
(void) sleep (SLOW_VMS_DELAY);
#endif /* SLOW_VMS */
#else /* VMS */
(void) execl ("/bin/sh", "/bin/sh", "-c",
(lockNow ? nowLocker : locker), 0);
#endif /* VMS */
_exit (EXIT_FAILURE);
default:
/*
* In general xautolock should keep its fingers off the real
* screensaver because no universally acceptable policy can
* be defined. In no case should it decide to disable or enable
* it all by itself. Setting the screensaver policy is something
* the locker should take care of. After all, xautolock is not
* supposed to know what the "locker" does and doesn't do.
* People might be using xautolock for totally different
* purposes (which, by the way, is why it will accept a
* different set of X resources after being renamed).
*
* Nevertheless, simply resetting the screensaver is a
* convenience action that aids many xlock users, and doesn't
* harm anyone (*). The problem with older versions of xlock
* is that they can be told to tqreplace (= disable) the real
* screensaver, but forget to reset that same screensaver if
* it was already active at the time xlock starts. I guess
* xlock initially wasn't designed to be run without a user
* actually typing the comand ;-).
*
* (*) Well, at least it used not to harm anyone, but with the
* advent of DPMS monitors, it now can mess up the power
* saving setup. Hence we better make it optional.
*
* Also, some xlock versions also unconditionally call
* XResetScreenSaver, yielding the same kind of problems
* with DPMS that xautolock did. The latest and greatest
* xlocks also have a -resetsaver option for this very
* reason. You may want to upgrade.
*/
if (resetSaver) (void) XResetScreenSaver(d);
setLockTrigger (lockTime);
(void) XSync (d,0);
}
/*
* Once the locker is running, all that needs to be done is to
* set the killTrigger if needed. Notice that this must be done
* even if we actually failed to start the locker. Otherwise
* the error would "propagate" from one feature to another.
*/
if (killerSpecified) setKillTrigger (killTime);
useRedelay = False;
}
lockNow = False;
}
}
#endif