Skip to content

Commit a4b16b2

Browse files
committed
Fix UIScaling issues on Linux
1 parent b744486 commit a4b16b2

5 files changed

Lines changed: 65 additions & 12 deletions

File tree

src/main/java/sc/fiji/snt/BookmarkManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,7 +1815,7 @@ void populateFromFile(final File file) throws IOException {
18151815
final int cIdx = bvvMode ? -1 : table.findColumnIndex(HEADER[5]);
18161816
final int tIdx = bvvMode ? -1 : table.findColumnIndex(HEADER[6]);
18171817

1818-
if (lIdx == -1 || xIdx == -1 || yIdx == -1 || zIdx == -1)
1818+
if (xIdx == -1 || yIdx == -1 || zIdx == -1)
18191819
throw new IOException("Unexpected column header(s) in CSV file.");
18201820
final List<Bookmark> dataList = new ArrayList<>();
18211821
for (int i = 0; i < table.getRowCount(); i++) {
@@ -1829,7 +1829,8 @@ void populateFromFile(final File file) throws IOException {
18291829
} catch (final IllegalArgumentException ignored) {}
18301830
}
18311831
}
1832-
final Bookmark b = new Bookmark((String) table.get(lIdx, i),
1832+
final String label = (tagIdx != -1) ? ((String) table.get(lIdx, i)) : "Loc";
1833+
final Bookmark b = new Bookmark(label,
18331834
(double) table.get(xIdx, i), (double) table.get(yIdx, i), (double) table.get(zIdx, i),
18341835
(cIdx == -1) ? 1 : (int) ((double) table.get(cIdx, i)),
18351836
(tIdx == -1) ? 1 : (int) ((double) table.get(tIdx, i)),

src/main/java/sc/fiji/snt/SNTUI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ public void windowClosing(final WindowEvent e) {
396396
c3.gridy++;
397397
InternalUtils.addSeparatorWithURL(tab3, "sciview:", false, c3);
398398
++c3.gridy;
399-
final String msg3 = "3D visualization framework supporting large image volumes, reconstructions, " +
400-
"meshes, virtual reality, and Cx3D simulations. Discrete graphics card recommended.";
399+
final String msg3 = "3D visualization framework supporting image volumes, meshes, virtual " +
400+
"reality, and Cx3D neurodevelopmental simulations. Discrete graphics card recommended.";
401401
tab3.add(GuiUtils.longSmallMsg(msg3, "sciview-logo-icon.svg", tab3), c3);
402402
c3.gridy++;
403403
tab3.add(sciViewerPanel(viewerPanelBuilder), c3);

src/main/java/sc/fiji/snt/gui/GuiUtils.java

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,7 @@ private static class SvgBackgroundJTextArea extends JTextArea {
16821682
private final FlatSVGIcon svgIcon;
16831683
private FlatSVGIcon derivedIcon = null;
16841684
private int derivedIconWidth = 0;
1685+
private float osScale = 1f;
16851686

16861687
SvgBackgroundJTextArea(final String svgFileName) {
16871688
this.svgIcon = new FlatSVGIcon("gui/" + svgFileName);
@@ -1696,19 +1697,26 @@ public void addNotify() {
16961697
// Compute the derived icon here (not in paintComponent) to avoid feedback
16971698
// loops between icon size, insets, wrapping, and component height
16981699
super.addNotify();
1699-
// Size the icon to 3 text rows: getRowHeight() is font-based and should be stable
1700-
final int iconHeight = getRowHeight() * 3;
1700+
// osScale = FlatLaF uiScale / AWT device scale
1701+
// It seems that on macOS and Windows, Java handles HiDPI natively: AWT deviceScale == uiScale,
1702+
// so osScale == 1 and all sizes are already in FlatLaF logical units. On Linux with GDK_SCALE, the OS
1703+
// scales everything _before_(!?) Java sees it: AWT deviceScale stays at 1 while uiScale absorbs
1704+
// the GDK factor, so sizes become in device pixels and must be divided by osScale to get FlatLaF logical
1705+
// units. FlatSVGIcon.derive() and getInsets() both expect FlatLaF logical units on the icon side
1706+
osScale = osScale(this);
1707+
final int iconHeight = (int) (getRowHeight() * 3 / osScale);
17011708
final float scale = (float) iconHeight / svgIcon.getIconHeight();
17021709
derivedIconWidth = Math.round(svgIcon.getIconWidth() * scale);
17031710
derivedIcon = svgIcon.derive(derivedIconWidth, iconHeight);
17041711
}
17051712

17061713
@Override
17071714
public Insets getInsets() {
1708-
// Reserve left space equal to icon width + one 'M' gap for readability
1715+
// derivedIconWidth is in FlatLaF logical units; multiply by osScale to convert to Swing layout coordinates.
1716+
// charWidth is also in FlatLaF logical units (it seems GDK_SCALE is already applied on Linux)
17091717
final Insets base = super.getInsets();
1710-
final int gap = getFontMetrics(getFont()).stringWidth("M");
1711-
return new Insets(base.top, base.left + derivedIconWidth + gap, base.bottom, base.right);
1718+
final int gap = (int) (getFontMetrics(getFont()).charWidth('m') * osScale);
1719+
return new Insets(base.top, base.left + (int)(derivedIconWidth * osScale) + gap, base.bottom, base.right);
17121720
}
17131721

17141722
@Override
@@ -1912,6 +1920,47 @@ public static double uiScale() {
19121920
return Math.max(1.0, ij.Prefs.getGuiScale());
19131921
}
19141922

1923+
/**
1924+
* Returns the OS-level scale factor that is NOT already accounted for by Java's HiDPI awareness.
1925+
* <p>
1926+
* On macOS and Windows, Java intercepts HiDPI natively: so this returns 1.0. On Linux with GDK_SCALE, the OS seems
1927+
* to scale everything before Java sees it: AWT/Swing stay at 1.0 scaling while {@link #uiScale()} absorbs the GDK
1928+
* factor, so font sizes, etc. are in device pixels and must be divided by the returned value to reach FlatLaF
1929+
* logical units.
1930+
* </p>
1931+
* Uses the default screen device; prefer {@link #osScale(Component)} when a
1932+
* component is available so multi-monitor setups are handled correctly.
1933+
*/
1934+
public static float osScale() {
1935+
try {
1936+
final double deviceScale = GraphicsEnvironment.getLocalGraphicsEnvironment()
1937+
.getDefaultScreenDevice()
1938+
.getDefaultConfiguration()
1939+
.getDefaultTransform()
1940+
.getScaleX();
1941+
return (float) (uiScale() / Math.max(1.0, deviceScale));
1942+
} catch (final Exception ignored) {
1943+
return 1f;
1944+
}
1945+
}
1946+
1947+
/**
1948+
* Component-aware variant of {@link #osScale()}: uses the component's own
1949+
* {@link java.awt.GraphicsConfiguration} so the correct scale is returned on
1950+
* multi-monitor setups where screens may have different DPI.
1951+
*/
1952+
public static float osScale(final Component c) {
1953+
if (c == null) return osScale();
1954+
try {
1955+
final java.awt.GraphicsConfiguration gc = c.getGraphicsConfiguration();
1956+
if (gc == null) return osScale();
1957+
final double deviceScale = gc.getDefaultTransform().getScaleX();
1958+
return (float) (uiScale() / Math.max(1.0, deviceScale));
1959+
} catch (final Exception ignored) {
1960+
return 1f;
1961+
}
1962+
}
1963+
19151964
public static void initSplashScreen() {
19161965
splashScreen = new SplashScreen();
19171966
splashScreen.addMouseListener(new MouseAdapter() {

src/main/java/sc/fiji/snt/gui/IconFactory.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
import com.formdev.flatlaf.FlatLaf;
2626
import com.formdev.flatlaf.icons.FlatAbstractIcon;
27-
import org.scijava.util.PlatformUtils;
2827

2928
import javax.swing.*;
3029
import javax.swing.border.TitledBorder;
@@ -440,8 +439,10 @@ else if (isExpanded)
440439
}
441440

442441
public static Icon accentIcon(final Color color, final boolean squarify) {
443-
final int size = (int) (FADerivedIcon.defSize() * (PlatformUtils.isLinux() ? .6f : .9f));
444-
return new AccentIcon(color, (squarify) ? size : size *2, size);
442+
// defSize() is based on uiFontSize(), which on Linux HiDPI (GDK_SCALE) is inflated
443+
// by the OS scale factor. Divide by osScale() to get FlatLaF logical units
444+
final int size = (int) (FADerivedIcon.defSize() / GuiUtils.osScale());
445+
return new AccentIcon(color, (squarify) ? size : size * 2, size);
445446
}
446447

447448
/* Creation of colorful JTree node icons */

src/main/java/sc/fiji/snt/gui/SNTSearchableBar.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
package sc.fiji.snt.gui;
2424

25+
import com.formdev.flatlaf.ui.FlatRoundBorder;
2526
import com.jidesoft.swing.Searchable;
2627
import com.jidesoft.swing.SearchableBar;
2728
import com.jidesoft.swing.SearchableBarIconsFactory;
@@ -306,6 +307,7 @@ private SearchField getModifiedTextField(final String placeholder) {
306307
updateHistoryMenu();
307308
optionsMenu.show(sf.optionsButton(), 0, sf.optionsButton().getHeight());
308309
});
310+
sf.setBorder(new FlatRoundBorder());
309311
return sf;
310312
}
311313

0 commit comments

Comments
 (0)