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