Scale the interface fractionally on Linux

Java2D on X11 (and so under XWayland) truncates its scale to a whole
number, drawing 150 % at 100 %. On Linux, pin Java2D to 1 and hand the
full factor to FlatLaf, taken from XSETTINGS Xft/DPI, KWin's Xwayland
scale or GDK_SCALE, or chosen in Options → Design.

The client's own sizes now go through UIScale: borders, gaps, dialog and
row sizes, icons (rendered at the scaled size, so they stay crisp),
custom-painted components and font sizes in the HTML views.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-23 22:33:27 +00:00
parent 1fddae3f0b
commit 9d996f48a2
57 changed files with 643 additions and 311 deletions

View File

@@ -1,5 +1,7 @@
package com.ts3client.ui;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.formdev.flatlaf.util.UIScale;
import com.ts3client.net.ChannelSettings;
import javax.swing.BorderFactory;
@@ -47,7 +49,7 @@ final class ChannelAdvancedPanel extends JPanel implements ChannelDialog.Tab {
ChannelAdvancedPanel() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
setBorder(new ScaledEmptyBorder(8, 8, 8, 8));
phoneticName.setToolTipText("Set phonetic nickname used for this channel by text-to-speech.");
deleteDelay.setToolTipText("<html><p>Delay in seconds after temporary channels are deleted"
@@ -79,12 +81,12 @@ final class ChannelAdvancedPanel extends JPanel implements ChannelDialog.Tab {
other.setAlignmentX(0f);
fixHeight(other);
add(other);
add(Box.createVerticalStrut(6));
add(Box.createVerticalStrut(UIScale.scale(6)));
JPanel limits = new JPanel();
limits.setLayout(new BoxLayout(limits, BoxLayout.X_AXIS));
limits.add(limitBox("Max Users", new JRadioButton[]{maxUsersUnlimited, maxUsersLimited}, maxUsers));
limits.add(Box.createHorizontalStrut(8));
limits.add(Box.createHorizontalStrut(UIScale.scale(8)));
limits.add(limitBox("Family Max Users",
new JRadioButton[]{familyInherited, familyUnlimited, familyLimited}, familyMaxUsers));
limits.setAlignmentX(0f);
@@ -140,7 +142,7 @@ final class ChannelAdvancedPanel extends JPanel implements ChannelDialog.Tab {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createTitledBorder("Other Settings"));
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(3, 4, 3, 4);
c.insets = UIScale.scale(new Insets(3, 4, 3, 4));
c.anchor = GridBagConstraints.WEST;
c.fill = GridBagConstraints.HORIZONTAL;
@@ -155,7 +157,7 @@ final class ChannelAdvancedPanel extends JPanel implements ChannelDialog.Tab {
c.gridy = 1;
c.weightx = 0;
panel.add(new JLabel("Delete delay:"), c);
JPanel delay = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
JPanel delay = new JPanel(new FlowLayout(FlowLayout.LEFT, UIScale.scale(4), 0));
delay.add(deleteDelay);
delay.add(deleteDelayMax);
c.gridx = 1;
@@ -183,7 +185,7 @@ final class ChannelAdvancedPanel extends JPanel implements ChannelDialog.Tab {
box.add(radio);
continue;
}
JPanel row = new JPanel(new FlowLayout(FlowLayout.LEFT, 6, 0));
JPanel row = new JPanel(new FlowLayout(FlowLayout.LEFT, UIScale.scale(6), 0));
row.setAlignmentX(0f);
row.add(radio);
row.add(spinner);