Request info to get user icons when a Jabber contact signs on. Fixes #4205
[adiumx.git] / Source / AdiumIdleManager.m
blob485e89383460d3bc3e51ad105a3688bbe2cc04fe
1 //
2 //  AdiumIdleManager.m
3 //  Adium
4 //
5 //  Created by Evan Schoenberg on 7/5/05.
6 //
8 #import "AdiumIdleManager.h"
9 #import "AIStatusController.h"
11 #define MACHINE_IDLE_THRESHOLD                  30      //30 seconds of inactivity is considered idle
12 #define MACHINE_ACTIVE_POLL_INTERVAL    30      //Poll every 30 seconds when the user is active
13 #define MACHINE_IDLE_POLL_INTERVAL              1       //Poll every second when the user is idle
15 //Private idle function
16 extern CFTimeInterval CGSSecondsSinceLastInputEvent(unsigned long evType);
18 @interface AdiumIdleManager (PRIVATE)
19 - (void)_setMachineIsIdle:(BOOL)inIdle;
20 - (void)screenSaverDidStart;
21 - (void)screenSaverDidStop;
22 @end
24 /*!
25  * @class AdiumIdleManager
26  * @brief Core class to manage sending notifications when the system is idle or no longe ridle
27  *
28  * Posts AIMachineIsIdleNotification to adium's notification center when the machine becomes idle.
29  * Posts AIMachineIsActiveNotification when the machine is no longer idle
30  * Posts AIMachineIdleUpdateNotification periodically while idle with an NSDictionary userInfo
31  *              containing an NSNumber double value @"Duration" (a CFTimeInterval) and an NSDate @"IdleSince".
32  */
33 @implementation AdiumIdleManager
35 /*!
36  * @brief Initialize
37  */
38 - (id)init
40         if ((self = [super init])) {
41                 [self _setMachineIsIdle:NO];
42                 [[NSDistributedNotificationCenter defaultCenter] addObserver:self
43                                                                                                                         selector:@selector(screenSaverDidStart)
44                                                                                                                                 name:@"com.apple.screensaver.didstart"
45                                                                                                                           object:nil];
46                 [[NSDistributedNotificationCenter defaultCenter] addObserver:self
47                                                                                                                         selector:@selector(screenSaverDidStop)
48                                                                                                                                 name:@"com.apple.screensaver.didstop"
49                                                                                                                           object:nil];
50         }
51         
52         return self;
55 /*!
56  * @brief Returns the current machine idle time
57  *
58  * Returns the current number of seconds the machine has been idle.  The machine is idle when there are no input
59  * events from the user (such as mouse movement or keyboard input) or when the screen saver is active.
60  * In addition to this method, the status controller sends out notifications when the machine becomes idle,
61  * stays idle, and returns to an active state.
62  */
63 - (CFTimeInterval)currentMachineIdle
65         CFTimeInterval idleTime;
67         /* CGSSecondsSinceLastInputEvent is a private function available in 10.2 and later. Note that CGEventSourceSecondsSinceLastEventType()
68          * should work as of 10.4 but doesn't return a sensical value.
69          */
70         idleTime = CGSSecondsSinceLastInputEvent(-1);
71         
72         /* On MDD Powermacs, the above function will return a large value when the machine is active (perhaps a -1?).
73          * Here we check for that value and correctly return a 0 idle time.
74          */
75         if (idleTime >= 18446744000.0) idleTime = 0.0; //18446744073.0 is the lowest I've seen on my MDD -ai            
76         
77     return idleTime;
80 /*!
81  * @brief Timer that checkes for machine idle
82  *
83  * This timer periodically checks the machine for inactivity.  When the machine has been inactive for atleast
84  * MACHINE_IDLE_THRESHOLD seconds, a notification is broadcast.
85  *
86  * When the machine is active, this timer is called infrequently.  It's not important to notice that the user went
87  * idle immediately, so we relax our CPU usage while waiting for an idle state to begin.
88  *
89  * When the machine is idle, the timer is called frequently.  It's important to notice immediately when the user
90  * returns.
91  */
92 - (void)_idleCheckTimer:(NSTimer *)inTimer
94         CFTimeInterval  currentIdle = [self currentMachineIdle];
95         
96         if (machineIsIdle) {
97                 if (currentIdle < lastSeenIdle) {
98                         /* If the machine is less idle than the last time we recorded, it means that activity has occured and the
99                         * user is no longer idle.
100                         */
101                         [self _setMachineIsIdle:NO];
102                 } else {
103                         //Periodically broadcast a 'MachineIdleUpdate' notification
104                         [[adium notificationCenter] postNotificationName:AIMachineIdleUpdateNotification
105                                                                                                           object:nil
106                                                                                                         userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
107                                                                                                                 [NSNumber numberWithDouble:currentIdle], @"Duration",
108                                                                                                                 [NSDate dateWithTimeIntervalSinceNow:-currentIdle], @"IdleSince",
109                                                                                                                 nil]];
110                 }
111         } else {
112                 //If machine inactivity is over the threshold, the user has gone idle.
113                 if (currentIdle > MACHINE_IDLE_THRESHOLD) [self _setMachineIsIdle:YES];
114         }
115         
116         lastSeenIdle = currentIdle;
120  * @brief Sets the machine as idle or not
122  * This internal method updates the frequency of our idle timer depending on whether the machine is considered
123  * idle or not.  It also posts the AIMachineIsIdleNotification and AIMachineIsActiveNotification notifications
124  * based on the passed idle state
125  */
126 - (void)_setMachineIsIdle:(BOOL)inIdle
128         machineIsIdle = inIdle;
129         
130         //Post the appropriate idle or active notification
131         if (machineIsIdle) {
132                 [[adium notificationCenter] postNotificationName:AIMachineIsIdleNotification object:nil];
133         } else {
134                 [[adium notificationCenter] postNotificationName:AIMachineIsActiveNotification object:nil];
135         }
136         
137         //Update our timer interval for either idle or active polling
138         [idleTimer invalidate];
139         [idleTimer release];
140         idleTimer = [[NSTimer scheduledTimerWithTimeInterval:(machineIsIdle ? MACHINE_IDLE_POLL_INTERVAL : MACHINE_ACTIVE_POLL_INTERVAL)
141                                                                                                   target:self
142                                                                                                 selector:@selector(_idleCheckTimer:)
143                                                                                                 userInfo:nil
144                                                                                                  repeats:YES] retain];
148  * @brief Called by the screen saver when it starts
150  * When the screen saver starts, we set ourself to idle.
151  */
152 - (void)screenSaverDidStart
154         [self _setMachineIsIdle:YES];
158  * @brief Called by the screen saver when it starts
160  * When the screen saver stops, we set ourself to active.
161  */
162 - (void)screenSaverDidStop
164         [self _setMachineIsIdle:NO];
168 @end