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:
parent
bb15ca12a8
commit
a5d7a7293e
|
@ -25,7 +25,7 @@ import dorkbox.util.jna.linux.structs.GtkStyle;
|
||||||
* <p>
|
* <p>
|
||||||
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
* 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
|
public
|
||||||
interface Gtk {
|
interface Gtk {
|
||||||
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep 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).
|
// 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
|
// 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
|
// make specific versions of GTK2 vs GTK3 APIs
|
||||||
// ALSO, GTK must be loaded via .init()
|
// 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;
|
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
|
* 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();
|
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
|
* 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!
|
* what you're doing!
|
||||||
|
|
|
@ -41,10 +41,6 @@ class Gtk2 implements Gtk {
|
||||||
public native
|
public native
|
||||||
void gtk_main();
|
void gtk_main();
|
||||||
|
|
||||||
@Override
|
|
||||||
public native
|
|
||||||
int gtk_main_level();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public native
|
public native
|
||||||
void gtk_main_quit();
|
void gtk_main_quit();
|
||||||
|
|
|
@ -27,24 +27,19 @@ import dorkbox.util.jna.linux.structs.GtkStyle;
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
class Gtk3 implements Gtk {
|
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/lib/x86_64-linux-gnu/libgtk-3.so.0 | grep gtk
|
||||||
// objdump -T /usr/local/lib/libgtk-3.so.0 | grep gtk
|
// objdump -T /usr/local/lib/libgtk-3.so.0 | grep gtk
|
||||||
|
|
||||||
/**
|
public native
|
||||||
* This function is typically used when implementing a GtkContainer subclass. Obtains the preferred size of a widget. The
|
int gtk_get_major_version();
|
||||||
* container uses this information to arrange its child widgets and decide what size allocations to give them with
|
|
||||||
* gtk_widget_size_allocate().
|
public native
|
||||||
*
|
int gtk_get_minor_version();
|
||||||
* 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.
|
public native
|
||||||
*
|
int gtk_get_micro_version();
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the minimum and natural size of a widget, taking into account the widget’s preference for height-for-width management.
|
* Retrieves the minimum and natural size of a widget, taking into account the widget’s preference for height-for-width management.
|
||||||
|
@ -64,15 +59,6 @@ class Gtk3 implements Gtk {
|
||||||
public native
|
public native
|
||||||
void gtk_widget_get_preferred_size(final Pointer widget, final Pointer minimum_size, final Pointer natural_size);
|
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,
|
* 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).
|
* 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
|
* @since 3.10
|
||||||
*/
|
*/
|
||||||
public native
|
public
|
||||||
int gdk_window_get_scale_factor(Pointer window);
|
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
|
@Override
|
||||||
public native
|
public native
|
||||||
|
@ -105,10 +114,6 @@ class Gtk3 implements Gtk {
|
||||||
public native
|
public native
|
||||||
void gtk_main();
|
void gtk_main();
|
||||||
|
|
||||||
@Override
|
|
||||||
public native
|
|
||||||
int gtk_main_level();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public native
|
public native
|
||||||
void gtk_main_quit();
|
void gtk_main_quit();
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -81,6 +81,7 @@ class GtkEventDispatch {
|
||||||
void run() {
|
void run() {
|
||||||
Glib.GLogFunc orig = null;
|
Glib.GLogFunc orig = null;
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
// don't suppress GTK warnings in debug mode
|
||||||
LoggerFactory.getLogger(GtkEventDispatch.class).debug("Running GTK Native Event Loop");
|
LoggerFactory.getLogger(GtkEventDispatch.class).debug("Running GTK Native Event Loop");
|
||||||
} else {
|
} else {
|
||||||
// NOTE: This can output warnings, so we suppress them
|
// NOTE: This can output warnings, so we suppress them
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package dorkbox.util.jna.linux;
|
package dorkbox.util.jna.linux;
|
||||||
|
|
||||||
import static dorkbox.util.jna.linux.Gtk.Gtk2;
|
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.sun.jna.Function;
|
import com.sun.jna.Function;
|
||||||
|
@ -84,23 +82,23 @@ class GtkLoader {
|
||||||
String gtk2LibName = "gtk-x11-2.0";
|
String gtk2LibName = "gtk-x11-2.0";
|
||||||
String gtk3LibName = "libgtk-3.so.0";
|
String gtk3LibName = "libgtk-3.so.0";
|
||||||
|
|
||||||
|
|
||||||
if (!_isLoaded && shouldUseGtk2) {
|
if (!_isLoaded && shouldUseGtk2) {
|
||||||
try {
|
try {
|
||||||
NativeLibrary library = JnaHelper.register(gtk2LibName, Gtk2.class);
|
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'
|
_isGtk2 = true;
|
||||||
// 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;
|
|
||||||
|
|
||||||
major = library.getGlobalVariableAddress("gtk_major_version").getInt(0);
|
major = library.getGlobalVariableAddress("gtk_major_version").getInt(0);
|
||||||
minor = library.getGlobalVariableAddress("gtk_minor_version").getInt(0);
|
minor = library.getGlobalVariableAddress("gtk_minor_version").getInt(0);
|
||||||
micro = library.getGlobalVariableAddress("gtk_micro_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) {
|
if (GtkEventDispatch.DEBUG) {
|
||||||
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
|
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
|
||||||
}
|
}
|
||||||
|
@ -116,26 +114,35 @@ class GtkLoader {
|
||||||
// start with version 3
|
// start with version 3
|
||||||
if (!_isLoaded) {
|
if (!_isLoaded) {
|
||||||
try {
|
try {
|
||||||
// ALSO map Gtk2.java to GTK3 library.
|
// have to get the version information FIRST, because there are some really old GTK3 libraries out there.
|
||||||
JnaHelper.register(gtk3LibName, Gtk3.class);
|
NativeLibrary library = JnaHelper.register(gtk3LibName, Gtk3VersionInfo.class);
|
||||||
gtk_status_icon_position_menu = Function.getFunction(gtk3LibName, "gtk_status_icon_position_menu");
|
|
||||||
Gtk3 gtk = new Gtk3();
|
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 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.
|
// 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;
|
_isLoaded = true;
|
||||||
|
|
||||||
major = gtk.gtk_get_major_version();
|
|
||||||
minor = gtk.gtk_get_minor_version();
|
|
||||||
micro = gtk.gtk_get_micro_version();
|
|
||||||
|
|
||||||
if (GtkEventDispatch.DEBUG) {
|
if (GtkEventDispatch.DEBUG) {
|
||||||
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk3LibName);
|
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk3LibName);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (GtkEventDispatch.DEBUG) {
|
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) {
|
if (!_isLoaded) {
|
||||||
try {
|
try {
|
||||||
NativeLibrary library = JnaHelper.register(gtk2LibName, Gtk2.class);
|
NativeLibrary library = JnaHelper.register(gtk2LibName, Gtk2.class);
|
||||||
gtk_status_icon_position_menu = Function.getFunction(gtk2LibName, "gtk_status_icon_position_menu");
|
|
||||||
_isGtk2 = true;
|
_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);
|
major = library.getGlobalVariableAddress("gtk_major_version").getInt(0);
|
||||||
minor = library.getGlobalVariableAddress("gtk_minor_version").getInt(0);
|
minor = library.getGlobalVariableAddress("gtk_minor_version").getInt(0);
|
||||||
micro = library.getGlobalVariableAddress("gtk_micro_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) {
|
if (GtkEventDispatch.DEBUG) {
|
||||||
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
|
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue