Tabbed servers: multiple simultaneous connections

Each connection now lives in its own ServerTab with its own tree, info
and chat views plus its own mic-mute, deafen, away and commander state.
MainFrame keeps only the shell (menus, toolbar, status bar) and shows
one tab at a time; the tab bar below the toolbar appears once a second
server is open.

Incoming voice from every connection mixes into the same output — each
connection already renders one line per speaker. Capture is exclusive:
a connection only opens the microphone while it holds it, and a toolbar
button moves it to the visible tab. The mic follows a disconnect to
another connected tab, and push-to-talk drives whoever holds it.

Startup bookmarks are no longer mutually exclusive: every flagged
bookmark opens its own tab.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 15:18:47 +00:00
parent 5db3f4d8c4
commit 03c6ea9a3b
7 changed files with 843 additions and 373 deletions

View File

@@ -166,6 +166,19 @@ public final class Icons {
});
}
/** Marks the server that currently owns the microphone. */
public static ImageIcon micActive() {
return make(g -> {
g.setColor(Theme.TALKING);
g.fillOval(1, 1, 14, 14);
g.setColor(Color.WHITE);
g.fillRoundRect(6, 3, 4, 6, 2, 2);
g.setStroke(new BasicStroke(1.4f));
g.drawArc(4, 6, 8, 6, 200, 140);
g.drawLine(8, 11, 8, 13);
});
}
public static ImageIcon settings() {
return make(g -> {
g.setColor(new Color(0x37474F));