IDEA-149337 UI fonts are too big

The logic of detecting the default system font size on Linux is improved. The default font size is used to derive the IDEA UI scale factor.
Another side of improvement goes into our custom Linux JDK. GTK L&F will be able to detect "Xft.dpi" value in any Linux Desktop Environment, not necessarily built on GTK (e.g. KDE).
"Xft.dpi" value is an X server resource which defines the fonts DPI. The value is set by a Linux DE automatically, or in response to users's settings.

With the new custom JDK, IDEA will get properly scaled font on virtually all Linux's we support. So, the logic of deriving the UI scale will be unified with what IDEA does on Windows.

With Oracle JDK, IDEA will behave the same way on GTK Linux DE's, but on other Linux's it will fallback to the old approach of detecting the UI scale based on the X server DPI (if set).
This commit is contained in:
Anton Tarasov
2016-03-23 18:03:53 +03:00
parent 840d2ef120
commit 95069ee9fd
7 changed files with 103 additions and 67 deletions
@@ -53,8 +53,15 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
/** Not tabbed pane. */
public static final int TABS_NONE = 0;
private String lafID;
public static UISettings getInstance() {
return ServiceManager.getService(UISettings.class);
UISettings instance = ServiceManager.getService(UISettings.class);
if (!instance.lafID.equals(UIManager.getLookAndFeel().getID())) {
// Re-init if LaF changed.
instance.init();
}
return instance;
}
/**
@@ -135,6 +142,10 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
private final EventDispatcher<UISettingsListener> myDispatcher = EventDispatcher.create(UISettingsListener.class);
public UISettings() {
init();
}
private void init() {
tweakPlatformDefaults();
setSystemFontFaceAndSize();
@@ -142,6 +153,7 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
if (scrollToSource != null) {
DEFAULT_AUTOSCROLL_TO_SOURCE = scrollToSource;
}
lafID = UIManager.getLookAndFeel().getID();
}
private void tweakPlatformDefaults() {
@@ -181,11 +193,9 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
}
private void setSystemFontFaceAndSize() {
if (FONT_FACE == null || FONT_SIZE <= 0) {
final Pair<String, Integer> fontData = getSystemFontFaceAndSize();
FONT_FACE = fontData.first;
FONT_SIZE = fontData.second;
}
final Pair<String, Integer> fontData = getSystemFontFaceAndSize();
FONT_FACE = fontData.first;
FONT_SIZE = fontData.second;
}
private static Pair<String, Integer> getSystemFontFaceAndSize() {
@@ -35,6 +35,7 @@ import com.intellij.openapi.wm.impl.DesktopLayout;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -147,7 +148,7 @@ public class TogglePresentationModeAction extends AnAction implements DumbAware
}
}
}
float scaleFactor = settings.PRESENTATION_MODE_FONT_SIZE / 12f;
float scaleFactor = settings.PRESENTATION_MODE_FONT_SIZE / UIUtil.DEF_SYSTEM_FONT_SIZE;
ourSavedScaleFactor = JBUI.scale(1f);
JBUI.setScaleFactor(scaleFactor);
for (Object key : ourSavedValues.keySet()) {
@@ -729,7 +729,7 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo
UISettings uiSettings = UISettings.getInstance();
if (uiSettings.OVERRIDE_NONIDEA_LAF_FONTS) {
storeOriginalFontDefaults(uiDefaults);
JBUI.setScaleFactor(uiSettings.FONT_SIZE/12f);
JBUI.setScaleFactor(uiSettings.FONT_SIZE/UIUtil.DEF_SYSTEM_FONT_SIZE);
initFontDefaults(uiDefaults, uiSettings.FONT_SIZE, new FontUIResource(uiSettings.FONT_FACE, Font.PLAIN, uiSettings.FONT_SIZE));
}
else {
@@ -745,7 +745,7 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo
defaults.put(resource, lfDefaults.get(resource));
}
}
JBUI.setScaleFactor(JBUI.Fonts.label().getSize()/12f);
JBUI.setScaleFactor(JBUI.Fonts.label().getSize()/UIUtil.DEF_SYSTEM_FONT_SIZE);
}
private void storeOriginalFontDefaults(UIDefaults defaults) {
@@ -149,7 +149,7 @@ public class DarculaLaf extends BasicLookAndFeel {
private static void applySystemFonts(UIDefaults defaults) {
try {
String fqn = UIManager.getSystemLookAndFeelClassName();
String fqn = UIUtil.getSystemLookAndFeelClassName();
Object systemLookAndFeel = Class.forName(fqn).newInstance();
final Method superMethod = BasicLookAndFeel.class.getDeclaredMethod("getDefaults");
superMethod.setAccessible(true);
@@ -468,6 +468,9 @@ cvs.roots.refresh.uses.vfs=true
cvs.roots.refresh.uses.vfs.description=Should CVS roots refresh after update use VFS
vcs.add.remove.silent=true
ide.ui.scale.override=false
ide.ui.scale=1.0
ide.new.notification.enabled=false
ide.new.notification.visible.count=2
@@ -36,61 +36,35 @@ import java.awt.*;
public class JBUI {
private static final Logger LOG = Logger.getInstance("#com.intellij.util.ui.JBUI");
private static float SCALE_FACTOR = calculateScaleFactor();
private static float scaleFactor = 1.0f;
private static float calculateScaleFactor() {
static {
calculateScaleFactor();
}
private static void calculateScaleFactor() {
if (SystemInfo.isMac) {
LOG.info("UI scale factor: 1.0");
return 1.0f;
scaleFactor = 1.0f;
return;
}
if (SystemProperties.has("hidpi") && !SystemProperties.is("hidpi")) {
LOG.info("UI scale factor: 1.0");
return 1.0f;
scaleFactor = 1.0f;
return;
}
float s = 1f;
UIUtil.initSystemFontData();
Pair<String, Integer> fdata = UIUtil.getSystemFontData();
// On Linux: rely on DPI
if (SystemInfo.isLinux) {
final int dpi = getSystemDPI();
if (dpi < 120) s = 1f;
else if (dpi < 144) s = 1.25f;
else if (dpi < 168) s = 1.5f;
else if (dpi < 192) s = 1.75f;
else s = 2f;
LOG.info("UI scale factor: " + s);
return s;
}
int size = -1;
// On Windows: rely on default system font
if (SystemInfo.isWindows) {
UIUtil.initSystemFontData();
Pair<String, Integer> fdata = UIUtil.getSystemFontData();
if (fdata != null) size = fdata.getSecond();
}
if (size == -1) {
int size;
if (fdata != null) {
size = fdata.getSecond();
} else {
size = Fonts.label().getSize();
}
if (size <= 13) s = 1.0f;
else if (size <= 16) s = 1.25f;
else if (size <= 18) s = 1.5f;
else if (size < 24) s = 1.75f;
else s = 2.0f;
LOG.info("UI scale factor: " + s);
return s;
}
private static int getSystemDPI() {
try {
return Toolkit.getDefaultToolkit().getScreenResolution();
} catch (HeadlessException e) {
return 96;
}
setScaleFactor(size/UIUtil.DEF_SYSTEM_FONT_SIZE);
}
public static void setScaleFactor(float scale) {
@@ -108,19 +82,22 @@ public class JBUI {
//Default UI font size for Unity and Gnome is 15. Scaling factor 1.25f works badly on Linux
scale = 1f;
}
LOG.info("UI scale factor changed: " + scale);
if (scaleFactor == scale) {
return;
}
LOG.info("UI scale factor: " + scale);
SCALE_FACTOR = scale;
scaleFactor = scale;
IconLoader.setScale(scale);
}
public static int scale(int i) {
return Math.round(SCALE_FACTOR * i);
return Math.round(scaleFactor * i);
}
public static int scaleFontSize(int fontSize) {
if (SCALE_FACTOR == 1.25f) return (int)(fontSize * 1.34f);
if (SCALE_FACTOR == 1.75f) return (int)(fontSize * 1.67f);
if (scaleFactor == 1.25f) return (int)(fontSize * 1.34f);
if (scaleFactor == 1.75f) return (int)(fontSize * 1.67f);
return scale(fontSize);
}
@@ -177,7 +154,7 @@ public class JBUI {
}
public static float scale(float f) {
return f * SCALE_FACTOR;
return f * scaleFactor;
}
public static JBInsets insets(Insets insets) {
@@ -185,7 +162,7 @@ public class JBUI {
}
public static boolean isHiDPI() {
return SCALE_FACTOR > 1.0f;
return scaleFactor > 1.0f;
}
public static class Fonts {
@@ -323,6 +323,8 @@ public class UIUtil {
private static volatile Pair<String, Integer> ourSystemFontData = null;
public static final float DEF_SYSTEM_FONT_SIZE = 12f; // TODO: consider 12 * 1.33 to compensate JDK's 72dpi font scale
@NonNls private static final String ROOT_PANE = "JRootPane.future";
private static final Ref<Boolean> ourRetina = Ref.create(SystemInfo.isMac ? null : false);
@@ -2542,9 +2544,16 @@ public class UIUtil {
}
}
public static String getSystemLookAndFeelClassName() {
// Force GTK LaF on Linux to let it retrieve system font settings
// with proper font scale based on Xft.dpi
return SystemInfo.isLinux ? "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" :
UIManager.getSystemLookAndFeelClassName();
}
public static void initDefaultLAF() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
UIManager.setLookAndFeel(getSystemLookAndFeelClassName());
initSystemFontData();
}
catch (Exception ignore) {}
@@ -2553,16 +2562,36 @@ public class UIUtil {
public static void initSystemFontData() {
if (ourSystemFontData != null) return;
// With JB Linux JDK the label font comes properly scaled based on Xft.dpi settings.
Font font = getLabelFont();
if (SystemInfo.isWindows) {
Float forcedScale = null;
if (Registry.is("ide.ui.scale.override")) {
forcedScale = Float.valueOf((float)Registry.get("ide.ui.scale").asDouble());
}
else if (SystemInfo.isLinux && !SystemInfo.isJetbrainsJvm) {
// With Oracle JDK: derive scale from X server DPI
float scale = getScreenScale();
if (scale > 1f) {
forcedScale = Float.valueOf(scale);
}
// Or otherwise leave the detected font. It's undetermined if it's scaled or not.
// If it is (likely with GTK DE), then the UI scale will be derived from it,
// if it's not, then IDEA will start unscaled. This lets the users of GTK DEs
// not to bother about X server DPI settings. Users of other DEs (like KDE)
// will have to set X server DPI to meet their display.
}
else if (SystemInfo.isWindows) {
//noinspection HardCodedStringLiteral
Font winFont = (Font)Toolkit.getDefaultToolkit().getDesktopProperty("win.messagebox.font");
if (winFont != null) font = winFont;
if (winFont != null) {
font = winFont; // comes scaled
}
}
else if (SystemInfo.isLinux && JBUI.isHiDPI()) {
// We don't expect the default GUI font to be scaled on Linux and do it ourselves.
// TODO: this is valid until HIDPI support comes to J2D/Swing on Linux.
font = JBFont.create(font);
if (forcedScale != null) {
// With forced scale, we derive font from a hard-coded value as we cannot be sure
// the system font comes unscaled.
font = font.deriveFont(DEF_SYSTEM_FONT_SIZE * forcedScale.floatValue());
}
ourSystemFontData = Pair.create(font.getName(), font.getSize());
}
@@ -2572,6 +2601,22 @@ public class UIUtil {
return ourSystemFontData;
}
private static float getScreenScale() {
int dpi = 96;
try {
dpi = Toolkit.getDefaultToolkit().getScreenResolution();
} catch (HeadlessException e) {
}
float scale = 1f;
if (dpi < 120) scale = 1f;
else if (dpi < 144) scale = 1.25f;
else if (dpi < 168) scale = 1.5f;
else if (dpi < 192) scale = 1.75f;
else scale = 2f;
return scale;
}
public static void addKeyboardShortcut(final JComponent target, final AbstractButton button, final KeyStroke keyStroke) {
target.registerKeyboardAction(
new ActionListener() {