Merge branch 'merge/develop_and_rebase_squashed_merge_JAL-3628+JAL-3608+JAL-3609...
authorBen Soares <b.soares@dundee.ac.uk>
Tue, 8 Dec 2020 20:42:31 +0000 (20:42 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Tue, 8 Dec 2020 20:42:31 +0000 (20:42 +0000)
1  2 
build.gradle
src/jalview/bin/Jalview.java
src/jalview/bin/Launcher.java
src/jalview/gui/Desktop.java

diff --combined build.gradle
@@@ -57,13 -57,24 +57,13 @@@ def string(Object o) 
    return o == null ? "" : o.toString()
  }
  
 -
 -ext {
 -  jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
 -  jalviewDirRelativePath = jalviewDir
 -
 -  // local build environment properties
 -  // can be "projectDir/local.properties"
 -  def localProps = "${projectDir}/local.properties"
 -  def propsFile = null;
 -  if (file(localProps).exists()) {
 -    propsFile = localProps
 +def overrideProperties(String propsFileName, boolean output = false) {
 +  if (propsFileName == null) {
 +    return
    }
 -  // or "../projectDir_local.properties"
 -  def dirLocalProps = projectDir.getParent() + "/" + projectDir.getName() + "_local.properties"
 -  if (file(dirLocalProps).exists()) {
 -    propsFile = dirLocalProps
 -  }
 -  if (propsFile != null) {
 +  def propsFile = file(propsFileName)
 +  if (propsFile != null && propsFile.exists()) {
 +    println("Using properties from file '${propsFileName}'")
      try {
        def p = new Properties()
        def localPropsFIS = new FileInputStream(propsFile)
        localPropsFIS.close()
        p.each {
          key, val -> 
 -          def oldval = findProperty(key)
 -          setProperty(key, val)
 -          if (oldval != null) {
 -            println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
 +          def oldval
 +          if (project.hasProperty(key)) {
 +            oldval = project.findProperty(key)
 +            project.setProperty(key, val)
 +            if (output) {
 +              println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
 +            }
            } else {
 -            println("Setting unknown property '${key}' with ${file(propsFile).getName()}s value '${val}'")
 +            ext.setProperty(key, val)
 +            if (output) {
 +              println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
 +            }
            }
        }
      } catch (Exception e) {
 -      System.out.println("Exception reading local.properties")
 +      println("Exception reading local.properties")
 +      e.printStackTrace()
      }
    }
 +}
 +
 +ext {
 +  jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
 +  jalviewDirRelativePath = jalviewDir
 +
 +  getdownChannelName = CHANNEL.toLowerCase()
 +  // default to "default". Currently only has different cosmetics for "develop", "release", "default"
 +  propertiesChannelName = ["develop", "release", "test-release"].contains(getdownChannelName) ? getdownChannelName : "default"
 +  // Import channel_properties
 +  channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
 +  channelGradleProperties = string("${channelDir}/channel_gradle.properties")
 +  overrideProperties(channelGradleProperties, false)
 +  // local build environment properties
 +  // can be "projectDir/local.properties"
 +  overrideProperties("${projectDir}/local.properties", true)
 +  // or "../projectDir_local.properties"
 +  overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
  
    ////  
    // Import releaseProps from the RELEASE file
  
    getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
    buildDist = true
 +  buildProperties = null
  
    // the following values might be overridden by the CHANNEL switch
 -  getdownChannelName = CHANNEL.toLowerCase()
    getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
    getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
    getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
    getdownAppDistDir = getdown_app_dir_alt
 +  getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
    reportRsyncCommand = false
    jvlChannelName = CHANNEL.toLowerCase()
    install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
 -  install4jDSStore = "DS_Store-NON-RELEASE"
 -  install4jDMGBackgroundImage = "jalview_dmg_background-NON-RELEASE.png"
 +  install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
 +  install4jDMGBackgroundImage = "${install4j_images_dir}/${install4j_dmg_background}"
    install4jInstallerName = "${jalview_name} Non-Release Installer"
    install4jExecutableName = jalview_name.replaceAll("[^\\w]+", "_").toLowerCase()
    install4jExtraScheme = "jalviewx"
 +  install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
 +  install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
 +  install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
 +  install4jBackground = string("${install4j_images_dir}/${install4j_background}")
    switch (CHANNEL) {
  
      case "BUILD":
      getdownAppDistDir = getdown_app_dir_release
      reportRsyncCommand = true
      install4jSuffix = ""
 -    install4jDSStore = "DS_Store"
 -    install4jDMGBackgroundImage = "jalview_dmg_background.png"
      install4jInstallerName = "${jalview_name} Installer"
      break
  
      // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
      JALVIEW_VERSION=JALVIEW_VERSION+"-develop"
      
 -    channelPropertiesFile = string("${channel_properties_dir}/develop_properties")
 -    getdownImagesDir = "${getdown_images_dir}/develop"
 -    getdownBgColour = "000000"
 -    getdownFgColour = "FFFFFF"
 -    getdownLightFgColour = "CCCCFF"
      install4jSuffix = "Develop"
 -    install4jDSStore = "DS_Store-DEVELOP"
 -    install4jDMGBackgroundImage = "jalview_dmg_background-DEVELOP.png"
      install4jExtraScheme = "jalviewd"
      install4jInstallerName = "${jalview_name} Develop Installer"
 -    install4jMacIconsFile = string("${install4j_utils_dir}/develop/${install4j_mac_icons_file}")
 -    install4jWindowsIconsFile = string("${install4j_utils_dir}/develop/${install4j_windows_icons_file}")
 -    install4jPngIconFile = string("${install4j_utils_dir}/develop/${install4j_png_icon_file}")
      break
  
      case "TEST-RELEASE":
      }
      JALVIEW_VERSION = JALVIEW_VERSION+"-test"
      install4jSuffix = "Test"
 -    install4jDSStore = "DS_Store-TEST-RELEASE"
 -    install4jDMGBackgroundImage = "jalview_dmg_background-TEST.png"
      install4jExtraScheme = "jalviewt"
      install4jInstallerName = "${jalview_name} Test Installer"
      break
      }
      JALVIEW_VERSION = "TEST"
      install4jSuffix = "Test-Local"
 -    install4jDSStore = "DS_Store-TEST-RELEASE"
 -    install4jDMGBackgroundImage = "jalview_dmg_background-TEST.png"
      install4jExtraScheme = "jalviewt"
      install4jInstallerName = "${jalview_name} Test Installer"
      break
    }
    // override getdownAppBase if requested
    if (findProperty("getdown_appbase_override") != null) {
 -    getdownAppBase = string(getProperty("getdown_appbase_override"))
 +    // revert to LOCAL if empty string
 +    if (string(getdown_appbase_override) == "") {
 +      getdownAppBase = file(getdownWebsiteDir).toURI().toString()
 +      getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
 +    } else {
 +      getdownAppBase = string(getdown_appbase_override)
 +    }
      println("Overriding getdown appbase with '${getdownAppBase}'")
    }
    // sanitise file name for jalview launcher file for this channel
    helpBuildDir = string("${resourceBuildDir}/help_build")
    docBuildDir = string("${resourceBuildDir}/doc_build")
  
 -  buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
 +  if (buildProperties == null) {
 +    buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
 +  }
    buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
    helpParentDir = string("${jalviewDir}/${help_parent_dir}")
    helpSourceDir = string("${helpParentDir}/${help_dir}")
@@@ -1188,9 -1177,6 +1188,9 @@@ task copyHelp(type: Copy) 
  
  
  task copyResources(type: Copy) {
 +  group = "build"
 +  description = "Copy (and make text substitutions in) the resources dir to the build area"
 +
    def inputDir = resourceDir
    def outputDir = resourcesBuildDir
    from(inputDir) {
    outputs.dir(outputDir)
  }
  
 +task copyChannelResources(type: Copy) {
 +  dependsOn copyResources
 +  group = "build"
 +  description = "Copy the channel resources dir to the build resources area"
 +
 +  def inputDir = "${channelDir}/${resource_dir}"
 +  def outputDir = resourcesBuildDir
 +  from inputDir
 +  into outputDir
 +
 +  inputs.dir(inputDir)
 +  outputs.dir(outputDir)
 +}
  
  task createBuildProperties(type: WriteProperties) {
    dependsOn copyResources
@@@ -1270,12 -1243,12 +1270,12 @@@ task buildIndices(type: JavaExec) 
    outputs.file("${workingDir}/JavaHelpSearch/TMAP")
  }
  
 -
  task prepare {
    dependsOn copyResources
    dependsOn copyDocs
    dependsOn copyHelp
    dependsOn createBuildProperties
 +  dependsOn copyChannelResources
    dependsOn convertMdFiles
    dependsOn buildIndices
  }
@@@ -1311,6 -1284,11 +1311,11 @@@ test 
      println("Setting Test LaF to '${testLaf}'")
      systemProperty "laf", testLaf
    }
+   def testHiDPIScale = project.findProperty("test_HiDPIScale")
+   if (testHiDPIScale != null) {
+     println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
+     systemProperty "sun.java2d.uiScale", testHiDPIScale
+   }
    sourceCompatibility = compile_source_compatibility
    targetCompatibility = compile_target_compatibility
    jvmArgs += additional_compiler_args
@@@ -1385,8 -1363,8 +1390,8 @@@ jar 
      "Implementation-Version": JALVIEW_VERSION
    }
  
 -  def distDir = "${jalviewDir}/${package_dir}"
 -  destinationDirectory = file(distDir)
 +  def outputDir = "${jalviewDir}/${package_dir}"
 +  destinationDirectory = file(outputDir)
    archiveFileName = rootProject.name+".jar"
  
    exclude "cache*/**"
    sourceSets.main.resources.srcDirs.each{ dir ->
      inputs.dir(dir)
    }
 -  outputs.file("${distDir}/${archiveFileName}")
 +  outputs.file("${outputDir}/${archiveFileName}")
  }
  
  
@@@ -1495,14 -1473,6 +1500,14 @@@ task getdownWebsite() 
      if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
        props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
      }
 +    if (getdownImagesDir != null && file(getdownImagesDir).exists()) {
 +      props.put("getdown_txt_ui.background_image", "${getdownImagesDir}/${getdown_background_image}")
 +      props.put("getdown_txt_ui.instant_background_image", "${getdownImagesDir}/${getdown_instant_background_image}")
 +      props.put("getdown_txt_ui.error_background", "${getdownImagesDir}/${getdown_error_background}")
 +      props.put("getdown_txt_ui.progress_image", "${getdownImagesDir}/${getdown_progress_image}")
 +      props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
 +      props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
 +    }
  
      props.put("getdown_txt_title", jalview_name)
      props.put("getdown_txt_ui.name", install4jApplicationName)
