Added GTK3 support (now libappindicator3 works correctly with regards to showing menu icons).Moved all GTK operations to a single thread. Moved error logs from System.err -> logger. Made SystemTray a singleton (it will no longer have the java-side get accidentally garbage collected).

This commit is contained in:
nathan 2016-02-13 15:07:21 +01:00
parent 9081643963
commit 176f64fd6e
3 changed files with 107 additions and 33 deletions

View File

@ -29,15 +29,28 @@ class AppIndicatorQuery {
*/ */
static volatile boolean isVersion3 = false; static volatile boolean isVersion3 = false;
/**
* Is AppIndicator loaded yet?
*/
static volatile boolean isLoaded = false;
public static public static
AppIndicator get() { AppIndicator get() {
Object library; Object library;
// NOTE: GtkSupport uses this info to figure out WHAT VERSION OF GTK to use: appindiactor1 -> GTk2, appindicator3 -> GTK3.
// start with base version // start with base version
try { try {
library = Native.loadLibrary("appindicator", AppIndicator.class); library = Native.loadLibrary("appindicator3", AppIndicator.class);
if (library != null) { if (library != null) {
String s = library.toString();
if (s.indexOf("appindicator3") > 0) {
isVersion3 = true;
}
isLoaded = true;
return (AppIndicator) library; return (AppIndicator) library;
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {

View File

@ -17,7 +17,6 @@ package dorkbox.util.jna.linux;
import com.sun.jna.Function; import com.sun.jna.Function;
import com.sun.jna.Library; import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer; import com.sun.jna.Pointer;
import com.sun.jna.Structure; import com.sun.jna.Structure;
import dorkbox.util.Keep; import dorkbox.util.Keep;
@ -25,15 +24,17 @@ import dorkbox.util.Keep;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
public interface Gtk extends Library { public
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep image interface Gtk extends Library {
Gtk INSTANCE = (Gtk) Native.loadLibrary("gtk-x11-2.0", Gtk.class);
// 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
Gtk INSTANCE = GtkSupport.get();
Function gtk_status_icon_position_menu = GtkSupport.gtk_status_icon_position_menu;
int FALSE = 0; int FALSE = 0;
int TRUE = 1; int TRUE = 1;
void gtk_box_pack_start(Pointer box, Pointer child, int expand, int fill, int padding);
void gtk_box_pack_end(Pointer box, Pointer child, int expand, int fill, int padding);
@Keep @Keep
class GdkEventButton extends Structure { class GdkEventButton extends Structure {
@ -51,43 +52,36 @@ public interface Gtk extends Library {
public double y_root; public double y_root;
@Override @Override
protected List<String> getFieldOrder() { protected
return Arrays.asList("type", List<String> getFieldOrder() {
"window", return Arrays.asList("type", "window", "send_event", "time", "x", "y", "axes", "state", "button", "device", "x_root", "y_root");
"send_event",
"time",
"x",
"y",
"axes",
"state",
"button",
"device",
"x_root",
"y_root");
} }
} }
Function gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu");
void gtk_init(int argc, String[] argv); void gtk_init(int argc, String[] argv);
/** /**
* Runs the main loop until gtk_main_quit() is called. * 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
* You can nest calls to gtk_main(). In that case gtk_main_quit() will make the innermost invocation of the main loop return. * innermost invocation of the main loop return.
*/ */
void gtk_main(); void gtk_main();
/** /**
* Makes the innermost invocation of the main loop return when it regains control. ONLY CALL FROM THE GtkSupport class, UNLESS * Makes the innermost invocation of the main loop return when it regains control. ONLY CALL FROM THE GtkSupport class, UNLESS you know
* you know what you're doing! * what you're doing!
*/ */
void gtk_main_quit(); void gtk_main_quit();
void gdk_threads_init(); void gdk_threads_init();
void gdk_threads_enter(); void gdk_threads_enter();
void gdk_threads_leave(); void gdk_threads_leave();
Pointer gtk_menu_new(); Pointer gtk_menu_new();
Pointer gtk_menu_item_new(); Pointer gtk_menu_item_new();
Pointer gtk_menu_item_new_with_label(String label); Pointer gtk_menu_item_new_with_label(String label);
// to create a menu entry WITH an icon. // to create a menu entry WITH an icon.
@ -95,15 +89,21 @@ public interface Gtk extends Library {
Pointer gtk_image_menu_item_new_with_label(String label); Pointer gtk_image_menu_item_new_with_label(String label);
void gtk_image_menu_item_set_image(Pointer image_menu_item, Pointer image); void gtk_image_menu_item_set_image(Pointer image_menu_item, Pointer image);
void gtk_image_menu_item_set_always_show_image(Pointer menu_item, int forceShow); void gtk_image_menu_item_set_always_show_image(Pointer menu_item, int forceShow);
Pointer gtk_bin_get_child(Pointer parent); Pointer gtk_bin_get_child(Pointer parent);
void gtk_label_set_text(Pointer label, String text); void gtk_label_set_text(Pointer label, String text);
void gtk_label_set_markup(Pointer label, Pointer markup); void gtk_label_set_markup(Pointer label, Pointer markup);
void gtk_label_set_use_markup(Pointer label, int gboolean); void gtk_label_set_use_markup(Pointer label, int gboolean);
Pointer gtk_status_icon_new(); Pointer gtk_status_icon_new();
void gtk_status_icon_set_from_file(Pointer widget, String lablel); void gtk_status_icon_set_from_file(Pointer widget, String lablel);
void gtk_status_icon_set_visible(Pointer widget, boolean visible); void gtk_status_icon_set_visible(Pointer widget, boolean visible);
@ -112,19 +112,25 @@ public interface Gtk extends Library {
// void gtk_status_icon_set_tooltip(Pointer widget, String tooltipText); // void gtk_status_icon_set_tooltip(Pointer widget, String tooltipText);
void gtk_status_icon_set_title(Pointer widget, String titleText); void gtk_status_icon_set_title(Pointer widget, String titleText);
void gtk_status_icon_set_name(Pointer widget, String name); void gtk_status_icon_set_name(Pointer widget, String name);
void gtk_menu_popup(Pointer menu, Pointer widget, Pointer bla, Function func, Pointer data, int button, int time); void gtk_menu_popup(Pointer menu, Pointer widget, Pointer bla, Function func, Pointer data, int button, int time);
void gtk_menu_item_set_label(Pointer menu_item, String label); void gtk_menu_item_set_label(Pointer menu_item, String label);
void gtk_menu_shell_append(Pointer menu_shell, Pointer child); void gtk_menu_shell_append(Pointer menu_shell, Pointer child);
void gtk_menu_shell_deactivate(Pointer menu_shell, Pointer child); void gtk_menu_shell_deactivate(Pointer menu_shell, Pointer child);
void gtk_widget_set_sensitive(Pointer widget, int sensitive); void gtk_widget_set_sensitive(Pointer widget, int sensitive);
void gtk_container_remove(Pointer menu, Pointer subItem); void gtk_container_remove(Pointer menu, Pointer subItem);
void gtk_widget_show(Pointer widget); void gtk_widget_show(Pointer widget);
void gtk_widget_show_all(Pointer widget); void gtk_widget_show_all(Pointer widget);
void gtk_widget_destroy(Pointer widget); void gtk_widget_destroy(Pointer widget);
} }

View File

@ -15,6 +15,8 @@
*/ */
package dorkbox.util.jna.linux; package dorkbox.util.jna.linux;
import com.sun.jna.Function;
import com.sun.jna.Native;
import dorkbox.util.Property; import dorkbox.util.Property;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
@ -22,8 +24,6 @@ import java.util.concurrent.CountDownLatch;
public public
class GtkSupport { class GtkSupport {
public static final boolean isSupported;
// RE: SWT // RE: SWT
// https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html#g-thread-init // https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html#g-thread-init
// Since version >= 2.24, threads can only init once. Multiple calls do nothing, and we can nest gtk_main() // Since version >= 2.24, threads can only init once. Multiple calls do nothing, and we can nest gtk_main()
@ -37,16 +37,71 @@ class GtkSupport {
/** Enables/Disables the creation of a native GTK event loop. Useful if you are already creating one via SWT/etc. */ /** Enables/Disables the creation of a native GTK event loop. Useful if you are already creating one via SWT/etc. */
public static boolean CREATE_EVENT_LOOP = true; public static boolean CREATE_EVENT_LOOP = true;
static { /**
boolean hasSupport = false; * must call get() before accessing this! Only "Gtk" interface should access this!
*/
static volatile Function gtk_status_icon_position_menu = null;
public static volatile boolean isGtk2 = false;
/**
* Helper for GTK, because we could have v3 or v2
*/
@SuppressWarnings("Duplicates")
public static
Gtk get() {
Object library;
if (AppIndicatorQuery.isLoaded) {
if (AppIndicatorQuery.isVersion3) {
// appindicator3 requires GTK3
try {
gtk_status_icon_position_menu = Function.getFunction("libgtk-3.so.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("libgtk-3.so.0", Gtk.class);
if (library != null) {
return (Gtk) library;
}
} catch (Throwable ignored) {
}
} else {
// appindicator1 requires GTK2
try {
gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("gtk-x11-2.0", Gtk.class);
if (library != null) {
isGtk2 = true;
return (Gtk) library;
}
} catch (Throwable ignored) {
}
}
}
// now for the defaults...
// start with version 3
try { try {
if (Gtk.INSTANCE != null && Gobject.INSTANCE != null && GThread.INSTANCE != null) { gtk_status_icon_position_menu = Function.getFunction("libgtk-3.so.0", "gtk_status_icon_position_menu");
hasSupport = true; library = Native.loadLibrary("libgtk-3.so.0", Gtk.class);
if (library != null) {
return (Gtk) library;
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
isSupported = hasSupport; // now version 2
try {
gtk_status_icon_position_menu = Function.getFunction("gtk-x11-2.0", "gtk_status_icon_position_menu");
library = Native.loadLibrary("gtk-x11-2.0", Gtk.class);
if (library != null) {
isGtk2 = true;
return (Gtk) library;
}
} catch (Throwable ignored) {
}
throw new RuntimeException("We apologize for this, but we are unable to determine the GTK library is in use, if " +
"or even if it is in use... Please create an issue for this and include your OS type and configuration.");
} }
public static public static