Added support (and configuration info) for using the SystemTray with SWT
This commit is contained in:
parent
6fac9be88e
commit
85ba4c9380
@ -21,7 +21,6 @@ import dorkbox.systemTray.linux.GtkSystemTray;
|
|||||||
import dorkbox.systemTray.linux.jna.AppIndicator;
|
import dorkbox.systemTray.linux.jna.AppIndicator;
|
||||||
import dorkbox.systemTray.linux.jna.GtkSupport;
|
import dorkbox.systemTray.linux.jna.GtkSupport;
|
||||||
import dorkbox.systemTray.swing.SwingSystemTray;
|
import dorkbox.systemTray.swing.SwingSystemTray;
|
||||||
import dorkbox.systemTray.swt.SwtSystemTray;
|
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.Property;
|
import dorkbox.util.Property;
|
||||||
import dorkbox.util.process.ShellProcessBuilder;
|
import dorkbox.util.process.ShellProcessBuilder;
|
||||||
@ -54,11 +53,33 @@ class SystemTray {
|
|||||||
/** Size of the tray, so that the icon can properly scale based on OS. (if it's not exact) */
|
/** Size of the tray, so that the icon can properly scale based on OS. (if it's not exact) */
|
||||||
public static int TRAY_SIZE = 22;
|
public static int TRAY_SIZE = 22;
|
||||||
|
|
||||||
private static final SystemTray systemTray;
|
@Property
|
||||||
|
/** Forces the system to always choose GTK2 (even when GTK3 might be available). JavaFX uses GTK2! */
|
||||||
|
public static boolean FORCE_GTK2 = false;
|
||||||
|
|
||||||
|
@Property
|
||||||
|
/**
|
||||||
|
* Forces the system to enter into JavaFX/Swt compatibility mode, where it will use GTK2 AND will not start/stop the GTK main loop.
|
||||||
|
* This is only necessary if autodetection fails.
|
||||||
|
*/
|
||||||
|
public static boolean COMPATIBILITY_MODE = false;
|
||||||
|
|
||||||
|
@Property
|
||||||
|
/**
|
||||||
|
* When in compatibility mode, when JavaFX/SWT primary windows are close, we want to make sure that the SystemTray is also closed.
|
||||||
|
* This property is available to disable this functionality in the situations where you don' want this to happen.
|
||||||
|
*/
|
||||||
|
public static boolean ENABLE_SHUTDOWN_HOOK = true;
|
||||||
|
|
||||||
|
private static volatile SystemTray systemTray = null;
|
||||||
|
|
||||||
static boolean isKDE = false;
|
static boolean isKDE = false;
|
||||||
|
|
||||||
static {
|
private static void init() {
|
||||||
|
if (systemTray != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Class<? extends SystemTray> trayType = null;
|
Class<? extends SystemTray> trayType = null;
|
||||||
|
|
||||||
boolean isJavaFxLoaded = false;
|
boolean isJavaFxLoaded = false;
|
||||||
@ -74,183 +95,192 @@ class SystemTray {
|
|||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe we should load the SWT version? (SWT's use of GTK is incompatible with how we use GTK)
|
// maybe we should load the SWT version? (In order for us to work with SWT, BOTH must be GTK2!!
|
||||||
|
COMPATIBILITY_MODE = isJavaFxLoaded || isSwtLoaded;
|
||||||
|
|
||||||
|
// kablooie if SWT is not configured in a way that works with us.
|
||||||
if (isSwtLoaded) {
|
if (isSwtLoaded) {
|
||||||
try {
|
// Necessary for us to work with SWT
|
||||||
trayType = SwtSystemTray.class;
|
// System.setProperty("SWT_GTK3", "0"); // Necessary for us to work with SWT
|
||||||
} catch (Throwable ignored) {
|
|
||||||
|
// was SWT forced?
|
||||||
|
boolean isSwt_GTK3 = !System.getProperty("SWT_GTK3").equals("0");
|
||||||
|
if (!isSwt_GTK3) {
|
||||||
|
// check a different property
|
||||||
|
isSwt_GTK3 = !System.getProperty("org.eclipse.swt.internal.gtk.version").startsWith("2.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSwt_GTK3) {
|
||||||
|
logger.error("Unable to use the SystemTray when SWT is configured to use GTK3. Please configure SWT to use GTK2, one such " +
|
||||||
|
"example is to set the system property `System.setProperty(\"SWT_GTK3\", \"0\");` before SWT is initialized");
|
||||||
|
|
||||||
|
throw new RuntimeException("SWT configured to use GTK3 and is incompatible with the SystemTray.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Note: AppIndicators DO NOT support tooltips. We could try to create one, by creating a GTK widget and attaching it on
|
|
||||||
// mouseover or something, but I don't know how to do that. It seems that tooltips for app-indicators are a custom job, as
|
|
||||||
// all examined ones sometimes have it (and it's more than just text), or they don't have it at all.
|
|
||||||
|
|
||||||
if (OS.isWindows()) {
|
|
||||||
// the tray icon size in windows is DIFFERENT than on Mac (TODO: test on mac with retina stuff).
|
// Note: AppIndicators DO NOT support tooltips. We could try to create one, by creating a GTK widget and attaching it on
|
||||||
TRAY_SIZE -= 4;
|
// mouseover or something, but I don't know how to do that. It seems that tooltips for app-indicators are a custom job, as
|
||||||
|
// all examined ones sometimes have it (and it's more than just text), or they don't have it at all.
|
||||||
|
|
||||||
|
if (OS.isWindows()) {
|
||||||
|
// the tray icon size in windows is DIFFERENT than on Mac (TODO: test on mac with retina stuff).
|
||||||
|
TRAY_SIZE -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OS.isLinux()) {
|
||||||
|
// see: https://askubuntu.com/questions/72549/how-to-determine-which-window-manager-is-running
|
||||||
|
|
||||||
|
// quick check, because we know that unity uses app-indicator. Maybe REALLY old versions do not. We support 14.04 LTE at least
|
||||||
|
String XDG = System.getenv("XDG_CURRENT_DESKTOP");
|
||||||
|
if ("Unity".equalsIgnoreCase(XDG)) {
|
||||||
|
try {
|
||||||
|
trayType = AppIndicatorTray.class;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if ("XFCE".equalsIgnoreCase(XDG)) {
|
||||||
if (OS.isLinux()) {
|
try {
|
||||||
// see: https://askubuntu.com/questions/72549/how-to-determine-which-window-manager-is-running
|
trayType = AppIndicatorTray.class;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
if (isJavaFxLoaded) {
|
// we can fail on AppIndicator, so this is the fallback
|
||||||
// we MUST use GTK2 with javaFX!
|
//noinspection EmptyCatchBlock
|
||||||
GtkSupport.FORCE_GTK2 = isJavaFxLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
// quick check, because we know that unity uses app-indicator. Maybe REALLY old versions do not. We support 14.04 LTE at least
|
|
||||||
String XDG = System.getenv("XDG_CURRENT_DESKTOP");
|
|
||||||
if ("Unity".equalsIgnoreCase(XDG)) {
|
|
||||||
try {
|
try {
|
||||||
trayType = AppIndicatorTray.class;
|
trayType = GtkSystemTray.class;
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable i) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ("XFCE".equalsIgnoreCase(XDG)) {
|
}
|
||||||
try {
|
else if ("LXDE".equalsIgnoreCase(XDG)) {
|
||||||
trayType = AppIndicatorTray.class;
|
try {
|
||||||
} catch (Throwable ignored) {
|
trayType = GtkSystemTray.class;
|
||||||
// we can fail on AppIndicator, so this is the fallback
|
} catch (Throwable ignored) {
|
||||||
//noinspection EmptyCatchBlock
|
|
||||||
try {
|
|
||||||
trayType = GtkSystemTray.class;
|
|
||||||
} catch (Throwable i) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ("LXDE".equalsIgnoreCase(XDG)) {
|
}
|
||||||
|
else if ("KDE".equalsIgnoreCase(XDG)) {
|
||||||
|
isKDE = true;
|
||||||
|
try {
|
||||||
|
trayType = AppIndicatorTray.class;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ("GNOME".equalsIgnoreCase(XDG)) {
|
||||||
|
// check other DE
|
||||||
|
String GDM = System.getenv("GDMSESSION");
|
||||||
|
|
||||||
|
if ("cinnamon".equalsIgnoreCase(GDM)) {
|
||||||
try {
|
try {
|
||||||
trayType = GtkSystemTray.class;
|
trayType = GtkSystemTray.class;
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ("KDE".equalsIgnoreCase(XDG)) {
|
else if ("gnome-classic".equalsIgnoreCase(GDM)) {
|
||||||
isKDE = true;
|
|
||||||
try {
|
try {
|
||||||
trayType = AppIndicatorTray.class;
|
trayType = GtkSystemTray.class;
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ("GNOME".equalsIgnoreCase(XDG)) {
|
else if ("gnome-fallback".equalsIgnoreCase(GDM)) {
|
||||||
// check other DE
|
try {
|
||||||
String GDM = System.getenv("GDMSESSION");
|
trayType = GtkSystemTray.class;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
if ("cinnamon".equalsIgnoreCase(GDM)) {
|
|
||||||
try {
|
|
||||||
trayType = GtkSystemTray.class;
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ("gnome-classic".equalsIgnoreCase(GDM)) {
|
|
||||||
try {
|
|
||||||
trayType = GtkSystemTray.class;
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ("gnome-fallback".equalsIgnoreCase(GDM)) {
|
|
||||||
try {
|
|
||||||
trayType = GtkSystemTray.class;
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// unknown exactly, install extension and go from there
|
|
||||||
if (trayType == null) {
|
|
||||||
// if the "topicons" extension is installed, don't install us (because it will override what we do, where ours
|
|
||||||
// is more specialized - so it only modified our tray icon (instead of ALL tray icons)
|
|
||||||
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8196);
|
|
||||||
PrintStream outputStream = new PrintStream(byteArrayOutputStream);
|
|
||||||
|
|
||||||
// gnome-shell --version
|
|
||||||
final ShellProcessBuilder shellVersion = new ShellProcessBuilder(outputStream);
|
|
||||||
shellVersion.setExecutable("gnome-shell");
|
|
||||||
shellVersion.addArgument("--version");
|
|
||||||
shellVersion.start();
|
|
||||||
|
|
||||||
String output = ShellProcessBuilder.getOutput(byteArrayOutputStream);
|
|
||||||
|
|
||||||
if (!output.isEmpty()) {
|
|
||||||
GnomeShellExtension.install(logger, output);
|
|
||||||
trayType = GtkSystemTray.class;
|
|
||||||
}
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
trayType = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to autodetect if we can use app indicators (or if we need to fallback to GTK indicators)
|
|
||||||
|
// unknown exactly, install extension and go from there
|
||||||
if (trayType == null) {
|
if (trayType == null) {
|
||||||
BufferedReader bin = null;
|
// if the "topicons" extension is installed, don't install us (because it will override what we do, where ours
|
||||||
|
// is more specialized - so it only modified our tray icon (instead of ALL tray icons)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// the ONLY guaranteed way to determine if indicator-application-service is running (and thus, using app-indicator),
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8196);
|
||||||
// is to look through all /proc/<pid>/status, and first line should be Name:\tindicator-appli
|
PrintStream outputStream = new PrintStream(byteArrayOutputStream);
|
||||||
File proc = new File("/proc");
|
|
||||||
File[] listFiles = proc.listFiles();
|
|
||||||
if (listFiles != null) {
|
|
||||||
for (File procs : listFiles) {
|
|
||||||
String name = procs.getName();
|
|
||||||
|
|
||||||
if (!Character.isDigit(name.charAt(0))) {
|
// gnome-shell --version
|
||||||
continue;
|
final ShellProcessBuilder shellVersion = new ShellProcessBuilder(outputStream);
|
||||||
}
|
shellVersion.setExecutable("gnome-shell");
|
||||||
|
shellVersion.addArgument("--version");
|
||||||
|
shellVersion.start();
|
||||||
|
|
||||||
File status = new File(procs, "status");
|
String output = ShellProcessBuilder.getOutput(byteArrayOutputStream);
|
||||||
if (!status.canRead()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
if (!output.isEmpty()) {
|
||||||
bin = new BufferedReader(new FileReader(status));
|
GnomeShellExtension.install(logger, output);
|
||||||
String readLine = bin.readLine();
|
trayType = GtkSystemTray.class;
|
||||||
|
|
||||||
if (readLine != null && readLine.contains("indicator-app")) {
|
|
||||||
// make sure we can also load the library (it might be the wrong version)
|
|
||||||
try {
|
|
||||||
//noinspection unused
|
|
||||||
final AppIndicator instance = AppIndicator.INSTANCE;
|
|
||||||
trayType = AppIndicatorTray.class;
|
|
||||||
|
|
||||||
if (AppIndicator.IS_VERSION_3) {
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("AppIndicator support detected, but unable to load the library. Falling back to GTK");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (bin != null) {
|
|
||||||
bin.close();
|
|
||||||
bin = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
} finally {
|
trayType = null;
|
||||||
if (bin != null) {
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to autodetect if we can use app indicators (or if we need to fallback to GTK indicators)
|
||||||
|
if (trayType == null) {
|
||||||
|
BufferedReader bin = null;
|
||||||
|
try {
|
||||||
|
// the ONLY guaranteed way to determine if indicator-application-service is running (and thus, using app-indicator),
|
||||||
|
// is to look through all /proc/<pid>/status, and first line should be Name:\tindicator-appli
|
||||||
|
File proc = new File("/proc");
|
||||||
|
File[] listFiles = proc.listFiles();
|
||||||
|
if (listFiles != null) {
|
||||||
|
for (File procs : listFiles) {
|
||||||
|
String name = procs.getName();
|
||||||
|
|
||||||
|
if (!Character.isDigit(name.charAt(0))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
File status = new File(procs, "status");
|
||||||
|
if (!status.canRead()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bin.close();
|
bin = new BufferedReader(new FileReader(status));
|
||||||
} catch (IOException ignored) {
|
String readLine = bin.readLine();
|
||||||
|
|
||||||
|
if (readLine != null && readLine.contains("indicator-app")) {
|
||||||
|
// make sure we can also load the library (it might be the wrong version)
|
||||||
|
try {
|
||||||
|
//noinspection unused
|
||||||
|
final AppIndicator instance = AppIndicator.INSTANCE;
|
||||||
|
trayType = AppIndicatorTray.class;
|
||||||
|
|
||||||
|
if (AppIndicator.IS_VERSION_3) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("AppIndicator support detected, but unable to load the library. Falling back to GTK");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (bin != null) {
|
||||||
|
bin.close();
|
||||||
|
bin = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
} finally {
|
||||||
|
if (bin != null) {
|
||||||
|
try {
|
||||||
|
bin.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// fallback...
|
// fallback...
|
||||||
if (trayType == null) {
|
if (trayType == null) {
|
||||||
trayType = GtkSystemTray.class;
|
trayType = GtkSystemTray.class;
|
||||||
logger.error("Unable to load the system tray native library. Please write an issue and include your OS type and " +
|
logger.error("Unable to load the system tray native library. Please write an issue and include your OS type and " +
|
||||||
"configuration");
|
"configuration");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +308,7 @@ class SystemTray {
|
|||||||
// the order of checking here is critical -- AppIndicator.IS_VERSION_3 initializes `appindicator` and `gtk`
|
// the order of checking here is critical -- AppIndicator.IS_VERSION_3 initializes `appindicator` and `gtk`
|
||||||
if (OS.isLinux() &&
|
if (OS.isLinux() &&
|
||||||
trayType == AppIndicatorTray.class &&
|
trayType == AppIndicatorTray.class &&
|
||||||
AppIndicator.IS_VERSION_3 && // this initializes the appindicator (since we specified that via the trayType)
|
AppIndicator.IS_VERSION_3 && // this initializes the appindicator (since we specified that via the trayType)
|
||||||
GtkSupport.isGtk2) {
|
GtkSupport.isGtk2) {
|
||||||
|
|
||||||
// NOTE:
|
// NOTE:
|
||||||
@ -308,10 +338,12 @@ class SystemTray {
|
|||||||
systemTray = systemTray_;
|
systemTray = systemTray_;
|
||||||
|
|
||||||
|
|
||||||
// Necessary because javaFX **ALSO** runs a gtk main loop, and when it stops (if we don't stop first), we become unresponsive.
|
// These install a shutdown hook in JavaFX/SWT, so that when the main window is closed -- the system tray is ALSO closed.
|
||||||
// we ONLY need this on linux for compatibility with JavaFX... (windows/mac don't use gtk)
|
if (COMPATIBILITY_MODE && ENABLE_SHUTDOWN_HOOK) {
|
||||||
if (OS.isLinux()) {
|
if (isJavaFxLoaded) {
|
||||||
if (isJavaFxLoaded || GtkSupport.JAVAFX_COMPATIBILITY_MODE) {
|
// Necessary because javaFX **ALSO** runs a gtk main loop, and when it stops (if we don't stop first), we become unresponsive.
|
||||||
|
// Also, it's nice to have us shutdown at the same time as the main application
|
||||||
|
|
||||||
// com.sun.javafx.tk.Toolkit.getToolkit()
|
// com.sun.javafx.tk.Toolkit.getToolkit()
|
||||||
// .addShutdownHook(new Runnable() {
|
// .addShutdownHook(new Runnable() {
|
||||||
// @Override
|
// @Override
|
||||||
@ -336,13 +368,35 @@ class SystemTray {
|
|||||||
});
|
});
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
logger.error("Unable to insert shutdown hook into JavaFX. Please create an issue with your OS and Java " +
|
logger.error("Unable to insert shutdown hook into JavaFX. Please create an issue with your OS and Java " +
|
||||||
"configuration so we may further investigate this issue.");
|
"version so we may further investigate this issue.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isSwtLoaded) {
|
||||||
|
// this is because SWT **ALSO** runs a gtk main loop, and when it stops (if we don't stop first), we become unresponsive
|
||||||
|
// Also, it's nice to have us shutdown at the same time as the main application
|
||||||
|
|
||||||
|
// During compile time (for production), this class is not compiled, and instead is copied over as a pre-compiled file
|
||||||
|
// This is so we don't have to rely on having SWT as part of the classpath during build.
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName("dorkbox.systemTray.swt.Swt");
|
||||||
|
Method method = clazz.getMethod("onShutdown", Runnable.class);
|
||||||
|
Object o = method.invoke(null, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
systemTray.shutdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
logger.error("Unable to insert shutdown hook into SWT. Please create an issue with your OS and Java " +
|
||||||
|
"version so we may further investigate this issue.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the version number.
|
* Gets the version number.
|
||||||
*/
|
*/
|
||||||
@ -360,6 +414,7 @@ class SystemTray {
|
|||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
SystemTray getSystemTray() {
|
SystemTray getSystemTray() {
|
||||||
|
init();
|
||||||
return systemTray;
|
return systemTray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package dorkbox.systemTray.linux.jna;
|
package dorkbox.systemTray.linux.jna;
|
||||||
|
|
||||||
import com.sun.jna.Native;
|
import com.sun.jna.Native;
|
||||||
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for AppIndicator, because it is absolutely mindboggling how those whom maintain the standard, can't agree to what that standard
|
* Helper for AppIndicator, because it is absolutely mindboggling how those whom maintain the standard, can't agree to what that standard
|
||||||
@ -44,7 +45,7 @@ class AppIndicatorQuery {
|
|||||||
|
|
||||||
// NOTE: GtkSupport uses this info to figure out WHAT VERSION OF GTK to use: appindiactor1 -> GTk2, appindicator3 -> GTK3.
|
// NOTE: GtkSupport uses this info to figure out WHAT VERSION OF GTK to use: appindiactor1 -> GTk2, appindicator3 -> GTK3.
|
||||||
|
|
||||||
if (GtkSupport.FORCE_GTK2) {
|
if (SystemTray.FORCE_GTK2 || SystemTray.COMPATIBILITY_MODE) {
|
||||||
// try loading appindicator1 first, maybe it's there?
|
// try loading appindicator1 first, maybe it's there?
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -117,7 +118,7 @@ class AppIndicatorQuery {
|
|||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException("We apologize for this, but we are unable to determine the appIndicator library is in use, if " +
|
throw new RuntimeException("We apologize for this, but we are unable to determine which the appIndicator 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.");
|
"or even if it is in use... Please create an issue for this and include your OS type and configuration.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,54 +17,37 @@ package dorkbox.systemTray.linux.jna;
|
|||||||
|
|
||||||
import com.sun.jna.Function;
|
import com.sun.jna.Function;
|
||||||
import com.sun.jna.Native;
|
import com.sun.jna.Native;
|
||||||
import dorkbox.util.Property;
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
public
|
public
|
||||||
class GtkSupport {
|
class GtkSupport {
|
||||||
// RE: SWT
|
|
||||||
// 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()
|
|
||||||
// in a nested loop.
|
|
||||||
|
|
||||||
private static volatile boolean started = false;
|
private static volatile boolean started = false;
|
||||||
private static final ArrayBlockingQueue<Runnable> dispatchEvents = new ArrayBlockingQueue<Runnable>(256);
|
private static final ArrayBlockingQueue<Runnable> dispatchEvents = new ArrayBlockingQueue<Runnable>(256);
|
||||||
private static volatile Thread gtkDispatchThread;
|
private static volatile Thread gtkDispatchThread;
|
||||||
|
|
||||||
@Property
|
|
||||||
/** Forces the system to always choose GTK2 (even when GTK3 might be available). JavaFX uses GTK2! */
|
|
||||||
public static boolean FORCE_GTK2 = false;
|
|
||||||
|
|
||||||
@Property
|
|
||||||
/**
|
|
||||||
* Forces the system to enter into JavaFX compatibility mode, where it will use GTK2 AND will not start/stop the GTK main loop.
|
|
||||||
* This is only necessary if autodetection fails
|
|
||||||
*/
|
|
||||||
public static boolean JAVAFX_COMPATIBILITY_MODE = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* must call get() before accessing this! Only "Gtk" interface should access this!
|
* must call get() before accessing this! Only "Gtk" interface should access this!
|
||||||
*/
|
*/
|
||||||
static volatile Function gtk_status_icon_position_menu = null;
|
static volatile Function gtk_status_icon_position_menu = null;
|
||||||
|
|
||||||
public static volatile boolean isGtk2 = false;
|
public static volatile boolean isGtk2 = false;
|
||||||
|
|
||||||
private static volatile boolean alreadyRunningGTK = false;
|
private static volatile boolean alreadyRunningGTK = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for GTK, because we could have v3 or v2.
|
* Helper for GTK, because we could have v3 or v2.
|
||||||
*
|
*
|
||||||
* Observations: JavaFX uses GTK2, and we can't load GTK3 if GTK2 symbols are loaded
|
* 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.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
public static
|
public static
|
||||||
Gtk get() {
|
Gtk get() {
|
||||||
Gtk library;
|
Gtk library;
|
||||||
|
|
||||||
boolean shouldUseGtk2 = GtkSupport.FORCE_GTK2 || JAVAFX_COMPATIBILITY_MODE;
|
boolean shouldUseGtk2 = SystemTray.FORCE_GTK2 || SystemTray.COMPATIBILITY_MODE;
|
||||||
alreadyRunningGTK = JAVAFX_COMPATIBILITY_MODE;
|
alreadyRunningGTK = SystemTray.COMPATIBILITY_MODE;
|
||||||
|
|
||||||
|
|
||||||
// for more info on JavaFX: https://docs.oracle.com/javafx/2/system_requirements_2-2-3/jfxpub-system_requirements_2-2-3.htm
|
// for more info on JavaFX: https://docs.oracle.com/javafx/2/system_requirements_2-2-3/jfxpub-system_requirements_2-2-3.htm
|
||||||
|
@ -24,6 +24,7 @@ import org.eclipse.swt.widgets.Display;
|
|||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,6 +42,10 @@ class TestTraySwt {
|
|||||||
|
|
||||||
public static
|
public static
|
||||||
void main(String[] args) {
|
void main(String[] args) {
|
||||||
|
System.setProperty("SWT_GTK3", "0"); // Necessary for us to work with SWT
|
||||||
|
|
||||||
|
System.load(new File("../../resources/Dependencies/jna/linux_64/libjna.so").getAbsolutePath()); //64bit linux library
|
||||||
|
|
||||||
new TestTraySwt();
|
new TestTraySwt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +107,13 @@ class TestTraySwt {
|
|||||||
public
|
public
|
||||||
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
void onClick(final SystemTray systemTray, final MenuEntry menuEntry) {
|
||||||
systemTray.shutdown();
|
systemTray.shutdown();
|
||||||
shell.close(); // close down SWT shell
|
|
||||||
|
Display.getDefault().asyncExec(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
shell.close(); // close down SWT shell
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user