Index: library/carbon/eclipseCarbonCommon.c =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.equinox.executable/library/carbon/eclipseCarbonCommon.c,v retrieving revision 1.5 diff -u -r1.5 eclipseCarbonCommon.c --- library/carbon/eclipseCarbonCommon.c 25 Apr 2007 20:33:57 -0000 1.5 +++ library/carbon/eclipseCarbonCommon.c 29 Aug 2007 14:01:07 -0000 @@ -29,6 +29,23 @@ int initialized = 0; +/* The semaphore that blocks until the openDocuments/openApplication + * Apple events have been received + */ +MPSemaphoreID startupEventSemaphore; + +/* The list of opened document paths from an openDocuments Apple event */ +_TCHAR** startupOpenedDocuments = NULL; + +/* The Apple Event event processor */ +static OSStatus appleEventProc(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon); + +/* The openApplication Apple Event callback */ +static pascal OSErr openApplicationAEProc(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); + +/* The openDocuments Apple Event callback */ +static pascal OSErr openDocumentsAEProc(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); + static void init() { if (!initialized) { ProcessSerialNumber psn; @@ -48,11 +65,30 @@ */ void initWindowSystem( int* pArgc, char* argv[], int showSplash ) { + EventTypeSpec kEvents[] = { {kEventClassAppleEvent, kEventAppleEvent} }; + char *homeDir = getProgramDir(); /*debug("install dir: %s\n", homeDir);*/ if (homeDir != NULL) chdir(homeDir); - + + /* Create a semaphore and immediately lock it. This will be + * unlocked by the openApplication or openDocuments Apple Event. + * The OS guarantees that one (and only one) of these will be + * sent during the app startup process. The events are delivered + * very quickly, so this only slightly increases startup time. The + * startJavaVM function in eclipseCarbon.c is also blocking on this + * event, because startJavaVM is called prior to this initialization + * process. + */ + MPCreateBinarySemaphore(&startupEventSemaphore); + MPWaitOnSemaphore(startupEventSemaphore, kDurationForever); + + /* Install the Apple Event handlers */ + InstallApplicationEventHandler(NewEventHandlerUPP(appleEventProc), GetEventTypeCount(kEvents), kEvents, 0, NULL); + AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, NewAEEventHandlerUPP(openApplicationAEProc), 0, false); + AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP(openDocumentsAEProc), 0, false); + if (showSplash) init(); } @@ -166,4 +202,97 @@ } CFRelease(url); return result; -} \ No newline at end of file +} + +/* This is taken from an Apple example on handling Apple Events manually */ +static OSStatus appleEventProc(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon) { + Boolean release = false; + EventRecord eventRecord; + OSErr ignoreErrForThisSample; + + // Events of type kEventAppleEvent must be removed from the queue + // before being passed to AEProcessAppleEvent. + if (IsEventInQueue(GetMainEventQueue(), inEvent)) { + // RemoveEventFromQueue will release the event, which will + // destroy it if we don't retain it first. + RetainEvent(inEvent); + release = true; + RemoveEventFromQueue(GetMainEventQueue(), inEvent); + } + + // Convert the event ref to the type AEProcessAppleEvent expects. + ConvertEventRefToEventRecord(inEvent, &eventRecord); + ignoreErrForThisSample = AEProcessAppleEvent(&eventRecord); + + if (release) { + ReleaseEvent(inEvent); + } + + // This Carbon event has been handled, even if no AppleEvent handlers + // were installed for the Apple event. + return noErr; +} + +/* openApplication doesn't do anything except signal the startup semaphore */ +static pascal OSErr openApplicationAEProc(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) { + MPSignalSemaphore(startupEventSemaphore); + return noErr; +} + +/* openDocuments parses out the list of files that triggered this application + * to launch, and sets them into the _TCHAR **startupOpenedDocuments which + * will be consumed by startJavaVM in eclipseCarbon.c as commandline + * paramaters. When this process is complete, the startup semaphore + * will be signalled. + */ +static pascal OSErr openDocumentsAEProc(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) { + AEDescList docList; + FSRef fsRef; + CFURLRef resolved; + Boolean isFolder, wasAliased; + CFStringRef string; + long index; + long count = 0; + OSErr err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList); + require_noerr(err, CantGetDocList); + + err = AECountItems(&docList, &count); + require_noerr(err, CantGetCount); + + //CFStringRef imageString = CFStringCreateWithCString(kCFAllocatorDefault, featureImage, kCFStringEncodingASCII); + startupOpenedDocuments = malloc((count) * sizeof(_TCHAR*)); + memset(startupOpenedDocuments, 0, (count) * sizeof(_TCHAR*)); + for (index = 1; index <= count; index++) { + err = AEGetNthPtr(&docList, index, typeFSRef, NULL, NULL, &fsRef, sizeof(FSRef), NULL); + require_noerr(err, CantGetDocDescPtr); + + if (FSResolveAliasFile(&fsRef, true, &isFolder, &wasAliased) == noErr) { + resolved = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsRef); + if (resolved != NULL) { + string = CFURLCopyFileSystemPath(resolved, kCFURLPOSIXPathStyle); + CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8); + char *s = malloc(length); + if (CFStringGetCString(string, s, length, kCFStringEncodingUTF8)) { + startupOpenedDocuments[index - 1] = s; + } + else { + free(s); + } + CFRelease(string); + CFRelease(resolved); + } + } + } + +CantGetCount: +CantGetDocDescPtr: + AEDisposeDesc(&docList); + +CantGetDocList: + if (err != noErr) { + // For handlers that expect a reply, add error information here. + } + + MPSignalSemaphore(startupEventSemaphore); + return err; +} Index: library/carbon/eclipseCarbon.c =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.equinox.executable/library/carbon/eclipseCarbon.c,v retrieving revision 1.17 diff -u -r1.17 eclipseCarbon.c --- library/carbon/eclipseCarbon.c 30 Jul 2007 17:58:16 -0000 1.17 +++ library/carbon/eclipseCarbon.c 29 Aug 2007 14:01:07 -0000 @@ -64,6 +64,11 @@ static CGImageSourceCreateWithURL_FUNC createWithURL = NULL; static CGImageSourceCreateImageAtIndex_FUNC createAtIndex = NULL; +/* Externed from eclipseCarbonCommon.c */ +extern MPSemaphoreID startupEventSemaphore; +/* Externed from eclipseCarbonCommon.c */ +extern _TCHAR** startupOpenedDocuments; + int main() { return -1; } @@ -265,6 +270,35 @@ int startJavaVM( _TCHAR* libPath, _TCHAR* vmArgs[], _TCHAR* progArgs[] ) { + _TCHAR** progArgsWithStartupDocuments; + int nProgArgs = 0; + int nStartupOpenedDocuments = 0; + + /* We have to do a small run of dispatch messages so we receive the openDocuments + * or openApplication Apple events + */ + dispatchMessages(); + + /* ... and we block on the startup event semaphore, which is flipped by the + * Apple Event handlers (either openDocuments or openApplication -- we are + * guaranteed to receive at least one of them). + */ + MPWaitOnSemaphore(startupEventSemaphore, kDurationForever); + + /* If the app was launched via openDocuments, then stuff the list of + * documents onto the front of the Java VM commandline + */ + if (startupOpenedDocuments != NULL) { + while(progArgs[++nProgArgs] != NULL) {} + while(startupOpenedDocuments[++nStartupOpenedDocuments] != NULL) {} + + progArgsWithStartupDocuments = malloc((nProgArgs + nStartupOpenedDocuments) * sizeof(_TCHAR*)); + memset(progArgsWithStartupDocuments, 0, (nProgArgs + nStartupOpenedDocuments) * sizeof(_TCHAR*)); + memcpy(progArgsWithStartupDocuments, startupOpenedDocuments, (nStartupOpenedDocuments - 1) * sizeof(_TCHAR*)); + memcpy(progArgsWithStartupDocuments + nStartupOpenedDocuments - 1, progArgs, nProgArgs * sizeof(_TCHAR*)); + progArgs = progArgsWithStartupDocuments; + } + if (secondThread == 0) return startJavaJNI(libPath, vmArgs, progArgs);