source: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEAppMenu.c@ 74

Last change on this file since 74 was 74, checked in by Nicholas Riley, 21 years ago

ICeCoffEE 1.3b2 plus some changes for 1.3

File size: 7.2 KB
Line 
1/*
2 * ICeCoffEEAppMenu.c
3 * ICeCoffEE APE
4 *
5 * Created by Nicholas Riley on Wed Jan 29 2003.
6 * Copyright (c) 2003 Nicholas Riley. All rights reserved.
7 *
8 */
9
10#include "ICeCoffEEAppMenu.h"
11#include "ICeCoffEEConfig.h"
12
13/* thanks to Slava Karpenko for this one! */
14OSStatus _LSCopyApplicationURLsForItemURL(CFURLRef inURL, LSRolesMask inRoleMask, CFArrayRef *outApps); // outApps to be CFReleased()
15
16#define THROW_ERR(e) { err = e; goto END; }
17#define SAFE_RELEASE(e) { if (e != NULL) CFRelease(e); }
18
19static CFStringRef ICCF_NameWithLocation(CFStringRef name, CFURLRef url) {
20 CFURLRef urlMinus = CFURLCreateCopyDeletingLastPathComponent(NULL, url);
21 CFStringRef urlString = CFURLCopyFileSystemPath(urlMinus, kCFURLPOSIXPathStyle);
22 CFStringRef nameWithLocation = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %s %@"), name, "Ñ", urlString);
23
24 SAFE_RELEASE(urlMinus);
25 SAFE_RELEASE(urlString);
26 return nameWithLocation;
27}
28
29static const MenuItemIndex kICAppMenuItemHasPath = 0xfffe;
30
31static CFStringRef
32
33OSStatus ICCF_LaunchURLWithApplication(ICInstance inst, ConstStr255Param hint, const char *urlData, long startIndex, long endIndex) {
34 Handle h = NewHandle(0);
35 CFURLRef url = NULL;
36 CFURLRef defaultAppURL = NULL;
37 CFArrayRef urlArray = NULL;
38 CFArrayRef appURLs = NULL;
39 CFMutableSetRef appPaths = NULL;
40 CFMutableDictionaryRef appNames = NULL;
41 MenuRef menu = NULL;
42 OSStatus err;
43
44 if (h == NULL) return MemError();
45
46 if ( (err = ICParseURL(inst, hint, urlData + startIndex, endIndex - startIndex + 1,
47 &startIndex, &endIndex, h)) != noErr) THROW_ERR(err);
48
49 if ( (url = CFURLCreateWithBytes(NULL, *h, GetHandleSize(h), kCFStringEncodingASCII,
50 NULL)) == NULL) THROW_ERR(paramErr);
51
52 CFIndex appCount = 0;
53 if ( (err = _LSCopyApplicationURLsForItemURL(url, kLSRolesAll, &appURLs)) != noErr)
54 THROW_ERR(err);
55
56 if (appURLs == NULL || (appCount = CFArrayGetCount(appURLs)) == 0)
57 THROW_ERR(kLSApplicationNotFoundErr);
58
59 if ( (appPaths = CFSetCreateMutable(NULL, appCount, &kCFCopyStringSetCallBacks)) == NULL)
60 THROW_ERR(memFullErr);
61
62 // values: index of single item with name; 0/NULL if no name; kICAppMenuItemHasPath if multiple items have name
63 if ( (appNames = CFDictionaryCreateMutable(NULL, appCount, &kCFCopyStringDictionaryKeyCallBacks, NULL)) == NULL)
64 THROW_ERR(memFullErr);
65
66 if ( (err = CreateNewMenu(0, kMenuAttrExcludesMarkColumn, &menu)) != noErr)
67 THROW_ERR(err);
68
69 MenuItemIndex menuItemIndex;
70 if ( (err = AppendMenuItemTextWithCFString(menu, ICCF_CopyLocalizedString(CFSTR("Open Location With")), kMenuItemAttrDisabled, 0, &menuItemIndex)) != noErr)
71 THROW_ERR(err);
72
73 if ( (urlArray = CFArrayCreate(NULL, (const void **)&url, 1, &kCFTypeArrayCallBacks)) == NULL)
74 THROW_ERR(memFullErr);
75
76 LSGetApplicationForURL(url, kLSRolesAll, NULL, &defaultAppURL);
77
78 CFIndex appIndex;
79 for (appIndex = 0 ; appIndex < appCount ; appIndex++) {
80 CFStringRef appName = NULL, appItemTitle = NULL;
81 CFBundleRef appBundle = NULL;
82 IconRef appIcon = NULL;
83 FSRef appRef;
84 CFURLRef appURL;
85 SInt16 label;
86
87 appURL = CFArrayGetValueAtIndex(appURLs, appIndex);
88 CFStringRef appPath = CFURLCopyPath(appURL);
89 if (CFSetContainsValue(appPaths, appPath))
90 continue;
91 CFSetAddValue(appPaths, appPath);
92
93 if ( (err = LSCopyDisplayNameForURL(appURL, &appName)) != noErr) THROW_ERR(err);
94
95 menuItemIndex = (long)CFDictionaryGetValue(appNames, appName);
96 if (menuItemIndex != 0) {
97 CFURLRef sameAppRef;
98 if (menuItemIndex != kICAppMenuItemHasPath && GetMenuItemRefCon(menu, menuItemIndex, (void *)&sameAppRef) == noErr) {
99 CFStringRef sameAppItemTitle = NULL;
100 if ( (err = CopyMenuItemTextAsCFString(menu, menuItemIndex, &sameAppItemTitle)) != noErr)
101 THROW_ERR(err);
102 CFStringRef appItemTitleWithVersion = ICCF_NameWithLocation(sameAppItemTitle, sameAppRef);
103 SetMenuItemTextWithCFString(menu, menuItemIndex, appItemTitleWithVersion);
104 SAFE_RELEASE(appItemTitleWithVersion);
105 CFDictionarySetValue(appNames, appName, (void *)(long)kICAppMenuItemHasPath);
106 }
107 }
108
109 CFRetain(appName);
110 appItemTitle = appName;
111
112 if ( (appBundle = CFBundleCreate(NULL, appURL)) != NULL) {
113 // prefer a short version string, e.g. "1.0 Beta" instead of "51" for Safari
114 CFStringRef appVersion = CFBundleGetValueForInfoDictionaryKey(appBundle, CFSTR("CFBundleShortVersionString"));
115 if (appVersion == NULL)
116 appVersion = CFBundleGetValueForInfoDictionaryKey(appBundle, kCFBundleVersionKey);
117 if (appVersion != NULL) {
118 appItemTitle = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ (%@)"), appName, appVersion);
119 CFRelease(appName);
120 }
121 CFRelease(appBundle);
122 }
123
124 if (menuItemIndex != 0) {
125 CFStringRef appItemTitleWithVersion = ICCF_NameWithLocation(appItemTitle, appURL);
126 CFRelease(appItemTitle);
127 appItemTitle = appItemTitleWithVersion;
128 }
129
130 if (defaultAppURL != NULL && CFEqual(appURL, defaultAppURL)) {
131 CFStringRef defaultFormat = ICCF_CopyLocalizedString(CFSTR("DefaultApp%@"));
132 CFStringRef appItemTitleWithDefault = CFStringCreateWithFormat(NULL, NULL, defaultFormat, appItemTitle);
133 CFRelease(appItemTitle);
134 appItemTitle = appItemTitleWithDefault;
135 defaultAppURL = NULL;
136 }
137
138 err = AppendMenuItemTextWithCFString(menu, appItemTitle, 0, 0, &menuItemIndex);
139 CFRelease(appItemTitle);
140 if (err != noErr) THROW_ERR(err);
141
142 if (!CFDictionaryContainsKey(appNames, appName)) {
143 CFDictionarySetValue(appNames, appName, (void *)(long)menuItemIndex);
144 CFRelease(appName);
145 }
146
147 if (!CFURLGetFSRef(appURL, &appRef)) THROW_ERR(paramErr);
148 err = GetIconRefFromFileInfo(&appRef, 0, NULL, kFSCatInfoNone, NULL, kIconServicesNormalUsageFlag, &appIcon, &label);
149 if (err != noErr) THROW_ERR(err);
150
151 SetMenuItemIconHandle(menu, menuItemIndex, kMenuIconRefType, (Handle)appIcon);
152 SetMenuItemRefCon(menu, menuItemIndex, (UInt32)appURL);
153 ReleaseIconRef(appIcon);
154 }
155 InsertMenu(menu, -1);
156 Point mousePoint;
157 GetGlobalMouse(&mousePoint);
158 long selectedAppIndex = PopUpMenuSelect(menu, mousePoint.v + 18, mousePoint.h - 30, 0/*popUpItem*/);
159 if (selectedAppIndex == 0) {
160 err = userCanceledErr;
161 } else {
162 CFURLRef appURL = NULL;
163 err = GetMenuItemRefCon(menu, selectedAppIndex, (void *)&appURL);
164 if (err == noErr) {
165 LSLaunchURLSpec lsSpec = {appURL, urlArray, NULL, kLSLaunchDefaults};
166 err = LSOpenFromURLSpec(&lsSpec, NULL);
167 }
168 }
169
170END:
171 if (h != NULL) DisposeHandle(h);
172 if (menu != NULL) {
173 DeleteMenu(GetMenuID(menu));
174 DisposeMenu(menu);
175 }
176 SAFE_RELEASE(url);
177 SAFE_RELEASE(urlArray);
178 SAFE_RELEASE(appURLs);
179 SAFE_RELEASE(appNames);
180 SAFE_RELEASE(appPaths);
181
182 return err;
183}
Note: See TracBrowser for help on using the repository browser.