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 <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;
31 extern NSString *NSWorkspaceSessionDidBecomeActiveNotification __attribute__((weak_import));
32 extern NSString *NSWorkspaceSessionDidResignActiveNotification __attribute__((weak_import));
35 * @class ESFastUserSwitchingSupportPlugin
36 * @brief Handle Fast User Switching and Screen Savers with a changed status and sound muting
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.
41 @implementation ESFastUserSwitchingSupportPlugin
44 * @brief Install plugin
48 NSNotificationCenter *workspaceCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
49 [workspaceCenter addObserver:self
50 selector:@selector(switchHandler:)
51 name:NSWorkspaceSessionDidBecomeActiveNotification
54 [workspaceCenter addObserver:self
55 selector:@selector(switchHandler:)
56 name:NSWorkspaceSessionDidResignActiveNotification
59 [[NSDistributedNotificationCenter defaultCenter] addObserver:self
60 selector:@selector(switchHandler:)
61 name:@"com.apple.screensaver.didstart"
64 [[NSDistributedNotificationCenter defaultCenter] addObserver:self
65 selector:@selector(switchHandler:)
66 name:@"com.apple.screensaver.didstop"
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];
75 * @brief Preferences changed
77 * Note whether we are supposed to change states on FUS or SS.
79 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
80 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
82 fastUserSwitchStatusID = [prefDict objectForKey:KEY_STATUS_FUS_STATUS_STATE_ID];
83 screenSaverStatusID = [prefDict objectForKey:KEY_STATUS_SS_STATUS_STATE_ID];
85 fastUserSwitchStatus = [[prefDict objectForKey:KEY_STATUS_FUS] boolValue];
86 screenSaverStatus = [[prefDict objectForKey:KEY_STATUS_SS] boolValue];
90 * @brief Uninstall plugin
92 - (void)uninstallPlugin
94 //Clear the fast switch away if we had it up before
95 [self switchHandler:nil];
97 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
98 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
99 [[adium preferenceController] unregisterPreferenceObserver:self];
104 [previousStatusStateDict release];
105 [accountsToReconnect release];
111 * @brief Handle a fast user switch or screen saver event
113 * Calling this with (notification == nil) is the same as when the user switches back.
115 * @param notification The notification has a name NSWorkspaceSessionDidResignActiveNotification when the user switches away and NSWorkspaceSessionDidBecomeActiveNotification when the user switches back.
117 -(void)switchHandler:(NSNotification*) notification
120 (([[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification] && fastUserSwitchStatus) ||
121 ([[notification name] isEqualToString:@"com.apple.screensaver.didstart"] && screenSaverStatus))) {
122 //Deactivation - go away
123 //Go away if we aren't already away, noting the current status states for restoration later
124 NSEnumerator *enumerator;
126 AIStatusItem *targetStatusState;
128 if (!previousStatusStateDict) previousStatusStateDict = [[NSMutableDictionary alloc] init];
130 if ([[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification])
131 targetStatusState = [[adium statusController] statusStateWithUniqueStatusID:fastUserSwitchStatusID];
133 targetStatusState = [[adium statusController] statusStateWithUniqueStatusID:screenSaverStatusID];
135 if ([targetStatusState isKindOfClass:[AIStatusGroup class]]) {
136 targetStatusState = [(AIStatusGroup *)targetStatusState anyContainedStatus];
139 if (targetStatusState) {
140 enumerator = [[[adium accountController] accounts] objectEnumerator];
141 while ((account = [enumerator nextObject])) {
142 AIStatus *currentStatusState = [account statusState];
143 if ([currentStatusState statusType] == AIAvailableStatusType) {
144 //Store the state the account is in at present
145 [previousStatusStateDict setObject:currentStatusState
146 forKey:[NSNumber numberWithUnsignedInt:[account hash]]];
148 if ([account online]) {
149 //If online, set the state
150 [account setStatusState:(AIStatus *)targetStatusState];
152 //If we just brought the account offline, note that it will need to be reconnected later
153 if ([targetStatusState statusType] == AIOfflineStatusType) {
154 if (!accountsToReconnect) accountsToReconnect = [[NSMutableSet alloc] init];
155 [accountsToReconnect addObject:account];
158 //If offline, set the state without coming online
159 [account setStatusStateAndRemainOffline:(AIStatus *)targetStatusState];
165 } else if (!notification ||
166 (([[notification name] isEqualToString:NSWorkspaceSessionDidBecomeActiveNotification] && fastUserSwitchStatus) ||
167 ([[notification name] isEqualToString:@"com.apple.screensaver.didstop"] && screenSaverStatus))) {
168 //Activation - return from away
170 //Remove the away status flag if we set it originally
171 NSEnumerator *enumerator;
174 enumerator = [[[adium accountController] accounts] objectEnumerator];
175 while ((account = [enumerator nextObject])) {
176 AIStatus *targetStatusState;
177 NSNumber *accountHash = [NSNumber numberWithUnsignedInt:[account hash]];
179 targetStatusState = [previousStatusStateDict objectForKey:accountHash];
180 if (targetStatusState) {
181 if ([account online] || [accountsToReconnect containsObject:account]) {
182 //If online or needs to be reconnected, set the previous state, going online if necessary
183 [account setStatusState:targetStatusState];
185 //If offline, set the state without coming online
186 [account setStatusStateAndRemainOffline:targetStatusState];
191 [previousStatusStateDict release]; previousStatusStateDict = nil;
192 [accountsToReconnect release]; accountsToReconnect = nil;