Changeset 221
- Timestamp:
- 05/11/06 22:26:01 (19 years ago)
- Location:
- trunk/Cocoa/F-Script Anywhere/Source
- Files:
-
- 1 added
- 1 deleted
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Cocoa/F-Script Anywhere/Source/English.lproj/MainMenu.nib/info.nib
r219 r221 8 8 <dict> 9 9 <key>29</key> 10 <string> 61 185232 44 0 0 1440 878 </string>10 <string>54 632 232 44 0 0 1440 878 </string> 11 11 </dict> 12 12 <key>IBFramework Version</key> … … 14 14 <key>IBOpenObjects</key> 15 15 <array> 16 <integer>229</integer> 16 17 <integer>29</integer> 17 18 <integer>195</integer> -
trunk/Cocoa/F-Script Anywhere/Source/FSAAppList.h
r219 r221 35 35 NSMutableSet *patchedApps; 36 36 NSMutableSet *patchingApps; 37 37 NSMutableArray *alwaysApps; 38 38 IBOutlet NSButton *installButton; 39 39 IBOutlet NSTableView *tableView; 40 40 BOOL finishedLaunch; 41 41 } 42 42 -
trunk/Cocoa/F-Script Anywhere/Source/FSAAppList.m
r220 r221 8 8 9 9 /* 10 10 11 11 F-Script Anywhere is free software; you can redistribute it and/or modify 12 12 it under the terms of the GNU General Public License as published by 13 13 the Free Software Foundation; either version 2 of the License, or 14 14 (at your option) any later version. 15 15 16 16 F-Script Anywhere is distributed in the hope that it will be useful, 17 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 19 GNU General Public License for more details. 20 20 21 21 You should have received a copy of the GNU General Public License 22 22 along with F-Script Anywhere; if not, write to the Free Software 23 23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 25 */24 25 */ 26 26 27 27 #include <sys/types.h> … … 57 57 58 58 static int sysctlbyname_with_pid (const char *name, pid_t pid, 59 60 59 void *oldp, size_t *oldlenp, 60 void *newp, size_t newlen); 61 61 int is_pid_native (pid_t pid); 62 62 … … 92 92 patchingApps = [[NSMutableSet alloc] init]; 93 93 appsByPID = [[NSMutableDictionary alloc] init]; 94 if(!([[NSUserDefaults standardUserDefaults] objectForKey:@"AlwaysApps"])) 95 alwaysApps = [[NSMutableArray array] retain]; 96 else 97 alwaysApps = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"AlwaysApps"]] retain]; 98 94 alwaysApps = [[NSMutableArray array] retain]; 95 99 96 [[tableView tableColumnWithIdentifier: FSATableColumnIdentifier_appNameAndIcon] 100 97 setDataCell: [NJRLabeledImageCell cell]]; … … 103 100 setDataCell: [[[NSImageCell alloc] init] autorelease]]; 104 101 [window setResizeIncrements: NSMakeSize(1, [tableView cellHeight])]; 105 106 107 102 [tableView setTarget:self]; 103 [tableView setAction:@selector(clickInTable:)]; 104 108 105 [self update]; 109 106 [window makeFirstResponder: tableView]; 107 108 [[NSNotificationCenter defaultCenter] addObserver:self 109 selector:@selector(update) 110 name:NSUserDefaultsDidChangeNotification 111 object:nil]; 110 112 } 111 113 … … 123 125 int row = [tableView selectedRow]; 124 126 if (row == -1) return -1; 125 127 126 128 return [[cocoaApps objectAtIndex: row] pid]; 127 129 } … … 158 160 int fd; 159 161 PEFContainerHeader pefHeader; 160 162 161 163 if (bundleExecutableLoc == NULL) 162 164 return NO; … … 164 166 if ( (bundleExecutablePath = [bundleExecutableLoc fileSystemRepresentation]) == NULL) 165 167 return NO; 166 168 167 169 if ( (fd = open(bundleExecutablePath, O_RDONLY, 0)) == -1) 168 170 return NO; 169 171 170 172 if (read(fd, &pefHeader, sizeof(pefHeader)) != sizeof(pefHeader)) 171 173 return NO; … … 173 175 if (pefHeader.tag1 != kPEFTag1 || pefHeader.tag2 != kPEFTag2) 174 176 return NO; 175 177 176 178 return YES; 177 179 } … … 187 189 -(BOOL)appIsNative:(DeVercruesseProcess *)app 188 190 { 189 191 return is_pid_native([app pid]); 190 192 } 191 193 … … 193 195 { 194 196 /* Try to determine if the application is a foreground Cocoa application. 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 197 In Jaguar, itÕs possible to mix Cocoa in a primarily Carbon application, 198 but we don't support such hybrids because the menu items we add depend 199 on Cocoa dispatch mechanisms. 200 201 The CPS 'flavor' mechanism (isCarbon, isCocoa) is broken in Mac OS X 202 10.1.2 through 10.1.5 and possibly earlier, reporting that all Cocoa apps 203 are Carbon apps. So we use some code extracted from otool to check 204 whether the application links to the Foundation, AppKit or Cocoa 205 frameworks. This problem is fixed in Jaguar, except that certain CFM 206 Carbon apps are reported to be Cocoa apps (Drop Drawers is one example). 207 Conversely, the appIsCocoa: code works on _most_ applications, but 208 Jaguar always correctly identifies Cocoa apps as isCocoa. 209 210 So, our checks go like this: 211 Is the application background-only? 212 Is the application Cocoa or Carbon according to the CPS flavor? 213 If it's Cocoa, is it a CFM app? If so, CPS is lying to us. 214 If it's "Carbon", does it link to AppKit, Foundation or Cocoa? 215 If so, it's really a Cocoa app. If not, it's a Carbon app. 216 217 Be careful not to call appIsCocoa: on a Classic application, you will 218 crash. 217 219 */ 218 220 219 221 /* 220 if ([app isCocoa] || [app isCarbon]) {221 222 223 224 225 [self appIsPEF: app] ? @" appIsPEF" : @"",226 227 }228 */229 222 if ([app isCocoa] || [app isCarbon]) { 223 NSLog(@"%@ |%@%@%@%@%@", [app name], 224 [app isBackgroundOnly] ? @" bgOnly" : @"", 225 [app isCocoa] ? @" isCocoa" : @"", 226 [app isCarbon] ? @" isCarbon" : @"", 227 [self appIsPEF: app] ? @" appIsPEF" : @"", 228 [self appIsCocoa: app] ? @" appIsCocoa" : @""); 229 } 230 */ 231 230 232 if ( ![app isBackgroundOnly] && 231 233 ( ( [app isCocoa] && ![self appIsPEF: app]) || 232 234 ( [app isCarbon] && [self appIsCocoa: app]))) { 233 234 235 236 237 238 239 235 if([self appIsNative:app]){ 236 [cocoaApps addObject: app]; 237 if(finishedLaunch){ 238 if([alwaysApps containsObject:[app name]] && ![patchedApps containsObject:app]) 239 [NSApp installBundleInAppWithPID:[app pid]]; 240 } 241 } 240 242 } 241 243 [appsByPID setObject: app forKey: [NSNumber numberWithInt: [app pid]]]; … … 249 251 NSArray *allApps; 250 252 DeVercruesseProcess *app; 251 253 252 254 [cocoaApps removeAllObjects]; 253 255 [appsByPID removeAllObjects]; 254 256 // [processManager update] unneeded: [processManager processes] sends update 255 257 256 258 allApps = [processManager processes]; 257 259 e = [allApps objectEnumerator]; 258 260 259 261 while ( (app = [e nextObject]) != nil) { 260 262 [self addApp: app]; 261 263 } 262 264 265 if([[NSUserDefaults standardUserDefaults] objectForKey:@"AlwaysApps"]){ 266 [[NSUserDefaults standardUserDefaults] synchronize]; 267 [alwaysApps removeAllObjects]; 268 [alwaysApps addObjectsFromArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"AlwaysApps"]]; 269 [tableView reloadData]; 270 } 263 271 [tableView noteNumberOfRowsChanged]; 264 272 [self _processStatusChanged]; … … 286 294 { 287 295 DeVercruesseProcess *app = [self _applicationForPID: pid]; 288 296 289 297 if (app != nil) { 290 298 [cocoaApps removeObject: app]; … … 292 300 [patchedApps removeObject: app]; 293 301 } 294 302 295 303 [tableView noteNumberOfRowsChanged]; 296 304 [self _processStatusChanged]; … … 305 313 if ([[tableColumn identifier] isEqualToString: FSATableColumnIdentifier_appNameAndIcon]) { 306 314 DeVercruesseProcess *app = [cocoaApps objectAtIndex: row]; 307 315 308 316 NSAssert1([cell isKindOfClass: [NJRLabeledImageCell class]], @"Cell is not what we expected, instead %@", cell); 309 317 [(NJRLabeledImageCell *)cell setImage: [app img]]; … … 315 323 { 316 324 BOOL canInstall = NO; 317 325 318 326 if (row != -1) { 319 327 DeVercruesseProcess *app = [cocoaApps objectAtIndex: row]; … … 321 329 [patchingApps containsObject: app]); 322 330 } 323 331 324 332 [installButton setEnabled: canInstall]; 325 333 … … 338 346 - (id)tableView:(NSTableView *)aTableView 339 347 objectValueForTableColumn:(NSTableColumn *)aTableColumn 340 row:(int)rowIndex348 row:(int)rowIndex 341 349 { 342 350 NSString *columnIdentifier = [aTableColumn identifier]; … … 359 367 } 360 368 } else if([columnIdentifier isEqualToString:FSATableColumnIdentifier_always]){ 361 362 363 364 365 369 if([alwaysApps containsObject:[[cocoaApps objectAtIndex: rowIndex] name]]) 370 return [NSNumber numberWithBool:YES]; 371 else 372 return [NSNumber numberWithBool:NO]; 373 } 366 374 return nil; 367 375 } … … 379 387 float heightChange = [[scrollView documentView] bounds].size.height - displayedHeight; 380 388 float heightExcess; 381 389 382 390 if (heightChange >= 0 && heightChange <= 1) { 383 391 // either the window is already optimal size, or it's too big … … 385 393 heightChange = (rowHeight * [tableView numberOfRows]) - displayedHeight; 386 394 } 387 395 388 396 frame.size.height += heightChange; 389 397 390 398 if ( (heightExcess = [window minSize].height - frame.size.height) > 1 || 391 399 (heightExcess = [window maxSize].height - frame.size.height) < 1) { … … 393 401 frame.size.height += heightExcess; 394 402 } 395 403 396 404 frame.origin.y -= heightChange; 397 405 398 406 return frame; 399 407 } … … 413 421 NSMethodSignature *sig = [NSApp methodSignatureForSelector: @selector(installBundleInFrontmostApp:)]; 414 422 NSInvocation *inv; 415 423 416 424 if (dockMenu != nil) { 417 425 // XXX release invocation … … 421 429 dockMenu = [[NSMenu alloc] init]; 422 430 } 423 431 424 432 NSAssert(frontApp != nil && appName != nil, @"Can't obtain information on the frontmost application"); 425 433 426 434 if ([patchedApps containsObject: frontApp]) { 427 435 status = [NSString stringWithFormat: NSLocalizedString(@"Installed in '%@'", "Dock menu disabled item displayed when FSA already installed, app name parameter"), appName]; … … 429 437 status = [NSString stringWithFormat: NSLocalizedString(@"Can't install because '%@' is not a Cocoa application", "Dock menu disabled item displayed when frontmost app not Cocoa, app name parameter"), appName]; 430 438 } 431 439 432 440 if (status == nil) { 433 441 menuItem = [dockMenu addItemWithTitle: [NSString stringWithFormat: NSLocalizedString(@"Install in '%@'", "Dock menu item to install FSA in frontmost app"), appName] … … 444 452 [menuItem setEnabled: NO]; 445 453 } 446 454 447 455 return dockMenu; 448 456 } … … 450 458 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 451 459 { 452 id anApp; 453 id e = [cocoaApps objectEnumerator]; 454 while(anApp = [e nextObject]){ 455 if([alwaysApps containsObject:[anApp name]] && ![patchedApps containsObject:anApp]){ 456 [NSApp installBundleInAppWithPID:[anApp pid]]; 457 } 460 id anApp; 461 id e = [cocoaApps objectEnumerator]; 462 while(anApp = [e nextObject]){ 463 if([alwaysApps containsObject:[anApp name]] && ![patchedApps containsObject:anApp]){ 464 [NSApp installBundleInAppWithPID:[anApp pid]]; 458 465 } 459 finishedLaunch = YES; 466 } 467 finishedLaunch = YES; 460 468 } 461 469 … … 467 475 -(void)clickInTable:(id)sender 468 476 { 469 if([sender clickedColumn] == 2){ 470 if([sender clickedRow] >= 0){ 471 NSString *appName = [[cocoaApps objectAtIndex:[sender clickedRow]] name]; 472 if(![alwaysApps containsObject:appName]){ 473 [NSApp installBundleInAppWithPID:[[cocoaApps objectAtIndex:[sender clickedRow]] pid]]; 474 [alwaysApps addObject:appName]; 475 } else 476 [alwaysApps removeObject:appName]; 477 [[NSUserDefaults standardUserDefaults] setObject:alwaysApps forKey:@"AlwaysApps"]; 478 } 477 if([sender clickedColumn] == 2){ 478 if([sender clickedRow] >= 0){ 479 NSString *appName = [[cocoaApps objectAtIndex:[sender clickedRow]] name]; 480 if(![alwaysApps containsObject:appName]){ 481 [NSApp installBundleInAppWithPID:[[cocoaApps objectAtIndex:[sender clickedRow]] pid]]; 482 [alwaysApps addObject:appName]; 483 } else 484 [alwaysApps removeObject:appName]; 485 [[NSUserDefaults standardUserDefaults] setObject:alwaysApps forKey:@"AlwaysApps"]; 479 486 } 487 } 480 488 } 481 489 … … 483 491 484 492 static int sysctlbyname_with_pid (const char *name, pid_t pid, 485 486 493 void *oldp, size_t *oldlenp, 494 void *newp, size_t newlen) 487 495 { 488 496 if (pid == 0) { 489 497 if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) { 490 498 fprintf(stderr, "sysctlbyname_with_pid(0): sysctlbyname failed:" 491 499 "%s\n", strerror(errno)); 492 500 return -1; 493 501 } … … 497 505 if (sysctlnametomib(name, mib, &len) == -1) { 498 506 fprintf(stderr, "sysctlbyname_with_pid: sysctlnametomib failed:" 499 507 "%s\n", strerror(errno)); 500 508 return -1; 501 509 } … … 515 523 int ret = 0; 516 524 size_t sz = sizeof(ret); 517 525 518 526 if (sysctlbyname_with_pid("sysctl.proc_native", pid, 519 520 527 &ret, &sz, NULL, 0) == -1) { 528 if (errno == ENOENT) { 521 529 // sysctl doesn't exist, which means that this version of Mac OS 522 530 // pre-dates Rosetta, so the application must be native.
Note:
See TracChangeset
for help on using the changeset viewer.