From b81995ab2bfc4de209e226ad13bd627fcaad7e14 Mon Sep 17 00:00:00 2001 From: nathan Date: Fri, 12 Feb 2016 11:51:35 +0100 Subject: [PATCH] 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) --- .../src/dorkbox/util/jna/linux/Gtk.java | 2 - .../dorkbox/util/jna/linux/GtkSupport.java | 94 ++++++++++++------- 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/Dorkbox-Util/src/dorkbox/util/jna/linux/Gtk.java b/Dorkbox-Util/src/dorkbox/util/jna/linux/Gtk.java index c4d733b..1b7ac40 100644 --- a/Dorkbox-Util/src/dorkbox/util/jna/linux/Gtk.java +++ b/Dorkbox-Util/src/dorkbox/util/jna/linux/Gtk.java @@ -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(); diff --git a/Dorkbox-Util/src/dorkbox/util/jna/linux/GtkSupport.java b/Dorkbox-Util/src/dorkbox/util/jna/linux/GtkSupport.java index c703395..0dc2e86 100644 --- a/Dorkbox-Util/src/dorkbox/util/jna/linux/GtkSupport.java +++ b/Dorkbox-Util/src/dorkbox/util/jna/linux/GtkSupport.java @@ -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 dispatchEvents = new ArrayBlockingQueue(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(); + } }