Changed support for SWT, added GtkSupport.DISABLE_EVENT_LOOP to disable the creation of the native event loop (ie: if using SWT, which already does this)

This commit is contained in:
nathan 2016-02-12 11:51:35 +01:00
parent 5b8cbadb84
commit b81995ab2b
2 changed files with 61 additions and 35 deletions

View File

@ -83,8 +83,6 @@ public interface Gtk extends Library {
void gtk_main_quit();
void gdk_threads_init();
void gdk_threads_enter();
void gdk_threads_leave();
Pointer gtk_menu_new();
Pointer gtk_menu_item_new();

View File

@ -15,45 +15,38 @@
*/
package dorkbox.util.jna.linux;
import dorkbox.util.Property;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
public
class GtkSupport {
public static final boolean isSupported;
private static final boolean hasSwt;
// RE: SWT
// https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html#g-thread-init
// Since version >= 2.24, threads can only init once. Multiple calls do nothing, and we can nest gtk_main()
// in a nested loop.
private static volatile boolean started = false;
private static final ArrayBlockingQueue<Runnable> dispatchEvents = new ArrayBlockingQueue<Runnable>(256);
private static volatile Thread gtkDispatchThread;
@Property
/** Disables the GTK event loop, if you are already creating one in SWT/etc. */
public static boolean DISABLE_EVENT_LOOP = false;
static {
boolean hasSupport = false;
boolean hasSWT_ = false;
try {
if (Gtk.INSTANCE != null && Gobject.INSTANCE != null && GThread.INSTANCE != null) {
hasSupport = true;
try {
Class<?> swtClass = Class.forName("org.eclipse.swt.widgets.Display");
if (swtClass != null) {
hasSWT_ = true;
}
} catch (Throwable ignore) {
}
// prep for the event loop.
// since SWT uses one already, it's not necessary to have two.
if (!hasSWT_) {
Gtk instance = Gtk.INSTANCE;
instance.gtk_init(0, null);
GThread.INSTANCE.g_thread_init(null);
instance.gdk_threads_init();
}
}
} catch (Throwable ignored) {
}
isSupported = hasSupport;
hasSwt = hasSWT_;
}
public static
@ -62,9 +55,26 @@ class GtkSupport {
if (!started) {
started = true;
// startup the GTK GUI event loop. There can be multiple/nested loops.
// since SWT uses one already, it's not necessary to have two.
if (!hasSwt) {
gtkDispatchThread = new Thread() {
@Override
public
void run() {
while (started) {
try {
final Runnable take = dispatchEvents.take();
take.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
gtkDispatchThread.setName("GTK Event Loop");
gtkDispatchThread.start();
if (!DISABLE_EVENT_LOOP) {
// startup the GTK GUI event loop. There can be multiple/nested loops.
final CountDownLatch blockUntilStarted = new CountDownLatch(1);
Thread gtkUpdateThread = new Thread() {
@Override
@ -74,17 +84,21 @@ class GtkSupport {
// notify our main thread to continue
blockUntilStarted.countDown();
instance.gdk_threads_enter();
// prep for the event loop.
instance.gdk_threads_init();
instance.gtk_init(0, null);
GThread.INSTANCE.g_thread_init(null);
instance.gtk_main();
// MUST leave as well!
instance.gdk_threads_leave();
}
};
gtkUpdateThread.setName("GTK Event Loop");
gtkUpdateThread.setName("GTK Event Loop (Native)");
gtkUpdateThread.start();
try {
// we CANNOT continue until the GTK thread has started! (ignored if SWT is used)
// we CANNOT continue until the GTK thread has started!
blockUntilStarted.await();
} catch (InterruptedException e) {
e.printStackTrace();
@ -93,11 +107,25 @@ class GtkSupport {
}
}
/**
* Best practices for GTK, is to call EVERYTHING for it on a SINGLE THREAD. This accomplishes that.
*/
public static
void shutdownGui() {
if (isSupported && !hasSwt) {
Gtk.INSTANCE.gtk_main_quit();
started = false;
void dispatch(Runnable runnable) {
try {
dispatchEvents.put(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static
void shutdownGui() {
if (!DISABLE_EVENT_LOOP) {
Gtk.INSTANCE.gtk_main_quit();
}
started = false;
gtkDispatchThread.interrupt();
}
}