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.
tdepowersave/src/inactivity.cpp

403 lines
12 KiB

/***************************************************************************
* Copyright (C) 2006-2007 by Danny Kukawka *
* <dkukawka@suse.de>, <danny.kukawka@web.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of version 2 of the GNU General Public License *
* as published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
/*! \file inactivity.cpp
* \brief In this file can be found the inactivity related code.
* \author Danny Kukawka, <dkukawka@suse.de>, <danny.kukawka@web.de>
* \date 2006-2007
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// own header
#include "inactivity.h"
/* needed for lXext C library linkage */
extern "C" {
#include <X11/Xproto.h>
#include <X11/extensions/dpms.h>
#include <X11/extensions/scrnsaver.h>
}
// TDE Headers
#include <tdelocale.h>
/*! The default constructor of the class autosuspend */
inactivity::inactivity(screen *disp) : display(disp),
prev_screensaver_enabled(false), prev_idle_time(0), correction_value(0) {
kdDebugFuncIn(trace);
proc = NULL;
timeToInactivity = 0;
blacklisted_running_last = 0;
pidof_call_failed = false;
pidof_call_started = false;
pidof_call_returned = false;
blacklisted_running = false;
int dummy = 0;
has_XSC_Extension = XScreenSaverQueryExtension( tqt_xdisplay(), &dummy, &dummy );
checkInactivity = new TQTimer( this );
connect( checkInactivity, TQT_SIGNAL(timeout()), this, TQT_SLOT(check()));
kdDebugFuncOut(trace);
}
/*! The default destructor of the class autosuspend */
inactivity::~inactivity() {
kdDebugFuncIn(trace);
delete proc;
proc = NULL;
kdDebugFuncOut(trace);
}
/*!
* This function start the monitoring of inactivity of user on the X-Server.
* Here we set the time for the signal \ref inactivityTimeExpired() and start
* the needed TQTimer.
* \param timeToExpire Integer value representing the time of inactivity which need
* to elapse befor send signal. The time is in seconds.
* \param blacked TQStringList with blacklisted programs which if detected with
* pidof() as running prevent the autosuspend.
*/
void inactivity::start( int timeToExpire, TQStringList blacked ) {
kdDebugFuncIn(trace);
blacklist = blacked;
if(timeToExpire > 0 && has_XSC_Extension){
stop();
timeToInactivity = (unsigned long) (timeToExpire * 1000);
prev_screensaver_enabled = false;
prev_idle_time = 0;
correction_value = 0;
checkInactivity->start(CHECK_for_INACTIVITY, true);
}
kdDebugFuncOut(trace);
}
/*!
* \b TQT_SLOT to call check as recheck inactivity if before a running PID
* request was detected.
*/
void inactivity::recheck() {
kdDebugFuncIn(trace);
check(true);
kdDebugFuncOut(trace);
}
/*!
* \b TQT_SLOT to call check without a recheck.
*/
void inactivity::check() {
check(false);
}
/*!
* \b TQT_SLOT to check the current idle-time of the X-Server and if there
* are blacklisted programs are running. If the through \ref timeToInactivity
* defined time is expired, this function emit signal \ref inactivityTimeExpired() .
* \param recheck boolean which define if this is a recheck or not.
* \li true, if this is a recheck. In this case we didn't call
* \ref checkBlacklisted() again
* \li false, if this is normal check
*/
void inactivity::check( bool recheck ) {
kdDebugFuncIn(trace);
if (timeToInactivity > 0) {
checkXInactivity();
if (!pidof_call_started && !recheck) checkBlacklisted();
if( idleTime < blacklisted_running_last ) {
blacklisted_running_last = idleTime;
}
if((idleTime - blacklisted_running_last ) >= timeToInactivity) {
if (!pidof_call_started) {
if (( pidof_call_returned && !blacklisted_running ) ||
( pidof_call_returned && pidof_call_failed )) {
emit inactivityTimeExpired();
}
else {
checkInactivity->start(CHECK_for_INACTIVITY, true);
}
}
else {
//called if there is a getPIDs() is running
TQTimer::singleShot(500, this, TQT_SLOT(recheck()));
}
}
else checkInactivity->start(CHECK_for_INACTIVITY, true);
} else {
kdWarning() << "timeToInactivity <= 0, stoped autosuspend checks!" << endl;
}
kdDebugFuncOut(trace);
}
/*!
* This function stop the monitoring and reset all variables and Timer.
*/
void inactivity::stop() {
kdDebugFuncIn(trace);
if (checkInactivity->isActive()) checkInactivity->stop();
timeToInactivity = 0;
idleTime = 0;
blacklisted_running_last = 0;
pidof_call_failed = false;
pidof_call_started = false;
pidof_call_returned = false;
blacklisted_running = false;
kdDebugFuncOut(trace);
}
/*!
* This function query the idle-time of user-imput from the X-Server and set
* the return value to \ref idleTime.
*/
void inactivity::checkXInactivity(){
kdDebugFuncIn(trace);
idleTime = getXInactivity();
kdDebug() << "autosuspend::checkXInactivity - idleTime: " << idleTime << endl;
kdDebugFuncOut(trace);
}
/*!
* This function query the idle-time of user-imput from the X-Server and
* return the current idle-time.
*/
unsigned long inactivity::getXInactivity(){
kdDebugFuncIn(trace);
if(has_XSC_Extension) {
static XScreenSaverInfo* mitInfo = 0;
if (!mitInfo) mitInfo = XScreenSaverAllocInfo ();
XScreenSaverQueryInfo (tqt_xdisplay(), DefaultRootWindow (tqt_xdisplay()), mitInfo);
kdDebugFuncOut(trace);
return workaroundCreepyXServer(mitInfo);
}
else {
kdDebugFuncOut(trace);
return 0;
}
}
/*!
* This function workaround an XServer idleTime bug in the
* XScreenSaverExtension, if dpms is running. In this case always the
* current dpms-state time is extracted from the current idletime.
* This mean: XScreenSaverInfo->idle is not the time since the last
* user activity, as descriped in the header file of the extension.
* This result in SUSE bug # and sf.net bug #
*
* Workaround: check if if XServer is in a dpms state, check the
* current timeout for this state and add this value to
* the current idle time and return.
*
* \param _mitInfo a pointer to a structure containing the current XScreenSaver state
* \return a unsigned long with the corrected idletime
*/
unsigned long inactivity::workaroundCreepyXServer(XScreenSaverInfo *_mitInfo){
kdDebugFuncOut(trace);
unsigned long _idleTime = _mitInfo->idle;
// Detect whether the screensaver has become active since the last time,
// because the idle time returned by XScreenSaverQueryInfo() is resetted
// to 0 when the screensaver kicks in. Correct the idle time value if the
// screensaver is active
bool screensaver_enabled = false;
if (display->checkScreenSaverActive())
{
screensaver_enabled = true;
}
if (!prev_screensaver_enabled && screensaver_enabled)
{
correction_value = prev_idle_time + CHECK_for_INACTIVITY - _idleTime;
}
prev_idle_time = _idleTime;
if (screensaver_enabled)
{
_idleTime += correction_value;
}
else
{
correction_value = 0;
}
prev_screensaver_enabled = screensaver_enabled;
int dummy;
CARD16 standby, suspend, off;
CARD16 state;
BOOL onoff;
Display *dpy = tqt_xdisplay();
kdDebug() << "Current idleTime: " << _idleTime << endl;
// Idle time is reset when the screensaver kicks in. Need to correct with the right offset
if (DPMSQueryExtension(dpy, &dummy, &dummy)) {
if (DPMSCapable(dpy)) {
DPMSGetTimeouts(dpy, &standby, &suspend, &off);
DPMSInfo(dpy, &state, &onoff);
if (onoff) {
switch (state) {
case DPMSModeStandby:
kdDebug() << "DPMS enabled. Monitor in Standby. Standby: "
<< standby << " sec" << endl;
// this check is a little bit paranoid, but be sure
if (_idleTime < (unsigned) (standby * 1000))
_idleTime += (standby * 1000);
break;
case DPMSModeSuspend:
kdDebug() << "DPMS enabled. Monitor in Suspend. Suspend: "
<< suspend << " sec" << endl;
if (_idleTime < (unsigned) ((suspend + standby) * 1000))
_idleTime += ((suspend + standby) * 1000);
break;
case DPMSModeOff:
kdDebug() << "DPMS enabled. Monitor is Off. Off: "
<< off << " sec" << endl;
if (_idleTime < (unsigned) ((off + suspend + standby) * 1000))
_idleTime += ((off + suspend + standby) * 1000);
break;
case DPMSModeOn:
default:
break;
}
}
}
}
kdDebug() << "Corrected idleTime: " << _idleTime << endl;
kdDebugFuncOut(trace);
return _idleTime;
}
/*!
* This funtion starts the monitoring of blacklisted processes.
*/
void inactivity::checkBlacklisted(){
kdDebugFuncIn(trace);
if (proc != NULL) {
delete proc;
proc = NULL;
}
proc = new TDEProcess;
*proc << "pidof" << blacklist;
connect( proc, TQT_SIGNAL(receivedStdout(TDEProcess *, char *, int)),this,
TQT_SLOT(getPIDs(TDEProcess *, char *, int)));
connect( proc, TQT_SIGNAL(processExited(TDEProcess *)),
TQT_SLOT(getPIDsExited(TDEProcess *)));
if (!proc->start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput))
{
emit displayErrorMsg(i18n("Could not start 'pidof'. "
"Could not autosuspend the machine.\n"
"Please check your installation."));
}
pidof_call_started = true;
pidof_call_returned = false;
pidof_call_failed = false;
kdDebugFuncOut(trace);
}
/*!
* \b TQT_SLOT to get the return of the command pidof and parse this to set
* \ref blacklisted_running .
* \param *proc pointer to the sending TDEProcess
* \param *buffer the char pointer to the output of the process to stdout
* \param *length the length of the buffer
*/
void inactivity::getPIDs(TDEProcess */*proc*/, char *buffer, int /*length*/) {
kdDebugFuncIn(trace);
TQString pids(buffer);
pids.remove(" ");
if(pids.isEmpty() || pids == "\n" ) {
kdDebug() << "NO! BLACKLISTED IS RUNNING" << endl;
blacklisted_running = false;
}
else {
if (pids.contains(TQRegExp("[0-9]"))) {
kdDebug() << "BLACKLISTED IS RUNNING" << endl;
blacklisted_running = true;
blacklisted_running_last = idleTime;
}
else {
kdError() << "GET BLACKLISTED FAILED - WRONG RETURN" << endl;
blacklisted_running = false;
pidof_call_failed = true;
}
}
kdDebugFuncOut(trace);
}
/*!
* \b TQT_SLOT which called if the call of pidof is exited
* \param proc the KPocess which called this SLOT
*/
void inactivity::getPIDsExited(TDEProcess *proc){
kdDebugFuncIn(trace);
pidof_call_returned = true;
pidof_call_started = false;
if (proc->normalExit()){
// if returned some pids or if pid returned nothing
if (proc->exitStatus() == 1 || proc->exitStatus() == 0){
pidof_call_failed = false;
kdDebugFuncOut(trace);
return;
}
}
// if something crashed/failed
pidof_call_failed = true;
kdDebugFuncOut(trace);
}
#include "inactivity.moc"