### Eclipse Workspace Patch 1.0 #P org.eclipse.equinox.executable Index: library/carbon/eclipseCarbon.c =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.equinox.executable/library/carbon/eclipseCarbon.c,v retrieving revision 1.27 diff -u -r1.27 eclipseCarbon.c --- library/carbon/eclipseCarbon.c 13 Nov 2009 20:20:21 -0000 1.27 +++ library/carbon/eclipseCarbon.c 30 Nov 2009 21:15:25 -0000 @@ -73,17 +73,81 @@ } @end + +@interface AppleEventDelegate : NSObject +- (void)handleOpenDocuments:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +@end +@implementation AppleEventDelegate + NSTimer *timer; + NSMutableArray *files; + +- (void)handleOpenDocuments:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + int count = [event numberOfItems]; + int index = 1; + + if (!files) { + files = [NSMutableArray arrayWithCapacity:count]; + [files retain]; + } + + for (index = 1; index<=count; index++) { + NSAppleEventDescriptor *desc = [event descriptorAtIndex:index]; + if (desc) { + desc = [desc coerceToDescriptorType:typeFSRef]; + CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, [[desc data] bytes]); + if (url) { + NSString *pathName = (NSString *)CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + [files addObject:pathName]; + [pathName release]; + CFRelease(url); + } + } + } + + if (!timer) { + timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 + target: self + selector: @selector(handleTimer:) + userInfo: nil + repeats: YES]; + } + [pool release]; +} +- (void) handleTimer: (NSTimer *) timer { + NSObject *delegate = [[NSApplication sharedApplication] delegate]; + if (delegate != NULL && [delegate respondsToSelector: @selector(application:openFiles:)]) { + [delegate performSelector:@selector(application:openFiles:) withObject:[NSApplication sharedApplication] withObject:files]; + [files release]; + [timer invalidate]; + } +} +@end #endif static CFRunLoopRef loopRef = NULL; static void * startThread(void * init); static void runEventLoop(CFRunLoopRef ref); static void dummyCallback(void * info) {} +#ifndef COCOA +static CFMutableArrayRef files; +static EventHandlerRef appHandler; +static int SWT_CLASS = 'SWT-'; +static int SWT_OPEN_FILE_KIND = 1; +static int SWT_OPEN_FILE_PARAM = 'odoc'; +#endif int main() { return -1; } +void installAppleEventHandler(); + +int reuseWorkbench(_TCHAR* filePath) { + installAppleEventHandler(); + return 0; +} + #ifdef COCOA /* Show the Splash Window @@ -149,6 +213,8 @@ static CGImageSourceCreateWithURL_FUNC createWithURL = NULL; static CGImageSourceCreateImageAtIndex_FUNC createAtIndex = NULL; +static pascal OSErr openDocumentsProc(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); + static OSStatus drawProc (EventHandlerCallRef eventHandlerCallRef, EventRef eventRef, void * data) { int result = CallNextEventHandler(eventHandlerCallRef, eventRef); if (image) { @@ -183,6 +249,66 @@ } } +static OSStatus appleEventProc(EventHandlerCallRef inCaller, EventRef theEvent, void* inRefcon) { + EventRecord eventRecord; + Boolean release = false; + EventQueueRef queue; + + queue = GetCurrentEventQueue(); + if (IsEventInQueue (queue, theEvent)) { + RetainEvent (theEvent); + release = true; + RemoveEventFromQueue (queue, theEvent); + } + ConvertEventRefToEventRecord (theEvent, &eventRecord); + AEProcessAppleEvent (&eventRecord); + if (release) ReleaseEvent (theEvent); + return noErr; +} + +static void timerProc(EventLoopTimerRef timer, void *userData) { + EventTargetRef target = GetApplicationEventTarget(); + CFIndex count = CFArrayGetCount (files); + int i; + for (i=0; i #include #include +#include +#include /* Global Variables */ char* defaultVM = "java"; @@ -47,10 +49,177 @@ static GdkPixbuf* pixbuf = 0; static GtkWidget* image = 0; +static sem_t* mutex; +static Atom appAtom, launcherAtom; +static char* file = NULL; +static int timerAttempts; + +static struct sigaction quitAction; +static struct sigaction intAction; + /* Local functions */ +static void catch_signal(int sig) { + //catch signals, free the lock, reinstall the original + //signal handlers and reraise the signal. + sem_post(mutex); + sem_close(mutex); + sigaction(SIGINT, &intAction, NULL); + sigaction(SIGQUIT, &intAction, NULL); + raise(sig); +} + +typedef int (*LockFunc) (); +int executeWithLock (char *name, LockFunc func) { + int result; + struct sigaction action; + + mutex = sem_open(name, O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 1); + if (mutex == SEM_FAILED) { + //create failed. Probably lock is already created so try opening the + //existing lock. + mutex = sem_open(name, 0); + } + if (mutex == SEM_FAILED) return -1; //this is an error. + + //install signal handler to free the lock if something bad + //happens. sem_t is not freed automatically when a process ends. + action.sa_handler = catch_signal; + sigaction(SIGINT, &action, &intAction); + sigaction(SIGQUIT, &action, &quitAction); + //sem_t has no timeouts on wait. :-( + sem_wait(mutex); + + result = func(); + + sem_post(mutex); + sem_close(mutex); + //reinstall the original signal handlers + sigaction(SIGINT, &intAction, NULL); + sigaction(SIGQUIT, &quitAction, NULL); + return result; +} + static void log_handler(const gchar* domain, GLogLevelFlags flags, const gchar* msg, gpointer data) { /* nothing */ } + +static int setAppWindowProperty() { + Window appWindow; + GdkWindow *propWindow; + GdkAtom propAtom; + char *propVal; + + //Look for the SWT window. If it's there, set a property on it. + appWindow = XGetSelectionOwner(GDK_DISPLAY(), appAtom); + if (appWindow) { + propWindow = gdk_window_foreign_new (appWindow); + propAtom = gdk_atom_intern("org.eclipse.swt.filePath.message", FALSE); + //append a colon delimiter in case more than one file gets + //appended to the app windows property. + if (file != NULL) { + propVal = malloc((_tcslen(file) + 2) * sizeof(char)); + _stprintf(propVal, _T_ECLIPSE("%s%s"), file, ":"); + } else { + propVal = malloc(2); + _stprintf(propVal, _T_ECLIPSE("%s"), ":"); + } + gdk_property_change(propWindow, propAtom, propAtom, 8, GDK_PROP_MODE_APPEND, (guchar *)propVal, _tcslen(propVal)); + free(propVal); + return 1; + } + return 0; +} + +int setWindowProperty() { + char *mutexPrefix = "SWT_Window_"; + char *appName; + int result; + + appName = malloc((_tcslen(mutexPrefix) + _tcslen(getOfficialName()) + 1) * sizeof(char)); + _stprintf(appName, _T_ECLIPSE("%s%s"), mutexPrefix, getOfficialName()); + result = executeWithLock(appName, setAppWindowProperty); + XSync (GDK_DISPLAY (), False); + free(appName); + return result; +} + +static gboolean timerProc (gpointer data) { + //try to se the app window property. If unsuccessfull return + //true to reschedule the timer. Try 60 times (1 minute) max. + timerAttempts ++; + return !setWindowProperty() && timerAttempts < 60; +} + +void findWindow() { + //try setWindowProperty every second until it succeeds + //or a minute has passed. + int count = 0; + while (count < 60 && !setWindowProperty()) { + count++; + sleep(1); + } +} + +int createLauncherWindow() { + Window window, launcherWindow; + //check if a launcher window exists. If none exists, we know we are the + //first and we should be launching the app. + window = XGetSelectionOwner(GDK_DISPLAY(), launcherAtom); + if (window == 0) { + //create a launcher window that other processes can find. + launcherWindow = XCreateWindow(GDK_DISPLAY(), RootWindow(GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY())), -10, -10, 1, 1, 0, 0, + InputOnly, CopyFromParent, (unsigned long) 0, (XSetWindowAttributes *)NULL); + //for some reason Set and Get are both necessary. Set alone does nothing. + XSetSelectionOwner(GDK_DISPLAY(), launcherAtom, launcherWindow, CurrentTime); + XGetSelectionOwner(GDK_DISPLAY(), launcherAtom); + //add a timeout to set the property on the apps window once the app is launched. + if (file != NULL) { + timerAttempts = 0; + g_timeout_add(1000, timerProc, 0); + } + return 0; + } + return 1; +} + +int reuseWorkbench(char* filePath) { + char *mutexPrefix = "SWT_Window_"; + char *mutexSuffix = "_Launcher"; + char *appName, *launcherName; + int result = 0; + + if(initWindowSystem(&initialArgc, initialArgv, 1) != 0) + return -1; + + file = filePath; + + //App name is defined in SWT as well. Values must be consistent. + appName = malloc((_tcslen(mutexPrefix) + _tcslen(getOfficialName()) + 1) * sizeof(char)); + _stprintf(appName, _T_ECLIPSE("%s%s"), mutexPrefix, getOfficialName()); + appAtom = XInternAtom(GDK_DISPLAY(), appName, FALSE); + free(appName); + launcherName = malloc((_tcslen(mutexPrefix) + _tcslen(getOfficialName()) + _tcslen(mutexSuffix) + 1) * sizeof(char)); + _stprintf(launcherName, _T_ECLIPSE("%s%s%s"), mutexPrefix, getOfficialName(), mutexSuffix); + launcherAtom = XInternAtom(GDK_DISPLAY(), launcherName, FALSE); + + //check if app is already running. Just set property if it is. + if (setWindowProperty()) return 1; + + result = executeWithLock(launcherName, createLauncherWindow); + + free(launcherName); + + if (result == 1) { + //The app is already being launched in another process. + //Wait for it to complete, set the property on its window, + //and exit this process. + if (file != NULL) findWindow(); + result = 1; + } + + return result; +} + /* Create and Display the Splash Window */ int showSplash( const char* featureImage ) { Index: library/gtk/eclipseGtk.h =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.equinox.executable/library/gtk/eclipseGtk.h,v retrieving revision 1.2 diff -u -r1.2 eclipseGtk.h --- library/gtk/eclipseGtk.h 16 Apr 2009 17:58:02 -0000 1.2 +++ library/gtk/eclipseGtk.h 30 Nov 2009 21:15:26 -0000 @@ -13,6 +13,7 @@ #include #include +#include struct GTK_PTRS { short not_initialized; Index: library/win32/eclipseWin.c =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.equinox.executable/library/win32/eclipseWin.c,v retrieving revision 1.26 diff -u -r1.26 eclipseWin.c --- library/win32/eclipseWin.c 13 Nov 2009 20:20:15 -0000 1.26 +++ library/win32/eclipseWin.c 30 Nov 2009 21:15:26 -0000 @@ -14,6 +14,7 @@ #include "eclipseUtil.h" #include "eclipseCommon.h" #include "eclipseJNI.h" +#include "eclipseShm.h" #include #include @@ -35,6 +36,13 @@ _TCHAR* vmLibrary = _T("jvm.dll"); _TCHAR* shippedVMDir = _T("jre\\bin\\"); +/* Define local variables for communicating with running eclipse instance. */ +static HANDLE mutex; +static UINT findWindowTimeout = 1000; +static UINT_PTR findWindowTimerId = 97; +static UINT timerCount = 0; +static _TCHAR* openFilePath; + /* Define the window system arguments for the Java VM. */ static _TCHAR* argVM[] = { NULL }; @@ -44,6 +52,7 @@ static UINT jvmExitTimeout = 100; static UINT_PTR jvmExitTimerId = 99; +static void CALLBACK findWindowProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime); static void CALLBACK detectJvmExit( HWND hwnd, UINT uMsg, UINT id, DWORD dwTime ); static _TCHAR* checkVMRegistryKey(HKEY jrekey, _TCHAR* subKeyName); static void adjustSearchPath( _TCHAR * vmLibrary ); @@ -69,6 +78,83 @@ #define COMPANY_NAME_KEY _T_ECLIPSE("\\StringFileInfo\\%04x%04x\\CompanyName") #define SUN_MICROSYSTEMS _T_ECLIPSE("Sun Microsystems") +static void sendOpenFileMessage(HWND window) { + _TCHAR* id; + UINT msg; + int size = (_tcslen(openFilePath) + 1) * sizeof(_TCHAR); + DWORD wParam; +#ifdef WIN64 + DWORDLONG lParam; +#else + DWORD lParam; +#endif + createSharedData(&id, size); + setSharedData(id, openFilePath); + msg = RegisterWindowMessage(_T("SWT_FILEOPEN")); + _stscanf(id, _T_ECLIPSE("%lx_%lx"), &wParam, &lParam); + SendMessage(window, msg, wParam, lParam); + destroySharedData(id); +} + +static int findSWTMessageWindow(int startTimer) { + HWND window; + _TCHAR *windowTitle, *windowPrefix, *name; + int result = 0; + + windowPrefix = _T("SWT_Window_"); + name = getOfficialName(); + windowTitle = malloc((_tcslen(windowPrefix) + _tcslen(name) + 1) * sizeof(_TCHAR)); + _stprintf(windowTitle, _T_ECLIPSE("%s%s"), windowPrefix, name); + window = FindWindow(NULL, windowTitle); + free(windowTitle); + if (window != NULL) { + sendOpenFileMessage(window); + ReleaseMutex(mutex); + CloseHandle(mutex); + result = 1; + } else { + if (startTimer) { + initWindowSystem(0, NULL, 0); + SetTimer( topWindow, findWindowTimerId, findWindowTimeout, findWindowProc ); + } + } + return result; +} + +static void CALLBACK findWindowProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime) { + if (findSWTMessageWindow(0)) { + KillTimer(hwnd, findWindowTimerId); + return; + } + if (timerCount++ >= 60) { + KillTimer(hwnd, findWindowTimerId); + ReleaseMutex(mutex); + CloseHandle(mutex); + } +} + +int reuseWorkbench(_TCHAR* filePath) { + _TCHAR* mutexPrefix = _T("SWT_Mutex_"); + _TCHAR* mutexName, *name; + DWORD result=0, lock; + + openFilePath = filePath; + name = getOfficialName(); + mutexName = malloc((_tcslen(mutexPrefix) + _tcslen(name) + 1) * sizeof(_TCHAR)); + _stprintf(mutexName, _T_ECLIPSE("%s%s"), mutexPrefix, name); + mutex = CreateMutex(NULL, FALSE, mutexName); + free(mutexName); + if (mutex == NULL) return -1; + //wait for up to 1 minute + lock = WaitForSingleObject(mutex, 60*1000); + if (lock == WAIT_OBJECT_0) { + result = findSWTMessageWindow(1); + } else { + CloseHandle(mutex); + } + return result; +} + /* Show the Splash Window * * Open the bitmap, insert into the splash window and display it.