/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pushingpixels.flamingo.internal.hidpi;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.WeakHashMap;
/**
* @author max
*/
public class UIUtil {
public static final boolean IS_OS_MAC = startsWith(getSystemProperty("os.name"), "Mac");
public static final boolean IS_VENDOR_APPLE = containsIgnoreCase(
getSystemProperty("java.vendor"), "Apple");
private static String getSystemProperty(String key) {
try {
return System.getProperty(key);
} catch (SecurityException e) {
// log("Can't read the System property " + key + ".");
return null;
}
}
private static boolean startsWith(String str, String prefix) {
return str != null && str.startsWith(prefix);
}
private static boolean containsIgnoreCase(String str, String searchFor) {
return str != null
&& str.toUpperCase(Locale.ENGLISH).contains(
searchFor.toUpperCase(Locale.ENGLISH));
}
/**
* Utility class for retina routine
*/
private final static class DetectRetinaKit {
private final static WeakHashMap<GraphicsDevice, Boolean> devicesToRetinaSupportCacheMap = new WeakHashMap<GraphicsDevice, Boolean>();
/**
* The best way to understand whether we are on a retina device is
* [NSScreen backingScaleFactor] But we should not invoke it from any
* thread. We do not have access to the AppKit thread on the other hand.
* So let's use a dedicated method. It is rather safe because it caches
* a value that has been got on AppKit previously.
*/
private static boolean isOracleMacRetinaDevice(GraphicsDevice device) {
if (IS_VENDOR_APPLE)
return false;
Boolean isRetina = devicesToRetinaSupportCacheMap.get(device);
if (isRetina != null) {
return isRetina;
}
Method getScaleFactorMethod = null;
try {
getScaleFactorMethod = Class.forName("sun.awt.CGraphicsDevice").getMethod("getScaleFactor");
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
}
try {
isRetina = getScaleFactorMethod == null || (Integer) getScaleFactorMethod.invoke(device) != 1;
} catch (IllegalAccessException e) {
isRetina = false;
} catch (InvocationTargetException e) {
isRetina = false;
} catch (IllegalArgumentException e) {
isRetina = false;
}
devicesToRetinaSupportCacheMap.put(device, isRetina);
return isRetina;
}
/**
* For JDK6 we have a dedicated property which does not allow to
* understand anything per device but could be useful for image
* creation. We will get true in case if at least one retina device is
* present.
*/
private static boolean hasAppleRetinaDevice() {
return (Float) Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor") != 1.0f;
}
/**
* This method perfectly detects retina Graphics2D for jdk7+ For Apple
* JDK6 it returns false.
*
* @param g
* graphics to be tested
* @return false if the device of the Graphics2D is not a retina device,
* jdk is an Apple JDK or Oracle API has been changed.
*/
private static boolean isMacRetina(Graphics2D g) {
GraphicsDevice device = g.getDeviceConfiguration().getDevice();
return isOracleMacRetinaDevice(device);
}
/**
* Checks that at least one retina device is present. Do not use this
* method if your are going to make decision for a particular screen.
* isRetina(Graphics2D) is more preferable
*
* @return true if at least one device is a retina device
*/
private static boolean isRetina() {
if (IS_VENDOR_APPLE) {
return hasAppleRetinaDevice();
}
// Oracle JDK
if (IS_OS_MAC) {
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] devices = e.getScreenDevices();
// now get the configurations for each device
for (GraphicsDevice device : devices) {
if (isOracleMacRetinaDevice(device)) {
return true;
}
}
}
return false;
}
}
public static boolean isRetina(Graphics2D graphics) {
if (IS_OS_MAC) {
return DetectRetinaKit.isMacRetina(graphics);
} else {
return isRetina();
}
}
private static Boolean cachedRetinaReply = null;
public static boolean isRetina() {
if (cachedRetinaReply != null) {
return cachedRetinaReply;
}
boolean result = false;
if (GraphicsEnvironment.isHeadless()) {
result = false;
} else if ("true".equalsIgnoreCase(System.getProperty("is.hidpi"))) {
// Temporary workaround for HiDPI on Windows/Linux
result = true;
} else {
result = DetectRetinaKit.isRetina();
}
cachedRetinaReply = Boolean.valueOf(result);
return cachedRetinaReply;
}
public static int getScaleFactor() {
return isRetina() ? 2 : 1;
}
}