Bug 120989

Summary: Can never be idle if compiled without libxss
Product: [Unmaintained] kopete Reporter: Isaac Wilcox <iwilcox>
Component: libkopeteAssignee: Kopete Developers <kopete-bugs-null>
Status: RESOLVED FIXED    
Severity: normal    
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: Compiled Sources   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description Isaac Wilcox 2006-01-29 18:23:03 UTC
Version:            (using KDE Devel)
Installed from:    Compiled sources
OS:                Linux

(This should be assigned to the libkopete component.)

I built Kopete from SVN in Debian today, after doing an "apt-get build-dep kopete".  It seems Debian somehow forgot to install libxss-dev, and I managed to build a Kopete without libxss support without noticing, which unearthed a bug.

In libkopete/kopeteaway.cpp, Kopete::Away::slotTimerTimeout() assumes an idle time of zero, then overwrites this with the idle time obtained from either libxss or the XIdle extension, if either are available.  Kopete then sets you active if the obtained idle time is less than Kopete's own recorded idle time.  But if neither libxss nor XIdle are available, the "obtained" idle time is still zero, so you're permanently set active.

The patch for bug 117513 should fix this; I'm just adding a bug here for completeness because other Debianites building from source might see this.

Cheers,

Zak (Isaac Wilcox)
Comment 1 Matt Rogers 2006-02-19 06:44:18 UTC
SVN commit 511207 by mattr:

Apply the patch from bug 117513 to fix several auto away issues with the code
that does this.

Patch by Issac Wilcox. Thanks so much for the patch!

BUG: 120989
BUG: 92949
BUG: 117513



 M  +3 -0      kopete/kopeteiface.cpp  
 M  +74 -15    libkopete/kopeteaway.cpp  
 M  +11 -3     libkopete/kopeteaway.h  


--- branches/kopete/0.12/kopete/kopete/kopeteiface.cpp #511206:511207
@@ -48,6 +48,9 @@
 		disconnectDCOPSignal("kdesktop", "KScreensaverIface",
 			"KDE_start_screensaver()", "setAutoAway()");
 	}
+	// FIXME: AFAICT, this never seems to fire.
+	connectDCOPSignal("kdesktop", "KScreensaverIface",
+		"KDE_stop_screensaver()", "setActive()", false);
 }
 
 QStringList KopeteIface::contacts()
--- branches/kopete/0.12/kopete/libkopete/kopeteaway.cpp #511206:511207
@@ -32,6 +32,7 @@
 #include <kconfig.h>
 #include <qtimer.h>
 #include <kapplication.h>
+#include <dcopref.h>
 
 #include <klocale.h>
 #include <kglobal.h>
@@ -122,10 +123,19 @@
 #ifdef Q_WS_X11
 	d->xIdleTime = 0;
 #endif
+	kdDebug(14010) << k_funcinfo << "Idle detection methods:" << endl;
+	kdDebug(14010) << k_funcinfo << "\tKScreensaverIface::isBlanked()" << endl;
+#ifdef Q_WS_X11
+	kdDebug(14010) << k_funcinfo << "\tX11 XQueryPointer()" << endl;
+#endif
 	if (d->useXidle)
-		kdDebug(14010) << "using X11 Xidle extension" << endl;
-	if(d->useMit)
-		kdDebug(14010) << "using X11 MIT Screensaver extension" << endl;
+	{
+		kdDebug(14010) << k_funcinfo << "\tX11 Xidle extension" << endl;
+	}
+	if (d->useMit)
+	{
+		kdDebug(14010) << k_funcinfo << "\tX11 MIT Screensaver extension" << endl;
+	}
 
 
 	load();
@@ -165,7 +175,7 @@
 	d->timer->start(4000);
 
 	//init the time and other
-	setActivity();
+	setActive();
 }
 
 Kopete::Away::~Away()