@@@ -1870,7 -1840,7 +1875,7 @@@ task installers(type: com.install4j.gra
      'BUNDLE_ID': install4jBundleId,
      'INTERNAL_ID': install4jInternalId,
      'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
 -    'MACOS_DS_STORE': install4jDSStore,
 +    'MACOS_DMG_DS_STORE': install4jDMGDSStore,
      'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
      'INSTALLER_NAME': install4jInstallerName,
      'INSTALL4J_UTILS_DIR': install4j_utils_dir,
      'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
      'EXECUTABLE_NAME': install4jExecutableName,
      'EXTRA_SCHEME': install4jExtraScheme,
 +    'MAC_ICONS_FILE': install4jMacIconsFile,
 +    'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
 +    'PNG_ICON_FILE': install4jPngIconFile,
 +    'BACKGROUND': install4jBackground,
 +
    ]
  
    //println("INSTALL4J VARIABLES:")
@@@ -68,7 -68,7 +68,8 @@@ import jalview.io.NewickFile
  import jalview.io.gff.SequenceOntologyFactory;
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemeProperty;
 +import jalview.util.ChannelProperties;
+ import jalview.util.HttpUtils;
  import jalview.util.MessageManager;
  import jalview.util.Platform;
  import jalview.ws.jws2.Jws2Discoverer;
