Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'features/org.eclipse.equinox.executable.feature/library/gtk/eclipseGtk.c')
-rw-r--r--features/org.eclipse.equinox.executable.feature/library/gtk/eclipseGtk.c329
1 files changed, 160 insertions, 169 deletions
diff --git a/features/org.eclipse.equinox.executable.feature/library/gtk/eclipseGtk.c b/features/org.eclipse.equinox.executable.feature/library/gtk/eclipseGtk.c
index 65f1b0c8a..e26e48a4d 100644
--- a/features/org.eclipse.equinox.executable.feature/library/gtk/eclipseGtk.c
+++ b/features/org.eclipse.equinox.executable.feature/library/gtk/eclipseGtk.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -23,9 +23,7 @@
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <dlfcn.h>
-#ifdef SOLARIS
-#include <sys/filio.h>
-#endif
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -34,10 +32,6 @@
#include <semaphore.h>
#include <fcntl.h>
-#ifdef HPUX
-#define SEM_FAILED (void *)-1
-#endif
-
/* Global Variables */
char* defaultVM = "java";
char* vmLibrary = "libjvm.so";
@@ -46,188 +40,186 @@ char* shippedVMDir = "jre/bin/";
/* Define the special arguments for the various Java VMs. */
static char* argVM_JAVA[] = { NULL };
+/*
+ * Define arguments that are required/used by platform (e.g SWT) to function properly on gtk. (via Java's System.getProperty(..)).
+ * These should not affect JVM itself (e.g flags shouldn't set things like memory usage of the JVM).
+ *
+ * Note, these may re-occur in *.product (i.e eclipse.ini) such that "java -jar launcher" would work (e.g a child eclipse).
+ * See bug 528414.
+ *
+ * For swt.dbus.init, see bottom of method (SWT/Gtk) Display.java:createDisplay().
+ */
+char* gtkPlatformJavaSystemProperties [] = { "-Dswt.dbus.init", NULL};
+
/* Define local variables . */
-static long splashHandle = 0;
+static GtkWidget* splashHandle = 0;
static GtkWidget* shellHandle = 0;
-static sem_t* mutex;
-static Atom appWindowAtom, launcherWindowAtom;
static _TCHAR** openFilePath = NULL; /* the files we want to open */
static int openFileTimeout = 60; /* number of seconds to wait before timeout */
-static int windowPropertySet = 0; /* set to 1 on success */
-
-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);
-}
+static int filesPassedToSWT = 0; /* set to 1 on success */
+static const int FILEOPEN_RETRY_TIMEOUT_MS = 1000;
+
+/** GDBus related */
+static const gchar GDBUS_SERVICE[] = "org.eclipse.swt";
+static const gchar GDBUS_OBJECT[] = "/org/eclipse/swt";
+static const gchar GDBUS_INTERFACE[] = "org.eclipse.swt";
+GDBusProxy *gdbus_proxy = NULL;
+
+gboolean gdbus_initProxy ();
+gboolean gdbus_testConnection();
+gboolean gdbus_FileOpen_TimerProc(gpointer data);
+gboolean gdbus_call_FileOpen ();
+
+/*
+ * Deals with opening files passed to eclipse. e.g: ./eclipse /myfile
+ *
+ * return 1 = Files passed to eclipse. Don't spawn another instance.
+ * 0 = Launch a new eclipse instance, will try to pass files to eclipse once instance is launched.
+ */
+gboolean reuseWorkbench(_TCHAR** filePath, int timeout) {
+ openFileTimeout = timeout;
+ openFilePath = filePath;
-typedef int (*LockFunc)();
-int executeWithLock(char *name, LockFunc func) {
- int result = -1;
- int lock = -1;
- struct sigaction action;
+ if (initWindowSystem(&initialArgc, initialArgv, 1) != 0)
+ return -1;
- 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);
-
- while ((lock = sem_trywait(mutex)) != 0) {
- if (errno == EAGAIN) {
- //couldn't acquire lock, sleep a bit and try again
- sleep(1);
- if (--openFileTimeout > 0)
- continue;
- }
- break;
+ if (!gdbus_initProxy()) {
+ _ftprintf(stderr, "Launcher Error. Could not init gdbus proxy. Bug? Launching eclipse without opening files passed in.\n");
+ return 0;
}
- if (lock == 0)
- result = func();
-
- sem_post(mutex);
- sem_close(mutex);
-
- //reinstall the original signal handlers
- sigaction(SIGINT, &intAction, NULL);
- sigaction(SIGQUIT, &quitAction, NULL);
- return result;
+ // If eclipse already open, just pass files.
+ if (gdbus_testConnection()) {
+ return gdbus_call_FileOpen();
+ } else {
+ // Otherwise add a timer that will keep trying to pass files to eclipse for a few minutes until it succeeds or times out.
+ // Note, the while loop in launchJavaVM() ensures the launcher doesn't quit before the timer expired.
+ gtk.g_timeout_add(FILEOPEN_RETRY_TIMEOUT_MS, gdbus_FileOpen_TimerProc, 0);
+ return 0;
+ }
}
-/* Create a "SWT_Window_" + APP_NAME string with optional suffix.
- * Caller should free the memory when finished */
-static char * createSWTWindowString(char * suffix, int semaphore) {
-#ifdef SOLARIS
- /* solaris requires semaphore names to start with '/' */
- char * prefix = semaphore != 0 ? _T_ECLIPSE("/SWT_Window_") : _T_ECLIPSE("SWT_Window_");
-#else
- char * prefix = _T_ECLIPSE("SWT_Window_");
-#endif
-
- char * result = malloc((_tcslen(prefix) + _tcslen(getOfficialName()) + (suffix != NULL ? _tcslen(suffix) : 0) + 1) * sizeof(char));
- if (suffix != NULL)
- _stprintf(result, _T_ECLIPSE("%s%s%s"), prefix, getOfficialName(), suffix);
- else
- _stprintf(result, _T_ECLIPSE("%s%s"), prefix, getOfficialName());
- return result;
+/**
+ * Initializes variables/structures for dbus connectivity to org.eclipse.swt.
+ * Can be called multiple times, only first time initializes, other times just return early (1).
+ *
+ * DO NOT USE TO TEST CONNECTION. Use dbus_testConnection() instead.
+ *
+ * return: 0 (false) bug, something that shouldn't fail failed. This can happen if dynamic function calls failed or gdbus is not available etc..
+ * 1 (true) proxy configured.
+ */
+gboolean gdbus_initProxy () {
+ if (gdbus_proxy != NULL)
+ return 1; // already initialized.
+
+ // Function 'g_type_init()' is not needed anymore as of glib 2.36 as gtype system is initialized earlier. It is marked as deprecated.
+ // It is here because at the time of writing, eclipse supports glib 2.28.
+ // It is dynamic to prevent compile warning. But should be removed once min glib eclipse version >= 2.36
+ gtk.g_type_init();
+
+ GError *error = NULL; // Some functions return errors through params
+ gdbus_proxy = gtk.g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, GDBUS_SERVICE, GDBUS_OBJECT, GDBUS_INTERFACE, NULL, &error);
+ if ((gdbus_proxy == NULL) || (error != NULL)) {
+ fprintf(stderr, "Launcher error: GDBus proxy init failed to connect %s:%s on %s.\n", GDBUS_SERVICE, GDBUS_OBJECT, GDBUS_INTERFACE);
+ if (error != NULL) {
+ _ftprintf(stderr, "Launcher error: GDBus gdbus_proxy init failed for reason: %s\n", error->message);
+ gtk.g_error_free (error);
+ }
+ return 0;
+ } else {
+ return 1;
+ }
}
-static int setAppWindowPropertyFn() {
- Window appWindow;
- Atom propAtom;
- _TCHAR *propVal;
-
- //Look for the SWT window. If it's there, set a property on it.
- appWindow = gtk.XGetSelectionOwner(gtk_GDK_DISPLAY, appWindowAtom);
- if (appWindow) {
- propAtom = gtk.XInternAtom(gtk_GDK_DISPLAY, "org.eclipse.swt.filePath.message", FALSE);
- //append a colon delimiter in case more than one file gets appended to the app windows property.
- propVal = concatPaths(openFilePath, _T_ECLIPSE(':'));
- gtk.XChangeProperty(gtk_GDK_DISPLAY, appWindow, propAtom, propAtom, 8, PropModeAppend, (unsigned char *)propVal, _tcslen(propVal));
- free(propVal);
- windowPropertySet = 1;
+/*
+ * Test if we can reach org.eclipse.swt dbus session.
+ *
+ * return 0 (false) No connection.
+ * 1 (true) org.eclipse.swt listens to calls.
+ */
+gboolean gdbus_testConnection() {
+ if (!gdbus_initProxy())
+ return 0;
+ GError *error = NULL; // Some functions return errors through params
+ GVariant *result; // The value result from a call
+ result = gtk.g_dbus_proxy_call_sync(gdbus_proxy, "org.freedesktop.DBus.Peer.Ping", 0, G_DBUS_CALL_FLAGS_NONE, /* Proxy default timeout */ -1, NULL, &error);
+ if (error != NULL) {
+ gtk.g_error_free(error);
+ return 0;
+ }
+ if (result != NULL) {
+ gtk.g_variant_unref (result);
return 1;
}
+ _ftprintf(stderr, "ERROR: testConnection failed due to unknown reason. Bug in eclipseGtk.c? Potential cause could be dynamic function not initialized properly\n");
return 0;
}
-/* set the Application window property by executing _setWindowPropertyFn within a semaphore */
-int setAppWindowProperty() {
- int result;
- char * mutexName = createSWTWindowString(NULL, 1);
- result = executeWithLock(mutexName, setAppWindowPropertyFn);
- gtk.XSync(gtk_GDK_DISPLAY, False);
- free(mutexName);
- return result;
-}
-
-/* timer callback function to call setAppWindowProperty */
-static gboolean setAppWindowTimerProc(gpointer data) {
- //try to set the app window property. If unsuccessful return true to reschedule the timer.
+/*
+ * Timer callback function.
+ *
+ * Try to pass files to eclipse. If eclipse not up yet, try again later.
+ *
+ * Timer ends when it returns false. (Files passed to eclipse or timeout).
+ */
+gboolean gdbus_FileOpen_TimerProc(gpointer data) {
+ if (openFileTimeout == 0)
+ return 0; // stop timer.
openFileTimeout--;
- return !setAppWindowProperty() && openFileTimeout > 0;
-}
-
-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(gtk_GDK_DISPLAY, launcherWindowAtom);
- if (window == 0) {
- //create a launcher window that other processes can find.
- launcherWindow = gtk.XCreateWindow(gtk_GDK_DISPLAY, gtk.XRootWindow(gtk_GDK_DISPLAY, gtk.XDefaultScreen(gtk_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(gtk_GDK_DISPLAY, launcherWindowAtom, launcherWindow, CurrentTime);
- gtk.XGetSelectionOwner(gtk_GDK_DISPLAY, launcherWindowAtom);
- //add a timeout to set the property on the apps window once the app is launched.
- gtk.g_timeout_add(1000, setAppWindowTimerProc, 0);
- return 0;
+ if (gdbus_testConnection()) {
+ gdbus_call_FileOpen();
+ filesPassedToSWT = 1;
+ return 0; // stop timer.
}
- return 1;
+ return 1; // run timer again.
}
-int reuseWorkbench(_TCHAR** filePath, int timeout) {
- char *appName, *launcherName;
- int result = 0;
+/*
+ * Call fileOpen method in SWT. Note, in SWT, see GDBus.java. fileOpen GDBusMethod is defined in Display.java.
+ * This call can be called multiple times if Eclipse hasn't launched yet.
+ *
+ * Return: FALSE (0) Call did not work. Probably eclipse not fired up yet. (try again later)
+ * TRUE (1) GDBus call completed successfully.
+ */
+gboolean gdbus_call_FileOpen () {
+ if (!gdbus_initProxy())
+ return 0;
- if (initWindowSystem(&initialArgc, initialArgv, 1) != 0)
- return -1;
+ // Construct GDBus arguments based on files passed into launcher.
+ GVariantBuilder *builder;
+ GVariant *paramaters;
+ builder = gtk.g_variant_builder_new ((const GVariantType *) "as"); // as = G_VARIANT_TYPE_STRING_ARRAY
- openFileTimeout = timeout;
- openFilePath = filePath;
-
- //App name is defined in SWT as well. Values must be consistent.
- appName = createSWTWindowString(NULL, 0);
- appWindowAtom = gtk.XInternAtom(gtk_GDK_DISPLAY, appName, FALSE);
- free(appName);
+ int i = -1;
+ while (openFilePath[++i] != NULL) {
+ gtk.g_variant_builder_add (builder, (const gchar *) (const GVariantType *) "s", (const gchar *) openFilePath[i]); // s = G_VARIANT_TYPE_STRING
+ }
- //check if app is already running. Just set property if it is.
- if (setAppWindowProperty() > 0)
- return 1;
+ paramaters = gtk.g_variant_new ("(as)", builder);
+ gtk.g_variant_builder_unref (builder);
- /* app is not running, create a launcher window to act as a mutex so we don't need to keep the semaphore locked */
- launcherName = createSWTWindowString(_T_ECLIPSE("_Launcher"), 1);
- launcherWindowAtom = gtk.XInternAtom(gtk_GDK_DISPLAY, launcherName, FALSE);
- result = executeWithLock(launcherName, createLauncherWindow);
- free(launcherName);
-
- if (result == 1) {
- //The app is already being launched in another process. Set the property on that app window and exit
- while (openFileTimeout > 0) {
- if (setAppWindowProperty() > 0)
- return 1; //success
- else {
- openFileTimeout--;
- sleep(1);
- }
+ // Send a message
+ GError *error = NULL;
+ GVariant *result;
+ result = gtk.g_dbus_proxy_call_sync(gdbus_proxy, "FileOpen", paramaters, G_DBUS_CALL_FLAGS_NONE, /* Proxy default timeout */ -1, NULL, &error);
+ if (error != NULL) {
+ gtk.g_error_free (error);
+ return 0; // did not work. Eclipse probably not up yet. Try again later.
+ } else {
+ if (result != NULL) {
+ // Because this not straight forward, below is an example of how to retrieve string return value if needed in the future.
+ // Note, arguments are packaged into a tuple because we deal with gdbus in dynamic way.
+ // gchar *str;
+ // g_variant_get(result, "(&s)", &str);
+ gtk.g_variant_unref(result);
}
- //timed out trying to set the app property
- result = 0;
+ return 1; // worked.
}
- return result;
}
/* Get current scaling-factor */
-float scaleFactor ()
-{
+float scaleFactor () {
float scaleFactor = 1;
GdkScreen * screen;
double resolution;
@@ -238,9 +230,9 @@ float scaleFactor ()
scaleFactor = (float)(resolution / 96);
return scaleFactor;
}
+
/* Create and Display the Splash Window */
-int showSplash( const char* featureImage )
-{
+int showSplash( const char* featureImage ) {
GtkWidget *image;
GdkPixbuf *pixbuf, *scaledPixbuf;
int width, height;
@@ -284,7 +276,7 @@ int showSplash( const char* featureImage )
gtk.gtk_window_set_position((GtkWindow*)(shellHandle), GTK_WIN_POS_CENTER);
gtk.gtk_window_resize((GtkWindow*)(shellHandle), gtk.gdk_pixbuf_get_width(scaledPixbuf), gtk.gdk_pixbuf_get_height(scaledPixbuf));
gtk.gtk_widget_show_all((GtkWidget*)(shellHandle));
- splashHandle = (long)shellHandle;
+ splashHandle = shellHandle;
dispatchMessages();
return 0;
}
@@ -295,7 +287,7 @@ void dispatchMessages() {
}
jlong getSplashHandle() {
- return splashHandle;
+ return (jlong) splashHandle;
}
void takeDownSplash() {
@@ -308,8 +300,7 @@ void takeDownSplash() {
}
/* Get the window system specific VM arguments */
-char** getArgVM( char* vm )
-{
+char** getArgVM( char* vm ) {
char** result;
/* if (isJ9VM( vm ))
@@ -320,8 +311,7 @@ char** getArgVM( char* vm )
return result;
}
-JavaResults* launchJavaVM( char* args[] )
-{
+JavaResults* launchJavaVM( char* args[] ) {
JavaResults* jvmResults = NULL;
pid_t jvmProcess, finishedProcess = 0;
int exitCode;
@@ -352,7 +342,9 @@ JavaResults* launchJavaVM( char* args[] )
sleepTime.tv_sec = 0;
sleepTime.tv_nsec = 5e+8; // 500 milliseconds
- while(openFileTimeout > 0 && !windowPropertySet && (finishedProcess = waitpid(jvmProcess, &exitCode, WNOHANG)) == 0) {
+ // Ensure we don't quit the launcher until gdbus_FileOpen_TimerProc() finished or timed out.
+ // If making any changes to this loop, ensure "./eclipse /myFile" still works.
+ while(openFileTimeout > 0 && !filesPassedToSWT && (finishedProcess = waitpid(jvmProcess, &exitCode, WNOHANG)) == 0) {
dispatchMessages();
nanosleep(&sleepTime, NULL);
}
@@ -363,6 +355,5 @@ JavaResults* launchJavaVM( char* args[] )
/* TODO, this should really be a runResult if we could distinguish the launch problem above */
jvmResults->launchResult = WEXITSTATUS(exitCode);
}
-
return jvmResults;
}

Back to the top