Index: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEESetServicesMenu.m
===================================================================
--- trunk/ICeCoffEE/ICeCoffEE/ICeCoffEESetServicesMenu.m	(revision 182)
+++ trunk/ICeCoffEE/ICeCoffEE/ICeCoffEESetServicesMenu.m	(revision 319)
@@ -8,4 +8,115 @@
 
 #import "ICeCoffEESetServicesMenu.h"
+#import "ICeCoffEEShared.h"
+
+// XXX rename me to something like "ICeCoffEEServicesMenu.m"
+
+// an approximate clone of HIToolbox's CreateServicesLocalizedDictKey
+static CFStringRef preferredLocalization(CFDictionaryRef localizations) {
+    if (localizations == NULL)
+	return NULL;
+    
+    CFIndex localizationCount = CFDictionaryGetCount(localizations);
+    if (localizationCount == 0)
+	return NULL;
+    
+    const void **locales = malloc(localizationCount * sizeof(void *));
+    if (locales == NULL)
+	return NULL;
+    
+    CFDictionaryGetKeysAndValues(localizations, locales, NULL);
+    CFArrayRef availableLocales = CFArrayCreate(NULL, locales, localizationCount, NULL);
+    if (availableLocales == NULL)
+	return NULL;
+    
+    // XXX does this actually work in a localized app?
+    CFArrayRef preferredLocales = CFBundleCopyPreferredLocalizationsFromArray(availableLocales);
+    // NSLog(@"%@ => %@", availableLocales, preferredLocales);
+    CFRelease(availableLocales);
+    CFStringRef preferredLocalization;
+    if (preferredLocales != NULL) {
+	if (CFArrayGetCount(preferredLocales) > 0) {
+	    CFStringRef preferredLocale = CFArrayGetValueAtIndex(preferredLocales, 0);
+	    preferredLocalization = (CFStringRef)CFDictionaryGetValue(localizations, preferredLocale);
+	}
+	CFRelease(preferredLocales);
+    }
+    if (preferredLocalization == NULL) {
+	preferredLocalization = (CFStringRef)CFDictionaryGetValue(localizations, CFSTR("default"));
+	if (preferredLocalization == NULL)
+	    preferredLocalization = (CFStringRef)CFDictionaryGetValue(localizations, (CFStringRef)locales[0]);
+    }
+    
+    free(locales);
+    // NSLog(@"%@", preferredLocalization);
+    return preferredLocalization;
+}
+
+NSArray *CFServiceControllerCopyServicesEntries(void);
+
+NSDictionary *ICCF_GetServicesInfo(void) {
+    NSArray *services = CFServiceControllerCopyServicesEntries();
+    // NSLog(@"%@", services);
+    
+    NSEnumerator *e = [services objectEnumerator];
+    NSDictionary *serviceEntry;
+    NSMutableDictionary *serviceDict = [[NSMutableDictionary alloc] init];
+    while ( (serviceEntry = (NSDictionary *)[e nextObject]) != nil) {
+	// XXX once tested, redo all this with CF, and no autoreleasing
+	// XXX items named the same as submenus (figure out how Cocoa itself does it, too)
+	// XXX use kICServiceSubmenu (recursion?)
+	NSString *itemPath = (NSString *)preferredLocalization((CFDictionaryRef)[serviceEntry objectForKey: @"NSMenuItem"]);
+	if (itemPath == nil) continue;
+	
+	NSString *bundlePath = [serviceEntry objectForKey: @"NSBundlePath"];
+	BOOL bubbledUp = (bundlePath == nil);
+	NSArray *itemComponents = [itemPath componentsSeparatedByString: @"/"];
+	NSEnumerator *ce = [itemComponents objectEnumerator];
+	NSString *itemComponent;
+	NSMutableDictionary *levelDict = serviceDict;
+	NSMutableDictionary *itemDict = nil;
+	while ( (itemComponent = (NSString *)[ce nextObject]) != nil) {
+	    // itemDict is nil if just created
+	    if (itemDict != nil && !bubbledUp) {
+		NSString *oldBundlePath = [levelDict objectForKey: (NSString *)kICServiceBundlePath];
+		if ([oldBundlePath isEqualToString: bundlePath])
+		    bubbledUp = YES;
+		else if (oldBundlePath != nil) {
+		    [oldBundlePath retain];
+		    [levelDict removeObjectForKey: (NSString *)kICServiceBundlePath];
+		    NSEnumerator *be = [levelDict objectEnumerator];
+		    while ( (itemDict = (NSMutableDictionary *)[be nextObject]) != nil)
+			[itemDict setObject: oldBundlePath forKey: (NSString *)kICServiceBundlePath];
+		    [oldBundlePath release];
+		}
+	    }
+	    itemDict = [levelDict objectForKey: itemComponent];
+	    if (itemDict == nil) {
+		itemDict = [[NSMutableDictionary alloc] init];
+		if (!bubbledUp) {
+		    [itemDict setObject: bundlePath forKey: (NSString *)kICServiceBundlePath];
+		    bubbledUp = YES;
+		}
+		[levelDict setObject: itemDict forKey: itemComponent];
+		levelDict = itemDict;
+		[itemDict release];
+		itemDict = nil;
+	    } else {
+		levelDict = itemDict;
+	    }
+	}
+	
+	if (!bubbledUp)
+	    [levelDict setObject: bundlePath forKey: (NSString *)kICServiceBundlePath];
+
+	NSString *keyEquivalent = (NSString *)preferredLocalization((CFDictionaryRef)[serviceEntry objectForKey: @"NSKeyEquivalent"]);
+	if (keyEquivalent == nil) continue;
+
+	[levelDict setObject: keyEquivalent forKey: (NSString *)kICServiceShortcut];
+    }
+    [services release];
+    
+    return [serviceDict autorelease];
+}
 
 
@@ -31,2 +142,17 @@
     }
 }
+
+IconRef ICCF_CopyIconRefForPath(NSString *path) {
+    IconRef icon;
+    FSRef fsr;
+    SInt16 label;
+    OSStatus err = noErr;
+    
+    err = FSPathMakeRef((const UInt8 *)[path fileSystemRepresentation], &fsr, NULL);
+    if (err != noErr) return NULL;
+    
+    err = GetIconRefFromFileInfo(&fsr, 0, NULL, kFSCatInfoNone, NULL, kIconServicesNormalUsageFlag, &icon, &label);
+    if (err != noErr) return NULL;
+    
+    return icon;
+}
