### 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 1 Dec 2009 23:18:43 -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, int timeout) { + 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 = gtk.XGetSelectionOwner(GDK_DISPLAY(), appAtom); + if (appWindow) { + propWindow = gtk.gdk_window_foreign_new (appWindow); + propAtom = gtk.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"), ":"); + } + gtk.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); + gtk.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 = gtk.XGetSelectionOwner(GDK_DISPLAY(), launcherAtom); + if (window == 0) { + //create a launcher window that other processes can find. + launcherWindow = gtk.XCreateWindow(GDK_DISPLAY(), gtk.XRootWindow(GDK_DISPLAY(), gtk.XDefaultScreen(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. + gtk.XSetSelectionOwner(GDK_DISPLAY(), launcherAtom, launcherWindow, CurrentTime); + gtk.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; + gtk.g_timeout_add(1000, timerProc, 0); + } + return 0; + } + return 1; +} + +int reuseWorkbench(char* filePath, int timeout) { + 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 1 Dec 2009 23:18:43 -0000 @@ -13,6 +13,7 @@ #include #include +#include struct GTK_PTRS { short not_initialized; @@ -43,6 +44,8 @@ gboolean (*g_main_context_iteration) (GMainContext*, gboolean); void (*g_object_unref) (gpointer); GObject* (*g_object_new) (GType, const gchar*, ...); + guint (*g_timeout_add) (guint, GSourceFunc, gpointer); + #ifdef SOLARIS GString* (*g_string_insert_c) (GString *, gssize, gchar); #endif @@ -51,6 +54,17 @@ int (*gdk_pixbuf_get_width) (const GdkPixbuf*); int (*gdk_pixbuf_get_height) (const GdkPixbuf*); void (*gdk_set_program_class) (const char*); + GdkWindow* (*gdk_window_foreign_new) (GdkNativeWindow); + void (*gdk_property_change) (GdkWindow*, GdkAtom, GdkAtom, gint, GdkPropMode, const guchar*, gint); + GdkAtom (*gdk_atom_intern) (const gchar*, gboolean); + + Window (*XGetSelectionOwner) (Display*, Atom); + void (*XSetSelectionOwner) (Display*, Atom, Window, Time); + Window (*XCreateWindow) (Display*, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual*, unsigned long, XSetWindowAttributes*); + void (*XSync) (Display*, Bool); + int (*XDefaultScreen) (Display*); + Window (*XRootWindow) (Display*, int); + }; extern struct GTK_PTRS gtk; Index: library/gtk/eclipseGtkInit.c =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.equinox.executable/library/gtk/eclipseGtkInit.c,v retrieving revision 1.2 diff -u -r1.2 eclipseGtkInit.c --- library/gtk/eclipseGtkInit.c 16 Apr 2009 17:58:02 -0000 1.2 +++ library/gtk/eclipseGtkInit.c 1 Dec 2009 23:18:43 -0000 @@ -44,6 +44,9 @@ }; /* functions from libgdk-x11-2.0 */ static FN_TABLE gdkFunctions[] = { FN_TABLE_ENTRY(gdk_set_program_class), + FN_TABLE_ENTRY(gdk_property_change), + FN_TABLE_ENTRY(gdk_atom_intern), + FN_TABLE_ENTRY(gdk_window_foreign_new), { NULL, NULL } }; /* functions from libgdk_pixbuf-2.0 */ @@ -57,12 +60,23 @@ FN_TABLE_ENTRY(g_log_remove_handler), FN_TABLE_ENTRY(g_main_context_iteration), FN_TABLE_ENTRY(g_object_unref), + FN_TABLE_ENTRY(g_timeout_add), #ifdef SOLARIS FN_TABLE_ENTRY(g_string_insert_c), #endif { NULL, NULL } }; +/* functions from libX11 */ +static FN_TABLE x11Functions[] = { FN_TABLE_ENTRY(XGetSelectionOwner), + FN_TABLE_ENTRY(XSetSelectionOwner), + FN_TABLE_ENTRY(XCreateWindow), + FN_TABLE_ENTRY(XSync), + FN_TABLE_ENTRY(XRootWindow), + FN_TABLE_ENTRY(XDefaultScreen), + { NULL, NULL } + }; + static int loadGtkSymbols( void * library, FN_TABLE * table) { int i = 0; @@ -82,6 +96,7 @@ void * gdkLib = dlopen(GDK_LIB, RTLD_LAZY); void * pixLib = dlopen(PIXBUF_LIB, RTLD_LAZY); void * gtkLib = dlopen(GTK_LIB, RTLD_LAZY); + void * x11Lib = dlopen(X11_LIB, RTLD_LAZY); /* initialize ptr struct to 0's */ memset(>k, 0, sizeof(struct GTK_PTRS)); @@ -90,6 +105,7 @@ if ( gdkLib == NULL || loadGtkSymbols(gdkLib, gdkFunctions) != 0) return -1; if ( pixLib == NULL || loadGtkSymbols(pixLib, pixFunctions) != 0) return -1; if ( objLib == NULL || loadGtkSymbols(objLib, gobjFunctions) != 0) return -1; + if ( x11Lib == NULL || loadGtkSymbols(x11Lib, x11Functions) != 0) return -1; return 0; } Index: library/gtk/make_linux.mak =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.equinox.executable/library/gtk/make_linux.mak,v retrieving revision 1.12 diff -u -r1.12 make_linux.mak --- library/gtk/make_linux.mak 31 Jul 2008 16:55:10 -0000 1.12 +++ library/gtk/make_linux.mak 1 Dec 2009 23:18:43 -0000 @@ -43,7 +43,7 @@ DLL = $(PROGRAM_LIBRARY) #LIBS = `pkg-config --libs-only-L gtk+-2.0` -lgtk-x11-2.0 -lgdk_pixbuf-2.0 -lgobject-2.0 -lgdk-x11-2.0 -lpthread -ldl LIBS = -lpthread -ldl -GTK_LIBS = -DGTK_LIB="\"libgtk-x11-2.0.so.0\"" -DGDK_LIB="\"libgdk-x11-2.0.so.0\"" -DPIXBUF_LIB="\"libgdk_pixbuf-2.0.so.0\"" -DGOBJ_LIB="\"libgobject-2.0.so.0\"" +GTK_LIBS = -DGTK_LIB="\"libgtk-x11-2.0.so.0\"" -DGDK_LIB="\"libgdk-x11-2.0.so.0\"" -DPIXBUF_LIB="\"libgdk_pixbuf-2.0.so.0\"" -DGOBJ_LIB="\"libgobject-2.0.so.0\"" -DX11_LIB="\"libX11.so.6\"" LFLAGS = -shared -fpic -Wl,--export-dynamic CFLAGS = -g -s -Wall\ -fpic \ Index: library/gtk/make_solaris.mak =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.equinox.executable/library/gtk/make_solaris.mak,v retrieving revision 1.10 diff -u -r1.10 make_solaris.mak --- library/gtk/make_solaris.mak 24 Apr 2009 19:19:14 -0000 1.10 +++ library/gtk/make_solaris.mak 1 Dec 2009 23:18:43 -0000 @@ -43,7 +43,7 @@ DLL = $(PROGRAM_LIBRARY) #LIBS = `pkg-config --libs-only-L gtk+-2.0` -lgtk-x11-2.0 -lgdk_pixbuf-2.0 -lgobject-2.0 -lgdk-x11-2.0 -lglib-2.0 -lthread -ldl -lc LIBS = -lthread -ldl -lc -GTK_LIBS = -DGTK_LIB="\"libgtk-x11-2.0.so.0\"" -DGDK_LIB="\"libgdk-x11-2.0.so.0\"" -DPIXBUF_LIB="\"libgdk_pixbuf-2.0.so.0\"" -DGOBJ_LIB="\"libgobject-2.0.so.0\"" +GTK_LIBS = -DGTK_LIB="\"libgtk-x11-2.0.so.0\"" -DGDK_LIB="\"libgdk-x11-2.0.so.0\"" -DPIXBUF_LIB="\"libgdk_pixbuf-2.0.so.0\"" -DGOBJ_LIB="\"libgobject-2.0.so.0\"" -DX11_LIB="\"libX11.so.6\"" LFLAGS = -G CFLAGS = $(OPTFLAG) \ -DSOLARIS \ 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 1 Dec 2009 23:18:43 -0000 @@ -14,6 +14,7 @@ #include "eclipseUtil.h" #include "eclipseCommon.h" #include "eclipseJNI.h" +#include "eclipseShm.h" #include #include @@ -35,6 +36,14 @@ _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 UINT openFileTimeout = 60; +static _TCHAR* openFilePath; + /* Define the window system arguments for the Java VM. */ static _TCHAR* argVM[] = { NULL }; @@ -44,6 +53,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 +79,98 @@ #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 does not return until the message has been processed */ + SendMessage(window, msg, wParam, lParam); + destroySharedData(id); +} + +static HWND findSWTMessageWindow() { + HWND window = NULL; + _TCHAR *windowTitle, *windowPrefix, *name; + + 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); + return window; +} + +static void CALLBACK findWindowProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime) { + HWND window = findSWTMessageWindow(); + if (window != NULL) { + sendOpenFileMessage(window); + ReleaseMutex(mutex); + CloseHandle(mutex); + KillTimer(hwnd, findWindowTimerId); + return; + } + + /* no window yet, set timer to try again later */ + if (timerCount++ >= openFileTimeout) { + KillTimer(hwnd, findWindowTimerId); + ReleaseMutex(mutex); + CloseHandle(mutex); + } +} + +int reuseWorkbench(_TCHAR* filePath, int timeout) { + _TCHAR* mutexPrefix = _T("SWT_Mutex_"); + _TCHAR* mutexName, *name; + DWORD lock; + HWND window = NULL; + + /* store for later */ + openFilePath = filePath; + openFileTimeout = timeout; + + 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 timeout seconds + lock = WaitForSingleObject(mutex, timeout * 1000); + if (lock != WAIT_OBJECT_0) { + /* failed to get the lock before timeout, We won't be reusing an existing eclipse. */ + CloseHandle(mutex); + return 0; + } + + /* we have the mutex, look for the SWT window */ + window = findSWTMessageWindow(); + if (window != NULL) { + sendOpenFileMessage(window); + ReleaseMutex(mutex); + CloseHandle(mutex); + return 1; /* success! */ + } + + /* no window, set a timer to look again later */ + if (initWindowSystem(0, NULL, 0) == 0) + SetTimer( topWindow, findWindowTimerId, findWindowTimeout, findWindowProc ); + + return 0; +} + /* Show the Splash Window * * Open the bitmap, insert into the splash window and display it.