Added support for detecting if javaFX already started the GTK event loop (and hooking into the right places for shutdown if it does).

This commit is contained in:
nathan 2016-02-14 12:58:45 +01:00
parent 2e692733b3
commit 56f4bac16a
2 changed files with 74 additions and 38 deletions

View File

@ -58,7 +58,7 @@ interface Gtk extends Library {
} }
} }
void gtk_init(int argc, String[] argv); boolean gtk_init_check(int argc, String[] argv);
/** /**
* Runs the main loop until gtk_main_quit() is called. You can nest calls to gtk_main(). In that case gtk_main_quit() will make the * Runs the main loop until gtk_main_quit() is called. You can nest calls to gtk_main(). In that case gtk_main_quit() will make the
@ -66,6 +66,10 @@ interface Gtk extends Library {
*/ */
void gtk_main(); void gtk_main();
/** sks for the current nesting level of the main loop. Useful to determine (at startup) if GTK is already runnign */
int gtk_main_level();
/** /**
* Makes the innermost invocation of the main loop return when it regains control. ONLY CALL FROM THE GtkSupport class, UNLESS you know * Makes the innermost invocation of the main loop return when it regains control. ONLY CALL FROM THE GtkSupport class, UNLESS you know
* what you're doing! * what you're doing!
@ -74,8 +78,8 @@ interface Gtk extends Library {
void gdk_threads_init(); void gdk_threads_init();
// tricky business. This should only be in the dispatch thread
void gdk_threads_enter(); void gdk_threads_enter();
void gdk_threads_leave(); void gdk_threads_leave();
Pointer gtk_menu_new(); Pointer gtk_menu_new();

View File

@ -44,15 +44,17 @@ class GtkSupport {
public static volatile boolean isGtk2 = false; public static volatile boolean isGtk2 = false;
private static volatile boolean alreadyRunningGTK = false;
/** /**
* Helper for GTK, because we could have v3 or v2. * Helper for GTK, because we could have v3 or v2.
* *
* Observations: SWT & JavaFX both use GTK2, and we can't load GTK3 if GTK2 symbols are loaded * Observations: JavaFX uses GTK2, and we can't load GTK3 if GTK2 symbols are loaded
*/ */
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")
public static public static
Gtk get() { Gtk get() {
Object library; Gtk library;
boolean shouldUseGtk2 = GtkSupport.FORCE_GTK2; boolean shouldUseGtk2 = GtkSupport.FORCE_GTK2;
@ -60,10 +62,14 @@ class GtkSupport {
if (shouldUseGtk2) { if (shouldUseGtk2) {
try { try {
gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu"); gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("gtk-x11-2.0", Gtk.class); library = (Gtk) Native.loadLibrary("gtk-x11-2.0", Gtk.class);
if (library != null) { if (library != null) {
isGtk2 = true; isGtk2 = true;
return (Gtk) library;
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
alreadyRunningGTK = library.gtk_main_level() != 0;
return library;
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
@ -74,9 +80,12 @@ class GtkSupport {
// appindicator3 requires GTK3 // appindicator3 requires GTK3
try { try {
gtk_status_icon_position_menu = Function.getFunction("libgtk-3.so.0", "gtk_status_icon_position_menu"); gtk_status_icon_position_menu = Function.getFunction("libgtk-3.so.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("libgtk-3.so.0", Gtk.class); library = (Gtk) Native.loadLibrary("libgtk-3.so.0", Gtk.class);
if (library != null) { if (library != null) {
return (Gtk) library; // when running inside of JavaFX, this will be '1'. All other times this should be '0'
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
alreadyRunningGTK = library.gtk_main_level() != 0;
return library;
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
@ -84,10 +93,14 @@ class GtkSupport {
// appindicator1 requires GTK2 // appindicator1 requires GTK2
try { try {
gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu"); gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("gtk-x11-2.0", Gtk.class); library = (Gtk) Native.loadLibrary("gtk-x11-2.0", Gtk.class);
if (library != null) { if (library != null) {
isGtk2 = true; isGtk2 = true;
return (Gtk) library;
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
alreadyRunningGTK = library.gtk_main_level() != 0;
return library;
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
@ -99,9 +112,12 @@ class GtkSupport {
// start with version 3 // start with version 3
try { try {
gtk_status_icon_position_menu = Function.getFunction("libgtk-3.so.0", "gtk_status_icon_position_menu"); gtk_status_icon_position_menu = Function.getFunction("libgtk-3.so.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("libgtk-3.so.0", Gtk.class); library = (Gtk) Native.loadLibrary("libgtk-3.so.0", Gtk.class);
if (library != null) { if (library != null) {
return (Gtk) library; // when running inside of JavaFX, this will be '1'. All other times this should be '0'
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
alreadyRunningGTK = library.gtk_main_level() != 0;
return library;
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
@ -109,10 +125,14 @@ class GtkSupport {
// now version 2 // now version 2
try { try {
gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu"); gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("gtk-x11-2.0", Gtk.class); library = (Gtk) Native.loadLibrary("gtk-x11-2.0", Gtk.class);
if (library != null) { if (library != null) {
isGtk2 = true; isGtk2 = true;
return (Gtk) library;
// when running inside of JavaFX, this will be '1'. All other times this should be '0'
// when it's '1', it means that someone else has stared GTK -- so we DO NOT NEED TO.
alreadyRunningGTK = library.gtk_main_level() != 0;
return library;
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
@ -127,6 +147,7 @@ class GtkSupport {
if (!started) { if (!started) {
started = true; started = true;
// GTK specifies that we ONLY run from a single thread. This guarantees that.
gtkDispatchThread = new Thread() { gtkDispatchThread = new Thread() {
@Override @Override
public public
@ -151,33 +172,41 @@ class GtkSupport {
// startup the GTK GUI event loop. There can be multiple/nested loops. // startup the GTK GUI event loop. There can be multiple/nested loops.
final CountDownLatch blockUntilStarted = new CountDownLatch(1);
Thread gtkUpdateThread = new Thread() {
@Override
public
void run() {
Gtk instance = Gtk.INSTANCE;
// prep for the event loop. // If JavaFX/SWT is used, this is UNNECESSARY
instance.gdk_threads_init(); if (!alreadyRunningGTK) {
instance.gtk_init(0, null); // only necessary if we are the only GTK instance running...
GThread.INSTANCE.g_thread_init(null); final CountDownLatch blockUntilStarted = new CountDownLatch(1);
Thread gtkUpdateThread = new Thread() {
@Override
public
void run() {
Gtk gtk = Gtk.INSTANCE;
// notify our main thread to continue // prep for the event loop.
blockUntilStarted.countDown(); gtk.gdk_threads_init();
gtk.gdk_threads_enter();
// blocks unit quit gtk.gtk_init_check(0, null);
instance.gtk_main();
// notify our main thread to continue
blockUntilStarted.countDown();
// blocks unit quit
// gtk.gtk_main();
gtk.gdk_threads_leave();
}
};
gtkUpdateThread.setName("GTK Event Loop (Native)");
gtkUpdateThread.start();
try {
// we CANNOT continue until the GTK thread has started!
blockUntilStarted.await();
} catch (InterruptedException e) {
e.printStackTrace();
} }
};
gtkUpdateThread.setName("GTK Event Loop (Native)");
gtkUpdateThread.start();
try {
// we CANNOT continue until the GTK thread has started!
blockUntilStarted.await();
} catch (InterruptedException e) {
e.printStackTrace();
} }
} }
} }
@ -196,7 +225,10 @@ class GtkSupport {
public static public static
void shutdownGui() { void shutdownGui() {
Gtk.INSTANCE.gtk_main_quit(); // If JavaFX/SWT is used, this is UNNECESSARY (an will break SWT/JavaFX shutdown)
if (!alreadyRunningGTK) {
Gtk.INSTANCE.gtk_main_quit();
}
started = false; started = false;