|
|
|
/***************************************************************************
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
// 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"
|