00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #define USE_DAPREFERENCES 1
00023
00024 #import "DownAndOutController.h"
00025 #import "DownAndOutView.h"
00026 #import "DAApplication.h"
00027
00028 #if USE_DAPREFERENCES
00029 #include "DAPreferences.h"
00030
00031 static DAPreferences * sPreferences = nil;
00032 #endif
00033
00035 #define DEFAULT_LOGOUT 300
00036
00037 #define DEFAULT_SHOULD_MOVE YES
00038
00039 #define DEFAULT_MESSAGE @"%n will log out automatically in %t"
00040
00041 #define DEFAULT_RADIUS 30
00042
00043 @implementation DownAndOutController
00044
00045 static DownAndOutController * sMainController = nil;
00046 static NSArray * sTags = nil;
00047
00050 + (void) initialize
00051 {
00052 if (self == [DownAndOutController class]) {
00053 NSDictionary * stdDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
00054 [NSNumber numberWithInt: DEFAULT_LOGOUT], @"secondsBeforeLogout",
00055 [NSNumber numberWithBool: DEFAULT_SHOULD_MOVE], @"shouldMove",
00056 [NSNumber numberWithBool: NO], @"usesImage",
00057 [NSNumber numberWithInt: DEFAULT_RADIUS], @"clockRadius",
00058 DEFAULT_MESSAGE, @"messageText",
00059 nil];
00060 #if USE_DAPREFERENCES
00061 sPreferences = [[DAPreferences alloc] initWithDefaults: stdDefaults];
00062 #else
00063 ScreenSaverDefaults * defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00064 [defaults registerDefaults: stdDefaults];
00065 #endif
00066
00067 sTags = [[NSArray alloc] initWithObjects:
00068 @"%s", @"%t", @"%n", @"%u", nil
00069 ];
00070 }
00071 }
00072
00073 - (id) initAsPreview: (BOOL) inIsPreview forView: (DownAndOutView *) aView
00074 {
00075 #if USE_DAPREFERENCES
00076 DAPreferences * defaults = sPreferences;
00077 #else
00078 ScreenSaverDefaults * defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00079 #endif
00080
00081 view = aView;
00082
00083 if (!inIsPreview && !sMainController)
00084 sMainController = self;
00085
00086 secondsBeforeLogout = [defaults integerForKey: @"secondsBeforeLogout"];
00087 shouldMove = [defaults boolForKey: @"shouldMove"];
00088
00089 if ([defaults boolForKey: @"usesImage"]) {
00090 NSData * imageData = [defaults dataForKey: @"addedImage"];
00091
00092 addedImage = (NSImage *) [NSUnarchiver unarchiveObjectWithData: imageData];
00093 [addedImage retain];
00094 }
00095 else
00096 addedImage = nil;
00097
00098 messageText = [[defaults stringForKey: @"messageText"] retain];
00099
00100 [view setClockRadius: [defaults integerForKey: @"clockRadius"]];
00101
00102 return self;
00103 }
00104
00105 - (void) dispose
00106 {
00107 [messageText release];
00108 [addedImage release];
00109 }
00110
00111 - (NSPanel *) panel
00112 {
00113 return panel;
00114 }
00115
00118 - (void) colorMessageField
00119 {
00120 NSTextStorage * storage = [messageField textStorage];
00121 NSString * content = [storage string];
00122 NSRange contentRange = NSMakeRange(0, [content length]);
00123
00124 [storage removeAttribute: NSForegroundColorAttributeName
00125 range: contentRange];
00126
00127 NSEnumerator * iter = [sTags objectEnumerator];
00128 NSString * curr;
00129
00130 while (curr = [iter nextObject]) {
00131 NSRange found = { 0, 0 };
00132 do {
00133 found = [content rangeOfString: curr
00134 options: NSLiteralSearch
00135 range: NSMakeRange(NSMaxRange(found),
00136 contentRange.length - NSMaxRange(found))];
00137 if (found.location != NSNotFound) {
00138 [storage addAttribute: NSForegroundColorAttributeName
00139 value: [NSColor blueColor]
00140 range: found];
00141 }
00142 } while (NSLocationInRange(found.location, contentRange));
00143 }
00144 }
00145
00148 - (void) awakeFromNib
00149 {
00150 #if USE_DAPREFERENCES
00151 DAPreferences * defaults = sPreferences;
00152 #else
00153 ScreenSaverDefaults * defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00154 #endif
00155
00156 [self setSecondsBeforeLogout: secondsBeforeLogout];
00157 if (shouldMove)
00158 [movementMatrix selectCellAtRow: 0 column: 0];
00159 else
00160 [movementMatrix selectCellAtRow: 1 column: 0];
00161 [imageWell setImage: addedImage];
00162 [imageClear setEnabled: (addedImage != nil)];
00163
00164 [[messageField textStorage]
00165 replaceCharactersInRange: NSMakeRange(0, [[messageField textStorage] length])
00166 withString: messageText];
00167 [self colorMessageField];
00168
00169 [sizeSlider setFloatValue: [defaults integerForKey: @"clockRadius"]];
00170 }
00171
00175 - (void) textDidChange: (NSNotification *) notice
00176 {
00177 if ([notice object] == messageField)
00178 [self colorMessageField];
00179 }
00180
00181 - (IBAction) moveSelected: (id) sender
00182 {
00183
00184 }
00185
00186 - (BOOL) shouldMove { return shouldMove; }
00187
00188 - (IBAction) endButton: (id) sender
00189 {
00190 if (sender == okButton) {
00191 secondsBeforeLogout = [timeStepper intValue];
00192 #if USE_DAPREFERENCES
00193 DAPreferences * defaults = sPreferences;
00194 #else
00195 ScreenSaverDefaults * defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00196 #endif
00197 [defaults setInteger: secondsBeforeLogout forKey: @"secondsBeforeLogout"];
00198
00199 int row = [movementMatrix selectedRow];
00200 shouldMove = (row == 0);
00201 [defaults setBool: shouldMove forKey: @"shouldMove"];
00202
00203 [self setAddedImage: [imageWell image]];
00204 if (addedImage) {
00205 [defaults setBool: YES forKey: @"usesImage"];
00206 NSData * imageData = [NSArchiver archivedDataWithRootObject: addedImage];
00207 [defaults setObject: imageData forKey: @"addedImage"];
00208 }
00209 else {
00210 [defaults setBool: NO forKey: @"usesImage"];
00211 [defaults removeObjectForKey: @"addedImage"];
00212 }
00213
00214 messageText = [[[messageField textStorage] string] copy];
00215 [defaults setObject: messageText forKey: @"messageText"];
00216
00217 float value = [sizeSlider floatValue];
00218 [view setClockRadius: value];
00219 [defaults setInteger: (int) value forKey: @"clockRadius"];
00220
00221 #if USE_DAPREFERENCES
00222 [defaults flushToFile];
00223 #endif
00224 }
00225
00226 [[NSApplication sharedApplication] endSheet: panel];
00227 }
00228
00229 - (IBAction) sliderAction: (id) sender
00230 {
00231 }
00232
00233 - (NSString *) messageText { return messageText; }
00234
00235 - (NSString *) messageTextForSeconds: (int) seconds
00236 {
00237 NSMutableString * retval = [NSMutableString stringWithString: messageText];
00238
00239 NSString * userID = (NSString *) CSCopyUserName(YES);
00240 [retval replaceOccurrencesOfString: @"%u" withString: userID
00241 options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00242
00243 NSString * userName = (NSString *) CSCopyUserName(NO);
00244 if (userName && [userName length]) {
00245 [retval replaceOccurrencesOfString: @"%n" withString: userName
00246 options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00247 }
00248 else {
00249 [retval replaceOccurrencesOfString: @"%n" withString: userID
00250 options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00251 }
00252 [userName release];
00253 [userID release];
00254
00255 NSString * secondsInt = [NSString stringWithFormat: @"%d", seconds];
00256 [retval replaceOccurrencesOfString: @"%s" withString: secondsInt
00257 options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00258
00259 NSString * secondsMss = [NSString stringWithFormat: @"%d:%02d", seconds/60, seconds%60];
00260 [retval replaceOccurrencesOfString: @"%t" withString: secondsMss
00261 options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00262
00263 return retval;
00264 }
00265
00266 - (void) setMessageText: (NSString *) newText
00267 {
00268 if (newText != messageText) {
00269 [messageText release];
00270 messageText = [newText retain];
00271
00272 [[messageField textStorage]
00273 replaceCharactersInRange: NSMakeRange(0, [[messageField textStorage] length])
00274 withString: newText];
00275 [self colorMessageField];
00276 }
00277 }
00278
00283 - (void) setTimeTextMinutes: (int) mins seconds: (int) secs
00284 {
00285 NSString * str = [NSString stringWithFormat: @"%d:%02d", mins, secs];
00286 [timeField setStringValue: str];
00287 }
00288
00289 - (void) setSecondsBeforeLogout: (int) seconds
00290 {
00291 if (seconds < 10)
00292 seconds = 10;
00293
00294 [self setTimeTextMinutes: (seconds / 60) seconds: (seconds % 60)];
00295 [timeStepper setIntValue: seconds];
00296 }
00297
00298 - (int) secondsBeforeLogout
00299 {
00300 return secondsBeforeLogout;
00301 }
00302
00303 - (IBAction) stepper: (id) sender
00304 {
00305 int value = [sender intValue];
00306 [self setSecondsBeforeLogout: value];
00307 }
00308
00309 - (IBAction) timeText: (id) sender
00310 {
00311 NSString * str = [sender stringValue];
00312 int minutes = 0;
00313 int seconds = 0;
00314
00315 int i, iLimit = [str length];
00316 int state = 0;
00317
00318 for (i = 0; i < iLimit && state < 9; i++) {
00319 unichar ch = [str characterAtIndex: i];
00320 switch (state) {
00321 case 0:
00322 if (ch >= '0' && ch <= '9') {
00323 seconds *= 10;
00324 seconds += (ch - '0');
00325 }
00326 else if (ch == ':' || ch == ' ' || ch == '.') {
00327 minutes = 60 * seconds;
00328 seconds = 0;
00329 state = 1;
00330 }
00331 else {
00332 state = 9;
00333 }
00334 break;
00335 case 1:
00336 if (ch >= '0' && ch <= '9') {
00337 seconds *= 10;
00338 seconds += (ch - '0');
00339 }
00340 else {
00341 state = 9;
00342 return;
00343 }
00344 break;
00345 }
00346 }
00347
00348 [self setSecondsBeforeLogout: seconds + minutes];
00349 }
00350
00356 - (NSMutableArray *) closableUIApplications
00357 {
00358 NSArray * exempt = [NSArray arrayWithObjects: @"Finder", nil];
00359 NSMutableArray * retval = [DAApplication launchedApplications];
00360 int i;
00361
00362
00363 for (i = [retval count] - 1; i >= 0; i--) {
00364 DAApplication * curr = [retval objectAtIndex: i];
00365 if ([exempt containsObject: [curr name]]) {
00366 [retval removeObject: curr];
00367 }
00368 }
00369
00370 return retval;
00371 }
00372
00373 - (void) quitApplications
00374 {
00375 if (self != sMainController)
00376 return;
00377
00378 NSMutableArray * apps = [self closableUIApplications];
00379 [apps makeObjectsPerformSelector: @selector(quitWithoutSaving)];
00380 }
00381
00382 - (void) killApplications
00383 {
00384 if (self != sMainController)
00385 return;
00386
00387 NSMutableArray * apps = [self closableUIApplications];
00388 [apps makeObjectsPerformSelector: @selector(killObj:) withObject: [NSNumber numberWithInt: 9]];
00389 }
00390
00391 - (NSString *) nameOfThisApplication
00392 {
00393 return [[[NSWorkspace sharedWorkspace] activeApplication] objectForKey: @"NSApplicationName"];
00394 }
00395
00396 - (void) logOut
00397 {
00398 if (self != sMainController)
00399 return;
00400
00401 NSAppleScript * script = [[NSAppleScript alloc] initWithSource:
00402 @"ignoring application responses\r"
00403 @"tell application \"loginwindow\" to Çevent aevtrlgoÈ\r"
00404 @"end ignoring"];
00405
00406
00407 NSAppleEventDescriptor * result;
00408 NSDictionary * errorDict;
00409
00410 result = [script executeAndReturnError: &errorDict];
00411 if (! result)
00412 NSLog(@"ErrorDict = %@", errorDict);
00413 }
00414
00415 - (void) makeTouchFile
00416 {
00417 NSString * userID = (NSString *) CSCopyUserName(YES);
00418 NSString * touchPath = [NSString stringWithFormat: @"/tmp/%@.DownAndOut", userID];
00419 NSMutableString * content = [NSMutableString string];
00420 NSEnumerator * iter = [[DAApplication quitApplicationNames] objectEnumerator];
00421 NSString * curr;
00422
00423 while (curr = [iter nextObject]) {
00424 if (![[DAApplication killedApplicationNames] containsObject: curr])
00425 [content appendFormat: @"Quit:\t%@\n", curr];
00426 }
00427
00428 iter = [[DAApplication killedApplicationNames] objectEnumerator];
00429 while (curr = [iter nextObject])
00430 [content appendFormat: @"Killed:\t%@\n", curr];
00431
00432 [content writeToFile: touchPath atomically: NO];
00433 }
00434
00435 - (IBAction) restoreDefaults: (id) sender
00436 {
00437 [self setSecondsBeforeLogout: DEFAULT_LOGOUT];
00438 if (DEFAULT_SHOULD_MOVE)
00439 [movementMatrix selectCellAtRow: 0 column: 0];
00440 else
00441 [movementMatrix selectCellAtRow: 1 column: 0];
00442 [imageWell setImage: nil];
00443 [imageClear setEnabled: NO];
00444
00445 [[messageField textStorage]
00446 replaceCharactersInRange: NSMakeRange(0, [[messageField textStorage] length])
00447 withString: DEFAULT_MESSAGE];
00448 [self colorMessageField];
00449 }
00450
00451 - (NSImage *) addedImage { return addedImage; }
00452
00453 - (void) setAddedImage: (NSImage *) anImage
00454 {
00455 if (anImage != addedImage) {
00456 [addedImage release];
00457 addedImage = [anImage retain];
00458
00459 [imageWell setImage: anImage];
00460 [imageClear setEnabled: (addedImage != nil)];
00461 }
00462 }
00463
00464 - (IBAction) imageAction: (id) sender
00465 {
00466 if (sender == imageClear) {
00467 [imageWell setImage: nil];
00468 }
00469 else if (sender == imageSet) {
00470 NSOpenPanel * openPanel = [NSOpenPanel openPanel];
00471
00472 [openPanel setCanChooseDirectories: NO];
00473 [openPanel setAllowsMultipleSelection: NO];
00474
00475 int answer = [openPanel runModalForTypes: [NSImage imageFileTypes]];
00476
00477 if (answer == NSOKButton) {
00478 NSImage * newImage = [[NSImage alloc] initWithContentsOfFile: [openPanel filename]];
00479 if (newImage)
00480 [imageWell setImage: newImage];
00481 [newImage release];
00482 }
00483 }
00484 else if (sender == imageWell) {
00485
00486 }
00487
00488 [imageClear setEnabled: ([imageWell image] != nil)];
00489 }
00490
00491 @end