Now support GTK3 versions less than 3.10 (3.4 was tested, as released on

Ubuntu 12.04). Make sure not to touch Gtk interface while loading Gtk
This commit is contained in:
nathan 2017-07-17 01:41:53 +02:00
parent bb15ca12a8
commit a5d7a7293e
6 changed files with 115 additions and 73 deletions

View File

@ -25,7 +25,7 @@ import dorkbox.util.jna.linux.structs.GtkStyle;
* <p>
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
*/
@SuppressWarnings({"Duplicates", "SameParameterValue", "DeprecatedIsStillUsed", "WeakerAccess"})
@SuppressWarnings({"Duplicates", "SameParameterValue", "DeprecatedIsStillUsed", "WeakerAccess", "UnusedReturnValue"})
public
interface Gtk {
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep gtk
@ -35,6 +35,12 @@ interface Gtk {
// For funsies to look at, SyncThing did a LOT of work on compatibility in python (unfortunate for us, but interesting).
// https://github.com/syncthing/syncthing-gtk/blob/b7a3bc00e3bb6d62365ae62b5395370f3dcc7f55/syncthing_gtk/statusicon.py
int FALSE = 0;
int TRUE = 1;
int MAJOR = GtkLoader.MAJOR;
int MINOR = GtkLoader.MINOR;
int MICRO = GtkLoader.MICRO;
// make specific versions of GTK2 vs GTK3 APIs
// ALSO, GTK must be loaded via .init()
@ -49,12 +55,7 @@ interface Gtk {
Function gtk_status_icon_position_menu = GtkLoader.gtk_status_icon_position_menu;
int FALSE = 0;
int TRUE = 1;
int MAJOR = GtkLoader.MAJOR;
int MINOR = GtkLoader.MINOR;
int MICRO = GtkLoader.MICRO;
/**
* Adds a function to be called whenever there are no higher priority events pending. If the function returns FALSE it is automatically
@ -78,11 +79,6 @@ interface Gtk {
*/
void gtk_main();
/**
* aks for the current nesting level of the main loop. Useful to determine (at startup) if GTK is already running
*/
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
* what you're doing!

View File

@ -41,10 +41,6 @@ class Gtk2 implements Gtk {
public native
void gtk_main();
@Override
public native
int gtk_main_level();
@Override
public native
void gtk_main_quit();

View File

@ -27,24 +27,19 @@ import dorkbox.util.jna.linux.structs.GtkStyle;
*/
public
class Gtk3 implements Gtk {
static Function gdk_window_get_scale_factor = null;
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 | grep gtk
// objdump -T /usr/local/lib/libgtk-3.so.0 | grep gtk
/**
* This function is typically used when implementing a GtkContainer subclass. Obtains the preferred size of a widget. The
* container uses this information to arrange its child widgets and decide what size allocations to give them with
* gtk_widget_size_allocate().
*
* You can also call this function from an application, with some caveats. Most notably, getting a size request requires the
* widget to be associated with a screen, because font information may be needed. Multihead-aware applications should keep this in mind.
*
* Also remember that the size request is not necessarily the size a widget will actually be allocated.
*/
@Override
public
void gtk_widget_size_request(final Pointer widget, final Pointer requisition) {
this.gtk_widget_get_preferred_size(widget, requisition, null);
}
public native
int gtk_get_major_version();
public native
int gtk_get_minor_version();
public native
int gtk_get_micro_version();
/**
* Retrieves the minimum and natural size of a widget, taking into account the widgets preference for height-for-width management.
@ -64,15 +59,6 @@ class Gtk3 implements Gtk {
public native
void gtk_widget_get_preferred_size(final Pointer widget, final Pointer minimum_size, final Pointer natural_size);
public native
int gtk_get_major_version();
public native
int gtk_get_minor_version();
public native
int gtk_get_micro_version();
/**
* Returns the internal scale factor that maps from window coordinates to the actual device pixels. On traditional systems this is 1,
* but on very high density outputs this can be a higher value (often 2).
@ -87,11 +73,34 @@ class Gtk3 implements Gtk {
*
* @since 3.10
*/
public native
int gdk_window_get_scale_factor(Pointer window);
public
int gdk_window_get_scale_factor(Pointer window) {
if (gdk_window_get_scale_factor != null) {
return gdk_window_get_scale_factor.invokeInt(new Object[]{window});
} else {
return 0;
}
}
///////////////////////////
//// GTK2 methods
///////////////////////////
/**
* This function is typically used when implementing a GtkContainer subclass. Obtains the preferred size of a widget. The
* container uses this information to arrange its child widgets and decide what size allocations to give them with
* gtk_widget_size_allocate().
*
* You can also call this function from an application, with some caveats. Most notably, getting a size request requires the
* widget to be associated with a screen, because font information may be needed. Multihead-aware applications should keep this in mind.
*
* Also remember that the size request is not necessarily the size a widget will actually be allocated.
*/
@Override
public
void gtk_widget_size_request(final Pointer widget, final Pointer requisition) {
this.gtk_widget_get_preferred_size(widget, requisition, null);
}
@Override
public native
@ -105,10 +114,6 @@ class Gtk3 implements Gtk {
public native
void gtk_main();
@Override
public native
int gtk_main_level();
@Override
public native
void gtk_main_quit();

View File

@ -0,0 +1,36 @@
/*
* Copyright 2017 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.util.jna.linux;
/**
* bindings for GTK+ 3 version info.
* <p>
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
*/
public
class Gtk3VersionInfo {
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 | grep gtk
// objdump -T /usr/local/lib/libgtk-3.so.0 | grep gtk
public native
int gtk_get_major_version();
public native
int gtk_get_minor_version();
public native
int gtk_get_micro_version();
}

View File

@ -81,6 +81,7 @@ class GtkEventDispatch {
void run() {
Glib.GLogFunc orig = null;
if (DEBUG) {
// don't suppress GTK warnings in debug mode
LoggerFactory.getLogger(GtkEventDispatch.class).debug("Running GTK Native Event Loop");
} else {
// NOTE: This can output warnings, so we suppress them

View File

@ -15,8 +15,6 @@
*/
package dorkbox.util.jna.linux;
import static dorkbox.util.jna.linux.Gtk.Gtk2;
import org.slf4j.LoggerFactory;
import com.sun.jna.Function;
@ -84,23 +82,23 @@ class GtkLoader {
String gtk2LibName = "gtk-x11-2.0";
String gtk3LibName = "libgtk-3.so.0";
if (!_isLoaded && shouldUseGtk2) {
try {
NativeLibrary library = JnaHelper.register(gtk2LibName, Gtk2.class);
gtk_status_icon_position_menu = Function.getFunction(gtk2LibName, "gtk_status_icon_position_menu");
_isGtk2 = true;
Gtk gtk = new Gtk2();
// 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 started GTK -- so we DO NOT NEED TO.
_alreadyRunningGTK = gtk.gtk_main_level() != 0;
_isLoaded = true;
_isGtk2 = true;
major = library.getGlobalVariableAddress("gtk_major_version").getInt(0);
minor = library.getGlobalVariableAddress("gtk_minor_version").getInt(0);
micro = library.getGlobalVariableAddress("gtk_micro_version").getInt(0);
gtk_status_icon_position_menu = library.getFunction( "gtk_status_icon_position_menu");
Function gtk_main_level = library.getFunction("gtk_main_level");
// 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 started GTK -- so we DO NOT NEED TO.
_alreadyRunningGTK = gtk_main_level.invokeInt(null) != 0;
_isLoaded = true;
if (GtkEventDispatch.DEBUG) {
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
}
@ -116,26 +114,35 @@ class GtkLoader {
// start with version 3
if (!_isLoaded) {
try {
// ALSO map Gtk2.java to GTK3 library.
JnaHelper.register(gtk3LibName, Gtk3.class);
gtk_status_icon_position_menu = Function.getFunction(gtk3LibName, "gtk_status_icon_position_menu");
Gtk3 gtk = new Gtk3();
// have to get the version information FIRST, because there are some really old GTK3 libraries out there.
NativeLibrary library = JnaHelper.register(gtk3LibName, Gtk3VersionInfo.class);
Gtk3VersionInfo version = new Gtk3VersionInfo();
major = version.gtk_get_major_version();
minor = version.gtk_get_minor_version();
micro = version.gtk_get_micro_version();
library.dispose();
library = JnaHelper.register(gtk3LibName, Gtk3.class);
if (major >= 3 && minor >= 10) {
// Abusing static fields this way is not proper, but it gets the job done nicely.
Gtk3.gdk_window_get_scale_factor = library.getFunction("gdk_window_get_scale_factor");
}
gtk_status_icon_position_menu = library.getFunction( "gtk_status_icon_position_menu");
Function gtk_main_level = library.getFunction("gtk_main_level");
// 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 started GTK -- so we DO NOT NEED TO.
_alreadyRunningGTK = gtk.gtk_main_level() != 0;
_alreadyRunningGTK = gtk_main_level.invokeInt(null) != 0;
_isLoaded = true;
major = gtk.gtk_get_major_version();
minor = gtk.gtk_get_minor_version();
micro = gtk.gtk_get_micro_version();
if (GtkEventDispatch.DEBUG) {
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk3LibName);
}
} catch (Throwable e) {
if (GtkEventDispatch.DEBUG) {
LoggerFactory.getLogger(GtkLoader.class).error("Error loading library", e);
LoggerFactory.getLogger(GtkLoader.class).error("Error loading library.", e);
}
}
}
@ -144,18 +151,19 @@ class GtkLoader {
if (!_isLoaded) {
try {
NativeLibrary library = JnaHelper.register(gtk2LibName, Gtk2.class);
gtk_status_icon_position_menu = Function.getFunction(gtk2LibName, "gtk_status_icon_position_menu");
_isGtk2 = true;
// 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 started GTK -- so we DO NOT NEED TO.
_alreadyRunningGTK = Gtk2.gtk_main_level() != 0;
_isLoaded = true;
major = library.getGlobalVariableAddress("gtk_major_version").getInt(0);
minor = library.getGlobalVariableAddress("gtk_minor_version").getInt(0);
micro = library.getGlobalVariableAddress("gtk_micro_version").getInt(0);
gtk_status_icon_position_menu = Function.getFunction(gtk2LibName, "gtk_status_icon_position_menu");
Function gtk_main_level = library.getFunction("gtk_main_level");
// 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 started GTK -- so we DO NOT NEED TO.
_alreadyRunningGTK = gtk_main_level.invokeInt(null) != 0;
_isLoaded = true;
if (GtkEventDispatch.DEBUG) {
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
}