diff --git a/src/dorkbox/jna/linux/Gtk.java b/src/dorkbox/jna/linux/Gtk.java index 98f1550..68f1a2b 100644 --- a/src/dorkbox/jna/linux/Gtk.java +++ b/src/dorkbox/jna/linux/Gtk.java @@ -60,6 +60,8 @@ interface Gtk { /** * This would NORMALLY have a 2nd argument that is a String[] -- however JNA direct-mapping DOES NOT support this. We are lucky * enough that we just pass 'null' as the second argument, therefore, we don't have to define that parameter here. + * + * This does the same thing as gtk_init(), but without a hard quit */ boolean gtk_init_check(int argc); @@ -291,12 +293,19 @@ interface Gtk { void gtk_widget_destroy(Pointer widget); /** - * Gets the GtkSettings object for screen , creating it if necessary. + * Gets the GtkSettings object for the screen, creating it if necessary. * * @since 2.2 */ Pointer gtk_settings_get_for_screen(Pointer screen); + /** + * Gets the GtkSettings object for the default GDK screen, creating it if necessary. + * + * @since 2.2 + */ + Pointer gtk_settings_get_default(); + /** * Finds all matching RC styles for a given widget, composites them together, and then creates a GtkStyle representing the composite * appearance. (GTK+ actually keeps a cache of previously created styles, so a new style may not be created.) diff --git a/src/dorkbox/jna/linux/Gtk2.java b/src/dorkbox/jna/linux/Gtk2.java index c8212a6..499cd3f 100644 --- a/src/dorkbox/jna/linux/Gtk2.java +++ b/src/dorkbox/jna/linux/Gtk2.java @@ -163,6 +163,10 @@ class Gtk2 implements Gtk { public native Pointer gtk_settings_get_for_screen(final Pointer screen); + @Override + public native + Pointer gtk_settings_get_default(); + @Override public native GtkStyle gtk_rc_get_style(final Pointer widget); diff --git a/src/dorkbox/jna/linux/Gtk3.java b/src/dorkbox/jna/linux/Gtk3.java index 1814bb6..6008805 100644 --- a/src/dorkbox/jna/linux/Gtk3.java +++ b/src/dorkbox/jna/linux/Gtk3.java @@ -262,6 +262,10 @@ class Gtk3 implements Gtk { public native Pointer gtk_settings_get_for_screen(final Pointer screen); + @Override + public native + Pointer gtk_settings_get_default(); + @Override public native GtkStyle gtk_rc_get_style(final Pointer widget); diff --git a/src/dorkbox/jna/linux/GtkCheck.java b/src/dorkbox/jna/linux/GtkCheck.java index 94ac259..86b33cd 100644 --- a/src/dorkbox/jna/linux/GtkCheck.java +++ b/src/dorkbox/jna/linux/GtkCheck.java @@ -15,9 +15,8 @@ */ package dorkbox.jna.linux; -import dorkbox.javaFx.JavaFx; +import dorkbox.jna.rendering.RenderProvider; import dorkbox.os.OS; -import dorkbox.swt.Swt; /** * Accessor methods/logic for determining if GTK is already loaded by the Swing/JavaFX/SWT, or if GTK has been manually loaded via @@ -104,20 +103,9 @@ class GtkCheck { } } - if (Swt.isLoaded) { - if (Swt.isGtk3) { - return 3; - } else { - return 2; - } - } - - if (JavaFx.isLoaded) { - if (JavaFx.isGtk3) { - return 3; - } else { - return 2; - } + int gtkVersion = RenderProvider.getGtkVersion(); + if (gtkVersion > 0) { + return gtkVersion; } /* diff --git a/src/dorkbox/jna/linux/GtkEventDispatch.java b/src/dorkbox/jna/linux/GtkEventDispatch.java index bda133f..6849fc1 100644 --- a/src/dorkbox/jna/linux/GtkEventDispatch.java +++ b/src/dorkbox/jna/linux/GtkEventDispatch.java @@ -27,8 +27,7 @@ import org.slf4j.LoggerFactory; import com.sun.jna.Pointer; -import dorkbox.javaFx.JavaFx; -import dorkbox.swt.Swt; +import dorkbox.jna.rendering.RenderProvider; public @@ -137,59 +136,7 @@ class GtkEventDispatch { } }); - if (JavaFx.isLoaded) { - if (!JavaFx.isEventThread()) { - try { - if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) { - if (DEBUG) { - LoggerFactory.getLogger(GtkEventDispatch.class) - .error("Something is very wrong. The waitForEventsToComplete took longer than expected.", - new Exception("")); - } - } - - // we have to WAIT until all events are done processing, OTHERWISE we have initialization issues - while (true) { - Thread.sleep(100); - - synchronized (gtkCallbacks) { - if (gtkCallbacks.isEmpty()) { - break; - } - } - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - else if (Swt.isLoaded) { - if (!Swt.isEventThread()) { - // we have to WAIT until all events are done processing, OTHERWISE we have initialization issues - try { - if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) { - if (DEBUG) { - LoggerFactory.getLogger(GtkEventDispatch.class) - .error("Something is very wrong. The waitForEventsToComplete took longer than expected.", - new Exception("")); - } - } - - while (true) { - Thread.sleep(100); - - synchronized (gtkCallbacks) { - if (gtkCallbacks.isEmpty()) { - break; - } - } - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - else { + if (!RenderProvider.isEventThread()) { try { if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) { if (DEBUG) { @@ -271,24 +218,8 @@ class GtkEventDispatch { */ public static void dispatch(final Runnable runnable) { - if (GtkLoader.alreadyRunningGTK) { - if (JavaFx.isLoaded) { - // JavaFX only - if (JavaFx.isEventThread()) { - // Run directly on the JavaFX event thread - runnable.run(); - } - else { - JavaFx.dispatch(runnable); - } - return; - } - - if (Swt.isLoaded && Swt.isEventThread()) { - // Run directly on the SWT event thread. If it's not on the dispatch thread, we will use GTK to put it there - runnable.run(); - return; - } + if (GtkLoader.alreadyRunningGTK && RenderProvider.dispatch(runnable)) { + return; } // not javafx diff --git a/src/dorkbox/jna/linux/GtkLoader.java b/src/dorkbox/jna/linux/GtkLoader.java index 36c5ce1..222de3c 100644 --- a/src/dorkbox/jna/linux/GtkLoader.java +++ b/src/dorkbox/jna/linux/GtkLoader.java @@ -21,8 +21,8 @@ import com.sun.jna.Function; import com.sun.jna.NativeLibrary; import dorkbox.jna.JnaHelper; +import dorkbox.jna.rendering.RenderProvider; import dorkbox.os.OS; -import dorkbox.swt.Swt; /** * Bindings for GTK+ 2. Bindings that are exclusively for GTK+ 3 are in that respective class @@ -213,9 +213,9 @@ class GtkLoader { if (shouldLoadGtk && _isLoaded) { isLoaded = true; - // depending on how the system is initialized, SWT may, or may not, have the gtk_main loop running. It will EVENTUALLY run, so we - // do not want to run our own GTK event loop. - _alreadyRunningGTK |= Swt.isLoaded; + // depending on how the system is initialized, SWT may, or may not, have the gtk_main loop running. + // It will ALWAYS EVENTUALLY run, so we do not want to run our own GTK event loop. It is also incompatible with our event loop + _alreadyRunningGTK |= RenderProvider.alreadyRunning(); alreadyRunningGTK = _alreadyRunningGTK; isGtk2 = _isGtk2; diff --git a/src/dorkbox/jna/rendering/DefaultProvider.java b/src/dorkbox/jna/rendering/DefaultProvider.java new file mode 100644 index 0000000..a676fa6 --- /dev/null +++ b/src/dorkbox/jna/rendering/DefaultProvider.java @@ -0,0 +1,55 @@ +/* + * Copyright 2021 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dorkbox.jna.rendering; + +class DefaultProvider implements Renderer { + @Override + public + boolean isSupported() { + return true; + } + + @Override + public + ProviderType getType() { + return ProviderType.NONE; + } + + @Override + public + boolean alreadyRunning() { + return false; + } + + @Override + public + boolean isEventThread() { + return false; + } + + @Override + public + int getGtkVersion() { + return 0; + } + + @Override + public + boolean dispatch(final Runnable runnable) { + return false; + } +} diff --git a/src/dorkbox/util/swing/package-info.java b/src/dorkbox/jna/rendering/ProviderType.java similarity index 87% rename from src/dorkbox/util/swing/package-info.java rename to src/dorkbox/jna/rendering/ProviderType.java index 927fb52..43177d7 100644 --- a/src/dorkbox/util/swing/package-info.java +++ b/src/dorkbox/jna/rendering/ProviderType.java @@ -14,4 +14,9 @@ * limitations under the License. */ -package dorkbox.util.swing; +package dorkbox.jna.rendering; + +public +enum ProviderType { + SWT, JAVAFX, NONE +} diff --git a/src/dorkbox/jna/rendering/RenderProvider.java b/src/dorkbox/jna/rendering/RenderProvider.java new file mode 100644 index 0000000..a460987 --- /dev/null +++ b/src/dorkbox/jna/rendering/RenderProvider.java @@ -0,0 +1,120 @@ +/* + * Copyright 2021 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dorkbox.jna.rendering; + +/** + * A "RenderProvider", is either None (internal implementation), JavaFX (either from Oracle, or the OpenJavaFX), or SWT (from Eclipse). + */ +public +class RenderProvider { + private static Renderer provider = new DefaultProvider(); + + /** + * Assigns the specified provider. This is primarily used by the SystemTray and GTK applications. + * + * @param provider which provider is used. This will change from the default provider to SWT or JAVAFX + */ + public static void set(Renderer provider) { + RenderProvider.provider = provider; + } + + /** + * @return true if the render provider is supported (correct library versions, etc) + */ + public static + boolean isSupported() { + return provider.isSupported(); + } + + /** + * @return true if the GTK provider type is the default provider. + */ + public static + boolean isDefault() { + return provider.getType() == ProviderType.NONE; + } + + /** + * @return true if the GTK provider type is JavaFX. + */ + public static + boolean isJavaFX() { + return provider.getType() == ProviderType.JAVAFX; + } + + /** + * @return true if the GTK provider type is SWT + */ + public static + boolean isSwt() { + return provider.getType() == ProviderType.SWT; + } + + /** + * @return the GTK provider type. SWT or JAVAFX (or none, if it's the null provider) + */ + public static + ProviderType getType() { + return provider.getType(); + } + + /** + * Necessary to determine if the current execution thread is the event dispatch thread, or a different thread + * + * @return true if the current thread is the dispatch/event thread + */ + public static + boolean isEventThread() { + return provider.isEventThread(); + } + + /** + * Used to discover the in-use version of GTK by the system (where appropriate) during startup. + * + * If this provider is not 'loaded', then this method will not be called. + * + * @return the GTK version in use by the provider. A return 0 will skip this provider's GTK version info + */ + public static + int getGtkVersion() { + return provider.getGtkVersion(); + } + + /** + * If we are currently on the dispatch thread, then we want to execute this task immediately. Otherwise, this task should be executed + * on the dispatch thread + * + * @return true if this task was dispatched by this provider, false if the default provider should handle it + */ + public static + boolean dispatch(final Runnable runnable) { + return provider.dispatch(runnable); + } + + /** + * depending on how the system is initialized, SWT may, or may not, have the gtk_main loop running. It will EVENTUALLY run, so we + * do not want to run our own GTK event loop. + * + * JavaFX is not so strange in how GTK starts, so (at least for now), we only care about SWT being loaded + * + * @return if we are SWT, then we are considered "already running". JavaFx provides a method to detected if it's running at startup + */ + public static + boolean alreadyRunning() { + return provider.alreadyRunning(); + } +} diff --git a/src/dorkbox/jna/rendering/Renderer.java b/src/dorkbox/jna/rendering/Renderer.java new file mode 100644 index 0000000..2425c49 --- /dev/null +++ b/src/dorkbox/jna/rendering/Renderer.java @@ -0,0 +1,55 @@ +/* + * Copyright 2021 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dorkbox.jna.rendering; + +public +interface Renderer { + boolean isSupported(); + + /** + * @return the GTK provider type. SWT or JAVAFX + */ + ProviderType getType(); + + /** + * depending on how the system is initialized, SWT may, or may not, have the gtk_main loop running. It will EVENTUALLY run, so we + * do not want to run our own GTK event loop. + *

+ * JavaFX is not so strange in how GTK starts, so (at least for now), we only care about SWT being loaded + * + * @return if we are SWT, then we are considered "already running" + */ + boolean alreadyRunning(); + + /** + * Necessary to determine if the current execution thread is the event dispatch thread, or a different thread + * + * @return true if the current thread is the dispatch/event thread + */ + boolean isEventThread(); + + /** + * Used to discover the in-use version of GTK by the system (where appropriate) during startup. + *

+ * If this provider is not 'loaded', then this method will not be called. + * + * @return the GTK version in use by the provider. A value of 0 means "ignore this" + */ + int getGtkVersion(); + + boolean dispatch(final Runnable runnable); +} diff --git a/src9/dorkbox/jna/rendering/EmptyClass.java b/src9/dorkbox/jna/rendering/EmptyClass.java new file mode 100644 index 0000000..587d037 --- /dev/null +++ b/src9/dorkbox/jna/rendering/EmptyClass.java @@ -0,0 +1,24 @@ +/* + * Copyright 2021 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dorkbox.jna.rendering; + +/** + * Required for intellij to not complain regarding `module-info` for a multi-release jar. + * This file is completely ignored by the gradle build process + */ +public +class EmptyClass {} diff --git a/src9/module-info.java b/src9/module-info.java index 22af1de..96d69df 100644 --- a/src9/module-info.java +++ b/src9/module-info.java @@ -1,6 +1,7 @@ module dorkbox.utilities { exports dorkbox.exit; exports dorkbox.jna; + exports dorkbox.jna.rendering; exports dorkbox.jna.linux; exports dorkbox.jna.linux.structs; exports dorkbox.jna.macos; @@ -24,7 +25,6 @@ module dorkbox.utilities { requires dorkbox.executor; requires dorkbox.updates; - requires static dorkbox.swtjavafx; requires static com.sun.jna; requires static com.sun.jna.platform;