// // DeVercruesseProcessManager.m // // Created by Frank Vercruesse on Wed Apr 04 2001. // Copyright (c) 2001 Frank Vercruesse. // // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. #import "DeVercruesseProcessManager.h" @implementation DeVercruesseProcessManager static DeVercruesseProcessManager *defaultManager = nil; + (id)defaultManager { return ( defaultManager ? defaultManager : [[self alloc] init] ); } - (id)init { if( defaultManager ) { [self dealloc]; } else if( [super init] ) { processes = [[NSMutableSet alloc] initWithCapacity:30]; defaultManager = self; } return defaultManager; } - (void)dealloc { [processes release]; if( self == defaultManager ) defaultManager = nil; } - (DeVercruesseProcess*)currentProcess { ProcessSerialNumber sn; DeVercruesseProcess *p, *q; CPSGetCurrentProcess( (CPSProcessSerNum*) &sn); if( p = [DeVercruesseProcess processWithPSN:&sn] ) { if( q = [processes member:p] ) p = q; // else // [processes addObject:p]; } return p; } - (DeVercruesseProcess*)frontProcess { ProcessSerialNumber sn; DeVercruesseProcess *p, *q; if( CPSGetFrontProcess( (CPSProcessSerNum*) &sn) != noErr ) CPSGetCurrentProcess( (CPSProcessSerNum*) &sn); if( p = [DeVercruesseProcess processWithPSN:&sn] ) { if( q = [processes member:p] ) p = q; // else // [processes addObject:p]; } return p; } - (DeVercruesseProcess*)nextToFrontProcess { ProcessSerialNumber sn; DeVercruesseProcess *p, *q; if( CPSGetNextToFrontProcess( (CPSProcessSerNum*) &sn) != noErr ) CPSGetCurrentProcess( (CPSProcessSerNum*) &sn); if( p = [DeVercruesseProcess processWithPSN:&sn] ) { if( q = [processes member:p] ) p = q; // else // [processes addObject:p]; } return p; } - (DeVercruesseProcess*)anyNoBGOnlyProcess { ProcessSerialNumber sn; DeVercruesseProcess *p, *q; sn.highLongOfPSN = 0; sn.lowLongOfPSN = kNoProcess; while( CPSGetNextProcess( (CPSProcessSerNum*) &sn) == noErr ) { if( (p = [DeVercruesseProcess processWithPSN:&sn]) && ![p isBackgroundOnly] ) { if( q = [processes member:p] ) p = q; // else // [processes addObject:p]; return p; } } return nil; } - (NSArray*)processes { [self update]; return [NSArray arrayWithArray:[processes allObjects]]; } - (void)update { ProcessSerialNumber sn; NSMutableSet *temp; DeVercruesseProcess *process, *existingProcess; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; sn.highLongOfPSN = 0; sn.lowLongOfPSN = kNoProcess; temp = [[NSMutableSet alloc] initWithCapacity: 30]; while( CPSGetNextProcess( (CPSProcessSerNum*) &sn) == noErr ) { // njr removed background-only check because we still get process launch notifications for background-only apps... if ( (process = [[DeVercruesseProcess alloc] initWithPSN:&sn]) != nil) { if ( (existingProcess = [processes member: process]) != nil ) { [temp addObject: existingProcess]; } else { [temp addObject: process]; } [process release]; } } [processes setSet: temp]; [pool release]; [temp release]; } - (void)showAll { ProcessSerialNumber *psn; psn = [[self frontProcess] psn]; CPSPostShowAllReq( (CPSProcessSerNum*) psn ); CPSPostShowReq( (CPSProcessSerNum*) psn ); } - (void)hideOthers { [self hideOthers:YES]; } - (void)hideOthers:(BOOL)ignoreRules { NSArray *p; NSEnumerator *enumerator; DeVercruesseProcess *process; p = [[ProcessMgr processes] retain]; enumerator = [p objectEnumerator]; while( process = [enumerator nextObject] ) { if( ![process isHidden] && ![process isEqualToFront] && (ignoreRules || ![self checkRule:@"optDontHide" withProcess:process]) ) { [process hide]; } } [p release]; } - (void)hideFront { [[self frontProcess] hide]; } - (void)setFront:(DeVercruesseProcess*)process { [process makeFront]; } // rules stuff - (void)setRules:(NSArray*)r { NSEnumerator *enumerator; NSDictionary *dict; NSMutableSet *hasRules, *keys; NSMutableDictionary *newRules; newRules = [[NSMutableDictionary alloc] initWithCapacity:10]; hasRules = [[NSMutableSet alloc] initWithCapacity:10]; [newRules setObject:hasRules forKey:@"_hasRules"]; [hasRules release]; keys = [[NSMutableSet alloc] initWithCapacity:10]; [newRules setObject:keys forKey:@"_keys"]; [keys release]; enumerator = [r objectEnumerator]; while( dict = [enumerator nextObject] ) { NSString *identifier, *key; NSEnumerator *keyEnumerator; NSDictionary *d2; identifier = [[NSString alloc] initWithFormat:@"%@%.8X%.8X", [dict objectForKey:@"identifier"], [[dict objectForKey:@"type"] unsignedIntValue], [[dict objectForKey:@"creator"] unsignedIntValue]]; [hasRules addObject:identifier]; [identifier release]; d2 = [dict objectForKey:@"rules"]; keyEnumerator = [d2 keyEnumerator]; while( key = [keyEnumerator nextObject] ) { NSMutableDictionary *d3; if( !(d3 = [newRules objectForKey:key]) ) { [keys addObject:key]; d3 = [[NSMutableDictionary alloc] initWithCapacity:10]; [newRules setObject:d3 forKey:key]; [d3 release]; } [d3 setObject:[d2 objectForKey:key] forKey:identifier]; } } [rules release]; rules = [[NSDictionary alloc] initWithDictionary:newRules]; [newRules release]; } - (BOOL)anyRulesForProcess:(DeVercruesseProcess*)process { if( !process || !rules ) return NO; return [[rules objectForKey:@"_hasRules"] containsObject:[process identifier]]; } - (BOOL)checkRule:(NSString*)ruleKey withProcess:(DeVercruesseProcess*)process { if( !ruleKey || !process || !rules ) return NO; return [[rules objectForKey:ruleKey] containsObject:[process identifier]]; } - (NSSet*)processIdentifiersForRule:(NSString*)ruleKey { return [rules objectForKey:ruleKey]; } - (int)optionsForRule:(NSString*)ruleKey withProcess:(DeVercruesseProcess*)process { NSDictionary *rule; NSNumber *options; if( !(rule = [rules objectForKey:ruleKey]) ) return 2; // use global setting if( !(options = [rule objectForKey:[process identifier]]) ) return 2; // use global setting return [options intValue]; } @end