GTK now starts up when on linux/unix, regardless of tray type.

This commit is contained in:
nathan 2017-06-25 23:50:22 +02:00
parent c70c96b5d9
commit 9dbee8cfc5
5 changed files with 163 additions and 195 deletions

View File

@ -89,18 +89,12 @@ class SystemTray {
}
@Property
/** Enables auto-detection for the system tray. This should be mostly successful.
* <p>
* Auto-detection will use DEFAULT_TRAY_SIZE as a 'base-line' for determining what size to use.
* <p>
* If auto-detection fails and the incorrect size is detected or used, disable this and specify the correct DEFAULT_TRAY_SIZE or
* DEFAULT_MENU_SIZE instead
*/
/** Enables auto-detection for the system tray. This should be mostly successful. */
public static boolean AUTO_SIZE = true;
@Property
/** Forces the system tray to always choose GTK2 (even when GTK3 might be available). */
public static boolean FORCE_GTK2 = false;
public static boolean FORCE_GTK2 = true;
@Property
/**
@ -108,7 +102,7 @@ class SystemTray {
* <p>
* This is an advanced feature, and it is recommended to leave at AutoDetect.
*/
public static TrayType FORCE_TRAY_TYPE = TrayType.Swing;
public static TrayType FORCE_TRAY_TYPE = TrayType.AutoDetect;
@Property
/**
@ -264,9 +258,9 @@ class SystemTray {
return;
}
// Windows can ONLY use Swing (non-native) - AWT/native looks absolutely horrid
// Windows can ONLY use Swing (non-native) - AWT/native looks absolutely horrid and is not an option
// OSx can use Swing (non-native) or AWT (native) .
// Linux can use Swing (non-native) menus + (native Icon via GTK or AppIndicator), GtkStatusIcon (native), or AppIndicator (native)
// Linux can use Swing (non-native), AWT (native), GtkStatusIcon (native), or AppIndicator (native)
if (OS.isWindows()) {
if (FORCE_TRAY_TYPE != TrayType.AutoDetect && FORCE_TRAY_TYPE != TrayType.Swing) {
// windows MUST use swing only!
@ -282,8 +276,6 @@ class SystemTray {
}
}
else if (OS.isLinux() || OS.isUnix()) {
// kablooie if SWT/JavaFX or Swing is not configured in a way that works with us.
if (FORCE_TRAY_TYPE != TrayType.Swing) {
// NOTE: if the UI uses the 'getSystemLookAndFeelClassName' and is on Linux, this will cause GTK2 to get loaded first,
// which will cause conflicts if one tries to use GTK3
if (!FORCE_GTK2 && !isJavaFxLoaded && !isSwtLoaded) {
@ -317,13 +309,10 @@ class SystemTray {
systemTrayMenu = null;
systemTray = null;
return;
}
}
}
if (isSwtLoaded) {
else if (isSwtLoaded) {
// Necessary for us to work with SWT based on version info. We can try to set us to be compatible with whatever it is set to
// System.setProperty("SWT_GTK3", "0");
@ -380,7 +369,6 @@ class SystemTray {
}
}
}
}
Class<? extends Tray> trayType = null;
@ -420,15 +408,16 @@ class SystemTray {
}
}
else if (OS.isMacOsX()) {
// macosx doesn't respond to all buttons (but should)
SystemTrayFixes.fixMacOS();
if (SystemTray.FORCE_TRAY_TYPE != TrayType.AutoDetect) {
// macos can ONLY use the AWT tray indicator, if you want it to follow the L&F of the OS. If we force a specific type,
// then allow that.
try {
trayType = selectType(TrayType.AWT);
} catch (Throwable e) {
logger.error("You might need to grant the AWTPermission `accessSystemTray` to the SecurityManager.");
}
}
}
else if ((OS.isLinux() || OS.isUnix())) {
// see: https://askubuntu.com/questions/72549/how-to-determine-which-window-manager-is-running
@ -635,36 +624,34 @@ class SystemTray {
// fallback...
if (trayType == null) {
trayType = selectTypeQuietly(TrayType.GtkStatusIcon);
logger.warn("Unable to determine the system window manager type. Falling back to GtkStatusIcon.");
logger.warn("Unable to determine the system window manager type. Using the Swing Tray type instead.");
trayType = selectTypeQuietly(TrayType.Swing);
}
// this is bad...
if (trayType == null) {
logger.error("SystemTray initialization failed. Unable to load the system tray native libraries. Please write an issue " +
"and include your OS type and configuration");
logger.error("SystemTray initialization failed. Unable to load the system tray native libraries. " +
"Using the Swing Tray type instead. Please write an issue and include your OS type and configuration");
systemTrayMenu = null;
systemTray = null;
return;
trayType = selectTypeQuietly(TrayType.Swing);
}
if (isTrayType(trayType, TrayType.AppIndicator) && OSUtil.Linux.isRoot()) {
// if are we running as ROOT, there can be issues (definitely on Ubuntu 16.04, maybe others)!
logger.error("Attempting to load the SystemTray as the 'root/sudo' user. This will likely not work because of dbus " +
"restrictions.");
"restrictions. Using the Swing Tray type instead.");
trayType = selectTypeQuietly(TrayType.Swing);
}
}
if (trayType == null) {
// unsupported tray, or unknown type
logger.error("SystemTray initialization failed. (Unable to discover which implementation to use). Something is seriously wrong.");
trayType = selectTypeQuietly(TrayType.Swing);
systemTrayMenu = null;
systemTray = null;
return;
// unsupported tray, or unknown type
logger.error("SystemTray initialization failed. (Unable to discover which implementation to use). Falling back to the Swing Tray.");
}
final AtomicReference<Tray> reference = new AtomicReference<Tray>();
@ -674,17 +661,17 @@ class SystemTray {
CacheUtil.tempDir = "SysTray";
try {
if ((OS.isLinux() || OS.isUnix()) && (isTrayType(trayType, TrayType.GtkStatusIcon) || isTrayType(trayType, TrayType.AppIndicator))) {
// at this point, the tray type is what it should be. If there are failures or special cases, all types will fall back to
// Swing.
if (OS.isLinux() || OS.isUnix()) {
// NOTE: appindicator1 -> GTk2, appindicator3 -> GTK3.
// appindicator3 doesn't support menu icons via GTK2!!
if (!Gtk.isLoaded) {
logger.error("Unable to initialize GTK! Something is severely wrong!");
systemTrayMenu = null;
systemTray = null;
return;
logger.error("Unable to initialize GTK! Something is severely wrong! Using the Swing Tray type instead.");
trayType = selectTypeQuietly(TrayType.Swing);
}
if (OSUtil.Linux.isArch()) {
else if (OSUtil.Linux.isArch()) {
// arch linux is fun!
if (isTrayType(trayType, TrayType.AppIndicator)) {
@ -696,47 +683,31 @@ class SystemTray {
if (!AppIndicator.isLoaded) {
if (Gtk.isGtk2) {
logger.error("Unable to initialize AppIndicator for Arch linux, it requires GTK2! " +
"Please install libappindicator, for example: 'sudo pacman -S libappindicator'");
systemTrayMenu = null;
systemTray = null;
return;
"Please install libappindicator, for example: 'sudo pacman -S libappindicator'. " +
"Using the Swing Tray type instead.");
} else {
logger.error("Unable to initialize AppIndicator for Arch linux, it requires GTK3! " +
"Please install libappindicator3, for example: 'sudo pacman -S libappindicator3'"); // GTK3
systemTrayMenu = null;
systemTray = null;
return;
}
}
}
"Please install libappindicator3, for example: 'sudo pacman -S libappindicator3'. " +
"Using the Swing Tray type instead."); // GTK3
}
if (isTrayType(trayType, TrayType.AppIndicator)) {
trayType = selectTypeQuietly(TrayType.Swing);
}
}
}
else if (isTrayType(trayType, TrayType.AppIndicator)) {
if (Gtk.isGtk2 && AppIndicator.isVersion3) {
try {
trayType = selectType(TrayType.GtkStatusIcon);
logger.warn("AppIndicator3 detected with GTK2, falling back to GTK2 system tray type. " +
"Please install libappindicator1 OR GTK3, for example: 'sudo apt-get install libappindicator1'");
} catch (Throwable e) {
if (DEBUG) {
logger.error("Cannot initialize _GtkStatusIconTray", e);
}
logger.error("AppIndicator3 detected with GTK2 and unable to fallback to using GTK2 system tray type." +
"AppIndicator3 requires GTK3 to be fully functional, and while this will work -- " +
"the menu icons WILL NOT be visible." +
" Please install libappindicator1 OR GTK3, for example: 'sudo apt-get install libappindicator1'");
"Please install libappindicator1 OR GTK3, for example: 'sudo apt-get install libappindicator1'. " +
"Using the Swing Tray type instead.");
systemTrayMenu = null;
systemTray = null;
return;
trayType = selectTypeQuietly(TrayType.Swing);
}
}
if (!AppIndicator.isLoaded) {
else if (!AppIndicator.isLoaded) {
// YIKES. Try to fallback to GtkStatusIndicator, since AppIndicator couldn't load.
logger.warn("Unable to initialize the AppIndicator correctly, falling back to GtkStatusIcon type");
trayType = selectTypeQuietly(TrayType.GtkStatusIcon);
logger.warn("Unable to initialize the AppIndicator correctly. Using the Swing Tray type instead.");
trayType = selectTypeQuietly(TrayType.Swing);
}
}
}
@ -753,6 +724,35 @@ class SystemTray {
Swt.init();
}
if (OS.isLinux() || OS.isUnix()) {
// linux/unix need access to GTK, so load it up before the tray is loaded!
Gtk.startGui();
Gtk.waitForEventsToComplete();
}
// initialize tray/menu image sizes. This must be BEFORE the system tray has been created
int trayImageSize = SizeAndScalingUtil.getTrayImageSize(trayType);
SizeAndScalingUtil.getMenuImageSize(trayType);
// this logic has to be before we create the system Tray
if (OS.isWindows()) {
// windows hard-codes the image size
SystemTrayFixes.fixWindows(trayImageSize);
}
else if (OS.isMacOsX()) {
// macosx doesn't respond to all buttons (but should)
SystemTrayFixes.fixMacOS();
}
else if ((OS.isLinux() || OS.isUnix())) {
// linux/mac doesn't have transparent backgrounds for swing
SystemTrayFixes.fixLinux(trayImageSize);
}
if ((isJavaFxLoaded || isSwtLoaded) && SwingUtilities.isEventDispatchThread()) {
// oh boy! This WILL NOT WORK. Let the dev know
@ -764,19 +764,6 @@ class SystemTray {
return;
}
// this logic has to be JUST before we create the system Tray
if (OS.isWindows()) {
// windows hard-codes the image size
SystemTrayFixes.fixWindows(SizeAndScalingUtil.getTrayImageSize(trayType));
} else if (OS.isMacOsX()) {
// macosx doesn't respond to all buttons (but should)
SystemTrayFixes.fixMacOS();
}
// initialize tray/menu image sizes
SizeAndScalingUtil.getTrayImageSize(trayType);
SizeAndScalingUtil.getMenuImageSize(trayType);
// javaFX and SWT should not start on the EDT!!
// if it's linux + native menus must not start on the EDT!

View File

@ -129,15 +129,8 @@ class Gtk {
_isLoaded = true;
}
// we can force the system to use the swing indicator, which WORKS, but doesn't support transparency in the icon.
if (!_isLoaded &&
(SystemTray.FORCE_TRAY_TYPE == SystemTray.TrayType.Swing || SystemTray.FORCE_TRAY_TYPE == SystemTray.TrayType.AWT)) {
if (SystemTray.DEBUG) {
logger.debug("Not loading GTK for Swing or AWT");
}
shouldLoadGtk = false;
_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";
@ -341,10 +334,10 @@ class Gtk {
void gtk_main();
/**
* Waits for the GUI to finish loading
* Waits for the all posted events to GTK to finish loading
*/
public static
void waitForStartup() {
void waitForEventsToComplete() {
final CountDownLatch blockUntilStarted = new CountDownLatch(1);
dispatch(new Runnable() {
@ -360,7 +353,7 @@ class Gtk {
try {
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
if (SystemTray.DEBUG) {
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
SystemTray.logger.error("Something is very wrong. The waitForEventsToComplete took longer than expected.",
new Exception(""));
}
}
@ -386,7 +379,7 @@ class Gtk {
try {
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
if (SystemTray.DEBUG) {
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
SystemTray.logger.error("Something is very wrong. The waitForEventsToComplete took longer than expected.",
new Exception(""));
}
}
@ -409,7 +402,7 @@ class Gtk {
try {
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
if (SystemTray.DEBUG) {
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
SystemTray.logger.error("Something is very wrong. The waitForEventsToComplete took longer than expected.",
new Exception(""));
}
}

View File

@ -99,8 +99,6 @@ class _AppIndicatorNativeTray extends Tray implements NativeUI {
_AppIndicatorNativeTray(final SystemTray systemTray) {
super();
Gtk.startGui();
// we override various methods, because each tray implementation is SLIGHTLY different. This allows us customization.
final GtkMenu gtkMenu = new GtkMenu() {
/**
@ -108,6 +106,7 @@ class _AppIndicatorNativeTray extends Tray implements NativeUI {
*
* ALWAYS CALLED ON THE EDT
*/
@Override
protected final
void onMenuAdded(final Pointer menu) {
// see: https://code.launchpad.net/~mterry/libappindicator/fix-menu-leak/+merge/53247
@ -227,7 +226,7 @@ class _AppIndicatorNativeTray extends Tray implements NativeUI {
}
});
Gtk.waitForStartup();
Gtk.waitForEventsToComplete();
bind(gtkMenu, null, systemTray);
}

View File

@ -62,8 +62,6 @@ class _GtkStatusIconNativeTray extends Tray implements NativeUI {
_GtkStatusIconNativeTray(final SystemTray systemTray) {
super();
Gtk.startGui();
// we override various methods, because each tray implementation is SLIGHTLY different. This allows us customization.
gtkMenu = new GtkMenu() {
@Override
@ -170,7 +168,7 @@ class _GtkStatusIconNativeTray extends Tray implements NativeUI {
}
});
Gtk.waitForStartup();
Gtk.waitForEventsToComplete();
// we have to be able to set our title, otherwise the gnome-shell extension WILL NOT work
Gtk.dispatch(new Runnable() {

View File

@ -61,11 +61,6 @@ class _SwingTray extends Tray implements SwingUI {
"type and configuration");
}
if (OS.isLinux() || OS.isUnix()) {
// linux/unix need access to GTK, so load it up!
Gtk.startGui();
}
// we override various methods, because each tray implementation is SLIGHTLY different. This allows us customization.
final SwingMenu swingMenu = new SwingMenu(null, null) {
@Override
@ -194,17 +189,13 @@ class _SwingTray extends Tray implements SwingUI {
if (OS.isLinux() || OS.isUnix()) {
// does not need to be called on the dispatch (it does that)
// does not need to be called on the dispatch (it does that). Startup happens in the SystemTray (in a special block),
// because we MUST startup the system tray BEFORE to access GTK before we create the swing version (to get size info)
Gtk.shutdownGui();
}
}
};
if (OS.isLinux() || OS.isUnix()) {
// linux/unix need access to GTK, so load it up!
Gtk.waitForStartup();
}
bind(swingMenu, null, systemTray);
}