1*0ad0daf4Snicm /* $OpenBSD: cmd-display-panes.c,v 1.46 2024/03/21 11:30:42 nicm Exp $ */
2669c539cSnicm
3669c539cSnicm /*
498ca8272Snicm * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5669c539cSnicm *
6669c539cSnicm * Permission to use, copy, modify, and distribute this software for any
7669c539cSnicm * purpose with or without fee is hereby granted, provided that the above
8669c539cSnicm * copyright notice and this permission notice appear in all copies.
9669c539cSnicm *
10669c539cSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11669c539cSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12669c539cSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13669c539cSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14669c539cSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15669c539cSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16669c539cSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17669c539cSnicm */
18669c539cSnicm
19669c539cSnicm #include <sys/types.h>
20669c539cSnicm
212413453fSnicm #include <stdlib.h>
2270c21bfbSnicm #include <string.h>
232413453fSnicm
24669c539cSnicm #include "tmux.h"
25669c539cSnicm
26669c539cSnicm /*
27669c539cSnicm * Display panes on a client.
28669c539cSnicm */
29669c539cSnicm
30e4c0b811Snicm static enum args_parse_type cmd_display_panes_args_parse(struct args *,
31e4c0b811Snicm u_int, char **);
3268e0a7f2Snicm static enum cmd_retval cmd_display_panes_exec(struct cmd *,
3368e0a7f2Snicm struct cmdq_item *);
342413453fSnicm
35669c539cSnicm const struct cmd_entry cmd_display_panes_entry = {
36c057646bSnicm .name = "display-panes",
37c057646bSnicm .alias = "displayp",
38c057646bSnicm
39e4c0b811Snicm .args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse },
4088eb9092Snicm .usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
41c057646bSnicm
42035dc73dSnicm .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
43c057646bSnicm .exec = cmd_display_panes_exec
44669c539cSnicm };
45669c539cSnicm
4670c21bfbSnicm struct cmd_display_panes_data {
4770c21bfbSnicm struct cmdq_item *item;
482db6a388Snicm struct args_command_state *state;
4970c21bfbSnicm };
5070c21bfbSnicm
51e4c0b811Snicm static enum args_parse_type
cmd_display_panes_args_parse(__unused struct args * args,__unused u_int idx,__unused char ** cause)52e4c0b811Snicm cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
53e4c0b811Snicm __unused char **cause)
54e4c0b811Snicm {
55e4c0b811Snicm return (ARGS_PARSE_COMMANDS_OR_STRING);
56e4c0b811Snicm }
57e4c0b811Snicm
5870c21bfbSnicm static void
cmd_display_panes_draw_pane(struct screen_redraw_ctx * ctx,struct window_pane * wp)5970c21bfbSnicm cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
6070c21bfbSnicm struct window_pane *wp)
61669c539cSnicm {
6270c21bfbSnicm struct client *c = ctx->c;
6370c21bfbSnicm struct tty *tty = &c->tty;
6470c21bfbSnicm struct session *s = c->session;
6570c21bfbSnicm struct options *oo = s->options;
6670c21bfbSnicm struct window *w = wp->window;
67cf629db8Snicm struct grid_cell fgc, bgc;
68cf629db8Snicm u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
6970c21bfbSnicm int colour, active_colour;
70cf629db8Snicm char buf[16], lbuf[16], rbuf[16], *ptr;
71cf629db8Snicm size_t len, llen, rlen;
72bf0d297eSnicm
7370c21bfbSnicm if (wp->xoff + wp->sx <= ctx->ox ||
7470c21bfbSnicm wp->xoff >= ctx->ox + ctx->sx ||
7570c21bfbSnicm wp->yoff + wp->sy <= ctx->oy ||
7670c21bfbSnicm wp->yoff >= ctx->oy + ctx->sy)
7770c21bfbSnicm return;
782413453fSnicm
7970c21bfbSnicm if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
8070c21bfbSnicm /* All visible. */
8170c21bfbSnicm xoff = wp->xoff - ctx->ox;
8270c21bfbSnicm sx = wp->sx;
8370c21bfbSnicm } else if (wp->xoff < ctx->ox &&
8470c21bfbSnicm wp->xoff + wp->sx > ctx->ox + ctx->sx) {
8570c21bfbSnicm /* Both left and right not visible. */
8670c21bfbSnicm xoff = 0;
8770c21bfbSnicm sx = ctx->sx;
8870c21bfbSnicm } else if (wp->xoff < ctx->ox) {
8970c21bfbSnicm /* Left not visible. */
9070c21bfbSnicm xoff = 0;
9170c21bfbSnicm sx = wp->sx - (ctx->ox - wp->xoff);
9270c21bfbSnicm } else {
9370c21bfbSnicm /* Right not visible. */
9470c21bfbSnicm xoff = wp->xoff - ctx->ox;
9570c21bfbSnicm sx = wp->sx - xoff;
963b2d01c0Snicm }
9770c21bfbSnicm if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
9870c21bfbSnicm /* All visible. */
9970c21bfbSnicm yoff = wp->yoff - ctx->oy;
10070c21bfbSnicm sy = wp->sy;
10170c21bfbSnicm } else if (wp->yoff < ctx->oy &&
10270c21bfbSnicm wp->yoff + wp->sy > ctx->oy + ctx->sy) {
10370c21bfbSnicm /* Both top and bottom not visible. */
10470c21bfbSnicm yoff = 0;
10570c21bfbSnicm sy = ctx->sy;
10670c21bfbSnicm } else if (wp->yoff < ctx->oy) {
10770c21bfbSnicm /* Top not visible. */
10870c21bfbSnicm yoff = 0;
10970c21bfbSnicm sy = wp->sy - (ctx->oy - wp->yoff);
11070c21bfbSnicm } else {
11170c21bfbSnicm /* Bottom not visible. */
11270c21bfbSnicm yoff = wp->yoff - ctx->oy;
11370c21bfbSnicm sy = wp->sy - yoff;
11470c21bfbSnicm }
115669c539cSnicm
11670c21bfbSnicm if (ctx->statustop)
11770c21bfbSnicm yoff += ctx->statuslines;
11870c21bfbSnicm px = sx / 2;
11970c21bfbSnicm py = sy / 2;
12070c21bfbSnicm
121cf629db8Snicm if (window_pane_index(wp, &pane) != 0)
12270c21bfbSnicm fatalx("index not found");
123cf629db8Snicm len = xsnprintf(buf, sizeof buf, "%u", pane);
12470c21bfbSnicm
12570c21bfbSnicm if (sx < len)
12670c21bfbSnicm return;
12770c21bfbSnicm colour = options_get_number(oo, "display-panes-colour");
12870c21bfbSnicm active_colour = options_get_number(oo, "display-panes-active-colour");
12970c21bfbSnicm
130cf629db8Snicm memcpy(&fgc, &grid_default_cell, sizeof fgc);
131cf629db8Snicm memcpy(&bgc, &grid_default_cell, sizeof bgc);
132cf629db8Snicm if (w->active == wp) {
133cf629db8Snicm fgc.fg = active_colour;
134cf629db8Snicm bgc.bg = active_colour;
135cf629db8Snicm } else {
136cf629db8Snicm fgc.fg = colour;
137cf629db8Snicm bgc.bg = colour;
138cf629db8Snicm }
139cf629db8Snicm
140cf629db8Snicm rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
141cf629db8Snicm if (pane > 9 && pane < 35)
142cf629db8Snicm llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
143cf629db8Snicm else
144cf629db8Snicm llen = 0;
145cf629db8Snicm
14670c21bfbSnicm if (sx < len * 6 || sy < 5) {
1472df6775cSnicm tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
148cf629db8Snicm if (sx >= len + llen + 1) {
149cf629db8Snicm len += llen + 1;
15070c21bfbSnicm tty_cursor(tty, xoff + px - len / 2, yoff + py);
151cf629db8Snicm tty_putn(tty, buf, len, len);
152cf629db8Snicm tty_putn(tty, " ", 1, 1);
153cf629db8Snicm tty_putn(tty, lbuf, llen, llen);
154cf629db8Snicm } else {
155cf629db8Snicm tty_cursor(tty, xoff + px - len / 2, yoff + py);
156cf629db8Snicm tty_putn(tty, buf, len, len);
157cf629db8Snicm }
158cf629db8Snicm goto out;
15970c21bfbSnicm }
16070c21bfbSnicm
16170c21bfbSnicm px -= len * 3;
16270c21bfbSnicm py -= 2;
16370c21bfbSnicm
1642df6775cSnicm tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL);
16570c21bfbSnicm for (ptr = buf; *ptr != '\0'; ptr++) {
16670c21bfbSnicm if (*ptr < '0' || *ptr > '9')
16770c21bfbSnicm continue;
16870c21bfbSnicm idx = *ptr - '0';
16970c21bfbSnicm
17070c21bfbSnicm for (j = 0; j < 5; j++) {
17170c21bfbSnicm for (i = px; i < px + 5; i++) {
17270c21bfbSnicm tty_cursor(tty, xoff + i, yoff + py + j);
17370c21bfbSnicm if (window_clock_table[idx][j][i - px])
17470c21bfbSnicm tty_putc(tty, ' ');
17570c21bfbSnicm }
17670c21bfbSnicm }
17770c21bfbSnicm px += 6;
17870c21bfbSnicm }
17970c21bfbSnicm
18033491e32Snicm if (sy <= 6)
181cf629db8Snicm goto out;
1822df6775cSnicm tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
183cf629db8Snicm if (rlen != 0 && sx >= rlen) {
184cf629db8Snicm tty_cursor(tty, xoff + sx - rlen, yoff);
185cf629db8Snicm tty_putn(tty, rbuf, rlen, rlen);
186cf629db8Snicm }
187cf629db8Snicm if (llen != 0) {
188cf629db8Snicm tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
189cf629db8Snicm yoff + py + 5);
190cf629db8Snicm tty_putn(tty, lbuf, llen, llen);
191cf629db8Snicm }
19270c21bfbSnicm
193cf629db8Snicm out:
19470c21bfbSnicm tty_cursor(tty, 0, 0);
19570c21bfbSnicm }
19670c21bfbSnicm
19770c21bfbSnicm static void
cmd_display_panes_draw(struct client * c,__unused void * data,struct screen_redraw_ctx * ctx)198f38784aeSnicm cmd_display_panes_draw(struct client *c, __unused void *data,
199f38784aeSnicm struct screen_redraw_ctx *ctx)
20070c21bfbSnicm {
20170c21bfbSnicm struct window *w = c->session->curw->window;
20270c21bfbSnicm struct window_pane *wp;
20370c21bfbSnicm
20470c21bfbSnicm log_debug("%s: %s @%u", __func__, c->name, w->id);
20570c21bfbSnicm
20670c21bfbSnicm TAILQ_FOREACH(wp, &w->panes, entry) {
20770c21bfbSnicm if (window_pane_visible(wp))
20870c21bfbSnicm cmd_display_panes_draw_pane(ctx, wp);
20970c21bfbSnicm }
210669c539cSnicm }
2112413453fSnicm
2122413453fSnicm static void
cmd_display_panes_free(__unused struct client * c,void * data)213f38784aeSnicm cmd_display_panes_free(__unused struct client *c, void *data)
2142413453fSnicm {
215f38784aeSnicm struct cmd_display_panes_data *cdata = data;
21670c21bfbSnicm
21770c21bfbSnicm if (cdata->item != NULL)
218780ca620Snicm cmdq_continue(cdata->item);
2192db6a388Snicm args_make_commands_free(cdata->state);
22070c21bfbSnicm free(cdata);
22170c21bfbSnicm }
22270c21bfbSnicm
22370c21bfbSnicm static int
cmd_display_panes_key(struct client * c,void * data,struct key_event * event)224f38784aeSnicm cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
22570c21bfbSnicm {
226f38784aeSnicm struct cmd_display_panes_data *cdata = data;
2272db6a388Snicm char *expanded, *error;
2282db6a388Snicm struct cmdq_item *item = cdata->item, *new_item;
2292db6a388Snicm struct cmd_list *cmdlist;
23070c21bfbSnicm struct window *w = c->session->curw->window;
23170c21bfbSnicm struct window_pane *wp;
232cf629db8Snicm u_int index;
233cf629db8Snicm key_code key;
2342413453fSnicm
235cf629db8Snicm if (event->key >= '0' && event->key <= '9')
236cf629db8Snicm index = event->key - '0';
237cf629db8Snicm else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
238cf629db8Snicm key = (event->key & KEYC_MASK_KEY);
239cf629db8Snicm if (key >= 'a' && key <= 'z')
240cf629db8Snicm index = 10 + (key - 'a');
241cf629db8Snicm else
242cf629db8Snicm return (-1);
243cf629db8Snicm } else
244ab90d8c3Snicm return (-1);
24570c21bfbSnicm
246cf629db8Snicm wp = window_pane_at_index(w, index);
247765b9a58Snicm if (wp == NULL)
24870c21bfbSnicm return (1);
249*0ad0daf4Snicm window_unzoom(w, 1);
250e8c2b18dSnicm
2512413453fSnicm xasprintf(&expanded, "%%%u", wp->id);
2522413453fSnicm
2532db6a388Snicm cmdlist = args_make_commands(cdata->state, 1, &expanded, &error);
2542db6a388Snicm if (cmdlist == NULL) {
2551c43462cSnicm cmdq_append(c, cmdq_get_error(error));
2561c43462cSnicm free(error);
2572db6a388Snicm } else if (item == NULL) {
2582db6a388Snicm new_item = cmdq_get_command(cmdlist, NULL);
2592db6a388Snicm cmdq_append(c, new_item);
2602db6a388Snicm } else {
2612db6a388Snicm new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
2622db6a388Snicm cmdq_insert_after(item, new_item);
2637018a461Snicm }
264765b9a58Snicm
2652413453fSnicm free(expanded);
26670c21bfbSnicm return (1);
2677018a461Snicm }
268e8c2b18dSnicm
26970c21bfbSnicm static enum cmd_retval
cmd_display_panes_exec(struct cmd * self,struct cmdq_item * item)27070c21bfbSnicm cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
27170c21bfbSnicm {
27290d7ba38Snicm struct args *args = cmd_get_args(self);
273035dc73dSnicm struct client *tc = cmdq_get_target_client(item);
274035dc73dSnicm struct session *s = tc->session;
27570c21bfbSnicm u_int delay;
27670c21bfbSnicm char *cause;
27770c21bfbSnicm struct cmd_display_panes_data *cdata;
2782db6a388Snicm int wait = !args_has(args, 'b');
279e8c2b18dSnicm
280035dc73dSnicm if (tc->overlay_draw != NULL)
28170c21bfbSnicm return (CMD_RETURN_NORMAL);
28270c21bfbSnicm
28370c21bfbSnicm if (args_has(args, 'd')) {
28470c21bfbSnicm delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
28570c21bfbSnicm if (cause != NULL) {
28670c21bfbSnicm cmdq_error(item, "delay %s", cause);
28770c21bfbSnicm free(cause);
28870c21bfbSnicm return (CMD_RETURN_ERROR);
28970c21bfbSnicm }
29070c21bfbSnicm } else
29170c21bfbSnicm delay = options_get_number(s->options, "display-panes-time");
29270c21bfbSnicm
2932db6a388Snicm cdata = xcalloc(1, sizeof *cdata);
2942db6a388Snicm if (wait)
29570c21bfbSnicm cdata->item = item;
2962db6a388Snicm cdata->state = args_make_commands_prepare(self, item, 0,
2972db6a388Snicm "select-pane -t \"%%%\"", wait, 0);
29870c21bfbSnicm
29988eb9092Snicm if (args_has(args, 'N')) {
30088eb9092Snicm server_client_set_overlay(tc, delay, NULL, NULL,
301c0287628Snicm cmd_display_panes_draw, NULL, cmd_display_panes_free, NULL,
30288eb9092Snicm cdata);
30388eb9092Snicm } else {
30488eb9092Snicm server_client_set_overlay(tc, delay, NULL, NULL,
30588eb9092Snicm cmd_display_panes_draw, cmd_display_panes_key,
306c0287628Snicm cmd_display_panes_free, NULL, cdata);
30788eb9092Snicm }
30870c21bfbSnicm
3092db6a388Snicm if (!wait)
31070c21bfbSnicm return (CMD_RETURN_NORMAL);
31170c21bfbSnicm return (CMD_RETURN_WAIT);
3122413453fSnicm }
313