e14c032b61930cb94b4b958826c38db60591b2c5
[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         jalview.bin.Console.errPrintln(setHiDPIScalePropertyName
120                 + " property give (" + setHiDPIScaleProperty
121                 + ") but not parseable as integer");
122       }
123     }
124     if (setHiDPI && setHiDPIScale > 0)
125     {
126       setHiDPIScale(setHiDPIScale);
127       return;
128     }
129
130     // check to see if the scale property has already been set by something else
131     // (e.g. the OS)
132     String existingProperty = System.getProperty(scalePropertyName);
133     if (existingProperty != null)
134     {
135       try
136       {
137         int existingPropertyVal = Integer.parseInt(existingProperty);
138         jalview.bin.Console.outPrintln("Existing " + scalePropertyName
139                 + " is " + existingPropertyVal);
140         if (existingPropertyVal > 1)
141         {
142           setHiDPIScale(existingPropertyVal);
143           return;
144         }
145       } catch (NumberFormatException e)
146       {
147         jalview.bin.Console.outPrintln(
148                 "Could not convert property " + scalePropertyName
149                         + " vale '" + existingProperty + "' to number");
150       }
151     }
152
153     // Try and auto guess a good scale based on reported DPI (not trustworthy)
154     // and screen resolution (more trustworthy)
155
156     // get screen dpi
157     screenInfo = getScreenInfo();
158     try
159     {
160       dpi = screenInfo.getScreenResolution();
161     } catch (HeadlessException e)
162     {
163       if (isLinux)
164       {
165         jalview.bin.Console.errPrintln(
166                 "Cannot get screen resolution: " + e.getMessage());
167       }
168     }
169
170     // try and get screen size height and width
171     try
172     {
173       int height = screenInfo.getScreenHeight();
174       int width = screenInfo.getScreenWidth();
175       // using mindimension in case of portrait screens
176       mindimension = Math.min(height, width);
177     } catch (HeadlessException e)
178     {
179       if (isLinux)
180       {
181         jalview.bin.Console
182                 .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 }