'IRC server connection management.'
 # built-ins
+from dataclasses import dataclass
 from socket import socket, gaierror as socket_gaierror
 from threading import Thread
 from typing import Callable, Iterator, NamedTuple, Optional, Self
                         (r'\\', '\\'))
 
 
-class LoginNames(NamedTuple):
+@dataclass
+class LoginNames:
     'Collects the names needed on server connect for USER, NICK commands.'
     user: str
     nick: str
     real: str
+    nick_confirmed: bool = False
 
 
 class InitConnectEvent(Event, PayloadMixin):
 
 
 class InitConnWindowEvent(ConnEvent, PayloadMixin):
-    'Event to trigger TUI making ConnectionWindow, nick in prompt = payload.'
-    payload: str
+    'Event to trigger TUI making ConnectionWindow.'
+    payload: LoginNames
 
 
-class _ConnectedEvent(ConnEvent, PayloadMixin):
-    'Event to signal opening of connection, with payload login names to send.'
-    payload: LoginNames
+class _ConnectedEvent(ConnEvent):
+    'Event to signal opening of connection.'
 
 
-class DisconnectedEvent(ConnEvent):
+class _DisconnectedEvent(ConnEvent):
     'Event to signal closing of connection'
 
 
     payload: str
 
 
-class NickSetEvent(ConnEvent, PayloadMixin):
-    'Event to signal nickname (= payload) having been set server-side.'
-    payload: str
+class NickSetEvent(ConnEvent):
+    'Event to signal nickname having been set server-side.'
 
 
 class SendEvent(ConnEvent, PayloadMixin):
         self._socket: Optional[socket] = None
         self._assumed_open = False
         self._loop: Optional[_ConnectionLoop] = None
-        self.broadcast_conn(InitConnWindowEvent, self._login.nick)
+        self.broadcast_conn(InitConnWindowEvent, self._login)
         self._start_connecting()
 
     def _start_connecting(self) -> None:
             self._assumed_open = True
             self._loop = _ConnectionLoop(conn_idx=self.conn_idx,
                                          q_to_main=self._q_to_main,
-                                         bonus_iterator=self._read_lines())
-            self.broadcast_conn(_ConnectedEvent, self._login)
+                                         bonus_iterator=self._read_lines(),
+                                         login=self._login,
+                                         set_login=self._set_login)
+            self.broadcast_conn(_ConnectedEvent)
 
         Thread(target=connect, daemon=True, args=(self,)).start()
 
+    def _set_login(self, **kwargs) -> None:
+        for key, val in kwargs.items():
+            setattr(self._login, key, val)
+        self.broadcast_conn(NickSetEvent)
+
     def close(self) -> None:
         'Close both _ConnectionLoop and socket.'
         self._assumed_open = False
+        self._set_login(nick_confirmed=False)
         if self._loop:
             self._loop.stop()
         self._loop = None
         elif isinstance(event, _ConnectedEvent):
             assert self._loop is not None
             self._loop.put(event)
-        elif isinstance(event, DisconnectedEvent):
+        elif isinstance(event, _DisconnectedEvent):
             self.close()
         elif isinstance(event, SendEvent):
             self.broadcast_conn(LogConnEvent, f'->: {event.payload.raw}')
 class _ConnectionLoop(Loop, BroadcastConnMixin):
     'Loop receiving and translating socket messages towards main loop.'
 
+    def __init__(self, login: LoginNames, set_login: Callable, **kwargs
+                 ) -> None:
+        super().__init__(**kwargs)
+        self._login = login
+        self._set_login = set_login
+
     def _send(self, verb: str, parameters: tuple[str, ...]) -> None:
         self.broadcast_conn(SendEvent, IrcMessage(verb, parameters))
 
             return False
         if isinstance(event, _ConnectedEvent):
             # self._send('CAP', ('LS', '302'))
-            self._send('USER', (event.payload.user, '0', '*',
-                                event.payload.real))
-            self._send('NICK', (event.payload.nick,))
+            self._send('USER', (self._login.user, '0', '*', self._login.real))
+            self._send('NICK', (self._login.nick,))
             # self._send('CAP', ('LIST',))
             # self._send('CAP', ('END',))
         return True
             self._send('PONG', (msg.parameters[0],))
         elif msg.verb == 'ERROR'\
                 and msg.parameters[0].startswith('Closing link:'):
-            self.broadcast_conn(DisconnectedEvent)
+            self.broadcast_conn(_DisconnectedEvent)
         elif msg.verb in {'001', 'NICK'}:
-            self.broadcast_conn(NickSetEvent, msg.parameters[0])
+            self._set_login(nick=msg.parameters[0], nick_confirmed=True)
 
 from ircplom.events import (BroadcastMixin, Event, EventQueue, Loop,
                             PayloadMixin, QuitEvent)
 from ircplom.irc_conn import (
-        BroadcastConnMixin, ConnEvent, DisconnectedEvent, InitConnectEvent,
-        InitConnWindowEvent, InitReconnectEvent, IrcMessage, LoginNames,
-        LogConnEvent, NickSetEvent, SendEvent, TIMEOUT_LOOP)
+        BroadcastConnMixin, ConnEvent, InitConnectEvent, InitConnWindowEvent,
+        InitReconnectEvent, IrcMessage, LoginNames, LogConnEvent, NickSetEvent,
+        SendEvent, TIMEOUT_LOOP)
 
 _MIN_HEIGHT = 4
 _MIN_WIDTH = 32
 
 class _ConnectionPromptWidget(_PromptWidget):
     'PromptWidget with attributes, methods for dealing with an IrcConnection.'
-    _nick: str = ''
-    _nick_confirmed: bool = False
+    login: LoginNames
 
     @property
     def _prompt(self) -> str:
-        return ((' ' if self._nick_confirmed else '?')
-                + self._nick
+        return ((' ' if self.login.nick_confirmed else '?')
+                + self.login.nick
                 + super()._prompt)
 
-    def update_prompt(self,
-                      nick_confirmed=False,
-                      nick: Optional[str] = None
-                      ) -> None:
-        'Update nickname-relevant knowledge to go into prompt string.'
-        self.tainted = True
-        self._nick_confirmed = nick_confirmed
-        if nick:
-            self._nick = nick
-
 
 class _Window(_Widget):
     'Collects a log and a prompt meant for the same content stream.'
     'Window with attributes and methods for dealing with an IrcConnection.'
     prompt: _ConnectionPromptWidget
 
+    def __init__(self, login: LoginNames, **kwargs) -> None:
+        super().__init__(**kwargs)
+        self.prompt.login = login
+
     def cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None:
         'Send QUIT command to server.'
         self.broadcast_conn(SendEvent, IrcMessage('QUIT', (quit_msg, )))
             conn_win = _ConnectionWindow(q_to_main=self._q_to_main,
                                          conn_idx=event.conn_idx,
                                          idx=len(self._windows),
-                                         term=self._term)
-            conn_win.prompt.update_prompt(nick_confirmed=False,
-                                          nick=event.payload)
+                                         term=self._term,
+                                         login=event.payload)
             self._windows += [conn_win]
             self._conn_windows += [conn_win]
             self._switch_window(conn_win.idx)
             if isinstance(event, LogConnEvent):
                 conn_win.log.append(event.payload)
             elif isinstance(event, NickSetEvent):
-                conn_win.prompt.update_prompt(nick_confirmed=True,
-                                              nick=event.payload)
-            elif isinstance(event, DisconnectedEvent):
-                conn_win.prompt.update_prompt(nick_confirmed=False)
+                conn_win.prompt.tainted = True
         else:
             return True
         self.window.draw_tainted()