Added "render provider" system, so that SWT and JavaFX can better integrate into how GTK works

This commit is contained in:
Robinson 2021-05-02 11:57:33 +02:00
parent 1234565980
commit d3675ddbaf
12 changed files with 291 additions and 96 deletions

View File

@ -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 * 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. * 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); boolean gtk_init_check(int argc);
@ -291,12 +293,19 @@ interface Gtk {
void gtk_widget_destroy(Pointer widget); 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 * @since 2.2
*/ */
Pointer gtk_settings_get_for_screen(Pointer screen); 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 * 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.) * appearance. (GTK+ actually keeps a cache of previously created styles, so a new style may not be created.)

View File

@ -163,6 +163,10 @@ class Gtk2 implements Gtk {
public native public native
Pointer gtk_settings_get_for_screen(final Pointer screen); Pointer gtk_settings_get_for_screen(final Pointer screen);
@Override
public native
Pointer gtk_settings_get_default();
@Override @Override
public native public native
GtkStyle gtk_rc_get_style(final Pointer widget); GtkStyle gtk_rc_get_style(final Pointer widget);

View File

@ -262,6 +262,10 @@ class Gtk3 implements Gtk {
public native public native
Pointer gtk_settings_get_for_screen(final Pointer screen); Pointer gtk_settings_get_for_screen(final Pointer screen);
@Override
public native
Pointer gtk_settings_get_default();
@Override @Override
public native public native
GtkStyle gtk_rc_get_style(final Pointer widget); GtkStyle gtk_rc_get_style(final Pointer widget);

View File

@ -15,9 +15,8 @@
*/ */
package dorkbox.jna.linux; package dorkbox.jna.linux;
import dorkbox.javaFx.JavaFx; import dorkbox.jna.rendering.RenderProvider;
import dorkbox.os.OS; 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 * 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) { int gtkVersion = RenderProvider.getGtkVersion();
if (Swt.isGtk3) { if (gtkVersion > 0) {
return 3; return gtkVersion;
} else {
return 2;
}
}
if (JavaFx.isLoaded) {
if (JavaFx.isGtk3) {
return 3;
} else {
return 2;
}
} }
/* /*

View File

@ -27,8 +27,7 @@ import org.slf4j.LoggerFactory;
import com.sun.jna.Pointer; import com.sun.jna.Pointer;
import dorkbox.javaFx.JavaFx; import dorkbox.jna.rendering.RenderProvider;
import dorkbox.swt.Swt;
public public
@ -137,59 +136,7 @@ class GtkEventDispatch {
} }
}); });
if (JavaFx.isLoaded) { if (!RenderProvider.isEventThread()) {
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 {
try { try {
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) { if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
if (DEBUG) { if (DEBUG) {
@ -271,26 +218,10 @@ class GtkEventDispatch {
*/ */
public static public static
void dispatch(final Runnable runnable) { void dispatch(final Runnable runnable) {
if (GtkLoader.alreadyRunningGTK) { if (GtkLoader.alreadyRunningGTK && RenderProvider.dispatch(runnable)) {
if (JavaFx.isLoaded) {
// JavaFX only
if (JavaFx.isEventThread()) {
// Run directly on the JavaFX event thread
runnable.run();
}
else {
JavaFx.dispatch(runnable);
}
return; 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;
}
}
// not javafx // not javafx
// gtk/swt are **mostly** the same in how events are dispatched, so we can use "raw" gtk methods for SWT // gtk/swt are **mostly** the same in how events are dispatched, so we can use "raw" gtk methods for SWT
if (isDispatch.get()) { if (isDispatch.get()) {

View File

@ -21,8 +21,8 @@ import com.sun.jna.Function;
import com.sun.jna.NativeLibrary; import com.sun.jna.NativeLibrary;
import dorkbox.jna.JnaHelper; import dorkbox.jna.JnaHelper;
import dorkbox.jna.rendering.RenderProvider;
import dorkbox.os.OS; import dorkbox.os.OS;
import dorkbox.swt.Swt;
/** /**
* Bindings for GTK+ 2. Bindings that are exclusively for GTK+ 3 are in that respective class * 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) { if (shouldLoadGtk && _isLoaded) {
isLoaded = true; 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 // depending on how the system is initialized, SWT may, or may not, have the gtk_main loop running.
// do not want to run our own GTK event loop. // 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 |= Swt.isLoaded; _alreadyRunningGTK |= RenderProvider.alreadyRunning();
alreadyRunningGTK = _alreadyRunningGTK; alreadyRunningGTK = _alreadyRunningGTK;
isGtk2 = _isGtk2; isGtk2 = _isGtk2;

View File

@ -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;
}
}

View File

@ -14,4 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package dorkbox.util.swing; package dorkbox.jna.rendering;
public
enum ProviderType {
SWT, JAVAFX, NONE
}

View File

@ -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();
}
}

View File

@ -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.
* <p>
* 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.
* <p>
* 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);
}

View File

@ -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 {}

View File

@ -1,6 +1,7 @@
module dorkbox.utilities { module dorkbox.utilities {
exports dorkbox.exit; exports dorkbox.exit;
exports dorkbox.jna; exports dorkbox.jna;
exports dorkbox.jna.rendering;
exports dorkbox.jna.linux; exports dorkbox.jna.linux;
exports dorkbox.jna.linux.structs; exports dorkbox.jna.linux.structs;
exports dorkbox.jna.macos; exports dorkbox.jna.macos;
@ -24,7 +25,6 @@ module dorkbox.utilities {
requires dorkbox.executor; requires dorkbox.executor;
requires dorkbox.updates; requires dorkbox.updates;
requires static dorkbox.swtjavafx;
requires static com.sun.jna; requires static com.sun.jna;
requires static com.sun.jna.platform; requires static com.sun.jna.platform;