JAL-3251 On linux set (sun.awt.X11.XToolkit.)awtAppClassName to set the grouped appli...
authorBen Soares <b.soares@dundee.ac.uk>
Wed, 10 Feb 2021 17:19:31 +0000 (17:19 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Wed, 10 Feb 2021 17:19:31 +0000 (17:19 +0000)
src/jalview/gui/Desktop.java

index abe1fad..195a313 100644 (file)
@@ -54,8 +54,10 @@ import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
@@ -394,24 +396,61 @@ public class Desktop extends jalview.jbgui.GDesktop
     doConfigureStructurePrefs();
     setTitle(ChannelProperties.getProperty("app_name") + " "
             + Cache.getProperty("VERSION"));
-    /*
-    if (!Platform.isAMac())
-    {
-      // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
-    }
-    else
+
+    /**
+     * Set taskbar "grouped windows" name for linux desktops (works in GNOME and KDE).
+     * This uses sun.awt.X11.XToolkit.awtAppClassName which is not officially documented or
+     * guaranteed to exist, so we access it via reflection.
+     * There appear to be unfathomable criteria about what this string can contain, and it if doesn't
+     * meet those criteria then "java" (KDE) or "jalview-bin-Jalview" (GNOME) is used.
+     * "Jalview", "Jalview Develop" and "Jalview Test" seem okay, but "Jalview non-release" does not.
+     * The reflection access may generate a warning:
+     * WARNING: An illegal reflective access operation has occurred
+     * WARNING: Illegal reflective access by jalview.gui.Desktop () to field sun.awt.X11.XToolkit.awtAppClassName
+     * which I don't think can be avoided.
+     */
+    if (Platform.isLinux())
     {
-     this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+      try
+      {
+        Toolkit xToolkit = Toolkit.getDefaultToolkit();
+        Field[] declaredFields = xToolkit.getClass().getDeclaredFields();
+        Field awtAppClassNameField = null;
+
+        if (Arrays.stream(declaredFields).anyMatch(f -> f.getName().equals("awtAppClassName")))
+        {
+          awtAppClassNameField = xToolkit.getClass()
+                  .getDeclaredField("awtAppClassName");
+        }
+
+        String title = ChannelProperties.getProperty("app_name");
+        if (awtAppClassNameField != null)
+        {
+          awtAppClassNameField.setAccessible(true);
+          awtAppClassNameField.set(xToolkit, title);
+        }
+        else
+        {
+          Cache.log.debug("XToolkit: awtAppClassName not found");
+        }
+      } catch (Exception e)
+      {
+        Cache.debug("Error setting awtAppClassName");
+        Cache.trace(Cache.getStackTraceString(e));
+      }
     }
-    */
 
+    /**
+     * APQHandlers sets handlers for About, Preferences and Quit actions peculiar to macOS's application menu.
+     * APQHandlers will check to see if a handler is supported before setting it.
+     */
     try
     {
       APQHandlers.setAPQHandlers(this);
     } catch (Throwable t)
     {
-      System.out.println("Error setting APQHandlers: " + t.toString());
-      // t.printStackTrace();
+      Cache.warn("Error setting APQHandlers: " + t.toString());
+      Cache.trace(Cache.getStackTraceString(t));
     }
     setIconImages(ChannelProperties.getIconList());