A common user annoyance is having alerts popping up at bad times. The worst is when the user is typing and focus gets stolen only to have subsequent key presses going to the new window, possibly resulting in the user inadvertently confirming something they didn’t want to. Peter Hosey discusses this particular case and outlines an NSAlert-based solution.
I recently submitted a patch for Sparkle+ to deal with a similar situation. It can be annoying to get an alert about a new version when you are working. A new version is not a “drop everything and deal with this now” type of alert. With this patch, when a new update is found, it will check the user’s idle time and hold off showing the panel until a certain amount of time has elapsed. This minimizes the chance of the user being in the middle of something when the alert comes up. Of course, this is only suitable for when the alert itself is not terribly critical or time-sensitive. It should not be used if it is in response to direct user action or if the alert is something that needs to be dealt with immediately.
Since this type of thing may be useful in other contexts, I’ve decided to generalize it and put it out there for your consumption. It’s a little NSObject category with two new methods:
performSelector:withObject:afterSystemIdleTime:withinTimeLimit:. The first will call the given method on the receiver when the user has been idle for the given period of time. The second method does the same but allows you to set a limit after which it will call the method regardless of idle time, thus preventing the method from being delayed indefinitely.
Beyond the use described above, you can use it in several other situations, such as doing some internal maintenance that may get in the way if the user is actively using the machine. You can reclaim/free memory, clear out caches, compact file stores, optimize data structures or whatever.
For the time being, I am using this in my Sparkle update alerts and my scheduled evaluation period expiration nags. What will be interesting is if this leads to some sort of “refrigerator light syndrome” where users notice that it only happens when they are not looking and are somehow bothered by it. Most likely, though, users probably won’t notice and, with any luck, they will be more receptive to the alerts when they do pop up. If that leads to an extra spring in their step, then I consider it a job well done.
The project is linked below. Make sure you read the Read Me file. If you end up using it, let me know.
Update (Jan 10, 2008): The original project had a couple files specified as absolute paths (so XCode wouldn’t find them). A new project has been put up with this error fixed. It is marked as version 0.6 in the package name and Read Me file.
Update (Feb 5, 2008): It appears that the
CGEventSourceSecondsSinceLastEventType() function hangs on Tiger systems. I have updated the code to check for the OS version and only do the idle delay on Leopard and later.
I am also looking into patching this in Sparkle+. If you are using Sparkle+ with this feature enabled, drop me a line or wait for the patch which will hopefully happen soon.