If you've ever written a GUI (WinForms) application and wanted to periodically run a background process (such as poll a database), or need to log off the user or close a connection after a certain amount of inactivity, this class may be for you.
I created this class so my application could occasionally check the database for updated records (by other users). I didn't want to run the check while the user was busy entering data, and I certainly didn't want to hit the database in the middle of some transactional save and risk blocking or even deadlocking the operation. So I needed to know when both the user and the CPU were idle. I also wanted to know when the application became idle, and also wanted periodic updates while the application remained idle.
I wound up using a two-step detection process:
- Hook into the
System.Windows.Forms.Application.Idle event to help detect when the user is idle. Note, I said help ....
- If the user is idle, use
System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime to determine if the CPU is idle (at least for this process).
I also had to add a third component, a timer, in order to continue detecting idle state. I found that while an application has focus, it seems to get a "pulse" (in the form of an
Application.Idle event) once a second, even if there are no timers in the application. However, once a different application gets focus, the background app no longer gets that pulse. If I dig around, I would expect to find that Windows™ is sending a system clock update to whichever application has focus. Regardless of its origin, I needed to give the class its own "heartbeat" so it would continue to operate as a background application.
Using the code
The main code is in the static class
public static event ApplicationIdle;
This static event is what you would normally use to listen for idleness. When the application is determined to be idle, you will receive an event containing an
ApplicationIdleEventArgs which tells you:
DateTime IdleSince: the time the application became idle.
TimeSpan IdleDuration: the length of time the application has been idle.
Additionally, you can query the following static class properties to learn:
bool IsIdle : Returns the last determined idle state. Idle state is recomputed once per second. Both the GUI and the CPU must be idle for this property to be
double CurrentGUIActivity: Returns an "indication" of the GUI activity, expressed as activity per second. 0 indicates no activity. GUI activities include user interactions (typing, moving mouse) as well as events, paint operations, etc.
double CurrentCPUUsage: Returns the percent CPU use for the current process (0.0-1.0). Will return
double.NaN if indeterminate.
Additionally, there are a couple of adjustable settings you can use to tune the idle detection for your application:
double GUIActivityThreshold: The threshold (GUI activity) for determining idleness. GUI activity below this level is considered "idle".
double CPUUsageThreshold: The threshold (CPU usage) for determining idleness. CPU usage below this level is considered "idle". A value >= 1.0 will disable CPU idle checking.
The demo app, shown above, displays all the available properties, and allows you to adjust behavior at run-time. Run the application and simply move the mouse, and the status indicator should flip from "idle" to "busy". Increase the GUI threshold until normal mouse movement does not reset the state. Then click the "Do iterations" button to perform a CPU-intensive task, which will also flip the state to "busy". You can adjust the CPU threshold as well, and a threshold of 100% will disable CPU checks in the idle detection. The "yield" checkbox determines if the form will continue to process GUI messages while the iterations are running.
If you watch closely, you may notice that the GUI indicator sometimes exceeds its threshold, but the class continues to think the application is idle! This is because the activity may occasionally spike, but the threshold is compared to average activity per second. So as long as the average activity over a second stays below the threshold, the application is deemed idle. The CPU counter works generally the same way, except its duration can vary (based on how frequently -- or infrequently -- it is called).
Points of Interest
In reality, this demo is not the best demonstration, because all the timers and frequent painting tend to throw off the idle detection. The act of showing you how idle the application is keeps it fairly busy!
App.Idle events counter in the demo. It displays the total number of
System.Windows.Forms.Application.Idle events received. You may want to compare it to the display from the following extremely trimmed down code:
public class IdleForm : System.Windows.Forms.Form
private System.Windows.Forms.Label label1;
private long idleCounter = 0;
private void InitializeComponent()
this.Size = new System.Drawing.Size(300,300);
this.label1 = new System.Windows.Forms.Label();
new System.Drawing.Font("Microsoft Sans Serif", 18F,
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(300,300);
public static void Main(string args)
private void Idle_Count(object sender, System.EventArgs e)
label1.Text = idleCounter.ToString();
Areas of Improvement
- Because "idleness" depends to a large degree on the capacity and speed of the machine the application runs on, one improvement would be to let the threshold values "auto-tune" by collecting usage stats for a few minutes, and adjusting the values accordingly.
- A third idle check could be added if you wanted to make sure the computer, and not just the application, is idle. In 1.1, you simply need to monitor
Process.GetProcessById(0).TotalProcessorTime, which tells you the amount of CPU time spent on the System Idle Process. In 2.0, I've heard it's a bit more difficult since the Framework no longer allows access to process 0.