Index: trunk/Cocoa/F-Script Anywhere/Source/FSAAppList.m
===================================================================
--- trunk/Cocoa/F-Script Anywhere/Source/FSAAppList.m	(revision 7)
+++ trunk/Cocoa/F-Script Anywhere/Source/FSAAppList.m	(revision 16)
@@ -25,4 +25,5 @@
 */
 
+#import "FSAnywhere.h"
 #import "FSAAppList.h"
 #import "FSAApp.h"
@@ -32,8 +33,14 @@
 #import "NSTableView-NJRExtensions.h"
 
+// for appIsPEF:
+#import <Carbon/Carbon.h>
+#import <fcntl.h>
+#import <unistd.h>
+
 NSString * const FSATableColumnIdentifier_appNameAndIcon = @"appNameAndIcon";
 NSString * const FSATableColumnIdentifier_checkMark = @"checkMark";
 
 NSString *FSACheckMarkCharacter;
+NSImage *FSACheckMarkImage;
 
 static const char *FSACocoaFrameworks[] = {
@@ -46,7 +53,16 @@
 @implementation FSAAppList
 
-+ (void)load;
++ (void)initialize;
 {
     FSACheckMarkCharacter = [[NSString alloc] initWithCharacters: (const unichar *)"\x27\x13" length: 1];
+    FSACheckMarkImage = [NSImage imageNamed: @"NSMenuCheckmark"];
+    if (FSACheckMarkImage == nil) {
+        FSACheckMarkImage = [[NSImage alloc] initByReferencingFile: [[NSBundle mainBundle] pathForResource: @"Fallback checkmark" ofType: @"tiff"]];
+        if (FSACheckMarkImage != nil && ![FSACheckMarkImage isValid]) {
+            [FSACheckMarkImage release];
+            FSACheckMarkImage = nil;
+        }
+        FSALog(@"Falling back to checkmark image from bundle: %@", FSACheckMarkImage);
+    }
 }
 
@@ -60,4 +76,7 @@
     [[tableView tableColumnWithIdentifier: FSATableColumnIdentifier_appNameAndIcon]
         setDataCell: [NJRLabeledImageCell cell]];
+    if (FSACheckMarkImage != nil)
+        [[tableView tableColumnWithIdentifier: FSATableColumnIdentifier_checkMark]
+            setDataCell: [[[NSImageCell alloc] init] autorelease]];
     [[tableView window] setResizeIncrements: NSMakeSize(1, [tableView cellHeight])];
 
@@ -90,4 +109,29 @@
 }
 
+- (BOOL)appIsPEF:(DeVercruesseProcess *)app;
+{
+    NSString *bundleExecutableLoc = [app executableLoc];
+    const char *bundleExecutablePath;
+    int fd;
+    PEFContainerHeader pefHeader;
+
+    if (bundleExecutableLoc == NULL)
+        return NO;
+    
+    if ( (bundleExecutablePath = [bundleExecutableLoc fileSystemRepresentation]) == NULL)
+	return NO;
+
+    if ( (fd = open(bundleExecutablePath, O_RDONLY, 0)) == -1)
+        return NO;
+
+    if (read(fd, &pefHeader, sizeof(pefHeader)) != sizeof(pefHeader))
+	return NO;
+    
+    if (pefHeader.tag1 != kPEFTag1 || pefHeader.tag2 != kPEFTag2)
+	return NO;
+
+    return YES;
+}
+
 - (BOOL)appIsCocoa:(DeVercruesseProcess *)app;
 {
@@ -100,7 +144,43 @@
 - (void)addApp:(DeVercruesseProcess *)app;
 {
-    if ( ([app isCarbon] || [app isCocoa]) // XXX OS X 10.1.2 (and earlier?) bug, Cocoa reported as Carbon
-         && ![app isBackgroundOnly]
-         && [self appIsCocoa: app]) {
+    /* Try to determine if the application is a foreground Cocoa application.
+       In Jaguar, itÕs possible to mix Cocoa in a primarily Carbon application,
+       but we don't support such hybrids because the menu items we add depend
+       on Cocoa dispatch mechanisms.
+    
+       The CPS 'flavor' mechanism (isCarbon, isCocoa) is broken in Mac OS X
+       10.1.2 through 10.1.5 and possibly earlier, reporting that all Cocoa apps
+       are Carbon apps.  So we use some code extracted from otool to check
+       whether the application links to the Foundation, AppKit or Cocoa
+       frameworks.  This problem is fixed in Jaguar, except that certain CFM
+       Carbon apps are reported to be Cocoa apps (Drop Drawers is one example).
+       Conversely, the appIsCocoa: code works on _most_ applications, but
+       Jaguar always correctly identifies Cocoa apps as isCocoa.
+
+       So, our checks go like this:
+         Is the application background-only?
+         Is the application Cocoa or Carbon according to the CPS flavor?
+           If it's Cocoa, is it a CFM app?  If so, CPS is lying to us.
+           If it's "Carbon", does it link to AppKit, Foundation or Cocoa?
+             If so, it's really a Cocoa app.  If not, it's a Carbon app.
+    
+       Be careful not to call appIsCocoa: on a Classic application, you will
+       crash.
+    */
+
+    /*
+    if ([app isCocoa] || [app isCarbon]) {
+        NSLog(@"%@ |%@%@%@%@%@", [app name],
+              [app isBackgroundOnly] ? @" bgOnly" : @"",
+              [app isCocoa] ? @" isCocoa" : @"",
+              [app isCarbon] ? @" isCarbon" : @"",
+	      [self appIsPEF: app] ? @" appIsPEF" : @"",
+              [self appIsCocoa: app] ? @" appIsCocoa" : @"");
+    }
+    */
+          
+    if ( ![app isBackgroundOnly] &&
+	 ( ( [app isCocoa] && ![self appIsPEF: app]) ||
+	   ( [app isCarbon] && [self appIsCocoa: app]))) {
         [cocoaApps addObject: app];
     }
@@ -203,5 +283,9 @@
         return [(DeVercruesseProcess *)[cocoaApps objectAtIndex: rowIndex] name];
     } else if ([columnIdentifier isEqualToString: FSATableColumnIdentifier_checkMark]) {
-        return [patchedApps containsObject: [cocoaApps objectAtIndex: rowIndex]] ? FSACheckMarkCharacter : @"";
+        BOOL isPatched = [patchedApps containsObject: [cocoaApps objectAtIndex: rowIndex]];
+        if (FSACheckMarkImage == nil)
+            return isPatched ? FSACheckMarkCharacter : @"";
+        else
+            return isPatched ? FSACheckMarkImage : nil;
     }
     return nil;
