Put NSAutoreleasePool usage around other distributed notification observer methods
[adiumx.git] / Source / ESFastUserSwitchingSupportPlugin.m
blobaeb3239b4d7bb0735c37be49be91fe398a60e018
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
11  * Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License along with this program; if not,
14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
17 #import <Adium/AIAccountControllerProtocol.h>
18 #import <Adium/AIPreferenceControllerProtocol.h>
19 #import "AISoundController.h"
20 #import "AIStatusController.h"
21 #import "ESFastUserSwitchingSupportPlugin.h"
22 #import <AIUtilities/AIAttributedStringAdditions.h>
23 #import <AIUtilities/AIApplicationAdditions.h>
24 #import <Adium/AIAccount.h>
25 #import <Adium/AIStatusGroup.h>
27 @interface ESFastUserSwitchingSupportPlugin (PRIVATE)
28 -(void)switchHandler:(NSNotification*) notification;
29 @end
31 extern NSString *NSWorkspaceSessionDidBecomeActiveNotification __attribute__((weak_import));
32 extern NSString *NSWorkspaceSessionDidResignActiveNotification __attribute__((weak_import));
34 /*!
35  * @class ESFastUserSwitchingSupportPlugin
36  * @brief Handle Fast User Switching and Screen Savers with a changed status and sound muting
37  *
38  * When the Screen Saver activates, or another user logs in via Fast User Switching (OS X 10.3 and above),
39  * this plugin sets a status state if an away state is not already set.
40  */
41 @implementation ESFastUserSwitchingSupportPlugin
43 /*!
44  * @brief Install plugin
45  */
46 - (void)installPlugin
48         NSNotificationCenter *workspaceCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
49         [workspaceCenter addObserver:self
50                             selector:@selector(switchHandler:)
51                                 name:NSWorkspaceSessionDidBecomeActiveNotification
52                               object:nil];
54         [workspaceCenter addObserver:self
55                             selector:@selector(switchHandler:)
56                                 name:NSWorkspaceSessionDidResignActiveNotification
57                               object:nil];
59         [[NSDistributedNotificationCenter defaultCenter] addObserver:self
60                             selector:@selector(switchHandler:)
61                                 name:@"com.apple.screensaver.didstart"
62                               object:nil];
63         
64         [[NSDistributedNotificationCenter defaultCenter] addObserver:self
65                             selector:@selector(switchHandler:)
66                                 name:@"com.apple.screensaver.didstop"
67                               object:nil];
69         //Observe preference changes for updating when and how we should automatically change our state
70         [[adium preferenceController] registerPreferenceObserver:self
71                                                                                                                 forGroup:PREF_GROUP_STATUS_PREFERENCES];
74 /*!
75  * @brief Preferences changed
76  *
77  * Note whether we are supposed to change states on FUS or SS.
78  */
79 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
80                                                         object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
82         [fastUserSwitchStatusID release];
83         fastUserSwitchStatusID = [[prefDict objectForKey:KEY_STATUS_FUS_STATUS_STATE_ID] retain];
84         [screenSaverStatusID release];
85         screenSaverStatusID    = [[prefDict objectForKey:KEY_STATUS_SS_STATUS_STATE_ID] retain];
86         
87         fastUserSwitchStatus = [[prefDict objectForKey:KEY_STATUS_FUS] boolValue];
88         screenSaverStatus = [[prefDict objectForKey:KEY_STATUS_SS] boolValue];
91 /*!
92  * @brief Uninstall plugin
93  */
94 - (void)uninstallPlugin
96         //Clear the fast switch away if we had it up before
97         [self switchHandler:nil];
99         [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
100         [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
101         [[adium preferenceController] unregisterPreferenceObserver:self];
104 - (void)dealloc
106         [previousStatusStateDict release];
107         [accountsToReconnect release];
108         
109         [fastUserSwitchStatusID release];
110         [screenSaverStatusID release];
112         [super dealloc];
116  * @brief Handle a fast user switch or screen saver event
118  * Calling this with (notification == nil) is the same as when the user switches back.
120  * @param notification The notification has a name NSWorkspaceSessionDidResignActiveNotification when the user switches away and NSWorkspaceSessionDidBecomeActiveNotification when the user switches back.
121  */
122 -(void)switchHandler:(NSNotification*) notification
124         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
126         if (notification &&
127                 (([[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification] && fastUserSwitchStatus) ||
128                         ([[notification name] isEqualToString:@"com.apple.screensaver.didstart"] && screenSaverStatus))) {
129                 //Deactivation - go away
130                 //Go away if we aren't already away, noting the current status states for restoration later
131                 NSEnumerator    *enumerator;
132                 AIAccount               *account;
133                 AIStatusItem    *targetStatusState;
135                 if (!previousStatusStateDict) previousStatusStateDict = [[NSMutableDictionary alloc] init];
137                 if ([[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification])
138                         targetStatusState = [[adium statusController] statusStateWithUniqueStatusID:fastUserSwitchStatusID];
139                 else
140                         targetStatusState = [[adium statusController] statusStateWithUniqueStatusID:screenSaverStatusID];
141                 
142                 if ([targetStatusState isKindOfClass:[AIStatusGroup class]]) {
143                         targetStatusState = [(AIStatusGroup *)targetStatusState anyContainedStatus];
144                 }
145                 
146                 if (targetStatusState) {
147                         enumerator = [[[adium accountController] accounts] objectEnumerator];
148                         while ((account = [enumerator nextObject])) {
149                                 AIStatus        *currentStatusState = [account statusState];
150                                 if ([currentStatusState statusType] == AIAvailableStatusType) {
151                                         //Store the state the account is in at present
152                                         [previousStatusStateDict setObject:currentStatusState
153                                                                                                 forKey:[NSNumber numberWithUnsignedInt:[account hash]]];
155                                         if ([account online]) {
156                                                 //If online, set the state
157                                                 [account setStatusState:(AIStatus *)targetStatusState];
158                                                 
159                                                 //If we just brought the account offline, note that it will need to be reconnected later
160                                                 if ([targetStatusState statusType] == AIOfflineStatusType) {
161                                                         if (!accountsToReconnect) accountsToReconnect = [[NSMutableSet alloc] init];
162                                                         [accountsToReconnect addObject:account];
163                                                 }
164                                         } else {
165                                                 //If offline, set the state without coming online
166                                                 [account setStatusStateAndRemainOffline:(AIStatus *)targetStatusState];
167                                         }
168                                 }
169                         }
170                 }
172         } else if (!notification ||
173                            (([[notification name] isEqualToString:NSWorkspaceSessionDidBecomeActiveNotification] && fastUserSwitchStatus) ||
174                                 ([[notification name] isEqualToString:@"com.apple.screensaver.didstop"] && screenSaverStatus))) {
175                 //Activation - return from away
177                 //Remove the away status flag if we set it originally
178                 NSEnumerator    *enumerator;
179                 AIAccount               *account;
181                 enumerator = [[[adium accountController] accounts] objectEnumerator];
182                 while ((account = [enumerator nextObject])) {
183                         AIStatus                *targetStatusState;
184                         NSNumber                *accountHash = [NSNumber numberWithUnsignedInt:[account hash]];
186                         targetStatusState = [previousStatusStateDict objectForKey:accountHash];
187                         if (targetStatusState) {
188                                 if ([account online] || [accountsToReconnect containsObject:account]) {
189                                         //If online or needs to be reconnected, set the previous state, going online if necessary
190                                         [account setStatusState:targetStatusState];
191                                 } else {
192                                         //If offline, set the state without coming online
193                                         [account setStatusStateAndRemainOffline:targetStatusState];
194                                 }
195                         }
196                 }
198                 [previousStatusStateDict release]; previousStatusStateDict = nil;
199                 [accountsToReconnect release]; accountsToReconnect = nil;
200         }
201         
202         [pool release];
205 @end