@@ -264,6 +274,42 @@
 
 void Kopete::Away::slotTimerTimeout()
 {
+	// Time to check whether we're active or autoaway.  We basically have two
+	// bits of info to go on - KDE's screensaver status
+	// (KScreenSaverIface::isBlanked()) and the X11 activity detection.
+	//
+	// Note that isBlanked() is a slight of a misnomer.  It returns true if we're:
+	//  - using a non-locking screensaver, which is running, or
+	//  - using a locking screensaver which is still locked, regardless of
+	//    whether the user is trying to unlock it right now
+	// Either way, it's only worth checking for activity if the screensaver
+	// isn't blanked/locked, because activity while blanked is impossible and
+	// activity while locked never matters (if there is any, it's probably just
+	// the cleaner wiping the keyboard :).
+
+	DCOPRef screenSaver("kdesktop", "KScreensaverIface");
+	DCOPReply isBlanked = screenSaver.call("isBlanked");
+	if (!(isBlanked.isValid() && isBlanked.type == "bool" && ((bool)isBlanked)))
+	{
+		// DCOP failed, or returned something odd, or the screensaver is
+		// inactive, so check for activity the X11 way.  It's only worth
+		// checking for autoaway if there's no activity, and because
+		// Screensaver blanking/locking implies autoAway activation (see
+		// KopeteIface::KopeteIface()), only worth checking autoAway when the
+		// screensaver isn't running.
+		if (isActivity())
+		{
+			setActive();
+		}
+		else if (!d->autoaway && d->useAutoAway && idleTime() > d->awayTimeout)
+		{
+			setAutoAway();
+		}
+	}
+}
+
+bool Kopete::Away::isActivity()
+{
 	// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
 	//
 	// KDE screensaver engine
@@ -271,6 +317,8 @@
 	// This module is a heavily modified xautolock.
 	// In fact as of KDE 2.0 this code is practically unrecognisable as xautolock.
 
+	bool activity = false;
+
 #ifdef Q_WS_X11
 	Display *dsp = qt_xdisplay();
 	Window           dummy_w;
@@ -305,9 +353,9 @@
 			}
 		}
 	}
-#endif
+
 	// =================================================================================
-#ifdef Q_WS_X11
+
 	Time xIdleTime = 0; // millisecs since last input event
 
 	#ifdef HasXidle
@@ -332,10 +380,19 @@
 
 	// =================================================================================
 
-	if (root_x != d->mouse_x || root_y != d->mouse_y || mask != d->mouse_mask || xIdleTime < d->xIdleTime+2000)
+	// Only check idle time if we have some way of measuring it, otherwise if
+	// we've neither Mit nor Xidle it'll still be zero and we'll always appear active.
+	// FIXME: what problem does the 2000ms fudge solve?
+	if (root_x != d->mouse_x || root_y != d->mouse_y || mask != d->mouse_mask
+		|| ((d->useXidle || d->useMit) && xIdleTime < d->xIdleTime + 2000))
 	{
-		if(d->mouse_x!=-1) //we just gone autoaway, not activity this time
-			setActivity();
+		// -1 => just gone autoaway, ignore apparent activity this time round
+		// anything else => genuine activity
+		// See setAutoAway().
+		if (d->mouse_x != -1)
+		{
+			activity = true;
+		}
 		d->mouse_x = root_x;
 		d->mouse_y = root_y;
 		d->mouse_mask = mask;
@@ -344,13 +401,10 @@
 #endif // Q_WS_X11
 	// =================================================================================
 
-	if(!d->autoaway && d->useAutoAway && idleTime() > d->awayTimeout)
-	{
-		setAutoAway();
-	}
+	return activity;
 }
 
