Click here to Skip to main content
15,867,968 members
Articles / Desktop Programming / Windows Forms
Article

Detecting Application Idleness

Rate me:
Please Sign up or sign in to vote.
4.71/5 (25 votes)
11 Apr 2006CPOL5 min read 164K   7.6K   129   22
A utility class that alerts your code when the application is idle.

Sample Image - screenshot.jpg

Introduction

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.

Background

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:

  1. Hook into the System.Windows.Forms.Application.Idle event to help detect when the user is idle. Note, I said help ....
  2. 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 ApplicationIdleTimer.

C#
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 true.
  • 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!

Watch the 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:

C#
using System;
using System.Windows.Forms;

namespace Demo
{
    public class IdleForm : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Label label1;
        private long idleCounter = 0;

        public IdleForm()
        {
            InitializeComponent();
            Application.Idle += 
               new System.EventHandler(this.Idle_Count);
        }
        private void InitializeComponent()
        {
            this.Size = new System.Drawing.Size(300,300);
            this.label1 = new System.Windows.Forms.Label();
            this.label1.Font = 
                new System.Drawing.Font("Microsoft Sans Serif", 18F, 
                System.Drawing.FontStyle.Regular, 
                System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(300,300);
            this.Controls.Add(label1);
        }

        public static void Main(string[] args) 
        {
            Application.Run(new IdleForm());
        }
        
        private void Idle_Count(object sender, System.EventArgs e)
        {
            idleCounter ++;
            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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Soren.Persian5-Jul-12 5:06
professionalSoren.Persian5-Jul-12 5:06 
QuestionCan Anyone change this C# code to vb.net ( Only ApplicationIdleTimer.cs ) thanks Pin
ThetNaing_8322-Jun-11 0:30
ThetNaing_8322-Jun-11 0:30 
GeneralThis is great Pin
jojodim3-Feb-11 22:23
jojodim3-Feb-11 22:23 
GeneralWhen typing the textbox in the demo application it show it is idle.. Pin
himanshu31322-Oct-09 10:56
himanshu31322-Oct-09 10:56 
GeneralRe: When typing the textbox in the demo application it show it is idle.. Pin
GWSyZyGy22-Oct-09 11:15
GWSyZyGy22-Oct-09 11:15 
GeneralDetect Application Busyness Pin
pluniewski9-Jan-09 0:25
pluniewski9-Jan-09 0:25 
QuestionHow do i avoid cross-threading exception in vb.net? Pin
josepaulino4-Oct-07 14:32
josepaulino4-Oct-07 14:32 
AnswerRe: How do i avoid cross-threading exception in vb.net? Pin
GWSyZyGy29-Oct-07 5:53
GWSyZyGy29-Oct-07 5:53 
GeneralProblems Pin
olegbi_q24-Oct-07 7:40
olegbi_q24-Oct-07 7:40 
GeneralRe: Problems Pin
GWSyZyGy29-Oct-07 5:51
GWSyZyGy29-Oct-07 5:51 
GeneralNice Example! Here a fix for crossthreading issue Pin
wbekker2-Apr-07 23:08
wbekker2-Apr-07 23:08 
QuestionRe: Nice Example! Here a fix for crossthreading issue Pin
josepaulino4-Oct-07 14:28
josepaulino4-Oct-07 14:28 
AnswerRe: Nice Example! Here a fix for crossthreading issue Pin
Patrice Dargenton9-Sep-11 21:26
Patrice Dargenton9-Sep-11 21:26 
QuestionCool, but Pin
alex.almeida14-Feb-07 8:15
alex.almeida14-Feb-07 8:15 
AnswerRe: Cool, but Pin
GWSyZyGy28-Mar-07 5:58
GWSyZyGy28-Mar-07 5:58 
GeneralAnother way Pin
gbarcalow7-Feb-07 12:46
gbarcalow7-Feb-07 12:46 
GeneralRe: Another way Pin
Sara Kulu17-Jul-07 10:58
Sara Kulu17-Jul-07 10:58 
Generalapplication idle time Pin
Higgs9621-Sep-06 10:20
Higgs9621-Sep-06 10:20 
GeneralThmbs up man! Pin
Sing Abend12-Aug-06 5:28
professionalSing Abend12-Aug-06 5:28 
GeneralAwesome seconded! Pin
pennidren14-Jun-06 6:54
pennidren14-Jun-06 6:54 
GeneralAwesome Pin
Girb12-Apr-06 1:54
Girb12-Apr-06 1:54 
GeneralRe: Awesome Pin
GWSyZyGy12-Apr-06 6:19
GWSyZyGy12-Apr-06 6:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.