diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index da2a27976..11b43bf22 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-refresh-client.c,v 1.54 2026/07/05 08:24:00 nicm Exp $ */ +/* $OpenBSD: cmd-refresh-client.c,v 1.55 2026/07/17 08:37:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -66,7 +66,6 @@ cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); const char *size = args_get(args, 'C'); u_int w, x, y; - struct client_window *cw; if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) { if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM || @@ -76,22 +75,16 @@ cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item) } log_debug("%s: client %s window @%u: size %ux%u", __func__, tc->name, w, x, y); - cw = server_client_add_client_window(tc, w); - cw->sx = x; - cw->sy = y; + control_set_window_size(tc, w, x, y); tc->flags |= CLIENT_WINDOWSIZECHANGED; recalculate_sizes_now(1); return (CMD_RETURN_NORMAL); } if (sscanf(size, "@%u:", &w) == 1) { - cw = server_client_get_client_window(tc, w); - if (cw != NULL) { - log_debug("%s: client %s window @%u: no size", __func__, - tc->name, w); - cw->sx = 0; - cw->sy = 0; - recalculate_sizes_now(1); - } + log_debug("%s: client %s window @%u: no size", __func__, + tc->name, w); + control_clear_window_size(tc, w); + recalculate_sizes_now(1); return (CMD_RETURN_NORMAL); } diff --git a/control.c b/control.c index 8b4ad3884..92645a8bc 100644 --- a/control.c +++ b/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.61 2026/07/10 15:45:11 nicm Exp $ */ +/* $OpenBSD: control.c,v 1.62 2026/07/17 08:37:29 nicm Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott @@ -78,9 +78,20 @@ struct control_pane { }; RB_HEAD(control_panes, control_pane); +/* Control client window size. */ +struct control_window { + u_int window; + u_int sx; + u_int sy; + + RB_ENTRY(control_window) entry; +}; +RB_HEAD(control_windows, control_window); + /* Control client state. */ struct control_state { struct control_panes panes; + struct control_windows windows; TAILQ_HEAD(, control_pane) pending_list; u_int pending_count; @@ -120,6 +131,18 @@ control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2) } RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp); +/* Compare control windows. */ +static int +control_window_cmp(struct control_window *cw1, struct control_window *cw2) +{ + if (cw1->window < cw2->window) + return (-1); + if (cw1->window > cw2->window) + return (1); + return (0); +} +RB_GENERATE_STATIC(control_windows, control_window, entry, control_window_cmp); + /* Free a block. */ static void control_free_block(struct control_state *cs, struct control_block *cb) @@ -161,6 +184,66 @@ control_add_pane(struct client *c, struct window_pane *wp) return (cp); } +/* Get window for this client. */ +static struct control_window * +control_get_window(struct client *c, u_int window) +{ + struct control_state *cs = c->control_state; + struct control_window cw = { .window = window }; + + if (cs == NULL) + return (NULL); + return (RB_FIND(control_windows, &cs->windows, &cw)); +} + +/* Set window size for this client. */ +void +control_set_window_size(struct client *c, u_int window, u_int sx, u_int sy) +{ + struct control_state *cs = c->control_state; + struct control_window *cw; + + if (cs == NULL) + return; + cw = control_get_window(c, window); + if (cw == NULL) { + cw = xcalloc(1, sizeof *cw); + cw->window = window; + RB_INSERT(control_windows, &cs->windows, cw); + } + cw->sx = sx; + cw->sy = sy; +} + +/* Get window size for this client. */ +int +control_get_window_size(struct client *c, u_int window, u_int *sx, u_int *sy) +{ + struct control_window *cw; + + if ((cw = control_get_window(c, window)) == NULL) + return (0); + *sx = cw->sx; + *sy = cw->sy; + return (1); +} + +/* Clear window size for this client. */ +void +control_clear_window_size(struct client *c, u_int window) +{ + struct control_state *cs = c->control_state; + struct control_window *cw; + + if (cs == NULL) + return; + cw = control_get_window(c, window); + if (cw != NULL) { + RB_REMOVE(control_windows, &cs->windows, cw); + free(cw); + } +} + /* Discard output for a pane. */ static void control_discard_pane(struct client *c, struct control_pane *cp) @@ -749,6 +832,7 @@ control_start(struct client *c) cs = c->control_state = xcalloc(1, sizeof *cs); RB_INIT(&cs->panes); + RB_INIT(&cs->windows); TAILQ_INIT(&cs->pending_list); TAILQ_INIT(&cs->all_blocks); cs->subs = monitor_create_client(c, control_sub_change, NULL); @@ -800,6 +884,7 @@ control_stop(struct client *c) { struct control_state *cs = c->control_state; struct control_block *cb, *cb1; + struct control_window *cw, *cw1; if (cs == NULL) return; @@ -811,6 +896,10 @@ control_stop(struct client *c) bufferevent_free(cs->read_event); control_reset_offsets(c); + RB_FOREACH_SAFE(cw, control_windows, &cs->windows, cw1) { + RB_REMOVE(control_windows, &cs->windows, cw); + free(cw); + } TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1) control_free_block(cs, cb); diff --git a/resize.c b/resize.c index 1d83e4b70..4f7ee490a 100644 --- a/resize.c +++ b/resize.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resize.c,v 1.57 2026/07/13 13:01:14 nicm Exp $ */ +/* $OpenBSD: resize.c,v 1.58 2026/07/17 08:37:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -134,9 +134,8 @@ clients_calculate_size(int type, int current, struct client *c, int, int, struct session *, struct window *), u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel) { - struct client *loop; - struct client_window *cw; - u_int cx, cy, n = 0; + struct client *loop; + u_int cx, cy, n = 0; /* * Start comparing with 0 for largest and UINT_MAX for smallest or @@ -187,20 +186,10 @@ clients_calculate_size(int type, int current, struct client *c, continue; } - /* - * If the client has a per-window size, use this instead if it is - * smaller. - */ - if (w != NULL) - cw = server_client_get_client_window(loop, w->id); - else - cw = NULL; - /* Work out this client's size. */ - if (cw != NULL && cw->sx != 0 && cw->sy != 0) { - cx = cw->sx; - cy = cw->sy; - } else { + if (w == NULL || + !control_get_window_size(loop, w->id, &cx, &cy) || + cx == 0 || cy == 0) { cx = loop->tty.sx; cy = loop->tty.sy - status_line_size(loop); } @@ -247,17 +236,16 @@ skip: /* Look up per-window size if any. */ if (~loop->flags & CLIENT_WINDOWSIZECHANGED) continue; - cw = server_client_get_client_window(loop, w->id); - if (cw == NULL) + if (!control_get_window_size(loop, w->id, &cx, &cy)) continue; /* Clamp the size. */ log_debug("%s: %s size for @%u is %ux%u", __func__, - loop->name, w->id, cw->sx, cw->sy); - if (cw->sx != 0 && *sx > cw->sx) - *sx = cw->sx; - if (cw->sy != 0 && *sy > cw->sy) - *sy = cw->sy; + loop->name, w->id, cx, cy); + if (cx != 0 && *sx > cx) + *sx = cx; + if (cy != 0 && *sy > cy) + *sy = cy; } } if (*sx != UINT_MAX && *sy != UINT_MAX) diff --git a/server-client.c b/server-client.c index e9c62a745..b4f39c1d7 100644 --- a/server-client.c +++ b/server-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server-client.c,v 1.495 2026/07/17 08:13:23 nicm Exp $ */ +/* $OpenBSD: server-client.c,v 1.496 2026/07/17 08:37:29 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -48,24 +49,46 @@ static void server_client_set_path(struct client *); static void server_client_set_progress_bar(struct client *); static void server_client_reset_state(struct client *); static void server_client_update_latest(struct client *); +static void server_client_remove_active_pane_client(struct client *); static void server_client_dispatch(struct imsg *, void *); static int server_client_dispatch_command(struct client *, struct imsg *); static int server_client_dispatch_identify(struct client *, struct imsg *); static int server_client_dispatch_shell(struct client *); static void server_client_report_theme(struct client *, enum client_theme); -/* Compare client windows. */ +/* Client active pane. */ +struct client_active_pane { + struct client *client; + u_int window; + struct window_pane *pane; + + RB_ENTRY(client_active_pane) entry; +}; +RB_HEAD(client_active_panes, client_active_pane); + +/* Compare client active panes. */ static int -server_client_window_cmp(struct client_window *cw1, - struct client_window *cw2) +server_client_active_pane_cmp(struct client_active_pane *cap1, + struct client_active_pane *cap2) { - if (cw1->window < cw2->window) + uintptr_t c1 = (uintptr_t)cap1->client; + uintptr_t c2 = (uintptr_t)cap2->client; + + if (c1 < c2) return (-1); - if (cw1->window > cw2->window) + if (c1 > c2) + return (1); + if (cap1->window < cap2->window) + return (-1); + if (cap1->window > cap2->window) return (1); return (0); } -RB_GENERATE(client_windows, client_window, entry, server_client_window_cmp); +RB_GENERATE_STATIC(client_active_panes, client_active_pane, entry, + server_client_active_pane_cmp); + +static struct client_active_panes client_active_panes = + RB_INITIALIZER(&client_active_panes); /* Number of attached clients. */ u_int @@ -309,7 +332,6 @@ server_client_create(int fd) c->out_fd = -1; c->queue = cmdq_new(); - RB_INIT(&c->windows); RB_INIT(&c->files); c->tty.sx = 80; @@ -500,7 +522,6 @@ void server_client_lost(struct client *c) { struct client_file *cf, *cf1; - struct client_window *cw, *cw1; if (cfg_client == c) cfg_client = NULL; @@ -509,15 +530,12 @@ server_client_lost(struct client *c) server_client_clear_overlay(c); status_prompt_clear(c); status_message_clear(c); + server_client_remove_active_pane_client(c); RB_FOREACH_SAFE(cf, client_files, &c->files, cf1) { cf->error = EINTR; file_fire_done(cf); } - RB_FOREACH_SAFE(cw, client_windows, &c->windows, cw1) { - RB_REMOVE(client_windows, &c->windows, cw); - free(cw); - } TAILQ_REMOVE(&clients, c, entry); log_debug("lost client %p", c); @@ -3083,28 +3101,29 @@ server_client_get_flags(struct client *c) return (s); } -/* Get client window. */ -struct client_window * -server_client_get_client_window(struct client *c, u_int id) +/* Get client active pane. */ +static struct client_active_pane * +server_client_get_active_pane(struct client *c, u_int id) { - struct client_window cw = { .window = id }; + struct client_active_pane cap = { .client = c, .window = id }; - return (RB_FIND(client_windows, &c->windows, &cw)); + return (RB_FIND(client_active_panes, &client_active_panes, &cap)); } -/* Add client window. */ -struct client_window * -server_client_add_client_window(struct client *c, u_int id) +/* Add client active pane. */ +static struct client_active_pane * +server_client_add_active_pane(struct client *c, u_int id) { - struct client_window *cw; + struct client_active_pane *cap; - cw = server_client_get_client_window(c, id); - if (cw == NULL) { - cw = xcalloc(1, sizeof *cw); - cw->window = id; - RB_INSERT(client_windows, &c->windows, cw); + cap = server_client_get_active_pane(c, id); + if (cap == NULL) { + cap = xcalloc(1, sizeof *cap); + cap->client = c; + cap->window = id; + RB_INSERT(client_active_panes, &client_active_panes, cap); } - return (cw); + return (cap); } /* Get client active pane. */ @@ -3113,7 +3132,7 @@ server_client_get_pane(struct client *c) { struct session *s = c->session; struct window *w; - struct client_window *cw; + struct client_active_pane *cap; if (s == NULL) return (NULL); @@ -3123,10 +3142,10 @@ server_client_get_pane(struct client *c) return (w->modal); if (~c->flags & CLIENT_ACTIVEPANE) return (w->active); - cw = server_client_get_client_window(c, w->id); - if (cw == NULL) + cap = server_client_get_active_pane(c, w->id); + if (cap == NULL) return (w->active); - return (cw->pane); + return (cap->pane); } /* Set client active pane. */ @@ -3134,32 +3153,47 @@ void server_client_set_pane(struct client *c, struct window_pane *wp) { struct session *s = c->session; - struct client_window *cw; + struct client_active_pane *cap; if (s == NULL) return; if (wp->window->modal != NULL && wp != wp->window->modal) return; - cw = server_client_add_client_window(c, s->curw->window->id); - cw->pane = wp; + cap = server_client_add_active_pane(c, s->curw->window->id); + cap->pane = wp; log_debug("%s pane now %%%u", c->name, wp->id); } -/* Remove pane from client lists. */ +/* Remove active pane entries for a client. */ +static void +server_client_remove_active_pane_client(struct client *c) +{ + struct client_active_pane *cap, *cap1; + + RB_FOREACH_SAFE(cap, client_active_panes, &client_active_panes, cap1) { + if (cap->client == c) { + RB_REMOVE(client_active_panes, &client_active_panes, cap); + free(cap); + } + } +} + +/* Remove pane from client state. */ void server_client_remove_pane(struct window_pane *wp) { - struct client *c; - struct window *w = wp->window; - struct client_window *cw; + struct client *c; + struct client_active_pane *cap, *cap1; + + RB_FOREACH_SAFE(cap, client_active_panes, &client_active_panes, cap1) { + if (cap->pane == wp) { + RB_REMOVE(client_active_panes, &client_active_panes, cap); + free(cap); + } + } TAILQ_FOREACH(c, &clients, entry) { - cw = server_client_get_client_window(c, w->id); - if (cw != NULL && cw->pane == wp) { - RB_REMOVE(client_windows, &c->windows, cw); - free(cw); - } if (c->tty.mouse_last_pane == (int)wp->id) { c->tty.mouse_last_pane = -1; c->tty.mouse_drag_update = NULL; diff --git a/tmux.h b/tmux.h index 947401b4e..3d3cae5d8 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1406 2026/07/15 13:02:33 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1407 2026/07/17 08:37:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -2033,18 +2033,6 @@ struct client_file { }; RB_HEAD(client_files, client_file); -/* Client window. */ -struct client_window { - u_int window; - struct window_pane *pane; - - u_int sx; - u_int sy; - - RB_ENTRY(client_window) entry; -}; -RB_HEAD(client_windows, client_window); - /* Maximum time to be pasting. */ #define CLIENT_PASTE_TIME_LIMIT 5 @@ -2148,8 +2136,6 @@ struct client { const char *user; struct cmdq_list *queue; - struct client_windows windows; - struct control_state *control_state; u_int pause_age; @@ -3237,7 +3223,6 @@ void printflike(1, 2) server_add_message(const char *, ...); int server_create_socket(uint64_t, char **); /* server-client.c */ -RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp); u_int server_client_how_many(void); void server_client_set_overlay(struct client *, u_int, overlay_check_cb, overlay_mode_cb, overlay_draw_cb, overlay_key_cb, @@ -3265,8 +3250,6 @@ void server_client_loop(void); const char *server_client_get_cwd(struct client *, struct session *); void server_client_set_flags(struct client *, const char *); const char *server_client_get_flags(struct client *); -struct client_window *server_client_get_client_window(struct client *, u_int); -struct client_window *server_client_add_client_window(struct client *, u_int); struct window_pane *server_client_get_pane(struct client *); void server_client_set_pane(struct client *, struct window_pane *); void server_client_remove_pane(struct window_pane *); @@ -3959,6 +3942,9 @@ void control_set_pane_on(struct client *, struct window_pane *); void control_set_pane_off(struct client *, struct window_pane *); void control_continue_pane(struct client *, struct window_pane *); void control_pause_pane(struct client *, struct window_pane *); +void control_set_window_size(struct client *, u_int, u_int, u_int); +int control_get_window_size(struct client *, u_int, u_int *, u_int *); +void control_clear_window_size(struct client *, u_int); struct window_pane_offset *control_pane_offset(struct client *, struct window_pane *, int *); void control_reset_offsets(struct client *);