2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
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.
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.
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.
17 #import "AIAccountController.h"
18 //#import "AIContentController.h"
19 #import "AIPreferenceController.h"
20 #import "AISoundController.h"
21 #import "AIStatusController.h"
22 #import "ESFastUserSwitchingSupportPlugin.h"
23 #import <AIUtilities/AIAttributedStringAdditions.h>
24 #import <AIUtilities/CBApplicationAdditions.h>
25 #import <Adium/AIAccount.h>
27 #define FAST_USER_SWITCH_AWAY_STRING AILocalizedString(@"I have switched logged in users. Someone else may be using the computer.","Fast user switching away message")
29 @interface ESFastUserSwitchingSupportPlugin (PRIVATE)
30 -(void)switchHandler:(NSNotification*) notification;
33 extern NSString *NSWorkspaceSessionDidBecomeActiveNotification __attribute__((weak_import));
34 extern NSString *NSWorkspaceSessionDidResignActiveNotification __attribute__((weak_import));
37 * @class ESFastUserSwitchingSupportPlugin
38 * @brief Handle Fast User Switching with a changed status and sound muting
40 * When another user logs in via Fast User Switching (OS X 10.3 and above), this plugin sets a status state if an away
41 * state is not already set. It also mutes sounds as per the HIG.
43 * At present, this plugin uses a hardcoded away message.
45 @implementation ESFastUserSwitchingSupportPlugin
48 * @brief Install plugin
50 * Has no effect on Jaguar
54 //only install on Panther.
55 if([NSApp isOnPantherOrBetter]) {
56 setAwayThroughFastUserSwitch = NO;
57 setMuteThroughFastUserSwitch = NO;
58 monitoringFastUserSwitch = NO;
60 NSNotificationCenter *workspaceCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
61 [workspaceCenter addObserver:self
62 selector:@selector(switchHandler:)
63 name:NSWorkspaceSessionDidBecomeActiveNotification
66 [workspaceCenter addObserver:self
67 selector:@selector(switchHandler:)
68 name:NSWorkspaceSessionDidResignActiveNotification
71 //Observe preference changes for updating when and how we should automatically change our state
72 [[adium preferenceController] registerPreferenceObserver:self
73 forGroup:PREF_GROUP_STATUS_PREFERENCES];
78 * @brief Preferences changed
80 * Note whether we are supposed to change states on FUS.
82 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
83 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
85 fastUserSwitchStatusID = [prefDict objectForKey:KEY_STATUS_FUS_STATUS_STATE_ID];
87 monitoringFastUserSwitch = (fastUserSwitchStatusID ?
88 [[prefDict objectForKey:KEY_STATUS_FUS] boolValue] :
93 * @brief Uninstall plugin
95 * Has no effect on Jaguar
97 - (void)uninstallPlugin
99 //only uninstall on Panther
100 if([NSApp isOnPantherOrBetter]) {
101 //Clear the fast switch away if we had it up before
102 [self switchHandler:nil];
104 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
105 [[adium preferenceController] unregisterPreferenceObserver:self];
111 [previousStatusStateDict release];
112 [accountsToReconnect release];
118 * @brief Handle a fast user switch event
120 * Calling this with (notification == nil) is the same as when the user switches back.
121 * Do not call this method in OS X 10.2.x.
123 * @param notification The notification has a name NSWorkspaceSessionDidResignActiveNotification when the user switches away and NSWorkspaceSessionDidBecomeActiveNotification when the user switches back.
125 -(void)switchHandler:(NSNotification*) notification
128 [[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification]) {
129 //Deactivation - go away
131 //Go away if we aren't already away, noting the current status states for restoration later
132 NSEnumerator *enumerator;
134 AIStatus *targetStatusState;
136 if(!previousStatusStateDict) previousStatusStateDict = [[NSMutableDictionary alloc] init];
138 targetStatusState = [[adium statusController] statusStateWithUniqueStatusID:fastUserSwitchStatusID];
140 if(targetStatusState){
141 enumerator = [[[adium accountController] accountArray] objectEnumerator];
142 while(account = [enumerator nextObject]){
143 AIStatus *currentStatusState = [account statusState];
144 if([currentStatusState statusType] == AIAvailableStatusType){
145 //Store the state the account is in at present
146 [previousStatusStateDict setObject:currentStatusState
147 forKey:[NSNumber numberWithUnsignedInt:[account hash]]];
149 if([account online]){
150 //If online, set the state
151 [account setStatusState:targetStatusState];
153 //If we just brought the account offline, note that it will need to be reconnected later
154 if([targetStatusState statusType] == AIOfflineStatusType){
155 if(!accountsToReconnect) accountsToReconnect = [[NSMutableSet alloc] init];
156 [accountsToReconnect addObject:account];
159 //If offline, set the state without coming online
160 [account setStatusStateAndRemainOffline:targetStatusState];
166 //Set a temporary mute if none already exists
167 NSNumber *oldTempMute = [[adium preferenceController] preferenceForKey:KEY_SOUND_TEMPORARY_MUTE
168 group:PREF_GROUP_SOUNDS];
169 if (!oldTempMute || ![oldTempMute boolValue]) {
170 [[adium preferenceController] setPreference:[NSNumber numberWithBool:YES]
171 forKey:KEY_SOUND_TEMPORARY_MUTE
172 group:PREF_GROUP_SOUNDS];
173 setMuteThroughFastUserSwitch = YES;
176 //Activation - return from away
178 //Remove the away status flag if we set it originally
179 NSEnumerator *enumerator;
182 enumerator = [[[adium accountController] accountArray] objectEnumerator];
183 while(account = [enumerator nextObject]){
184 AIStatus *targetStatusState;
185 NSNumber *accountHash = [NSNumber numberWithUnsignedInt:[account hash]];
187 targetStatusState = [previousStatusStateDict objectForKey:accountHash];
188 if(targetStatusState){
189 if([account online] || [accountsToReconnect containsObject:account]){
190 //If online or needs to be reconnected, set the previous state, going online if necessary
191 [account setStatusState:targetStatusState];
193 //If offline, set the state without coming online
194 [account setStatusStateAndRemainOffline:targetStatusState];
199 //Clear the temporary mute if necessary
200 if (setMuteThroughFastUserSwitch) {
201 [[adium preferenceController] setPreference:nil
202 forKey:KEY_SOUND_TEMPORARY_MUTE
203 group:PREF_GROUP_SOUNDS];
206 [previousStatusStateDict release]; previousStatusStateDict = nil;
207 [accountsToReconnect release]; accountsToReconnect = nil;