@@@ -95,8 -95,9 +96,9 @@@ public class Jalvie
      Platform.getURLCommandArguments();
    }
  
-   // singleton instance of this class
+   /*
+    * singleton instance of this class
+    */
    private static Jalview instance;
  
    private Desktop desktop;
                    "Invalid jabaws parameter: " + jabawsUrl + " ignored");
          }
        }
      }
      String defs = aparser.getValue("setprop");
      while (defs != null)
      {
          {
            Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
          }
+         // DISABLED FOR SECURITY REASONS
+         // TODO: add a property to allow properties to be overriden by cli args
+         // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
        }
        defs = aparser.getValue("setprop");
      }
  
      desktop = null;
  
-     // property laf = "crossplatform", "system", "gtk", "metal" or "mac"
-     // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
-     // try Quaqua/Vaqua.
-     String lafProp = System.getProperty("laf");
-     String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
-     String laf = "none";
-     if (lafProp != null)
-     {
-       laf = lafProp;
-     }
-     else if (lafSetting != null)
-     {
-       laf = lafSetting;
-     }
-     boolean lafSet = false;
-     switch (laf)
-     {
-     case "crossplatform":
-       lafSet = setCrossPlatformLookAndFeel();
-       if (!lafSet)
-       {
-         System.err.println("Could not set requested laf=" + laf);
-       }
-       break;
-     case "system":
-       lafSet = setSystemLookAndFeel();
-       if (!lafSet)
-       {
-         System.err.println("Could not set requested laf=" + laf);
-       }
-       break;
-     case "gtk":
-       lafSet = setGtkLookAndFeel();
-     {
-       System.err.println("Could not set requested laf=" + laf);
-     }
-       break;
-     case "metal":
-       lafSet = setMetalLookAndFeel();
-     {
-       System.err.println("Could not set requested laf=" + laf);
-     }
-       break;
-     case "nimbus":
-       lafSet = setNimbusLookAndFeel();
-     {
-       System.err.println("Could not set requested laf=" + laf);
-     }
-       break;
-     case "quaqua":
-       lafSet = setQuaquaLookAndFeel();
-     {
-       System.err.println("Could not set requested laf=" + laf);
-     }
-       break;
-     case "vaqua":
-       lafSet = setVaquaLookAndFeel();
-     {
-       System.err.println("Could not set requested laf=" + laf);
-     }
-       break;
-     case "mac":
-       lafSet = setMacLookAndFeel();
-       if (!lafSet)
-       {
-         System.err.println("Could not set requested laf=" + laf);
-       }
-       break;
-     case "none":
-       break;
-     default:
-       System.err.println("Requested laf=" + laf + " not implemented");
-     }
-     if (!lafSet)
-     {
-       setSystemLookAndFeel();
-       if (Platform.isLinux() && !Platform.isJS())
-       {
-         setMetalLookAndFeel();
-       }
-       if (Platform.isAMacAndNotJS())
-       {
-         setMacLookAndFeel();
-       }
-     }
+     setLookAndFeel();
  
      /*
       * configure 'full' SO model if preferences say to, else use the default (full SO)
  
      if (!headless)
      {
+       Desktop.nosplash = aparser.contains("nosplash");
        desktop = new Desktop();
        desktop.setInBatchMode(true); // indicate we are starting up
  
        try
        {
          JalviewTaskbar.setTaskbar(this);
+       } catch (Exception e)
+       {
+         Cache.log.info("Cannot set Taskbar");
+         Cache.log.error(e.getMessage());
+         // e.printStackTrace();
        } catch (Throwable t)
        {
-         System.out.println("Error setting Taskbar: " + t.getMessage());
+         Cache.log.info("Cannot set Taskbar");
+         Cache.log.error(t.getMessage());
+         // t.printStackTrace();
        }
  
+       // set Proxy settings before all the internet calls
+       Cache.setProxyPropertiesFromPreferences();
        desktop.setVisible(true);
  
        if (!Platform.isJS())
         * @j2sIgnore
         */
        {
-         desktop.startServiceDiscovery();
+         if (!aparser.contains("nowebservicediscovery"))
+         {
+           desktop.startServiceDiscovery();
+         }
          if (!aparser.contains("nousagestats"))
          {
            startUsageStats(desktop);
         * @j2sIgnore
         */
        {
-         if (!file.startsWith("http://") && !file.startsWith("https://"))
-         // BH 2019 added https check for Java
+         if (!HttpUtils.startsWithHttpOrHttps(file))
          {
            if (!(new File(file)).exists())
            {
          Cache.removeProperty("STARTUP_FILE");
        }
  
-       protocol = DataSourceType.FILE;
-       if (file.indexOf("http:") > -1)
-       {
-         protocol = DataSourceType.URL;
-       }
+       protocol = AppletFormatAdapter.checkProtocol(file);
  
        if (file.endsWith(".jar"))
        {
      }
    }
  
-   private static boolean setCrossPlatformLookAndFeel()
+   private static void setLookAndFeel()
    {
-     return setGenericLookAndFeel(false);
+     // property laf = "crossplatform", "system", "gtk", "metal", "nimbus" or
+     // "mac"
+     // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
+     // try Quaqua/Vaqua.
+     String lafProp = System.getProperty("laf");
+     String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
+     String laf = "none";
+     if (lafProp != null)
+     {
+       laf = lafProp;
+     }
+     else if (lafSetting != null)
+     {
+       laf = lafSetting;
+     }
+     boolean lafSet = false;
+     switch (laf)
+     {
+     case "crossplatform":
+       lafSet = setCrossPlatformLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "system":
+       lafSet = setSystemLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "gtk":
+       lafSet = setGtkLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "metal":
+       lafSet = setMetalLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "nimbus":
+       lafSet = setNimbusLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "quaqua":
+       lafSet = setQuaquaLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "vaqua":
+       lafSet = setVaquaLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "mac":
+       lafSet = setMacLookAndFeel();
+       if (!lafSet)
+       {
+         Cache.log.error("Could not set requested laf=" + laf);
+       }
+       break;
+     case "none":
+       break;
+     default:
+       Cache.log.error("Requested laf=" + laf + " not implemented");
+     }
+     if (!lafSet)
+     {
+       setSystemLookAndFeel();
+       if (Platform.isLinux())
+       {
+         setMetalLookAndFeel();
+       }
+       if (Platform.isMac())
+       {
+         setMacLookAndFeel();
+       }
+     }
    }
  
-   private static boolean setSystemLookAndFeel()
+   private static boolean setCrossPlatformLookAndFeel()
    {
-     return setGenericLookAndFeel(true);
+     boolean set = false;
+     try
+     {
+       UIManager.setLookAndFeel(
+               UIManager.getCrossPlatformLookAndFeelClassName());
+       set = true;
+     } catch (Exception ex)
+     {
+       Cache.log.error("Unexpected Look and Feel Exception");
+       Cache.log.error(ex.getMessage());
+       Cache.log.debug(Cache.getStackTraceString(ex));
+     }
+     return set;
    }
  
-   private static boolean setGenericLookAndFeel(boolean system)
+   private static boolean setSystemLookAndFeel()
    {
      boolean set = false;
      try
      {
-       UIManager.setLookAndFeel(
-               system ? UIManager.getSystemLookAndFeelClassName()
-                       : UIManager.getCrossPlatformLookAndFeelClassName());
+       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        set = true;
      } catch (Exception ex)
      {
-       System.err.println("Unexpected Look and Feel Exception");
-       ex.printStackTrace();
+       Cache.log.error("Unexpected Look and Feel Exception");
+       Cache.log.error(ex.getMessage());
+       Cache.log.debug(Cache.getStackTraceString(ex));
      }
      return set;
    }
        set = true;
      } catch (Exception ex)
      {
-       System.err.println("Unexpected Look and Feel Exception");
-       ex.printStackTrace();
+       Cache.log.error("Unexpected Look and Feel Exception");
+       Cache.log.error(ex.getMessage());
+       Cache.log.debug(Cache.getStackTraceString(ex));
      }
      return set;
    }
    {
      boolean set = false;
      System.setProperty("com.apple.mrj.application.apple.menu.about.name",
 -            "Jalview");
 +            ChannelProperties.getProperty("app_name"));
      System.setProperty("apple.laf.useScreenMenuBar", "true");
      set = setQuaquaLookAndFeel();
      if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
                      + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
                      + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
                      + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n"
 +                    + "-jvmmempc=PERCENT\tOnly available with standalone executable jar or jalview.bin.Launcher. Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected. See https://www.jalview.org/help/html/memory.html for more details.\n"
 +                    + "-jvmmemmax=MAXMEMORY\tOnly available with standalone executable jar or jalview.bin.Launcher. Limit maximum heap size (memory) to MAXMEMORY. MAXMEMORY can be specified in bytes, kilobytes(k), megabytes(m), gigabytes(g) or if you're lucky enough, terabytes(t). This defaults to 32g if total physical memory can be detected, or to 8g if total physical memory cannot be detected. See https://www.jalview.org/help/html/memory.html for more details.\n"
                      + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
    }
  
