77228c0200b0dee8e39a9c7e7a2b6f3a1f61dca6
[jalview.git] / src / jalview / bin / HiDPISetting.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.bin;
22
23 import java.awt.HeadlessException;
24 import java.util.Locale;
25
26 public class HiDPISetting
27 {
28   private static final int hidpiThreshold = 160;
29
30   private static final int hidpiMultiThreshold = 240;
31
32   private static final int bigScreenThreshold = 1400;
33
34   public static final String scalePropertyName = "sun.java2d.uiScale";
35
36   private static final boolean isLinux;
37
38   // private static final boolean isAMac;
39
40   // private static final boolean isWindows;
41
42   public static final String setHiDPIPropertyName = "setHiDPI";
43
44   public static final String setHiDPIScalePropertyName = "setHiDPIScale";
45
46   private static boolean setHiDPI = false;
47
48   private static int setHiDPIScale = 0;
49
50   public static int dpi = 0;
51
52   public static int mindimension = 0;
53
54   public static int width = 0;
55
56   public static int scale = 0;
57
58   public final static int MAX_SCALE = 8;
59
60   private static boolean doneInit = false;
61
62   private static boolean allowScalePropertyArg = false;
63
64   private static ScreenInfo screenInfo = new ScreenInfo();
65
66   static
67   {
68     String system = System.getProperty("os.name") == null ? null
69             : System.getProperty("os.name").toLowerCase(Locale.ROOT);
70     if (system != null)
71     {
72       isLinux = system.indexOf("linux") > -1;
73       // isAMac = system.indexOf("mac") > -1;
74       // isWindows = system.indexOf("windows") > -1;
75     }
76     else
77     {
78       isLinux = false;
79       // isAMac = isWindows = false;
80     }
81   }
82
83   private static void init()
84   {
85     if (doneInit)
86     {
87       return;
88     }
89
90     // get and use command line property values first
91     String setHiDPIProperty = System.getProperty(setHiDPIPropertyName);
92     boolean setHiDPIPropertyBool = Boolean.parseBoolean(setHiDPIProperty);
93
94     // allow -DsetHiDPI=false to turn off HiDPI scaling
95     if (setHiDPIProperty != null && !setHiDPIPropertyBool)
96     {
97       clear();
98       doneInit = true;
99       return;
100     }
101
102     setHiDPI = setHiDPIProperty != null && setHiDPIPropertyBool;
103
104     String setHiDPIScaleProperty = System
105             .getProperty(setHiDPIScalePropertyName);
106     if (setHiDPIScaleProperty != null)
107     {
108       try
109       {
110         setHiDPIScale = Integer.parseInt(setHiDPIScaleProperty);
111         // if setHiDPIScale property is validly set and setHiDPI property wasn't
112         // attempted to be set we assume setHiDPIScale to be true
113         if (setHiDPIProperty == null)
114         {
115           setHiDPI = true;
116         }
117       } catch (NumberFormatException e)
118       {
119         System.err.println(setHiDPIScalePropertyName + " property give ("
120                 + setHiDPIScaleProperty + ") but not parseable as integer");
121       }
122     }
123     if (setHiDPI && setHiDPIScale > 0)
124     {
125       setHiDPIScale(setHiDPIScale);
126       return;
127     }
128
129     // check to see if the scale property has already been set by something else
130     // (e.g. the OS)
131     String existingProperty = System.getProperty(scalePropertyName);
132     if (existingProperty != null)
133     {
134       try
135       {
136         int existingPropertyVal = Integer.parseInt(existingProperty);
137         System.out.println("Existing " + scalePropertyName + " is "
138                 + existingPropertyVal);
139         if (existingPropertyVal > 1)
140         {
141           setHiDPIScale(existingPropertyVal);
142           return;
143         }
144       } catch (NumberFormatException e)
145       {
146         System.out.println("Could not convert property " + scalePropertyName
147                 + " vale '" + existingProperty + "' to number");
148       }
149     }
150
151     // Try and auto guess a good scale based on reported DPI (not trustworthy)
152     // and screen resolution (more trustworthy)
153
154     // get screen dpi
155     screenInfo = getScreenInfo();
156     try
157     {
158       dpi = screenInfo.getScreenResolution();
159     } catch (HeadlessException e)
160     {
161       if (isLinux)
162       {
163         System.err
164                 .println("Cannot get screen resolution: " + e.getMessage());
165       }
166     }
167
168     // try and get screen size height and width
169     try
170     {
171       int height = screenInfo.getScreenHeight();
172       int width = screenInfo.getScreenWidth();
173       // using mindimension in case of portrait screens
174       mindimension = Math.min(height, width);
175     } catch (HeadlessException e)
176     {
177       if (isLinux)
178       {
179         System.err.println("Cannot get screen size height and width:"
180                 + e.getMessage());
181       }
182     }
183
184     // attempt at a formula for scaling based on screen dpi and mindimension.
185     // scale will be an integer >=1. This formula is based on some testing and
186     // guesswork!
187
188     // scale based on reported dpi. if dpi>hidpiThreshold then scale=2+multiples
189     // of hidpiMultiThreshold (else scale=1)
190     // (e.g. dpi of 110 scales 1. dpi of 120 scales 2. dpi of 360 scales 3)
191     int dpiScale = (dpi - hidpiThreshold > 0)
192             ? 2 + ((dpi - hidpiThreshold) / hidpiMultiThreshold)
193             : 1;
194
195     int dimensionScale = 1 + (mindimension / bigScreenThreshold);
196
197     // reject outrageous values -- dpiScale in particular could be mistaken
198     if (dpiScale > MAX_SCALE)
199     {
200       dpiScale = 1;
201     }
202     if (dimensionScale > MAX_SCALE)
203     {
204       dimensionScale = 1;
205     }
206
207     // choose larger of dimensionScale or dpiScale (most likely dimensionScale
208     // as dpiScale often misreported)
209     int autoScale = Math.max(dpiScale, dimensionScale);
210
211     // only make an automatic change if scale is changed and other conditions
212     // (OS is linux) apply, or if setHiDPI has been specified
213     if ((autoScale > 1 && isLinux) || setHiDPI)
214     {
215       setHiDPIScale(autoScale);
216       return;
217     }
218
219     // looks like we're not doing any scaling
220     doneInit = true;
221   }
222
223   public static void setHiDPIScale(int s)
224   {
225     scale = s;
226     allowScalePropertyArg = true;
227     doneInit = true;
228   }
229
230   public static String getScalePropertyArg(int s)
231   {
232     return "-D" + scalePropertyName + "=" + String.valueOf(s);
233   }
234
235   public static String getScalePropertyArg()
236   {
237     init();
238     // HiDPI setting. Just looking at Linux to start with. Test with Windows.
239     return allowScalePropertyArg ? getScalePropertyArg(scale) : null;
240   }
241
242   public static void clear()
243   {
244     setHiDPI = false;
245     setHiDPIScale = 0;
246     dpi = 0;
247     mindimension = 0;
248     width = 0;
249     scale = 0;
250     doneInit = false;
251     allowScalePropertyArg = false;
252   }
253
254   public static void setScreenInfo(ScreenInfo si)
255   {
256     screenInfo = si;
257   }
258
259   public static ScreenInfo getScreenInfo()
260   {
261     if (screenInfo == null)
262     {
263       screenInfo = new ScreenInfo();
264     }
265     return screenInfo;
266   }
267 }