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.config.Bookmark;
import com.ts3client.config.Bookmarks;
import com.ts3client.config.IdentityStore;
@@ -7,7 +9,6 @@ import com.ts3client.config.Settings;
import com.ts3client.teamspeak.TeamSpeakImporter;
import com.ts3client.teamspeak.TeamSpeakSettingsDb;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
@@ -81,10 +82,10 @@ public final class BookmarksDialog extends JDialog {
details = buildDetails();
JScrollPane listScroll = new JScrollPane(list);
listScroll.setPreferredSize(new Dimension(180, 320));
listScroll.setPreferredSize(UIScale.scale(new Dimension(180, 320)));
JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, listScroll, details);
split.setBorder(BorderFactory.createEmptyBorder(8, 8, 4, 8));
split.setBorder(new ScaledEmptyBorder(8, 8, 4, 8));
split.setResizeWeight(0.3);
split.setContinuousLayout(true);
@@ -105,7 +106,7 @@ public final class BookmarksDialog extends JDialog {
persist();
}
});
setSize(new Dimension(640, 400));
setSize(UIScale.scale(new Dimension(640, 400)));
setLocationRelativeTo(owner);
}
@@ -113,7 +114,7 @@ public final class BookmarksDialog extends JDialog {
private JPanel buildDetails() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 0));
panel.setBorder(new ScaledEmptyBorder(0, 8, 0, 0));
channel.setToolTipText("Channel path, e.g. \"Lobby/Games\", or a channel id. "
+ "Leave empty for the server's default channel.");
@@ -143,7 +144,7 @@ public final class BookmarksDialog extends JDialog {
private void addRow(JPanel panel, int row, String text, java.awt.Component field) {
GridBagConstraints c = new GridBagConstraints();
c.gridy = row;
c.insets = new Insets(2, 0, 2, 4);
c.insets = UIScale.scale(new Insets(2, 0, 2, 4));
c.anchor = GridBagConstraints.WEST;
c.gridx = 0;
panel.add(new JLabel(text), c);
@@ -156,7 +157,7 @@ public final class BookmarksDialog extends JDialog {
private JPanel buildButtons() {
JPanel buttons = new JPanel();
buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
buttons.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8));
buttons.setBorder(new ScaledEmptyBorder(0, 8, 8, 8));
addButton(buttons, "Add", this::addBookmark);
addButton(buttons, "Remove", this::removeSelected);
if (TeamSpeakSettingsDb.locate() != null) {
@@ -174,7 +175,7 @@ public final class BookmarksDialog extends JDialog {
JButton b = new JButton(text);
b.addActionListener(e -> action.run());
panel.add(b);
panel.add(Box.createHorizontalStrut(4));
panel.add(Box.createHorizontalStrut(UIScale.scale(4)));
return b;
}