@@@ -26,8 -26,6 +26,8 @@@ import java.lang.management.ManagementF
  import java.util.ArrayList;
  import java.util.List;
  
 +import jalview.util.ChannelProperties;
 +
  /**
   * A Launcher class for Jalview. This class is used to launch Jalview from the
   * shadowJar when Getdown is not used or available. It attempts to take all the
@@@ -47,8 -45,7 +47,8 @@@ public class Launche
  {
    private final static String startClass = "jalview.bin.Jalview";
  
 -  private final static String dockIconPath = "JalviewLogo_Huge.png";
 +  private final static String dockIconPath = ChannelProperties
 +          .getProperty("logo.512");
  
    /**
     * main method for jalview.bin.Launcher. This restarts the same JRE's JVM with
        {
          // -Xdock:name=... doesn't actually work :(
          // Leaving it in in case it gets fixed
 -        command.add("-Xdock:name=" + "Jalview");
 +        command.add(
 +                "-Xdock:name=" + ChannelProperties.getProperty("app_name"));
        }
      }
  
      String scalePropertyArg = HiDPISetting.getScalePropertyArg();
      if (scalePropertyArg != null)
      {
+       System.out.println("Running " + startClass + " with scale setting "
+               + scalePropertyArg);
        command.add(scalePropertyArg);
      }
  
  
      final ProcessBuilder builder = new ProcessBuilder(command);
  
 -    // System.out.println("COMMAND: " + String.join(" ", builder.command()));
 +    if (Boolean.parseBoolean(System.getProperty("launcherprint", "false")))
 +    {
 +      System.out.println(
 +              "LAUNCHER COMMAND: " + String.join(" ", builder.command()));
 +    }
      System.out.println("Running " + startClass + " with "
-             + (memSetting == null ? "no memory setting" : memSetting));
+             + (memSetting == null ? "no memory setting"
+                     : ("memory setting " + memSetting)));
  
 -    if (Boolean.parseBoolean(System.getProperty("launcherstop")))
 +    if (Boolean.parseBoolean(System.getProperty("launcherstop", "false")))
      {
        System.exit(0);
      }
@@@ -25,6 -25,7 +25,7 @@@ import java.awt.Color
  import java.awt.Dimension;
  import java.awt.FontMetrics;
  import java.awt.Graphics;
+ import java.awt.Graphics2D;
  import java.awt.GridLayout;
  import java.awt.Point;
  import java.awt.Rectangle;
@@@ -47,6 -48,7 +48,7 @@@ import java.awt.event.MouseAdapter
  import java.awt.event.MouseEvent;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
+ import java.awt.geom.AffineTransform;
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  import java.io.File;
@@@ -114,7 -116,6 +116,7 @@@ import jalview.project.Jalview2XML
  import jalview.structure.StructureSelectionManager;
  import jalview.urls.IdOrgSettings;
  import jalview.util.BrowserLauncher;
 +import jalview.util.ChannelProperties;
  import jalview.util.ImageMaker.TYPE;
  import jalview.util.MessageManager;
  import jalview.util.Platform;
@@@ -160,6 -161,8 +162,8 @@@ public class Desktop extends jalview.jb
  
    private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
  
+   public static boolean nosplash = false;
    /**
     * news reader - null if it was never started.
     */
      instance = this;
  
      doConfigureStructurePrefs();
 -    setTitle("Jalview " + Cache.getProperty("VERSION"));
 +    setTitle(ChannelProperties.getProperty("app_name") + " "
 +            + Cache.getProperty("VERSION"));
      /*
      if (!Platform.isAMac())
      {
        checkURLLinks();
  
        // Spawn a thread that shows the splashscreen
-       SwingUtilities.invokeLater(new Runnable()
+       if (!nosplash)
        {
-         @Override
-         public void run()
+         SwingUtilities.invokeLater(new Runnable()
          {
-           new SplashScreen(true);
-         }
-       });
+           @Override
+           public void run()
+           {
+             new SplashScreen(true);
+           }
+         });
+       }
  
        // Thread off a new instance of the file chooser - this reduces the time
        // it
        }
      });
      desktop.addMouseListener(ma);
    }
  
    /**
    @Override
    protected void preferences_actionPerformed(ActionEvent e)
    {
-     new Preferences();
+     Preferences.openPreferences();
    }
  
    /**
                    10, getHeight() - fm.getHeight());
          }
        }
+       // output debug scale message. Important for jalview.bin.HiDPISettingTest2
+       Desktop.debugScaleMessage(Desktop.getDesktop().getGraphics());
      }
    }
  
      }
      return result;
    }
+   public static final String debugScaleMessage = "Desktop graphics transform scale=";
+   private static boolean debugScaleMessageDone = false;
+   public static void debugScaleMessage(Graphics g)
+   {
+     if (debugScaleMessageDone)
+     {
+       return;
+     }
+     // output used by tests to check HiDPI scaling settings in action
+     try
+     {
+       Graphics2D gg = (Graphics2D) g;
+       if (gg != null)
+       {
+         AffineTransform t = gg.getTransform();
+         double scaleX = t.getScaleX();
+         double scaleY = t.getScaleY();
+         Cache.debug(debugScaleMessage + scaleX + " (X)");
+         Cache.debug(debugScaleMessage + scaleY + " (Y)");
+         debugScaleMessageDone = true;
+       }
+       else
+       {
+         Cache.debug("Desktop graphics null");
+       }
+     } catch (Exception e)
+     {
+       Cache.debug(Cache.getStackTraceString(e));
+     }
+   }
  }