Dock the tray icon once the window is on screen

Docking waits for the panel to adopt the icon, which held up the main
window; wait at most half a second for it before falling back to AWT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 12:25:44 +00:00
parent 75df46a03a
commit 002b1ac7ce
2 changed files with 15 additions and 4 deletions

View File

@@ -79,8 +79,8 @@ public final class MainFrame extends JFrame implements ServerTabPane.Listener {
private MainMenuBar menuBar; private MainMenuBar menuBar;
private javax.swing.Timer statusTimer; private javax.swing.Timer statusTimer;
/** Mirrors the active server's own client state next to the clock. */ /** Mirrors the active server's own client state next to the clock; set once the window is up. */
private TrayController tray; private volatile TrayController tray;
private MainToolbar toolbar; private MainToolbar toolbar;
private StatusBar statusBar; private StatusBar statusBar;
@@ -112,12 +112,17 @@ public final class MainFrame extends JFrame implements ServerTabPane.Listener {
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
quit(); quit();
} }
@Override
public void windowOpened(WindowEvent e) {
// Docking waits for the panel to adopt the icon, so it must not hold up the window.
SwingUtilities.invokeLater(MainFrame.this::installTray);
}
}); });
// Catches Ctrl+C / SIGTERM so we still leave the servers cleanly. // Catches Ctrl+C / SIGTERM so we still leave the servers cleanly.
Runtime.getRuntime().addShutdownHook(shutdownHook); Runtime.getRuntime().addShutdownHook(shutdownHook);
setMinimumSize(UIScale.scale(new Dimension(720, 480))); setMinimumSize(UIScale.scale(new Dimension(720, 480)));
tray = new TrayController(this, this::quit);
menuBar = buildMenuBar(); menuBar = buildMenuBar();
setJMenuBar(menuBar); setJMenuBar(menuBar);
@@ -853,6 +858,12 @@ public final class MainFrame extends JFrame implements ServerTabPane.Listener {
return selected != null && selected.session().isConnected() ? selected : null; return selected != null && selected.session().isConnected() ? selected : null;
} }
private void installTray() {
if (shuttingDown.get()) return;
tray = new TrayController(this, this::quit);
updateTray();
}
private void updateTray() { private void updateTray() {
if (tray == null) return; if (tray == null) return;
ServerTab tab = trayTab(); ServerTab tab = trayTab();

View File

@@ -33,7 +33,7 @@ public final class X11Tray implements TrayBackend {
private static final int DEFAULT_SIZE = 24; private static final int DEFAULT_SIZE = 24;
private static final int POLL_MS = 40; private static final int POLL_MS = 40;
/** How long to give the panel to adopt the icon before falling back to AWT. */ /** How long to give the panel to adopt the icon before falling back to AWT. */
private static final int DOCK_TIMEOUT_MS = 1500; private static final int DOCK_TIMEOUT_MS = 500;
/** Anything narrower than this is a sliver, not an icon the panel meant to give us. */ /** Anything narrower than this is a sliver, not an icon the panel meant to give us. */
private static final int MIN_SENSIBLE_SIZE = 8; private static final int MIN_SENSIBLE_SIZE = 8;
/** A tall panel should still not get a huge icon. */ /** A tall panel should still not get a huge icon. */