Moved JNA to Utility module for use by other applications.
This commit is contained in:
parent
8cbc753baa
commit
bf5142919d
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.OS;
|
||||||
|
import dorkbox.util.jna.JnaHelper;
|
||||||
|
import dorkbox.util.jna.linux.structs.AppIndicatorInstanceStruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bindings for libappindicator
|
||||||
|
*
|
||||||
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"Duplicates", "SameParameterValue", "DanglingJavadoc"})
|
||||||
|
public
|
||||||
|
class AppIndicator {
|
||||||
|
public static final boolean isVersion3;
|
||||||
|
public static final boolean isLoaded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loader for AppIndicator, because it is absolutely mindboggling how those whom maintain the standard, can't agree to what that
|
||||||
|
* standard library naming convention or features/API set is. We just try until we find one that works, and are able to map the
|
||||||
|
* symbols we need. There are bash commands that will tell us the linked library name, however - I'd rather not run bash commands
|
||||||
|
* to determine this.
|
||||||
|
*
|
||||||
|
* This is so hacky it makes me sick.
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
boolean _isVersion3 = false;
|
||||||
|
boolean _isLoaded = false;
|
||||||
|
|
||||||
|
boolean shouldLoadAppIndicator = !(OS.isWindows() || OS.isMacOsX());
|
||||||
|
if (!shouldLoadAppIndicator) {
|
||||||
|
_isLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// objdump -T /usr/lib/x86_64-linux-gnu/libappindicator.so.1 | grep foo
|
||||||
|
// objdump -T /usr/lib/x86_64-linux-gnu/libappindicator3.so.1 | grep foo
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
// ALSO WHAT VERSION OF GTK to use? appindiactor1 -> GTK2, appindicator3 -> GTK3.
|
||||||
|
// appindiactor1 is GKT2 only (can't use GTK3 bindings with it)
|
||||||
|
// appindicator3 doesn't support menu icons via GTK2!!
|
||||||
|
|
||||||
|
// if (!_isLoaded && SystemTray.FORCE_TRAY_TYPE == SystemTray.TrayType.GtkStatusIcon) {
|
||||||
|
// // if we force GTK type system tray, don't attempt to load AppIndicator libs
|
||||||
|
// if (GtkEventDispatch.DEBUG) {
|
||||||
|
// LoggerFactory.getLogger(AppIndicator.class).debug("Forced GtkStatusIcon tray type, not using AppIndicator");
|
||||||
|
// }
|
||||||
|
// _isLoaded = true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (!_isLoaded && GtkEventDispatch.FORCE_GTK2) {
|
||||||
|
// if specified, try loading appindicator1 first, maybe it's there?
|
||||||
|
// note: we can have GTK2 + appindicator3, but NOT ALWAYS.
|
||||||
|
try {
|
||||||
|
// deliberately without the "1" at the end.
|
||||||
|
final NativeLibrary library = JnaHelper.register("appindicator", AppIndicator.class);
|
||||||
|
if (library != null) {
|
||||||
|
_isLoaded = true;
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(AppIndicator.class).debug("Error loading GTK2 explicit appindicator. {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String nameToCheck1;
|
||||||
|
String nameToCheck2;
|
||||||
|
|
||||||
|
if (Gtk.isGtk2) {
|
||||||
|
nameToCheck1 = "appindicator"; // deliberately without the "1" at the end.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nameToCheck1 = "appindicator3";
|
||||||
|
}
|
||||||
|
|
||||||
|
// start with base version using whatever the OS specifies as the proper symbolic link
|
||||||
|
if (!_isLoaded) {
|
||||||
|
try {
|
||||||
|
final NativeLibrary library = JnaHelper.register(nameToCheck1, AppIndicator.class);
|
||||||
|
String s = library.getFile().getName();
|
||||||
|
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(AppIndicator.class).debug("Loading library (first attempt): '{}'", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.contains("appindicator3")) {
|
||||||
|
_isVersion3 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoaded = true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", nameToCheck1, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// maybe it's really GTK2 version? who knows...
|
||||||
|
if (!_isLoaded) {
|
||||||
|
try {
|
||||||
|
JnaHelper.register("appindicator", AppIndicator.class);
|
||||||
|
_isLoaded = true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", "appindicator", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are GTK2, change the order we check and load libraries
|
||||||
|
|
||||||
|
if (Gtk.isGtk2) {
|
||||||
|
nameToCheck1 = "appindicator-gtk";
|
||||||
|
nameToCheck2 = "appindicator-gtk3";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nameToCheck1 = "appindicator-gtk3";
|
||||||
|
nameToCheck2 = "appindicator-gtk";
|
||||||
|
}
|
||||||
|
|
||||||
|
// another type. who knows...
|
||||||
|
if (!_isLoaded) {
|
||||||
|
try {
|
||||||
|
JnaHelper.register(nameToCheck1, AppIndicator.class);
|
||||||
|
_isLoaded = true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", nameToCheck1, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is HORRID. such a PITA
|
||||||
|
if (!_isLoaded) {
|
||||||
|
try {
|
||||||
|
JnaHelper.register(nameToCheck2, AppIndicator.class);
|
||||||
|
_isLoaded = true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", nameToCheck2, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We fall back to GtkStatusIndicator or Swing if this cannot load
|
||||||
|
if (shouldLoadAppIndicator && _isLoaded) {
|
||||||
|
isLoaded = true;
|
||||||
|
isVersion3 = _isVersion3;
|
||||||
|
} else {
|
||||||
|
isLoaded = false;
|
||||||
|
isVersion3 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: AppIndicators DO NOT support tooltips, as per mark shuttleworth. Rather stupid IMHO.
|
||||||
|
// See: https://bugs.launchpad.net/indicator-application/+bug/527458/comments/12
|
||||||
|
|
||||||
|
public static final int CATEGORY_APPLICATION_STATUS = 0;
|
||||||
|
// public static final int CATEGORY_COMMUNICATIONS = 1;
|
||||||
|
// public static final int CATEGORY_SYSTEM_SERVICES = 2;
|
||||||
|
// public static final int CATEGORY_HARDWARE = 3;
|
||||||
|
// public static final int CATEGORY_OTHER = 4;
|
||||||
|
|
||||||
|
public static final int STATUS_PASSIVE = 0;
|
||||||
|
public static final int STATUS_ACTIVE = 1;
|
||||||
|
// public static final int STATUS_ATTENTION = 2;
|
||||||
|
|
||||||
|
|
||||||
|
public static native
|
||||||
|
AppIndicatorInstanceStruct app_indicator_new(String id, String icon_name, int category);
|
||||||
|
|
||||||
|
public static native void app_indicator_set_title(AppIndicatorInstanceStruct self, String title);
|
||||||
|
public static native void app_indicator_set_status(AppIndicatorInstanceStruct self, int status);
|
||||||
|
public static native void app_indicator_set_menu(AppIndicatorInstanceStruct self, Pointer menu);
|
||||||
|
public static native void app_indicator_set_icon(AppIndicatorInstanceStruct self, String icon_name);
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
interface FuncCallback extends Callback {
|
||||||
|
/**
|
||||||
|
* @return Gtk.FALSE if it will be automatically removed from the stack once it's handled
|
||||||
|
*/
|
||||||
|
int callback(Pointer data);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public
|
||||||
|
interface GCallback extends Callback {
|
||||||
|
/**
|
||||||
|
* @return Gtk.TRUE if we handled this event
|
||||||
|
*/
|
||||||
|
int callback(Pointer instance, Pointer data);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
import dorkbox.util.jna.linux.structs.GdkEventButton;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public
|
||||||
|
interface GEventCallback extends Callback {
|
||||||
|
void callback(Pointer instance, GdkEventButton event);
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.jna.JnaHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bindings for glib-2.0
|
||||||
|
*
|
||||||
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class Glib {
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
NativeLibrary library = JnaHelper.register("glib-2.0", Glib.class);
|
||||||
|
if (library == null) {
|
||||||
|
LoggerFactory.getLogger(Glib.class).error("Error loading Glib library, it failed to load.");
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LoggerFactory.getLogger(Glib.class).error("Error loading Glib library, it failed to load {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface GLogLevelFlags {
|
||||||
|
public static final int RECURSION = 1 << 0;
|
||||||
|
public static final int FATAL = 1 << 1;
|
||||||
|
/* GLib log levels */
|
||||||
|
public static final int ERROR = 1 << 2; /* always fatal */
|
||||||
|
public static final int CRITICAL = 1 << 3;
|
||||||
|
public static final int WARNING = 1 << 4;
|
||||||
|
public static final int MESSAGE = 1 << 5;
|
||||||
|
public static final int INFO = 1 << 6;
|
||||||
|
public static final int DEBUG = 1 << 7;
|
||||||
|
public static final int MASK = ~(RECURSION | FATAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface GLogFunc extends Callback {
|
||||||
|
void callback (String log_domain, int log_level, String message, Pointer data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Glib.GLogFunc nullLogFunc = new Glib.GLogFunc() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void callback(final String log_domain, final int log_level, final String message, final Pointer data) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static native int g_log_set_handler(String log_domain, int levels, GLogFunc handler, Pointer user_data);
|
||||||
|
public static native void g_log_default_handler (String log_domain, int log_level, String message, Pointer unused_data);
|
||||||
|
public static native GLogFunc g_log_set_default_handler(GLogFunc log_func, Pointer user_data);
|
||||||
|
public static native void g_log_remove_handler (String log_domain, int handler_id);
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.jna.JnaHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bindings for libgobject-2.0
|
||||||
|
*
|
||||||
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class Gobject {
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
NativeLibrary library = JnaHelper.register("gobject-2.0", Gobject.class);
|
||||||
|
if (library == null) {
|
||||||
|
LoggerFactory.getLogger(Gobject.class).error("Error loading GObject library, it failed to load.");
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LoggerFactory.getLogger(Gobject.class).error("Error loading GObject library, it failed to load {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// objdump -T /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 | grep block
|
||||||
|
|
||||||
|
public static native void g_object_unref(Pointer object);
|
||||||
|
|
||||||
|
public static native void g_object_force_floating(Pointer object);
|
||||||
|
public static native void g_object_ref_sink(Pointer object);
|
||||||
|
|
||||||
|
// note: the return type here MUST be long to avoid issues on freeBSD. NativeLong (previously used) worked on everything except BSD.
|
||||||
|
public static native long g_signal_connect_object(Pointer instance, String detailed_signal, Callback c_handler, Pointer object, int connect_flags);
|
||||||
|
|
||||||
|
public static native void g_signal_handler_block(Pointer instance, long handlerId);
|
||||||
|
public static native void g_signal_handler_unblock(Pointer instance, long handlerId);
|
||||||
|
|
||||||
|
public static native void g_object_get(Pointer instance, String property_name, Pointer value, Pointer terminator);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Types are here https://developer.gnome.org/gobject/stable/gobject-Type-Information.html
|
||||||
|
public static native void g_value_init(Pointer gvalue, double type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the current value in value (if any) and "unsets" the type, this releases all resources associated with this GValue.
|
||||||
|
* An unset value is the same as an uninitialized (zero-filled) GValue structure.
|
||||||
|
*/
|
||||||
|
public static native void g_value_unset(Pointer gvalue);
|
||||||
|
|
||||||
|
public static native String g_value_get_string(Pointer gvalue);
|
||||||
|
public static native int g_value_get_int(Pointer gvalue);
|
||||||
|
|
||||||
|
public static native Pointer g_type_class_ref(Pointer widgetType);
|
||||||
|
public static native void g_type_class_unref(Pointer widgetClass);
|
||||||
|
}
|
|
@ -0,0 +1,383 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import com.sun.jna.Function;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.jna.linux.structs.GtkStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bindings for GTK+ 2. Bindings that are exclusively for GTK+ 3 are in that respective class
|
||||||
|
* <p>
|
||||||
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"Duplicates", "SameParameterValue", "DeprecatedIsStillUsed", "WeakerAccess"})
|
||||||
|
public
|
||||||
|
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-3.so.0 | grep gtk
|
||||||
|
// objdump -T /usr/local/lib/libgtk-3.so.0 | grep 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
|
||||||
|
|
||||||
|
|
||||||
|
// make specific versions of GTK2 vs GTK3 APIs
|
||||||
|
// ALSO, GTK must be loaded via .init()
|
||||||
|
Gtk Gtk2 = GtkLoader.init() && GtkLoader.isGtk2 ? new Gtk2() : new Gtk3();
|
||||||
|
Gtk3 Gtk3 = GtkLoader.isGtk2 ? null : (Gtk3) Gtk2;
|
||||||
|
|
||||||
|
boolean isGtk2 = GtkLoader.isGtk2;
|
||||||
|
boolean isGtk3 = GtkLoader.isGtk3;
|
||||||
|
boolean isLoaded = GtkLoader.isLoaded;
|
||||||
|
|
||||||
|
boolean alreadyRunningGTK = GtkLoader.alreadyRunningGTK;
|
||||||
|
|
||||||
|
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
|
||||||
|
* removed from the list of event sources and will not be called again.
|
||||||
|
* <p>
|
||||||
|
* This variant of g_idle_add_full() calls function with the GDK lock held. It can be thought of a MT-safe version for GTK+ widgets
|
||||||
|
* for the following use case, where you have to worry about idle_callback() running in thread A and accessing self after it has
|
||||||
|
* been finalized in thread B.
|
||||||
|
*/
|
||||||
|
int gdk_threads_add_idle_full(int priority, FuncCallback function, Pointer data, Pointer notify);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
boolean gtk_init_check(int argc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the main loop until gtk_main_quit() is called. You can nest calls to gtk_main(). In that case gtk_main_quit() will make the
|
||||||
|
* innermost invocation of the main loop return.
|
||||||
|
*/
|
||||||
|
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!
|
||||||
|
*/
|
||||||
|
void gtk_main_quit();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GtkMenu
|
||||||
|
*/
|
||||||
|
Pointer gtk_menu_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets or replaces the menu item’s submenu, or removes it when a NULL submenu is passed.
|
||||||
|
*/
|
||||||
|
void gtk_menu_item_set_submenu(Pointer menuEntry, Pointer menu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GtkSeparatorMenuItem.
|
||||||
|
*/
|
||||||
|
Pointer gtk_separator_menu_item_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GtkImage displaying the file filename . If the file isn’t found or can’t be loaded, the resulting GtkImage will
|
||||||
|
* display a “broken image” icon. This function never returns NULL, it always returns a valid GtkImage widget.
|
||||||
|
* <p>
|
||||||
|
* If the file contains an animation, the image will contain an animation.
|
||||||
|
*/
|
||||||
|
Pointer gtk_image_new_from_file(String iconPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the active state of the menu item’s check box.
|
||||||
|
*/
|
||||||
|
void gtk_check_menu_item_set_active(Pointer check_menu_item, boolean isChecked);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GtkImageMenuItem containing a label. The label will be created using gtk_label_new_with_mnemonic(), so underscores
|
||||||
|
* in label indicate the mnemonic for the menu item.
|
||||||
|
* <p>
|
||||||
|
* uses '_' to define which key is the mnemonic
|
||||||
|
* <p>
|
||||||
|
* gtk_image_menu_item_new_with_mnemonic has been deprecated since version 3.10 and should not be used in newly-written code.
|
||||||
|
* NOTE: Use gtk_menu_item_new_with_mnemonic() instead.
|
||||||
|
*/
|
||||||
|
Pointer gtk_image_menu_item_new_with_mnemonic(String label);
|
||||||
|
|
||||||
|
Pointer gtk_check_menu_item_new_with_mnemonic(String label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the image of image_menu_item to the given widget. Note that it depends on the show-menu-images setting whether the image
|
||||||
|
* will be displayed or not.
|
||||||
|
* <p>
|
||||||
|
* gtk_image_menu_item_set_image has been deprecated since version 3.10 and should not be used in newly-written code.
|
||||||
|
*/
|
||||||
|
void gtk_image_menu_item_set_image(Pointer image_menu_item, Pointer image);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If TRUE, the menu item will ignore the “gtk-menu-images” setting and always show the image, if available.
|
||||||
|
* Use this property if the menuitem would be useless or hard to use without the image
|
||||||
|
* <p>
|
||||||
|
* gtk_image_menu_item_set_always_show_image has been deprecated since version 3.10 and should not be used in newly-written code.
|
||||||
|
*/
|
||||||
|
void gtk_image_menu_item_set_always_show_image(Pointer menu_item, boolean forceShow);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty status icon object.
|
||||||
|
* <p>
|
||||||
|
* gtk_status_icon_new has been deprecated since version 3.14 and should not be used in newly-written code.
|
||||||
|
* Use notifications
|
||||||
|
*/
|
||||||
|
Pointer gtk_status_icon_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the root window (parent all other windows are inside) for the default display and screen.
|
||||||
|
*
|
||||||
|
* @return the default root window
|
||||||
|
*/
|
||||||
|
Pointer gdk_get_default_root_window();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default screen for the default display. (See gdk_display_get_default()).
|
||||||
|
*
|
||||||
|
* @return a GdkScreen, or NULL if there is no default display.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
Pointer gdk_screen_get_default();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the resolution for font handling on the screen; see gdk_screen_set_resolution() for full details.
|
||||||
|
*
|
||||||
|
* IE:
|
||||||
|
*
|
||||||
|
* The resolution for font handling on the screen. This is a scale factor between points specified in a PangoFontDescription and
|
||||||
|
* cairo units. The default value is 96, meaning that a 10 point font will be 13 units high. (10 * 96. / 72. = 13.3).
|
||||||
|
*
|
||||||
|
* @return the current resolution, or -1 if no resolution has been set.
|
||||||
|
*
|
||||||
|
* @since Since: 2.10
|
||||||
|
*/
|
||||||
|
double gdk_screen_get_resolution(Pointer screen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes status_icon display the file filename . See gtk_status_icon_new_from_file() for details.
|
||||||
|
* <p>
|
||||||
|
* gtk_status_icon_set_from_file has been deprecated since version 3.14 and should not be used in newly-written code.
|
||||||
|
* Use notifications
|
||||||
|
*/
|
||||||
|
void gtk_status_icon_set_from_file(Pointer widget, String label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows or hides a status icon.
|
||||||
|
* <p>
|
||||||
|
* gtk_status_icon_set_visible has been deprecated since version 3.14 and should not be used in newly-written code.
|
||||||
|
* Use notifications
|
||||||
|
*/
|
||||||
|
void gtk_status_icon_set_visible(Pointer widget, boolean visible);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text as the contents of the tooltip.
|
||||||
|
* This function will take care of setting “has-tooltip” to TRUE and of the default handler for the “query-tooltip” signal.
|
||||||
|
*
|
||||||
|
* app indicators don't support this
|
||||||
|
*
|
||||||
|
* gtk_status_icon_set_tooltip_text has been deprecated since version 3.14 and should not be used in newly-written code.
|
||||||
|
* Use notifications
|
||||||
|
*/
|
||||||
|
void gtk_status_icon_set_tooltip_text(Pointer widget, String tooltipText);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the title of this tray icon. This should be a short, human-readable, localized string describing the tray icon. It may be used
|
||||||
|
* by tools like screen readers to render the tray icon.
|
||||||
|
* <p>
|
||||||
|
* gtk_status_icon_set_title has been deprecated since version 3.14 and should not be used in newly-written code.
|
||||||
|
* Use notifications
|
||||||
|
*/
|
||||||
|
void gtk_status_icon_set_title(Pointer widget, String titleText);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of this tray icon. This should be a string identifying this icon. It is may be used for sorting the icons in the
|
||||||
|
* tray and will not be shown to the user.
|
||||||
|
* <p>
|
||||||
|
* gtk_status_icon_set_name has been deprecated since version 3.14 and should not be used in newly-written code.
|
||||||
|
* Use notifications
|
||||||
|
*/
|
||||||
|
void gtk_status_icon_set_name(Pointer widget, String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a menu and makes it available for selection.
|
||||||
|
* <p>
|
||||||
|
* gtk_menu_popup has been deprecated since version 3.22 and should not be used in newly-written code.
|
||||||
|
* NOTE: Please use gtk_menu_popup_at_widget(), gtk_menu_popup_at_pointer(). or gtk_menu_popup_at_rect() instead
|
||||||
|
*/
|
||||||
|
void gtk_menu_popup(Pointer menu, Pointer widget, Pointer bla, Function func, Pointer data, int button, int time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text on the menu_item label
|
||||||
|
*/
|
||||||
|
void gtk_menu_item_set_label(Pointer menu_item, String label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new GtkMenuItem to the end of the menu shell's item list.
|
||||||
|
*/
|
||||||
|
void gtk_menu_shell_append(Pointer menu_shell, Pointer child);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the sensitivity of a widget. A widget is sensitive if the user can interact with it. Insensitive widgets are “grayed out”
|
||||||
|
* and the user can’t interact with them. Insensitive widgets are known as “inactive”, “disabled”, or “ghosted” in some other toolkits.
|
||||||
|
*/
|
||||||
|
void gtk_widget_set_sensitive(Pointer widget, boolean sensitive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively shows a widget, and any child widgets (if the widget is a container)
|
||||||
|
*/
|
||||||
|
void gtk_widget_show_all(Pointer widget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes widget from container . widget must be inside container . Note that container will own a reference to widget , and that
|
||||||
|
* this may be the last reference held; so removing a widget from its container can destroy that widget.
|
||||||
|
* <p>
|
||||||
|
* If you want to use widget again, you need to add a reference to it before removing it from a container, using g_object_ref().
|
||||||
|
* If you don’t want to use widget again it’s usually more efficient to simply destroy it directly using gtk_widget_destroy()
|
||||||
|
* since this will remove it from the container and help break any circular reference count cycles.
|
||||||
|
*/
|
||||||
|
void gtk_container_remove(Pointer parentWidget, Pointer widget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a widget.
|
||||||
|
* When a widget is destroyed all references it holds on other objects will be released:
|
||||||
|
* - if the widget is inside a container, it will be removed from its parent
|
||||||
|
* - if the widget is a container, all its children will be destroyed, recursively
|
||||||
|
* - if the widget is a top level, it will be removed from the list of top level widgets that GTK+ maintains internally
|
||||||
|
* <p>
|
||||||
|
* It's expected that all references held on the widget will also be released; you should connect to the “destroy” signal if you
|
||||||
|
* hold a reference to widget and you wish to remove it when this function is called. It is not necessary to do so if you are
|
||||||
|
* implementing a GtkContainer, as you'll be able to use the GtkContainerClass.remove() virtual function for that.
|
||||||
|
* <p>
|
||||||
|
* It's important to notice that gtk_widget_destroy() will only cause the widget to be finalized if no additional references,
|
||||||
|
* acquired using g_object_ref(), are held on it. In case additional references are in place, the widget will be in an "inert" state
|
||||||
|
* after calling this function; widget will still point to valid memory, allowing you to release the references you hold, but you
|
||||||
|
* may not query the widget's own state.
|
||||||
|
* <p>
|
||||||
|
* NOTE You should typically call this function on top level widgets, and rarely on child widgets.
|
||||||
|
*/
|
||||||
|
void gtk_widget_destroy(Pointer widget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the GtkSettings object for screen , creating it if necessary.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
Pointer gtk_settings_get_for_screen(Pointer screen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.)
|
||||||
|
*/
|
||||||
|
GtkStyle gtk_rc_get_style(Pointer widget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds widget to container . Typically used for simple containers such as GtkWindow, GtkFrame, or GtkButton; for more complicated
|
||||||
|
* layout containers such as GtkBox or GtkTable, this function will pick default packing parameters that may not be correct. So
|
||||||
|
* consider functions such as gtk_box_pack_start() and gtk_table_attach() as an alternative to gtk_container_add() in those cases.
|
||||||
|
* A widget may be added to only one container at a time; you can't place the same widget inside two different containers.
|
||||||
|
*/
|
||||||
|
void gtk_container_add(Pointer offscreen, Pointer widget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get's the child from a GTK Bin object
|
||||||
|
*/
|
||||||
|
Pointer gtk_bin_get_child(Pointer bin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PangoLayout used to display the label. The layout is useful to e.g. convert text positions to pixel positions, in
|
||||||
|
* combination with gtk_label_get_layout_offsets(). The returned layout is owned by the label so need not be freed by the caller.
|
||||||
|
*
|
||||||
|
* The label is free to recreate its layout at any time, so it should be considered read-only.
|
||||||
|
*/
|
||||||
|
Pointer gtk_label_get_layout(Pointer label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the logical and ink extents of layout in device units. This function just calls pango_layout_get_extents() followed
|
||||||
|
* by two pango_extents_to_pixels() calls, rounding ink_rect and logical_rect such that the rounded rectangles fully contain the
|
||||||
|
* unrounded one (that is, passes them as first argument to pango_extents_to_pixels()).
|
||||||
|
*
|
||||||
|
* @param layout a PangoLayout
|
||||||
|
* @param ink_rect rectangle used to store the extents of the layout as drawn or NULL to indicate that the result is not needed.
|
||||||
|
* @param logical_rect rectangle used to store the logical extents of the layout or NULL to indicate that the result is not needed.
|
||||||
|
*/
|
||||||
|
void pango_layout_get_pixel_extents(Pointer layout, Pointer ink_rect, Pointer logical_rect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the GDK (windowing system) resources associated with a widget. For example, widget->window will be created when a widget
|
||||||
|
* is realized. Normally realization happens implicitly; if you show a widget and all its parent containers, then the widget will
|
||||||
|
* be realized and mapped automatically.
|
||||||
|
*
|
||||||
|
* Realizing a widget requires all the widget’s parent widgets to be realized; calling gtk_widget_realize() realizes the widget’s
|
||||||
|
* parents in addition to widget itself. If a widget is not yet inside a toplevel window when you realize it, bad things will happen.
|
||||||
|
*
|
||||||
|
* This function is primarily used in widget implementations, and isn’t very useful otherwise. Many times when you think you might
|
||||||
|
* need it, a better approach is to connect to a signal that will be called after the widget is realized automatically, such as
|
||||||
|
* “draw”. Or simply g_signal_connect() to the “realize” signal.
|
||||||
|
*/
|
||||||
|
void gtk_widget_realize(Pointer widget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a toplevel container widget that is used to retrieve snapshots of widgets without showing them on the screen.
|
||||||
|
*
|
||||||
|
* @since 2.20
|
||||||
|
*/
|
||||||
|
Pointer gtk_offscreen_window_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void gtk_widget_size_request(final Pointer widget, final Pointer requisition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GtkImageMenuItem containing the image and text from a stock item. Some stock ids have preprocessor macros
|
||||||
|
* like GTK_STOCK_OK and GTK_STOCK_APPLY.
|
||||||
|
*
|
||||||
|
* @param stock_id the name of the stock item.
|
||||||
|
* @param accel_group the GtkAccelGroup to add the menu items accelerator to, or NULL.
|
||||||
|
*
|
||||||
|
* @return a new GtkImageMenuItem.
|
||||||
|
*/
|
||||||
|
Pointer gtk_image_menu_item_new_from_stock(String stock_id, Pointer accel_group);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.sun.jna.Function;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.jna.linux.structs.GtkStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bindings for GTK+ 2. Bindings that are exclusively for GTK+ 3 are in that respective class
|
||||||
|
* <p>
|
||||||
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class Gtk2 implements Gtk {
|
||||||
|
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep gtk
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int gdk_threads_add_idle_full(final int priority, final FuncCallback function, final Pointer data, final Pointer notify);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean gtk_init_check(final int argc);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_main();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int gtk_main_level();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_main_quit();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_menu_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_item_set_submenu(final Pointer menuEntry, final Pointer menu);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_separator_menu_item_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_image_new_from_file(final String iconPath);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_check_menu_item_set_active(final Pointer check_menu_item, final boolean isChecked);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_image_menu_item_new_with_mnemonic(final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_check_menu_item_new_with_mnemonic(final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_image_menu_item_set_image(final Pointer image_menu_item, final Pointer image);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_image_menu_item_set_always_show_image(final Pointer menu_item, final boolean forceShow);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_status_icon_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gdk_get_default_root_window();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gdk_screen_get_default();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
double gdk_screen_get_resolution(final Pointer screen);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_from_file(final Pointer widget, final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_visible(final Pointer widget, final boolean visible);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_tooltip_text(final Pointer widget, final String tooltipText);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_title(final Pointer widget, final String titleText);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_name(final Pointer widget, final String name);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_popup(final Pointer menu,
|
||||||
|
final Pointer widget,
|
||||||
|
final Pointer bla,
|
||||||
|
final Function func,
|
||||||
|
final Pointer data,
|
||||||
|
final int button,
|
||||||
|
final int time);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_item_set_label(final Pointer menu_item, final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_shell_append(final Pointer menu_shell, final Pointer child);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_set_sensitive(final Pointer widget, final boolean sensitive);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_show_all(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_container_remove(final Pointer parentWidget, final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_destroy(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_settings_get_for_screen(final Pointer screen);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
GtkStyle gtk_rc_get_style(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_container_add(final Pointer offscreen, final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_bin_get_child(final Pointer bin);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_label_get_layout(final Pointer label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void pango_layout_get_pixel_extents(final Pointer layout, final Pointer ink_rect, final Pointer logical_rect);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_realize(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_offscreen_window_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_size_request(final Pointer widget, final Pointer requisition);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_image_menu_item_new_from_stock(final String stock_id, final Pointer accel_group);
|
||||||
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.sun.jna.Function;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.jna.linux.structs.GtkStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bindings for GTK+ 3.
|
||||||
|
* <p>
|
||||||
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class Gtk3 implements 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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the minimum and natural size of a widget, taking into account the widget’s preference for height-for-width management.
|
||||||
|
* <p>
|
||||||
|
* This is used to retrieve a suitable size by container widgets which do not impose any restrictions on the child placement.
|
||||||
|
* It can be used to deduce toplevel window and menu sizes as well as child widgets in free-form containers such as GtkLayout.
|
||||||
|
* <p>
|
||||||
|
* Handle with care. Note that the natural height of a height-for-width widget will generally be a smaller size than the minimum
|
||||||
|
* height, since the required height for the natural width is generally smaller than the required height for the minimum width.
|
||||||
|
* <p>
|
||||||
|
* Use gtk_widget_get_preferred_height_and_baseline_for_width() if you want to support baseline alignment.
|
||||||
|
*
|
||||||
|
* @param widget a GtkWidget instance
|
||||||
|
* @param minimum_size location for storing the minimum size, or NULL.
|
||||||
|
* @param natural_size location for storing the natural size, or NULL.
|
||||||
|
*/
|
||||||
|
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).
|
||||||
|
* <p>
|
||||||
|
* A higher value means that drawing is automatically scaled up to a higher resolution, so any code doing drawing will automatically
|
||||||
|
* look nicer. However, if you are supplying pixel-based data the scale value can be used to determine whether to use a pixel
|
||||||
|
* resource with higher resolution data.
|
||||||
|
* <p>
|
||||||
|
* The scale of a window may change during runtime, if this happens a configure event will be sent to the toplevel window.
|
||||||
|
*
|
||||||
|
* @return the scale factor
|
||||||
|
*
|
||||||
|
* @since 3.10
|
||||||
|
*/
|
||||||
|
public native
|
||||||
|
int gdk_window_get_scale_factor(Pointer window);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int gdk_threads_add_idle_full(final int priority, final FuncCallback function, final Pointer data, final Pointer notify);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
boolean gtk_init_check(final int argc);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_main();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
int gtk_main_level();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_main_quit();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_menu_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_item_set_submenu(final Pointer menuEntry, final Pointer menu);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_separator_menu_item_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_image_new_from_file(final String iconPath);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_check_menu_item_set_active(final Pointer check_menu_item, final boolean isChecked);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_image_menu_item_new_with_mnemonic(final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_check_menu_item_new_with_mnemonic(final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_image_menu_item_set_image(final Pointer image_menu_item, final Pointer image);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_image_menu_item_set_always_show_image(final Pointer menu_item, final boolean forceShow);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_status_icon_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gdk_get_default_root_window();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gdk_screen_get_default();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
double gdk_screen_get_resolution(final Pointer screen);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_from_file(final Pointer widget, final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_visible(final Pointer widget, final boolean visible);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_tooltip_text(final Pointer widget, final String tooltipText);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_title(final Pointer widget, final String titleText);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_status_icon_set_name(final Pointer widget, final String name);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_popup(final Pointer menu,
|
||||||
|
final Pointer widget,
|
||||||
|
final Pointer bla,
|
||||||
|
final Function func,
|
||||||
|
final Pointer data,
|
||||||
|
final int button,
|
||||||
|
final int time);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_item_set_label(final Pointer menu_item, final String label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_menu_shell_append(final Pointer menu_shell, final Pointer child);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_set_sensitive(final Pointer widget, final boolean sensitive);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_show_all(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_container_remove(final Pointer parentWidget, final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_destroy(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_settings_get_for_screen(final Pointer screen);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
GtkStyle gtk_rc_get_style(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_container_add(final Pointer offscreen, final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_bin_get_child(final Pointer bin);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_label_get_layout(final Pointer label);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void pango_layout_get_pixel_extents(final Pointer layout, final Pointer ink_rect, final Pointer logical_rect);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
void gtk_widget_realize(final Pointer widget);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_offscreen_window_new();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native
|
||||||
|
Pointer gtk_image_menu_item_new_from_stock(final String stock_id, final Pointer accel_group);
|
||||||
|
}
|
|
@ -0,0 +1,362 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import static dorkbox.util.jna.linux.Gtk.Gtk2;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.util.Framework;
|
||||||
|
import dorkbox.util.JavaFX;
|
||||||
|
import dorkbox.util.Swt;
|
||||||
|
|
||||||
|
public
|
||||||
|
class GtkEventDispatch {
|
||||||
|
static boolean FORCE_GTK2 = false;
|
||||||
|
static boolean DEBUG = false;
|
||||||
|
|
||||||
|
private static final boolean isSwtLoaded = Framework.isSwtLoaded;
|
||||||
|
private static final boolean isJavaFxLoaded = Framework.isJavaFxLoaded;
|
||||||
|
|
||||||
|
// have to save these in a field to prevent GC on the objects (since they go out-of-scope from java)
|
||||||
|
private static final LinkedList<Object> gtkCallbacks = new LinkedList<Object>();
|
||||||
|
|
||||||
|
// This is required because the EDT needs to have it's own value for this boolean, that is a different value than the main thread
|
||||||
|
private static ThreadLocal<Boolean> isDispatch = new ThreadLocal<Boolean>() {
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
Boolean initialValue() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static volatile boolean started = false;
|
||||||
|
|
||||||
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
|
private static Thread gtkUpdateThread = null;
|
||||||
|
|
||||||
|
// when debugging the EDT, we need a longer timeout.
|
||||||
|
private static final boolean debugEDT = true;
|
||||||
|
|
||||||
|
// timeout is in seconds
|
||||||
|
private static final int TIMEOUT = debugEDT ? 10000000 : 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static
|
||||||
|
void startGui(final boolean FORCE_GTK2, final boolean DEBUG) {
|
||||||
|
// only permit one startup per JVM instance
|
||||||
|
if (!started) {
|
||||||
|
started = true;
|
||||||
|
|
||||||
|
GtkEventDispatch.FORCE_GTK2 = FORCE_GTK2;
|
||||||
|
GtkEventDispatch.DEBUG = DEBUG;
|
||||||
|
|
||||||
|
// startup the GTK GUI event loop. There can be multiple/nested loops.
|
||||||
|
|
||||||
|
|
||||||
|
if (!GtkLoader.alreadyRunningGTK) {
|
||||||
|
// If JavaFX/SWT is used, this is UNNECESSARY (we can detect if the GTK main_loop is running)
|
||||||
|
|
||||||
|
gtkUpdateThread = new Thread() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
Glib.GLogFunc orig = null;
|
||||||
|
if (DEBUG) {
|
||||||
|
LoggerFactory.getLogger(GtkEventDispatch.class).debug("Running GTK Native Event Loop");
|
||||||
|
} else {
|
||||||
|
// NOTE: This can output warnings, so we suppress them
|
||||||
|
orig = Glib.g_log_set_default_handler(Glib.nullLogFunc, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// prep for the event loop.
|
||||||
|
// GThread.g_thread_init(null); would be needed for g_idle_add()
|
||||||
|
|
||||||
|
if (!Gtk2.gtk_init_check(0)) {
|
||||||
|
throw new RuntimeException("Error starting GTK");
|
||||||
|
}
|
||||||
|
|
||||||
|
// gdk_threads_enter(); would be needed for g_idle_add()
|
||||||
|
|
||||||
|
if (orig != null) {
|
||||||
|
Glib.g_log_set_default_handler(orig, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// blocks unit quit
|
||||||
|
Gtk2.gtk_main();
|
||||||
|
|
||||||
|
// clean up threads
|
||||||
|
// gdk_threads_leave(); would be needed for g_idle_add()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gtkUpdateThread.setDaemon(false); // explicitly NOT daemon so that this will hold the JVM open as necessary
|
||||||
|
gtkUpdateThread.setName("GTK Native Event Loop");
|
||||||
|
gtkUpdateThread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the all posted events to GTK to finish loading
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
public static
|
||||||
|
void waitForEventsToComplete() {
|
||||||
|
final CountDownLatch blockUntilStarted = new CountDownLatch(1);
|
||||||
|
|
||||||
|
dispatch(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
blockUntilStarted.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isJavaFxLoaded) {
|
||||||
|
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 (isSwtLoaded) {
|
||||||
|
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 {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Best practices for GTK, is to call EVERYTHING for it on the GTK THREAD. This accomplishes that.
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
void dispatch(final Runnable runnable) {
|
||||||
|
if (GtkLoader.alreadyRunningGTK) {
|
||||||
|
if (isJavaFxLoaded) {
|
||||||
|
// JavaFX only
|
||||||
|
if (JavaFX.isEventThread()) {
|
||||||
|
// Run directly on the JavaFX event thread
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JavaFX.dispatch(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSwtLoaded) {
|
||||||
|
if (Swt.isEventThread()) {
|
||||||
|
// Run directly on the SWT event thread. If it's not on the dispatch thread, we can use raw GTK to put it there
|
||||||
|
runnable.run();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not javafx
|
||||||
|
// gtk/swt are **mostly** the same in how events are dispatched, so we can use "raw" gtk methods for SWT
|
||||||
|
if (isDispatch.get()) {
|
||||||
|
// Run directly on the dispatch thread
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final FuncCallback callback = new FuncCallback() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
int callback(final Pointer data) {
|
||||||
|
synchronized (gtkCallbacks) {
|
||||||
|
gtkCallbacks.removeFirst(); // now that we've 'handled' it, we can remove it from our callback list
|
||||||
|
}
|
||||||
|
|
||||||
|
isDispatch.set(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
runnable.run();
|
||||||
|
} finally {
|
||||||
|
isDispatch.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Gtk2.FALSE; // don't want to call this again
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
synchronized (gtkCallbacks) {
|
||||||
|
gtkCallbacks.offer(callback); // prevent GC from collecting this object before it can be called
|
||||||
|
}
|
||||||
|
|
||||||
|
// the correct way to do it. Add with a slightly higher value
|
||||||
|
Gtk2.gdk_threads_add_idle_full(100, callback, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
void shutdownGui() {
|
||||||
|
dispatchAndWait(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
// If JavaFX/SWT is used, this is UNNECESSARY (and will break SWT/JavaFX shutdown)
|
||||||
|
if (!GtkLoader.alreadyRunningGTK) {
|
||||||
|
Gtk2.gtk_main_quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
void dispatchAndWait(final Runnable runnable) {
|
||||||
|
if (isDispatch.get()) {
|
||||||
|
// Run directly on the dispatch thread (should not "redispatch" this again)
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
dispatch(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
try {
|
||||||
|
runnable.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LoggerFactory.getLogger(GtkEventDispatch.class).error("Error during GTK run loop: ", e);
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// this is slightly different than how swing does it. We have a timeout here so that we can make sure that updates on the GUI
|
||||||
|
// thread occur in REASONABLE time-frames, and alert the user if not.
|
||||||
|
try {
|
||||||
|
if (!countDownLatch.await(TIMEOUT, TimeUnit.SECONDS)) {
|
||||||
|
if (DEBUG) {
|
||||||
|
LoggerFactory.getLogger(GtkEventDispatch.class).error(
|
||||||
|
"Something is very wrong. The Event Dispatch Queue took longer than " + TIMEOUT + " seconds " +
|
||||||
|
"to complete.", new Exception(""));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new RuntimeException("Something is very wrong. The Event Dispatch Queue took longer than " + TIMEOUT +
|
||||||
|
" seconds " + "to complete.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LoggerFactory.getLogger(GtkEventDispatch.class).error("Error waiting for dispatch to complete.", new Exception(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* required to properly setup the dispatch flag when using native menus
|
||||||
|
*
|
||||||
|
* @param callback will never be null.
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
void proxyClick(final Object source, final ActionListener callback) {
|
||||||
|
isDispatch.set(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (source != null) {
|
||||||
|
callback.actionPerformed(new ActionEvent(source, ActionEvent.ACTION_PERFORMED, ""));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// checkbox entries will not pass the menuEntry in, because they redispatch the click event so that the checkbox state is
|
||||||
|
// toggled
|
||||||
|
callback.actionPerformed(null);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
isDispatch.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import static dorkbox.util.jna.linux.Gtk.Gtk2;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.sun.jna.Function;
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
|
||||||
|
import dorkbox.util.Framework;
|
||||||
|
import dorkbox.util.OS;
|
||||||
|
import dorkbox.util.jna.JnaHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bindings for GTK+ 2. Bindings that are exclusively for GTK+ 3 are in that respective class
|
||||||
|
* <p>
|
||||||
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"Duplicates", "SameParameterValue", "DeprecatedIsStillUsed", "WeakerAccess"})
|
||||||
|
public
|
||||||
|
class GtkLoader {
|
||||||
|
// 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-3.so.0 | grep gtk
|
||||||
|
// objdump -T /usr/local/lib/libgtk-3.so.0 | grep 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
|
||||||
|
|
||||||
|
// NOTE: AppIndicator uses this info to figure out WHAT VERSION OF appindicator to use: GTK2 -> appindicator1, GTK3 -> appindicator3
|
||||||
|
static boolean isGtk2;
|
||||||
|
static boolean isGtk3;
|
||||||
|
static boolean isLoaded;
|
||||||
|
|
||||||
|
|
||||||
|
static boolean alreadyRunningGTK;
|
||||||
|
|
||||||
|
static Function gtk_status_icon_position_menu = null;
|
||||||
|
|
||||||
|
static int MAJOR;
|
||||||
|
static int MINOR;
|
||||||
|
static int MICRO;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can have GTK v3 or v2.
|
||||||
|
*
|
||||||
|
* Observations:
|
||||||
|
* JavaFX uses GTK2, and we can't load GTK3 if GTK2 symbols are loaded
|
||||||
|
* SWT uses GTK2 or GTK3. We do not work with the GTK3 version of SWT.
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
boolean shouldUseGtk2 = GtkEventDispatch.FORCE_GTK2;
|
||||||
|
boolean _isGtk2 = false;
|
||||||
|
boolean _isLoaded = false;
|
||||||
|
boolean _alreadyRunningGTK = false;
|
||||||
|
int major = 0;
|
||||||
|
int minor = 0;
|
||||||
|
int micro = 0;
|
||||||
|
|
||||||
|
boolean shouldLoadGtk = !(OS.isWindows() || OS.isMacOsX());
|
||||||
|
if (!shouldLoadGtk) {
|
||||||
|
_isLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can force the system to use the swing indicator, which WORKS, but doesn't support transparency in the icon. However, there
|
||||||
|
// are certain GTK functions we might want to use (even if we are Swing or AWT), so we load GTK anyways...
|
||||||
|
|
||||||
|
// in some cases, we ALWAYS want to try GTK2 first
|
||||||
|
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;
|
||||||
|
|
||||||
|
major = library.getGlobalVariableAddress("gtk_major_version").getInt(0);
|
||||||
|
minor = library.getGlobalVariableAddress("gtk_minor_version").getInt(0);
|
||||||
|
micro = library.getGlobalVariableAddress("gtk_micro_version").getInt(0);
|
||||||
|
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(GtkLoader.class).error("Error loading library", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now for the defaults...
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now version 2
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(GtkLoader.class).debug("GTK: {}", gtk2LibName);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (GtkEventDispatch.DEBUG) {
|
||||||
|
LoggerFactory.getLogger(GtkLoader.class).error("Error loading library", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 |= Framework.isSwtLoaded;
|
||||||
|
|
||||||
|
alreadyRunningGTK = _alreadyRunningGTK;
|
||||||
|
isGtk2 = _isGtk2;
|
||||||
|
isGtk3 = !_isGtk2;
|
||||||
|
|
||||||
|
MAJOR = major;
|
||||||
|
MINOR = minor;
|
||||||
|
MICRO = micro;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isLoaded = false;
|
||||||
|
|
||||||
|
alreadyRunningGTK = false;
|
||||||
|
isGtk2 = false;
|
||||||
|
isGtk3 = false;
|
||||||
|
|
||||||
|
MAJOR = 0;
|
||||||
|
MINOR = 0;
|
||||||
|
MICRO = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldLoadGtk) {
|
||||||
|
if (!_isLoaded) {
|
||||||
|
throw new RuntimeException("We apologize for this, but we are unable to determine the GTK library is in use, " +
|
||||||
|
"or even if it is in use... Please create an issue for this and include your OS type and configuration.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
boolean init() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package dorkbox.util.jna.linux;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unused", "PointlessBitwiseExpression"})
|
||||||
|
public
|
||||||
|
class GtkState {
|
||||||
|
public static final int NORMAL = 0x0; // normal state.
|
||||||
|
public static final int ACTIVE = 0x1; // pressed-in or activated; e.g. buttons while the mouse button is held down.
|
||||||
|
public static final int PRELIGHT = 0x2; // color when the mouse is over an activatable widget.
|
||||||
|
public static final int SELECTED = 0x3; // color when something is selected, e.g. when selecting some text to cut/copy.
|
||||||
|
public static final int INSENSITIVE = 0x4; // color when the mouse is over an activatable widget.
|
||||||
|
|
||||||
|
public static final int FLAG_NORMAL = 0;
|
||||||
|
public static final int FLAG_ACTIVE = 1 << 0;
|
||||||
|
public static final int FLAG_PRELIGHT = 1 << 1;
|
||||||
|
public static final int FLAG_SELECTED = 1 << 2;
|
||||||
|
public static final int FLAG_INSENSITIVE = 1 << 3;
|
||||||
|
public static final int FLAG_INCONSISTENT = 1 << 4;
|
||||||
|
public static final int FLAG_FOCUSED = 1 << 5;
|
||||||
|
public static final int FLAG_BACKDROP = 1 << 6;
|
||||||
|
}
|
|
@ -0,0 +1,524 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static dorkbox.util.jna.linux.Gtk.Gtk2;
|
||||||
|
import static dorkbox.util.jna.linux.Gtk.Gtk3;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
|
|
||||||
|
import dorkbox.util.FileUtil;
|
||||||
|
import dorkbox.util.Framework;
|
||||||
|
import dorkbox.util.MathUtil;
|
||||||
|
import dorkbox.util.OS;
|
||||||
|
import dorkbox.util.OSUtil;
|
||||||
|
import dorkbox.util.Swt;
|
||||||
|
import dorkbox.util.jna.linux.structs.GtkRequisition;
|
||||||
|
import dorkbox.util.jna.linux.structs.GtkStyle;
|
||||||
|
import dorkbox.util.jna.linux.structs.PangoRectangle;
|
||||||
|
import dorkbox.util.process.ShellProcessBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to contain all of the various methods needed to get information set by a GTK theme.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"deprecation", "WeakerAccess"})
|
||||||
|
public
|
||||||
|
class GtkTheme {
|
||||||
|
public static
|
||||||
|
Rectangle getPixelTextHeight(String text) {
|
||||||
|
// the following method requires an offscreen widget to get the size of text (for the checkmark size) via pango
|
||||||
|
// don't forget to destroy everything!
|
||||||
|
Pointer menu = null;
|
||||||
|
Pointer item = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
menu = Gtk2.gtk_menu_new();
|
||||||
|
item = Gtk2.gtk_image_menu_item_new_with_mnemonic(text);
|
||||||
|
|
||||||
|
Gtk2.gtk_container_add(menu, item);
|
||||||
|
|
||||||
|
Gtk2.gtk_widget_realize(menu);
|
||||||
|
Gtk2.gtk_widget_realize(item);
|
||||||
|
Gtk2.gtk_widget_show_all(menu);
|
||||||
|
|
||||||
|
// get the text widget (GtkAccelLabel/GtkLabel) from inside the GtkMenuItem
|
||||||
|
Pointer textLabel = Gtk2.gtk_bin_get_child(item);
|
||||||
|
Pointer pangoLayout = Gtk2.gtk_label_get_layout(textLabel);
|
||||||
|
|
||||||
|
// ink pixel size is how much exact space it takes on the screen
|
||||||
|
PangoRectangle ink = new PangoRectangle();
|
||||||
|
|
||||||
|
Gtk2.pango_layout_get_pixel_extents(pangoLayout, ink.getPointer(), null);
|
||||||
|
ink.read();
|
||||||
|
|
||||||
|
return new Rectangle(ink.width, ink.height);
|
||||||
|
} finally {
|
||||||
|
Gtk2.gtk_widget_destroy(item);
|
||||||
|
Gtk2.gtk_widget_destroy(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the size of the GTK menu entry's IMAGE, as best as we can tell, for determining how large of icons to use for the menu entry
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
int getMenuEntryImageSize() {
|
||||||
|
final AtomicReference<Integer> imageHeight = new AtomicReference<Integer>();
|
||||||
|
|
||||||
|
GtkEventDispatch.dispatchAndWait(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
Pointer offscreen = Gtk2.gtk_offscreen_window_new();
|
||||||
|
|
||||||
|
// get the default icon size for the "paste" icon.
|
||||||
|
Pointer item = Gtk2.gtk_image_menu_item_new_from_stock("gtk-paste", null);
|
||||||
|
|
||||||
|
Gtk2.gtk_container_add(offscreen, item);
|
||||||
|
|
||||||
|
PointerByReference r = new PointerByReference();
|
||||||
|
Gobject.g_object_get(item, "image", r.getPointer(), null);
|
||||||
|
|
||||||
|
Pointer imageWidget = r.getValue();
|
||||||
|
GtkRequisition gtkRequisition = new GtkRequisition();
|
||||||
|
Gtk2.gtk_widget_size_request(imageWidget, gtkRequisition.getPointer());
|
||||||
|
gtkRequisition.read();
|
||||||
|
|
||||||
|
imageHeight.set(gtkRequisition.height);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
int height = imageHeight.get();
|
||||||
|
if (height > 0) {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 16; // who knows?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the system tray indicator size.
|
||||||
|
* - AppIndicator: will properly scale the image if it's not the correct size
|
||||||
|
* - GtkStatusIndicator: ??
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
int getIndicatorSize() {
|
||||||
|
// Linux is similar enough, that it just uses this method
|
||||||
|
// https://wiki.archlinux.org/index.php/HiDPI
|
||||||
|
|
||||||
|
// 96 DPI is the default
|
||||||
|
final double defaultDPI = 96.0;
|
||||||
|
|
||||||
|
final AtomicReference<Double> screenScale = new AtomicReference<Double>();
|
||||||
|
final AtomicInteger screenDPI = new AtomicInteger();
|
||||||
|
screenScale.set(0D);
|
||||||
|
screenDPI.set(0);
|
||||||
|
|
||||||
|
if (Framework.isSwtLoaded) {
|
||||||
|
screenDPI.set(Swt.getDpi());
|
||||||
|
} else {
|
||||||
|
GtkEventDispatch.dispatchAndWait(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
// screen DPI
|
||||||
|
Pointer screen = Gtk2.gdk_screen_get_default(); // DOES NOT like SWT
|
||||||
|
if (screen != null) {
|
||||||
|
// this call makes NO SENSE, but reading the documentation shows it is the CORRECT call.
|
||||||
|
screenDPI.set((int) Gtk2.gdk_screen_get_resolution(screen));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Gtk2.isGtk3) {
|
||||||
|
Pointer window = Gtk2.gdk_get_default_root_window(); // DOES NOT LIKE SWT
|
||||||
|
if (window != null) {
|
||||||
|
double scale = Gtk3.gdk_window_get_scale_factor(window);
|
||||||
|
screenScale.set(scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
if (screenDPI.get() == 0) {
|
||||||
|
// GET THE DPI IN LINUX
|
||||||
|
// https://wiki.archlinux.org/index.php/Talk:GNOME
|
||||||
|
Object detectedValue = Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Xft/DPI");
|
||||||
|
if (detectedValue instanceof Integer) {
|
||||||
|
int dpi = ((Integer) detectedValue) / 1024;
|
||||||
|
if (dpi == -1) {
|
||||||
|
screenDPI.set((int) defaultDPI);
|
||||||
|
}
|
||||||
|
if (dpi < 50) {
|
||||||
|
// 50 dpi is the minimum value gnome allows
|
||||||
|
screenDPI.set(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check system ENV variables.
|
||||||
|
if (screenScale.get() == 0) {
|
||||||
|
String envVar = System.getenv("QT_AUTO_SCREEN_SCALE_FACTOR");
|
||||||
|
if (envVar != null) {
|
||||||
|
try {
|
||||||
|
screenScale.set(Double.parseDouble(envVar));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check system ENV variables.
|
||||||
|
if (screenScale.get() == 0) {
|
||||||
|
String envVar = System.getenv("QT_SCALE_FACTOR");
|
||||||
|
if (envVar != null) {
|
||||||
|
try {
|
||||||
|
screenScale.set(Double.parseDouble(envVar));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check system ENV variables.
|
||||||
|
if (screenScale.get() == 0) {
|
||||||
|
String envVar = System.getenv("GDK_SCALE");
|
||||||
|
if (envVar != null) {
|
||||||
|
try {
|
||||||
|
screenScale.set(Double.parseDouble(envVar));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check system ENV variables.
|
||||||
|
if (screenScale.get() == 0) {
|
||||||
|
String envVar = System.getenv("ELM_SCALE");
|
||||||
|
if (envVar != null) {
|
||||||
|
try {
|
||||||
|
screenScale.set(Double.parseDouble(envVar));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
OSUtil.DesktopEnv.Env env = OSUtil.DesktopEnv.get();
|
||||||
|
// sometimes the scaling-factor is set. If we have gsettings, great! otherwise try KDE
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8196);
|
||||||
|
PrintStream outputStream = new PrintStream(byteArrayOutputStream);
|
||||||
|
|
||||||
|
// gsettings get org.gnome.desktop.interface scaling-factor
|
||||||
|
final ShellProcessBuilder shellVersion = new ShellProcessBuilder(outputStream);
|
||||||
|
shellVersion.setExecutable("gsettings");
|
||||||
|
shellVersion.addArgument("get");
|
||||||
|
shellVersion.addArgument("org.gnome.desktop.interface");
|
||||||
|
shellVersion.addArgument("scaling-factor");
|
||||||
|
shellVersion.start();
|
||||||
|
|
||||||
|
String output = ShellProcessBuilder.getOutput(byteArrayOutputStream);
|
||||||
|
|
||||||
|
if (!output.isEmpty()) {
|
||||||
|
// DEFAULT icon size is 16. HiDpi changes this scale, so we should use it as well.
|
||||||
|
// should be: uint32 0 or something
|
||||||
|
if (output.contains("uint32")) {
|
||||||
|
String value = output.substring(output.indexOf("uint") + 7, output.length());
|
||||||
|
|
||||||
|
// 0 is disabled (no scaling)
|
||||||
|
// 1 is enabled (default scale)
|
||||||
|
// 2 is 2x scale
|
||||||
|
// 3 is 3x scale
|
||||||
|
// etc
|
||||||
|
|
||||||
|
double scalingFactor = Double.parseDouble(value);
|
||||||
|
if (scalingFactor >= 1) {
|
||||||
|
screenScale.set(scalingFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A setting of 2, 3, etc, which is all you can do with scaling-factor
|
||||||
|
// To enable HiDPI, use gsettings:
|
||||||
|
// gsettings set org.gnome.desktop.interface scaling-factor 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OSUtil.DesktopEnv.isKDE()) {
|
||||||
|
// check the custom KDE override file
|
||||||
|
try {
|
||||||
|
File customSettings = new File("/usr/bin/startkde-custom");
|
||||||
|
if (customSettings.canRead()) {
|
||||||
|
List<String> lines = FileUtil.readLines(customSettings);
|
||||||
|
for (String line : lines) {
|
||||||
|
String str = "export GDK_SCALE=";
|
||||||
|
int i = line.indexOf(str);
|
||||||
|
if (i > -1) {
|
||||||
|
String scale = line.substring(i + str.length());
|
||||||
|
double scalingFactor = Double.parseDouble(scale);
|
||||||
|
if (scalingFactor >= 1) {
|
||||||
|
screenScale.set(scalingFactor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.err.println("screen scale: " + screenScale.get());
|
||||||
|
// System.err.println("screen DPI: " + screenDPI.get());
|
||||||
|
|
||||||
|
if (OSUtil.DesktopEnv.isKDE()) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Looking in plasma-framework/src/declarativeimports/core/units.cpp:
|
||||||
|
// Scale the icon sizes up using the devicePixelRatio
|
||||||
|
// This function returns the next stepping icon size
|
||||||
|
// and multiplies the global settings with the dpi ratio.
|
||||||
|
const qreal ratio = devicePixelRatio();
|
||||||
|
|
||||||
|
if (ratio < 1.5) {
|
||||||
|
return size;
|
||||||
|
} else if (ratio < 2.0) {
|
||||||
|
return size * 1.5;
|
||||||
|
} else if (ratio < 2.5) {
|
||||||
|
return size * 2.0;
|
||||||
|
} else if (ratio < 3.0) {
|
||||||
|
return size * 2.5;
|
||||||
|
} else if (ratio < 3.5) {
|
||||||
|
return size * 3.0;
|
||||||
|
} else {
|
||||||
|
return size * ratio;
|
||||||
|
}
|
||||||
|
My ratio is 1.47674, that means I have no scaling at all when there is a 1.5 factor existing. Is it reasonable? Wouldn't it make more sense to use the factor the closest to the ratio rather than what is done here?
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
File mainFile = new File("/usr/share/plasma/plasmoids/org.kde.plasma.private.systemtray/contents/config/main.xml");
|
||||||
|
if (mainFile.canRead()) {
|
||||||
|
List<String> lines = FileUtil.readLines(mainFile);
|
||||||
|
boolean found = false;
|
||||||
|
int index;
|
||||||
|
for (final String line : lines) {
|
||||||
|
if (line.contains("<entry name=\"iconSize\" type=\"Int\">")) {
|
||||||
|
found = true;
|
||||||
|
// have to get the "default" line value
|
||||||
|
}
|
||||||
|
|
||||||
|
String str = "<default>";
|
||||||
|
if (found && (index = line.indexOf(str)) > -1) {
|
||||||
|
// this is our line. now get the value.
|
||||||
|
String substring = line.substring(index + str.length(), line.indexOf("</default>", index));
|
||||||
|
|
||||||
|
if (MathUtil.isInteger(substring)) {
|
||||||
|
// Default icon size for the systray icons, it's an enum which values mean,
|
||||||
|
// Small, SmallMedium, Medium, Large, Huge, Enormous respectively.
|
||||||
|
// On low DPI systems they correspond to :
|
||||||
|
// 16, 22, 32, 48, 64, 128 pixels.
|
||||||
|
// On high DPI systems those values would be scaled up, depending on the DPI.
|
||||||
|
int imageSize = 0;
|
||||||
|
int imageSizeEnum = Integer.parseInt(substring);
|
||||||
|
switch (imageSizeEnum) {
|
||||||
|
case 0:
|
||||||
|
imageSize = 16;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
imageSize = 22;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
imageSize = 32;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
imageSize = 48;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
imageSize = 64;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
imageSize = 128;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageSize > 0) {
|
||||||
|
double scaleRatio = screenDPI.get() / defaultDPI;
|
||||||
|
|
||||||
|
return (int) (scaleRatio * imageSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (OSUtil.Linux.isUbuntu() && env == OSUtil.DesktopEnv.Env.Unity || env == OSUtil.DesktopEnv.Env.Unity7) {
|
||||||
|
// if we measure on ubuntu unity using a screen shot (using swing, so....) , the max size was 24, HOWEVER this goes from
|
||||||
|
// the top->bottom of the indicator bar -- and since it was swing, it uses a different rendering method and it (honestly)
|
||||||
|
// looks weird, because there is no padding for the icon. The official AppIndicator size is hardcoded...
|
||||||
|
// http://bazaar.launchpad.net/~indicator-applet-developers/libindicator/trunk.16.10/view/head:/libindicator/indicator-image-helper.c
|
||||||
|
|
||||||
|
return 22;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// xfce is easy, because it's not a GTK setting for the size (xfce notification area maximum icon size)
|
||||||
|
if (env == OSUtil.DesktopEnv.Env.XFCE) {
|
||||||
|
String properties = OSUtil.DesktopEnv.queryXfce("xfce4-panel", null);
|
||||||
|
List<String> propertiesAsList = Arrays.asList(properties.split(OS.LINE_SEPARATOR));
|
||||||
|
for (String prop : propertiesAsList) {
|
||||||
|
if (prop.startsWith("/plugins/") && prop.endsWith("/size-max")) {
|
||||||
|
// this is the property we are looking for (we just don't know which panel it's on)
|
||||||
|
|
||||||
|
String size = OSUtil.DesktopEnv.queryXfce("xfce4-panel", prop);
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(size);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LoggerFactory.getLogger(GtkTheme.class)
|
||||||
|
.error("Unable to get XFCE notification panel size for channel '{}', property '{}'",
|
||||||
|
"xfce4-panel", prop, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default...
|
||||||
|
return 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// try to use GTK to get the tray icon size
|
||||||
|
final AtomicInteger traySize = new AtomicInteger();
|
||||||
|
|
||||||
|
|
||||||
|
if (Framework.isSwtLoaded) {
|
||||||
|
} else {
|
||||||
|
GtkEventDispatch.dispatchAndWait(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
Pointer screen = Gtk2.gdk_screen_get_default();
|
||||||
|
Pointer settings = null;
|
||||||
|
|
||||||
|
if (screen != null) {
|
||||||
|
settings = Gtk2.gtk_settings_get_for_screen(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings != null) {
|
||||||
|
PointerByReference pointer = new PointerByReference();
|
||||||
|
|
||||||
|
// https://wiki.archlinux.org/index.php/GTK%2B
|
||||||
|
// To use smaller icons, use a line like this:
|
||||||
|
// gtk-icon-sizes = "panel-menu=16,16:panel=16,16:gtk-menu=16,16:gtk-large-toolbar=16,16:gtk-small-toolbar=16,16:gtk-button=16,16"
|
||||||
|
|
||||||
|
// this gets icon sizes. On XFCE, ubuntu, it returns "panel-menu-bar=24,24"
|
||||||
|
// NOTE: gtk-icon-sizes is deprecated and ignored since GTK+ 3.10.
|
||||||
|
|
||||||
|
// A list of icon sizes. The list is separated by colons, and item has the form: size-name = width , height
|
||||||
|
Gobject.g_object_get(settings, "gtk-icon-sizes", pointer.getPointer(), null);
|
||||||
|
|
||||||
|
Pointer value = pointer.getValue();
|
||||||
|
if (value != null) {
|
||||||
|
String iconSizes = value.getString(0);
|
||||||
|
String[] strings = new String[] {"panel-menu-bar=", "panel=", "gtk-large-toolbar=", "gtk-small-toolbar="};
|
||||||
|
for (String var : strings) {
|
||||||
|
int i = iconSizes.indexOf(var);
|
||||||
|
if (i >= 0) {
|
||||||
|
String size = iconSizes.substring(i + var.length(), iconSizes.indexOf(",", i));
|
||||||
|
|
||||||
|
if (MathUtil.isInteger(size)) {
|
||||||
|
traySize.set(Integer.parseInt(size));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = traySize.get();
|
||||||
|
if (i != 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sane default
|
||||||
|
return 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the widget color of text for the current theme, or black. It is important that this is called AFTER GTK has been initialized.
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
Color getTextColor() {
|
||||||
|
final AtomicReference<Color> color = new AtomicReference<Color>(null);
|
||||||
|
GtkEventDispatch.dispatchAndWait(new Runnable() {
|
||||||
|
@SuppressWarnings("UnusedAssignment")
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
Color c = null;
|
||||||
|
|
||||||
|
// the following method requires an offscreen widget to get the style information from.
|
||||||
|
// don't forget to destroy everything!
|
||||||
|
Pointer menu = null;
|
||||||
|
Pointer item = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
menu = Gtk2.gtk_menu_new();
|
||||||
|
item = Gtk2.gtk_image_menu_item_new_with_mnemonic("a");
|
||||||
|
|
||||||
|
Gtk2.gtk_container_add(menu, item);
|
||||||
|
|
||||||
|
Gtk2.gtk_widget_realize(menu);
|
||||||
|
Gtk2.gtk_widget_realize(item);
|
||||||
|
Gtk2.gtk_widget_show_all(menu);
|
||||||
|
|
||||||
|
GtkStyle style = Gtk2.gtk_rc_get_style(item);
|
||||||
|
style.read();
|
||||||
|
|
||||||
|
// this is the same color chromium uses (fg)
|
||||||
|
// https://chromium.googlesource.com/chromium/src/+/b3ca230ddd7d1238ee96ed26ea23e369f10dd655/chrome/browser/ui/libgtk2ui/gtk2_ui.cc#873
|
||||||
|
c = style.fg[GtkState.NORMAL].getColor();
|
||||||
|
|
||||||
|
color.set(c);
|
||||||
|
} finally {
|
||||||
|
Gtk2.gtk_widget_destroy(item);
|
||||||
|
Gtk2.gtk_widget_destroy(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return color.get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public
|
||||||
|
class AppIndicatorInstanceStruct extends Structure {
|
||||||
|
public GObjectStruct parent;
|
||||||
|
public Pointer priv;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("parent", "priv");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public
|
||||||
|
class GObjectStruct extends Structure {
|
||||||
|
public
|
||||||
|
class ByValue extends GObjectStruct implements Structure.ByValue {}
|
||||||
|
|
||||||
|
|
||||||
|
public
|
||||||
|
class ByReference extends GObjectStruct implements Structure.ByReference {}
|
||||||
|
|
||||||
|
|
||||||
|
public GTypeInstanceStruct g_type_instance;
|
||||||
|
public int ref_count;
|
||||||
|
public Pointer qdata;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("g_type_instance", "ref_count", "qdata");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public
|
||||||
|
class GTypeInstanceStruct extends Structure {
|
||||||
|
public
|
||||||
|
class ByValue extends GTypeInstanceStruct implements Structure.ByValue {}
|
||||||
|
|
||||||
|
|
||||||
|
public
|
||||||
|
class ByReference extends GTypeInstanceStruct implements Structure.ByReference {}
|
||||||
|
|
||||||
|
|
||||||
|
public Pointer g_class;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("g_class");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* 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.structs;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://developer.gnome.org/gdk3/stable/gdk3-Colors.html
|
||||||
|
*
|
||||||
|
* GdkColor has been deprecated since version 3.14 and should not be used in newly-written code.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class GdkColor extends Structure {
|
||||||
|
|
||||||
|
/* The color type.
|
||||||
|
* A color consists of red, green and blue values in the
|
||||||
|
* range 0-65535 and a pixel value. The pixel value is highly
|
||||||
|
* dependent on the depth and colormap which this color will
|
||||||
|
* be used to draw into. Therefore, sharing colors between
|
||||||
|
* colormaps is a bad idea.
|
||||||
|
*/
|
||||||
|
public int pixel;
|
||||||
|
public short red;
|
||||||
|
public short green;
|
||||||
|
public short blue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert from positive int (value between 0 and 65535, these are 16 bits per pixel) to values from 0-255
|
||||||
|
*/
|
||||||
|
private static int convert(int inputColor) {
|
||||||
|
return (inputColor & 0x0000FFFF >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int red() {
|
||||||
|
return convert(red);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int green() {
|
||||||
|
return convert(green);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int blue() {
|
||||||
|
return convert(blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
Color getColor() {
|
||||||
|
read(); // have to read the struct members first!
|
||||||
|
return new Color(red(), green(), blue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
String toString() {
|
||||||
|
return "[r=" + red() + ",g=" + green() + ",b=" + blue() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("pixel", "red", "green", "blue");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public
|
||||||
|
class ByValue extends GdkColor implements Structure.ByValue {}
|
||||||
|
|
||||||
|
|
||||||
|
public static
|
||||||
|
class ByReference extends GdkColor implements Structure.ByReference {}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public
|
||||||
|
class GdkEventButton extends Structure {
|
||||||
|
public int type;
|
||||||
|
public Pointer window;
|
||||||
|
public int send_event;
|
||||||
|
public int time;
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public Pointer axes;
|
||||||
|
public int state;
|
||||||
|
public int button;
|
||||||
|
public Pointer device;
|
||||||
|
public double x_root;
|
||||||
|
public double y_root;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("type", "window", "send_event", "time", "x", "y", "axes", "state", "button", "device", "x_root", "y_root");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://developer.gimp.org/api/2.0/gtk/GtkWidget.html#GtkRequisition
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class GtkRequisition extends Structure {
|
||||||
|
|
||||||
|
public int width;
|
||||||
|
public int height;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("width", "height");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* 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.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import dorkbox.util.Keep;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public
|
||||||
|
class GtkStyle extends Structure {
|
||||||
|
/*
|
||||||
|
* There are several 'directives' to change the attributes of a widget.
|
||||||
|
* fg - Sets the foreground color of a widget.
|
||||||
|
* bg - Sets the background color of a widget.
|
||||||
|
* text - Sets the foreground color for widgets that have editable text.
|
||||||
|
* base - Sets the background color for widgets that have editable text.
|
||||||
|
* bg_pixmap - Sets the background of a widget to a tiled pixmap.
|
||||||
|
* font_name - Sets the font to be used with the given widget.
|
||||||
|
* xthickness - Sets the left and right border width. This is not what you might think; it sets the borders of children(?)
|
||||||
|
* ythickness - similar to above but for the top and bottom.
|
||||||
|
*
|
||||||
|
* There are several states a widget can be in, and you can set different colors, pixmaps and fonts for each state. These states are:
|
||||||
|
* NORMAL - The normal state of a widget. Ie the mouse is not over it, and it is not being pressed, etc.
|
||||||
|
* PRELIGHT - When the mouse is over top of the widget, colors defined using this state will be in effect.
|
||||||
|
* ACTIVE - When the widget is pressed or clicked it will be active, and the attributes assigned by this tag will be in effect.
|
||||||
|
* INSENSITIVE - This is the state when a widget is 'greyed out'. It is not active, and cannot be clicked on.
|
||||||
|
* SELECTED - When an object is selected, it takes these attributes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static
|
||||||
|
class ByReference extends GtkStyle implements Structure.ByReference {
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
class ByValue extends GtkStyle implements Structure.ByValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
// required, even though it's "private" in the corresponding C code. OTHERWISE the memory offsets are INCORRECT.
|
||||||
|
public GObjectStruct parent_instance;
|
||||||
|
|
||||||
|
/** fg: foreground for drawing GtkLabel */
|
||||||
|
public GdkColor fg[] = new GdkColor[5];
|
||||||
|
|
||||||
|
/** bg: the usual background color, gray by default */
|
||||||
|
public GdkColor bg[] = new GdkColor[5];
|
||||||
|
|
||||||
|
public GdkColor light[] = new GdkColor[5];
|
||||||
|
public GdkColor dark[] = new GdkColor[5];
|
||||||
|
public GdkColor mid[] = new GdkColor[5];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* text: text for entries and text widgets (although in GTK 1.2 sometimes fg gets used, this is more or less a bug and fixed in GTK 2.0).
|
||||||
|
*/
|
||||||
|
public GdkColor text[] = new GdkColor[5];
|
||||||
|
|
||||||
|
/** base: background when using text, colored white in the default theme. */
|
||||||
|
public GdkColor base[] = new GdkColor[5];
|
||||||
|
|
||||||
|
/** Halfway between text/base */
|
||||||
|
public GdkColor text_aa[] = new GdkColor[5];
|
||||||
|
|
||||||
|
public GdkColor black;
|
||||||
|
public GdkColor white;
|
||||||
|
public Pointer /*PangoFontDescription*/ font_desc;
|
||||||
|
public int xthickness;
|
||||||
|
public int ythickness;
|
||||||
|
public Pointer /*cairo_pattern_t*/ background[] = new Pointer[5];
|
||||||
|
|
||||||
|
public
|
||||||
|
void debug(final int gtkState) {
|
||||||
|
System.err.println("base " + base[gtkState].getColor());
|
||||||
|
System.err.println("text " + text[gtkState].getColor());
|
||||||
|
System.err.println("text_aa " + text_aa[gtkState].getColor());
|
||||||
|
System.err.println("bg " + bg[gtkState].getColor());
|
||||||
|
System.err.println("fg " + fg[gtkState].getColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("parent_instance",
|
||||||
|
"fg",
|
||||||
|
"bg",
|
||||||
|
"light",
|
||||||
|
"dark",
|
||||||
|
"mid",
|
||||||
|
"text",
|
||||||
|
"base",
|
||||||
|
"text_aa",
|
||||||
|
"black",
|
||||||
|
"white",
|
||||||
|
"font_desc",
|
||||||
|
"xthickness",
|
||||||
|
"ythickness",
|
||||||
|
"background");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.structs;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://developer.gnome.org/pango/stable/pango-Glyph-Storage.html#PangoRectangle
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class PangoRectangle extends Structure {
|
||||||
|
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
public int width;
|
||||||
|
public int height;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("x", "y", "width", "height");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue