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,8 +1,9 @@
package com.ts3client.ui;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.formdev.flatlaf.util.UIScale;
import com.ts3client.config.Settings;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
@@ -74,7 +75,7 @@ final class MainToolbar extends JToolBar {
setFloatable(false);
setBackground(Theme.toolbarBg());
setBorder(BorderFactory.createEmptyBorder(4, 6, 4, 6));
setBorder(new ScaledEmptyBorder(4, 6, 4, 6));
setComponentPopupMenu(buildContextMenu());
connectButton = new JButton(Icons.connect());
@@ -152,7 +153,7 @@ final class MainToolbar extends JToolBar {
/** The Master Volume slider: multiplies both voice and notification volume. */
private JComponent buildMasterVolumeControl() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 4, 0));
JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT, UIScale.scale(4), 0));
panel.setOpaque(false);
panel.setAlignmentY(Component.CENTER_ALIGNMENT);
@@ -164,7 +165,7 @@ final class MainToolbar extends JToolBar {
slider.setOpaque(false);
slider.setToolTipText("Master volume (voice + notifications) — scroll to adjust");
slider.setAlignmentY(Component.CENTER_ALIGNMENT);
slider.setPreferredSize(new Dimension(135, slider.getPreferredSize().height));
slider.setPreferredSize(new Dimension(UIScale.scale(135), slider.getPreferredSize().height));
slider.addChangeListener(e -> {
settings.masterVolume = slider.getValue() / 100.0;
listener.onMasterVolumeChanged();