JAL-3609 New auto-scale 'formula' for linux HiDPI. Tested to work for UHD screen...
[jalview.git] / src / jalview / bin / HiDPISetting.java
1 package jalview.bin;
2
3 import java.awt.HeadlessException;
4 import java.awt.Toolkit;
5
6 public class HiDPISetting
7 {
8   private static final int hidpiThreshold = 160;
9
10   private static final int hidpiMultiThreshold = 240;
11
12   private static final int bigScreenThreshold = 1400;
13
14   private static final String scalePropertyName = "sun.java2d.uiScale";
15
16   private static final boolean isLinux;
17
18   // private static final boolean isAMac;
19
20   // private static final boolean isWindows;
21
22   public static final String setHiDPIPropertyName = "setHiDPI";
23
24   public static final String setHiDPIScalePropertyName = "setHiDPIScale";
25
26   private static boolean setHiDPI = false;
27
28   private static int setHiDPIScale = 0;
29
30   public static int dpi = 0;
31
32   public static int mindimension = 0;
33
34   public static int width = 0;
35
36   public static int scale = 0;
37
38   private static boolean doneInit = false;
39
40   private static boolean allowScalePropertyArg = false;
41
42   static
43   {
44     String system = System.getProperty("os.name") == null ? null
45             : System.getProperty("os.name").toLowerCase();
46     if (system != null)
47     {
48       isLinux = system.indexOf("linux") > -1;
49       // isAMac = system.indexOf("mac") > -1;
50       // isWindows = system.indexOf("windows") > -1;
51     }
52     else
53     {
54       isLinux = false;
55       // isAMac = isWindows = false;
56     }
57   }
58
59   private static void init()
60   {
61     if (doneInit)
62     {
63       return;
64     }
65
66     // get and use command line property values first
67     String setHiDPIProperty = System.getProperty(setHiDPIPropertyName);
68     setHiDPI = setHiDPIProperty != null
69             && setHiDPIProperty.equalsIgnoreCase("true");
70
71     String setHiDPIScaleProperty = System
72             .getProperty(setHiDPIScalePropertyName);
73     if (setHiDPIScaleProperty != null)
74     {
75       try
76       {
77         setHiDPIScale = Integer.parseInt(setHiDPIScaleProperty);
78       } catch (NumberFormatException e)
79       {
80         System.err.println(setHiDPIScalePropertyName + " property give ("
81                 + setHiDPIScaleProperty + ") but not parseable as integer");
82       }
83     }
84     if (setHiDPI && setHiDPIScale > 0)
85     {
86       setHiDPIScale(setHiDPIScale);
87       return;
88     }
89
90     // check to see if the scale property has already been set by something else
91     // (e.g. the OS)
92     String existingProperty = System.getProperty(scalePropertyName);
93     if (existingProperty != null)
94     {
95       try
96       {
97         int existingPropertyVal = Integer.parseInt(existingProperty);
98         System.out.println("Existing " + scalePropertyName + " is "
99                 + existingPropertyVal);
100         if (existingPropertyVal > 1)
101         {
102           setHiDPIScale(existingPropertyVal);
103           return;
104         }
105       } catch (NumberFormatException e)
106       {
107         System.out.println("Could not convert property " + scalePropertyName
108                 + " vale '" + existingProperty + "' to number");
109       }
110     }
111
112     // Try and auto guess a good scale based on reported DPI (not trustworthy)
113     // and screen resolution (more trustworthy)
114
115     // get screen dpi
116     try
117     {
118       dpi = Toolkit.getDefaultToolkit().getScreenResolution();
119     } catch (HeadlessException e)
120     {
121       System.err.println("Cannot get screen resolution: " + e.getMessage());
122     }
123
124     // try and get screen size height and width
125     try
126     {
127       int height = Toolkit.getDefaultToolkit().getScreenSize().height;
128       int width = Toolkit.getDefaultToolkit().getScreenSize().width;
129       // using mindimension in case of portrait screens
130       mindimension = Math.min(height, width);
131     } catch (HeadlessException e)
132     {
133       System.err.println(
134               "Cannot get screen size height and width:" + e.getMessage());
135     }
136
137     // attempt at a formula for scaling based on screen dpi and mindimension.
138     // scale will be an integer >=1. This formula is based on some testing and
139     // guesswork!
140
141     // scale based on reported dpi. if dpi>hidpiThreshold then scale=2+multiples
142     // of hidpiMultiThreshold (else scale=1)
143     // (e.g. dpi of 110 scales 1. dpi of 120 scales 2. dpi of 360 scales 3)
144     int dpiScale = (dpi - hidpiThreshold > 0)
145             ? 2 + ((dpi - hidpiThreshold) / hidpiMultiThreshold)
146             : 1;
147
148     int dimensionScale = 1 + (mindimension / bigScreenThreshold);
149
150     // choose larger of dimensionScale or dpiScale (most likely dimensionScale
151     // as dpiScale often misreported)
152     int autoScale = Math.max(dpiScale, dimensionScale);
153
154     // only make an automatic change if scale is changed and other conditions
155     // (OS is linux) apply, or if setHiDPI has been specified
156     if ((autoScale > 1 && isLinux) || setHiDPI)
157     {
158       setHiDPIScale(autoScale);
159       return;
160     }
161
162     // looks like we're not doing any scaling
163     doneInit = true;
164   }
165
166   public static void setHiDPIScale(int s)
167   {
168     scale = s;
169     allowScalePropertyArg = true;
170     doneInit = true;
171   }
172
173   public static String getScalePropertyArg()
174   {
175     init();
176     // HiDPI setting. Just looking at Linux to start with. Test with Windows.
177     return allowScalePropertyArg ? "-D" + scalePropertyName + "=" + scale
178             : null;
179   }
180 }