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,6 @@
package com.ts3client.ui;
import com.formdev.flatlaf.util.UIScale;
import com.ts3client.net.Group;
import com.ts3client.net.IconRepository;
@@ -42,7 +43,7 @@ public final class GroupIcons {
// its own style; only server-uploaded icons come off the wire. The theme keeps
// its own cache, so those are not cached again here.
if (iconId > 0 && iconId <= IconRepository.MAX_BUNDLED_ID) {
ImageIcon themed = IconTheme.icon("GROUP_" + iconId, SIZE);
ImageIcon themed = IconTheme.icon("GROUP_" + iconId, UIScale.scale(SIZE));
if (themed != null) return themed;
}
@@ -54,8 +55,9 @@ public final class GroupIcons {
ImageIcon icon = new ImageIcon(data);
if (icon.getIconWidth() <= 0) return null;
if (icon.getIconWidth() != SIZE || icon.getIconHeight() != SIZE) {
icon = new ImageIcon(icon.getImage().getScaledInstance(SIZE, SIZE, Image.SCALE_SMOOTH));
int size = UIScale.scale(SIZE);
if (icon.getIconWidth() != size || icon.getIconHeight() != size) {
icon = new ImageIcon(icon.getImage().getScaledInstance(size, size, Image.SCALE_SMOOTH));
}
decoded.put(iconId, icon);
return icon;
@@ -89,15 +91,16 @@ public final class GroupIcons {
int offset = x;
for (Icon icon : icons) {
icon.paintIcon(c, g, offset, y + (getIconHeight() - icon.getIconHeight()) / 2);
offset += icon.getIconWidth() + GAP;
offset += icon.getIconWidth() + UIScale.scale(GAP);
}
}
@Override
public int getIconWidth() {
int width = 0;
for (Icon icon : icons) width += icon.getIconWidth() + GAP;
return Math.max(0, width - GAP);
int gap = UIScale.scale(GAP);
for (Icon icon : icons) width += icon.getIconWidth() + gap;
return Math.max(0, width - gap);
}
@Override