-void Kopete::Away::setActivity()
+void Kopete::Away::setActive()
 {
 //	kdDebug(14010) << k_funcinfo << "Found activity on desktop, resetting away timer" << endl;
 	d->idleTime.start();
@@ -381,7 +435,12 @@
 
 void Kopete::Away::setAutoAway()
 {
-	d->mouse_x=-1; //do not go availiable automaticaly after
+	// A value of -1 in mouse_x indicates to checkActivity() that next time it
+	// fires it should ignore any apparent idle/mouse/keyboard changes.
+	// I think the point of this is that if you manually start the screensaver
+	// then there'll unavoidably be some residual mouse/keyboard activity
+	// that should be ignored.
+	d->mouse_x = -1;
 
 //	kdDebug(14010) << k_funcinfo << "Going AutoAway!" << endl;
 	d->autoaway = true;
--- branches/kopete/0.12/kopete/libkopete/kopeteaway.h #511206:511207
@@ -139,6 +139,14 @@
 	 */
 	void save();
 
+	/**
+	 * @brief Check for activity using X11 methods
+	 * @return true if activity was detected, otherwise false
+	 *
+	 * Attempt to detect activity using a variety of X11 methods.
+	 */
+	bool isActivity();
+
 	//Away( const Away &rhs );
 	//Away &operator=( const Away &rhs );
 	static Away *instance;
@@ -150,14 +158,14 @@
 
 public slots:
 	/**
-	 * @brief Set the activity
+	 * @brief Mark the user active
 	 *
-	 * Plugins can set the activity if they discover activity by another way than the mouse or the keyboard
+	 * Plugins can mark the user active if they discover activity by another way than the mouse or the keyboard
 	 * (example, the motion auto away plugin)
 	 * this will reset the @ref idleTime to 0, and set all protocols to available (online) if the state was
 	 * set automatically to away because of idleness, and if they was previously online
 	 */
-	void setActivity();
+	void setActive();
 
 	/**
 	 * Use this method if you want to go in the autoaway mode.
Comment 2 Matt Rogers 2006-02-19 16:36:38 UTC
SVN commit 511336 by mattr:

backport patches for bugs 120989, 92949, and 117513
Should be in KDE 3.5.2 and the upcoming 0.12 release.

CCBUG: 120989, 92949, 117513



 M  +3 -0      kopete/kopeteiface.cpp  
 M  +74 -15    libkopete/kopeteaway.cpp  
 M  +11 -3     libkopete/kopeteaway.h  


--- branches/KDE/3.5/kdenetwork/kopete/kopete/kopeteiface.cpp #511335:511336
@@ -48,6 +48,9 @@
 		disconnectDCOPSignal("kdesktop", "KScreensaverIface",
 			"KDE_start_screensaver()", "setAutoAway()");
 	}
+	// FIXME: AFAICT, this never seems to fire.
+	connectDCOPSignal("kdesktop", "KScreensaverIface",
+		"KDE_stop_screensaver()", "setActive()", false);
 }
 
 QStringList KopeteIface::contacts()
--- branches/KDE/3.5/kdenetwork/kopete/libkopete/kopeteaway.cpp #511335:511336
@@ -32,6 +32,7 @@
 #include <kconfig.h>
 #include <qtimer.h>
 #include <kapplication.h>
+#include <dcopref.h>
 
 #include <klocale.h>
 #include <kglobal.h>
@@ -122,10 +123,19 @@
 #ifdef Q_WS_X11
 	d->xIdleTime = 0;
 #endif
+	kdDebug(14010) << k_funcinfo << "Idle detection methods:" << endl;
+	kdDebug(14010) << k_funcinfo << "\tKScreensaverIface::isBlanked()" << endl;
+#ifdef Q_WS_X11
+	kdDebug(14010) << k_funcinfo << "\tX11 XQueryPointer()" << endl;
+#endif
 	if (d->useXidle)
-		kdDebug(14010) << "using X11 Xidle extension" << endl;
-	if(d->useMit)
-		kdDebug(14010) << "using X11 MIT Screensaver extension" << endl;
+	{
+		kdDebug(14010) << k_funcinfo << "\tX11 Xidle extension" << endl;
+	}
+	if (d->useMit)
+	{
+		kdDebug(14010) << k_funcinfo << "\tX11 MIT Screensaver extension" << endl;
+	}
 
 
 	load();
@@ -165,7 +175,7 @@
 	d->timer->start(4000);
 
 	//init the time and other
-	setActivity();
+	setActive();
 }
 
 Kopete::Away::~Away()
@@ -264,6 +274,42 @@
 
 void Kopete::Away::slotTimerTimeout()
 {
+	// Time to check whether we're active or autoaway.  We basically have two
+	// bits of info to go on - KDE's screensaver status
+	// (KScreenSaverIface::isBlanked()) and the X11 activity detection.
+	//
+	// Note that isBlanked() is a slight of a misnomer.  It returns true if we're:
+	//  - using a non-locking screensaver, which is running, or
+	//  - using a locking screensaver which is still locked, regardless of
+	//    whether the user is trying to unlock it right now
+	// Either way, it's only worth checking for activity if the screensaver
+	// isn't blanked/locked, because activity while blanked is impossible and
+	// activity while locked never matters (if there is any, it's probably just
+	// the cleaner wiping the keyboard :).
+
+	DCOPRef screenSaver("kdesktop", "KScreensaverIface");
+	DCOPReply isBlanked = screenSaver.call("isBlanked");
+	if (!(isBlanked.isValid() && isBlanked.type == "bool" && ((bool)isBlanked)))
+	{
+		// DCOP failed, or returned something odd, or the screensaver is
+		// inactive, so check for activity the X11 way.  It's only worth
+		// checking for autoaway if there's no activity, and because
+		// Screensaver blanking/locking implies autoAway activation (see
+		// KopeteIface::KopeteIface()), only worth checking autoAway when the
+		// screensaver isn't running.
+		if (isActivity())
+		{
+			setActive();
+		}
+		else if (!d->autoaway && d->useAutoAway && idleTime() > d->awayTimeout)
+		{
+			setAutoAway();
+		}
+	}
+}
+
+bool Kopete::Away::isActivity()
+{
 	// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
 	//
 	// KDE screensaver engine
@@ -271,6 +317,8 @@
 	// This module is a heavily modified xautolock.
 	// In fact as of KDE 2.0 this code is practically unrecognisable as xautolock.
 
+	bool activity = false;
+
 #ifdef Q_WS_X11
 	Display *dsp = qt_xdisplay();
 	Window           dummy_w;
@@ -305,9 +353,9 @@
 			}
 		}
 	}
-#endif
+
 	// =================================================================================
-#ifdef Q_WS_X11
+
 	Time xIdleTime = 0; // millisecs since last input event
 
 	#ifdef HasXidle
@@ -332,10 +380,19 @@
 
 	// =================================================================================
 
-	if (root_x != d->mouse_x || root_y != d->mouse_y || mask != d->mouse_mask || xIdleTime < d->xIdleTime+2000)
+	// Only check idle time if we have some way of measuring it, otherwise if
+	// we've neither Mit nor Xidle it'll still be zero and we'll always appear active.
+	// FIXME: what problem does the 2000ms fudge solve?
+	if (root_x != d->mouse_x || root_y != d->mouse_y || mask != d->mouse_mask
+		|| ((d->useXidle || d->useMit) && xIdleTime < d->xIdleTime + 2000))
 	{
-		if(d->mouse_x!=-1) //we just gone autoaway, not activity this time
-			setActivity();
+		// -1 => just gone autoaway, ignore apparent activity this time round
+		// anything else => genuine activity
+		// See setAutoAway().
+		if (d->mouse_x != -1)
+		{
+			activity = true;
+		}
 		d->mouse_x = root_x;
 		d->mouse_y = root_y;
 		d->mouse_mask = mask;
@@ -344,13 +401,10 @@
 #endif // Q_WS_X11
 	// =================================================================================
 
-	if(!d->autoaway && d->useAutoAway && idleTime() > d->awayTimeout)
-	{
-		setAutoAway();
-	}
+	return activity;
 }
 
-void Kopete::Away::setActivity()
+void Kopete::Away::setActive()
 {
 //	kdDebug(14010) << k_funcinfo << "Found activity on desktop, resetting away timer" << endl;
 	d->idleTime.start();
@@ -381,7 +435,12 @@
 
 void Kopete::Away::setAutoAway()
 {
-	d->mouse_x=-1; //do not go availiable automaticaly after
+	// A value of -1 in mouse_x indicates to checkActivity() that next time it
+	// fires it should ignore any apparent idle/mouse/keyboard changes.
+	// I think the point of this is that if you manually start the screensaver
+	// then there'll unavoidably be some residual mouse/keyboard activity
+	// that should be ignored.
+	d->mouse_x = -1;
 
 //	kdDebug(14010) << k_funcinfo << "Going AutoAway!" << endl;
 	d->autoaway = true;
--- branches/KDE/3.5/kdenetwork/kopete/libkopete/kopeteaway.h #511335:511336
@@ -139,6 +139,14 @@
 	 */
 	void save();
 
+	/**
+	 * @brief Check for activity using X11 methods
+	 * @return true if activity was detected, otherwise false
+	 *
+	 * Attempt to detect activity using a variety of X11 methods.
+	 */
+	bool isActivity();
+
 	//Away( const Away &rhs );
 	//Away &operator=( const Away &rhs );
 	static Away *instance;
@@ -150,14 +158,14 @@
 
 public slots:
 	/**
-	 * @brief Set the activity
+	 * @brief Mark the user active
 	 *
-	 * Plugins can set the activity if they discover activity by another way than the mouse or the keyboard
+	 * Plugins can mark the user active if they discover activity by another way than the mouse or the keyboard
 	 * (example, the motion auto away plugin)
 	 * this will reset the @ref idleTime to 0, and set all protocols to available (online) if the state was
 	 * set automatically to away because of idleness, and if they was previously online
 	 */
-	void setActivity();
+	void setActive();
 
 	/**
 	 * Use this method if you want to go in the autoaway mode.