@@ -134,6 +134,7 @@ pub const ClientState = struct {
134134 mode : mode_mod.Mode = .normal ,
135135 recv_buf : [RECV_BUF_SIZE ]u8 = undefined ,
136136 recv_len : usize = 0 ,
137+ write_failed : bool = false ,
137138 allocator : std.mem.Allocator ,
138139
139140 pub fn init (allocator : std.mem.Allocator , id : u16 , fd : posix.fd_t ) ! * ClientState {
@@ -347,7 +348,7 @@ pub const Server = struct {
347348
348349 if (tag == TAG_LISTEN ) {
349350 // Accept a new client connection
350- const new_fd = posix .accept (self .listen_fd , null , null , posix .SOCK .CLOEXEC ) catch continue ;
351+ const new_fd = posix .accept (self .listen_fd , null , null , posix .SOCK .CLOEXEC | posix . SOCK . NONBLOCK ) catch continue ;
351352 if (self .clients .count () >= MAX_CLIENTS ) {
352353 posix .close (new_fd );
353354 continue ;
@@ -448,6 +449,12 @@ pub const Server = struct {
448449 cs .rows = hp .rows ;
449450 cs .screen .resize (hp .cols , hp .rows ) catch {};
450451 cs .screen .invalidate ();
452+ // Initialize active_panes for all existing tabs
453+ for (self .tab_manager .tabs , 0.. ) | maybe_tab , i | {
454+ if (maybe_tab ) | t | {
455+ cs .active_panes [@intCast (i )] = pane_mod .firstLeafId (t .pane_tree .root );
456+ }
457+ }
451458 if (self .active_client == null ) {
452459 self .active_client = client_id ;
453460 }
@@ -557,15 +564,21 @@ pub const Server = struct {
557564 const new_tab_idx = self .tab_manager .createTab (new_pane_id ) catch return ;
558565 self .spawnPaneState (new_pane_id ) catch return ;
559566 cs .active_tab = new_tab_idx ;
560- cs .active_panes [new_tab_idx ] = new_pane_id ;
567+ // Propagate new tab's focused pane to ALL clients
568+ var it = self .clients .valueIterator ();
569+ while (it .next ()) | other_cs | {
570+ other_cs .* .active_panes [new_tab_idx ] = new_pane_id ;
571+ }
561572 self .invalidateAllClients ();
562573 self .composeAll ();
563574 },
564575 .close_tab = > {
565- self .destroyAllPanesInTab (cs .active_tab );
566- const nearest = self .tab_manager .closeTab (cs .active_tab ) orelse return ;
567- // Update ALL clients viewing the closed tab
576+ // Reject closing the last tab before destroying any state
577+ if (self .tab_manager .tabCount () <= 1 ) return ;
568578 const closed_tab = cs .active_tab ;
579+ self .destroyAllPanesInTab (closed_tab );
580+ const nearest = self .tab_manager .closeTab (closed_tab ) orelse return ;
581+ // Update ALL clients viewing the closed tab
569582 var it = self .clients .valueIterator ();
570583 while (it .next ()) | other_cs | {
571584 if (other_cs .* .active_tab == closed_tab ) {
@@ -822,6 +835,8 @@ pub const Server = struct {
822835 while (it .next ()) | cs | {
823836 self .composeForClient (cs .* );
824837 }
838+ // Disconnect clients that failed to write (corrupted protocol stream)
839+ self .sweepFailedClients ();
825840 }
826841
827842 // ── resizePtysForClient ──────────────────────────────────────────────
@@ -1185,8 +1200,14 @@ pub const Server = struct {
11851200 const n = try protocol .encodeFrame (& buf , msg_type , payload );
11861201 var sent : usize = 0 ;
11871202 while (sent < n ) {
1188- const w = try posix .write (cs .fd , buf [sent .. n ]);
1189- if (w == 0 ) return error .BrokenPipe ;
1203+ const w = posix .write (cs .fd , buf [sent .. n ]) catch | err | {
1204+ cs .write_failed = true ;
1205+ return err ;
1206+ };
1207+ if (w == 0 ) {
1208+ cs .write_failed = true ;
1209+ return error .BrokenPipe ;
1210+ }
11901211 sent += w ;
11911212 }
11921213 }
@@ -1213,6 +1234,27 @@ pub const Server = struct {
12131234 }
12141235 }
12151236
1237+ // ── sweepFailedClients ─────────────────────────────────────────────
1238+
1239+ /// Disconnect clients whose write_failed flag is set (protocol stream corrupted).
1240+ /// Safe to call after iteration since it collects IDs first.
1241+ fn sweepFailedClients (self : * Server ) void {
1242+ var to_remove : [MAX_CLIENTS ]u16 = undefined ;
1243+ var count : u8 = 0 ;
1244+ var it = self .clients .iterator ();
1245+ while (it .next ()) | entry | {
1246+ if (entry .value_ptr .* .write_failed ) {
1247+ if (count < MAX_CLIENTS ) {
1248+ to_remove [count ] = entry .key_ptr .* ;
1249+ count += 1 ;
1250+ }
1251+ }
1252+ }
1253+ for (to_remove [0.. count ]) | cid | {
1254+ self .disconnectClient (cid );
1255+ }
1256+ }
1257+
12161258 // ── destroyAllPanesInTab ─────────────────────────────────────────────
12171259
12181260 fn destroyAllPanesInTab (self : * Server , tab_idx : u8 ) void {
0 commit comments