JAL-4409 JAL-4160 Don't let getdown turn jalviewX:// URIs into absolute local file...
[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 import jalview.util.ErrorLog;
27
28 public class HiDPISetting
29 {
30   private static final int hidpiThreshold = 160;
31
32   private static final int hidpiMultiThreshold = 240;
33
34   private static final int bigScreenThreshold = 1400;
35
36   public static final String scalePropertyName = "sun.java2d.uiScale";
37
38   private static final boolean isLinux;
39
40   // private static final boolean isAMac;
41
42   // private static final boolean isWindows;
43
44   public static final String setHiDPIPropertyName = "setHiDPI";
45
46   public static final String setHiDPIScalePropertyName = "setHiDPIScale";
47
48   private static boolean setHiDPI = false;
49
50   private static int setHiDPIScale = 0;
51
52   public static int dpi = 0;
53
54   public static int mindimension = 0;
55
56   public static int width = 0;
57
58   public static int scale = 0;
59
60   public final static int MAX_SCALE = 8;
61
62   private static boolean doneInit = false;
63
64   private static boolean allowScalePropertyArg = false;
65
66   private static ScreenInfo screenInfo = new ScreenInfo();
67
68   static
69   {
70     String system = System.getProperty("os.name") == null ? null
71             : System.getProperty("os.name").toLowerCase(Locale.ROOT);
72     if (system != null)
73     {
74       isLinux = system.indexOf("linux") > -1;
75       // isAMac = system.indexOf("mac") > -1;
76       // isWindows = system.indexOf("windows") > -1;
77     }
78     else
79     {
80       isLinux = false;
81       // isAMac = isWindows = false;
82     }
83   }
84
85   private static void init()
86   {
87     if (doneInit)
88     {
89       return;
90     }
91
92     // get and use command line property values first
93     String setHiDPIProperty = System.getProperty(setHiDPIPropertyName);
94     boolean setHiDPIPropertyBool = Boolean.parseBoolean(setHiDPIProperty);
95
96     // allow -DsetHiDPI=false to turn off HiDPI scaling
97     if (setHiDPIProperty != null && !setHiDPIPropertyBool)
98     {
99       clear();
100       doneInit = true;
101       return;
102     }
103
104     setHiDPI = setHiDPIProperty != null && setHiDPIPropertyBool;
105
106     String setHiDPIScaleProperty = System
107             .getProperty(setHiDPIScalePropertyName);
108     if (setHiDPIScaleProperty != null)
109     {
110       try
111       {
112         setHiDPIScale = Integer.parseInt(setHiDPIScaleProperty);
113         // if setHiDPIScale property is validly set and setHiDPI property wasn't
114         // attempted to be set we assume setHiDPIScale to be true
115         if (setHiDPIProperty == null)
116         {
117           setHiDPI = true;
118         }
119       } catch (NumberFormatException e)
120       {
121         ErrorLog.errPrintln(setHiDPIScalePropertyName + " property give ("
122                 + setHiDPIScaleProperty + ") but not parseable as integer");
123       }
124     }
125     if (setHiDPI && setHiDPIScale > 0)
126     {
127       setHiDPIScale(setHiDPIScale);
128       return;
129     }
130
131     // check to see if the scale property has already been set by something else
132     // (e.g. the OS)
133     String existingProperty = System.getProperty(scalePropertyName);
134     if (existingProperty != null)
135     {
136       try
137       {
138         int existingPropertyVal = Integer.parseInt(existingProperty);
139         ErrorLog.outPrintln("Existing " + scalePropertyName + " is "
140                 + existingPropertyVal);
141         if (existingPropertyVal > 1)
142         {
143           setHiDPIScale(existingPropertyVal);
144           return;
145         }
146       } catch (NumberFormatException e)
147       {
148         ErrorLog.outPrintln(
149                 "Could not convert property " + scalePropertyName
150                         + " vale '" + existingProperty + "' to number");
151       }
152     }
153
154     // Try and auto guess a good scale based on reported DPI (not trustworthy)
155     // and screen resolution (more trustworthy)
156
157     // get screen dpi
158     screenInfo = getScreenInfo();
159     try
160     {
161       dpi = screenInfo.getScreenResolution();
162     } catch (HeadlessException e)
163     {
164       if (isLinux)
165       {
166         ErrorLog.errPrintln(
167                 "Cannot get screen resolution: " + e.getMessage());
168       }
169     }
170
171     // try and get screen size height and width
172     try
173     {
174       int height = screenInfo.getScreenHeight();
175       int width = screenInfo.getScreenWidth();
176       // using mindimension in case of portrait screens
177       mindimension = Math.min(height, width);
178     } catch (HeadlessException e)
179     {
180       if (isLinux)
181       {
182         ErrorLog.errPrintln("Cannot get screen size height and width:"
183                 + e.getMessage());
184       }
185     }
186
187     // attempt at a formula for scaling based on screen dpi and mindimension.
188     // scale will be an integer >=1. This formula is based on some testing and
189     // guesswork!
190
191     // scale based on reported dpi. if dpi>hidpiThreshold then scale=2+multiples
192     // of hidpiMultiThreshold (else scale=1)
193     // (e.g. dpi of 110 scales 1. dpi of 120 scales 2. dpi of 360 scales 3)
194     int dpiScale = (dpi - hidpiThreshold > 0)
195             ? 2 + ((dpi - hidpiThreshold) / hidpiMultiThreshold)
196             : 1;
197
198     int dimensionScale = 1 + (mindimension / bigScreenThreshold);
199
200     // reject outrageous values -- dpiScale in particular could be mistaken
201     if (dpiScale > MAX_SCALE)
202     {
203       dpiScale = 1;
204     }
205     if (dimensionScale > MAX_SCALE)
206     {
207       dimensionScale = 1;
208     }
209
210     // choose larger of dimensionScale or dpiScale (most likely dimensionScale
211     // as dpiScale often misreported)
212     int autoScale = Math.max(dpiScale, dimensionScale);
213
214     // only make an automatic change if scale is changed and other conditions
215     // (OS is linux) apply, or if setHiDPI has been specified
216     if ((autoScale > 1 && isLinux) || setHiDPI)
217     {
218       setHiDPIScale(autoScale);
219       return;
220     }
221
222     // looks like we're not doing any scaling
223     doneInit = true;
224   }
225
226   public static void setHiDPIScale(int s)
227   {
228     scale = s;
229     allowScalePropertyArg = true;
230     doneInit = true;
231   }
232
233   public static String getScalePropertyArg(int s)
234   {
235     return "-D" + scalePropertyName + "=" + String.valueOf(s);
236   }
237
238   public static String getScalePropertyArg()
239   {
240     init();
241     // HiDPI setting. Just looking at Linux to start with. Test with Windows.
242     return allowScalePropertyArg ? getScalePropertyArg(scale) : null;
243   }
244
245   public static void clear()
246   {
247     setHiDPI = false;
248     setHiDPIScale = 0;
249     dpi = 0;
250     mindimension = 0;
251     width = 0;
252     scale = 0;
253     doneInit = false;
254     allowScalePropertyArg = false;
255   }
256
257   public static void setScreenInfo(ScreenInfo si)
258   {
259     screenInfo = si;
260   }
261
262   public static ScreenInfo getScreenInfo()
263   {
264     if (screenInfo == null)
265     {
266       screenInfo = new ScreenInfo();
267     }
268     return screenInfo;
269   }
270 }