From 10283d022f893226abc275ddfca9f6ac5a4af457 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 12 Oct 2019 10:44:11 +0200 Subject: [PATCH] Linux: initialize font (#2) --- CHANGELOG.md | 1 + .../java/com/formdev/flatlaf/FlatLaf.java | 3 +- .../com/formdev/flatlaf/LinuxFontPolicy.java | 110 ++++++++++++++++++ .../com/formdev/flatlaf/FlatTestFrame.java | 5 +- .../com/formdev/flatlaf/demo/ControlBar.java | 5 +- 5 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 flatlaf-core/src/main/java/com/formdev/flatlaf/LinuxFontPolicy.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5816ad8c..92e807cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FlatLaf Change Log ## Unreleased +- Support Linux. (issue #2) - Added `Flat*Laf.install()` methods. - macOS: Use native screen menu bar if system property `apple.laf.useScreenMenuBar` is `true`. diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index c9f74985..b6859842 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -201,7 +201,8 @@ public abstract class FlatLaf uiFont = (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font ); } else if( SystemInfo.IS_LINUX ) { - System.err.println( "WARNING: FlatLaf is not yet tested on Linux!" ); + Font font = LinuxFontPolicy.getFont(); + uiFont = (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font ); } if( uiFont == null ) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/LinuxFontPolicy.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/LinuxFontPolicy.java new file mode 100644 index 00000000..283e0bea --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/LinuxFontPolicy.java @@ -0,0 +1,110 @@ +/* + * Copyright 2019 FormDev Software GmbH + * + * 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 com.formdev.flatlaf; + +import java.awt.Font; +import java.awt.GraphicsEnvironment; +import java.awt.Toolkit; +import java.util.StringTokenizer; +import javax.swing.text.StyleContext; + +/** + * @author Karl Tauber + */ +class LinuxFontPolicy +{ + static Font getFont() { + // see class com.sun.java.swing.plaf.gtk.PangoFonts background information + + Object fontName = Toolkit.getDefaultToolkit().getDesktopProperty( "gnome.Gtk/FontName" ); + if( !(fontName instanceof String) ) + fontName = "sans 10"; + + String family = ""; + int style = Font.PLAIN; + int size = 10; + + StringTokenizer st = new StringTokenizer( (String) fontName ); + while( st.hasMoreTokens() ) { + String word = st.nextToken(); + + if( word.equalsIgnoreCase( "italic" ) ) + style |= Font.ITALIC; + else if( word.equalsIgnoreCase( "bold" ) ) + style |= Font.BOLD; + else if( Character.isDigit( word.charAt( 0 ) ) ) { + try { + size = Integer.parseInt( word ); + } catch( NumberFormatException ex ) { + // ignore + } + } else + family = family.isEmpty() ? word : (family + ' ' + word); + } + + // scale font size + double dsize = size * getSystemFontScale(); + size = (int) (dsize + 0.5); + if( size < 1 ) + size = 1; + + // handle logical font names + String logicalFamily = mapFcName( family.toLowerCase() ); + if( logicalFamily != null ) + family = logicalFamily; + + // using StyleContext.getFont() here because it uses + // sun.font.FontUtilities.getCompositeFontUIResource() + Font font = new StyleContext().getFont( family, style, size ); + + // set font size in floating points + font = font.deriveFont( style, (float) dsize ); + + return font; + } + + private static double getSystemFontScale() { + // see class com.sun.java.swing.plaf.gtk.PangoFonts background information + + Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "gnome.Xft/DPI" ); + if( value instanceof Integer ) { + int dpi = ((Integer)value).intValue() / 1024; + if( dpi == -1 ) + dpi = 96; + if( dpi < 50 ) + dpi = 50; + return dpi / 72.0; + } else { + return GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration() + .getNormalizingTransform().getScaleY(); + } + } + + /** + * map GTK/fontconfig names to equivalent JDK logical font name + */ + private static String mapFcName( String name ) { + switch( name ) { + case "sans": return "sansserif"; + case "sans-serif": return "sansserif"; + case "serif": return "serif"; + case "monospace": return "monospaced"; + } + return null; + } +} diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatTestFrame.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatTestFrame.java index 5982a042..17bef683 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatTestFrame.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatTestFrame.java @@ -97,7 +97,8 @@ public class FlatTestFrame continue; if( (SystemInfo.IS_WINDOWS && className.equals( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" )) || - (SystemInfo.IS_MAC && className.equals( "com.apple.laf.AquaLookAndFeel") ) ) + (SystemInfo.IS_MAC && className.equals( "com.apple.laf.AquaLookAndFeel") ) || + (SystemInfo.IS_LINUX && className.equals( "com.sun.java.swing.plaf.gtk.GTKLookAndFeel") ) ) name += " (F9)"; else if( className.equals( MetalLookAndFeel.class.getName() ) ) name += " (F10)"; @@ -135,6 +136,8 @@ public class FlatTestFrame registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" ); else if( SystemInfo.IS_MAC ) registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.apple.laf.AquaLookAndFeel" ); + else if( SystemInfo.IS_LINUX ) + registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" ); registerSwitchToLookAndFeel( KeyEvent.VK_F10, MetalLookAndFeel.class.getName() ); registerSwitchToLookAndFeel( KeyEvent.VK_F11, NimbusLookAndFeel.class.getName() ); diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java index 5ea729b6..b4d09372 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java @@ -58,7 +58,8 @@ class ControlBar continue; if( (SystemInfo.IS_WINDOWS && className.equals( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" )) || - (SystemInfo.IS_MAC && className.equals( "com.apple.laf.AquaLookAndFeel") ) ) + (SystemInfo.IS_MAC && className.equals( "com.apple.laf.AquaLookAndFeel") ) || + (SystemInfo.IS_LINUX && className.equals( "com.sun.java.swing.plaf.gtk.GTKLookAndFeel") ) ) name += " (F9)"; else if( className.equals( MetalLookAndFeel.class.getName() ) ) name += " (F10)"; @@ -94,6 +95,8 @@ class ControlBar registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" ); else if( SystemInfo.IS_MAC ) registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.apple.laf.AquaLookAndFeel" ); + else if( SystemInfo.IS_LINUX ) + registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" ); registerSwitchToLookAndFeel( KeyEvent.VK_F10, MetalLookAndFeel.class.getName() ); registerSwitchToLookAndFeel( KeyEvent.VK_F11, NimbusLookAndFeel.class.getName() );