xref: /openbsd-src/usr.bin/tmux/cmd-display-panes.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /* $OpenBSD: cmd-display-panes.c,v 1.29 2019/06/26 18:28:31 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * Display panes on a client.
28  */
29 
30 static enum cmd_retval	cmd_display_panes_exec(struct cmd *,
31 			    struct cmdq_item *);
32 
33 const struct cmd_entry cmd_display_panes_entry = {
34 	.name = "display-panes",
35 	.alias = "displayp",
36 
37 	.args = { "bd:t:", 0, 1 },
38 	.usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
39 
40 	.flags = CMD_AFTERHOOK,
41 	.exec = cmd_display_panes_exec
42 };
43 
44 struct cmd_display_panes_data {
45 	struct cmdq_item	*item;
46 	char			*command;
47 };
48 
49 static void
50 cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
51     struct window_pane *wp)
52 {
53 	struct client		*c = ctx->c;
54 	struct tty		*tty = &c->tty;
55 	struct session		*s = c->session;
56 	struct options		*oo = s->options;
57 	struct window		*w = wp->window;
58 	struct grid_cell	 gc;
59 	u_int			 idx, px, py, i, j, xoff, yoff, sx, sy;
60 	int			 colour, active_colour;
61 	char			 buf[16], *ptr;
62 	size_t			 len;
63 
64 	if (wp->xoff + wp->sx <= ctx->ox ||
65 	    wp->xoff >= ctx->ox + ctx->sx ||
66 	    wp->yoff + wp->sy <= ctx->oy ||
67 	    wp->yoff >= ctx->oy + ctx->sy)
68 		return;
69 
70 	if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
71 		/* All visible. */
72 		xoff = wp->xoff - ctx->ox;
73 		sx = wp->sx;
74 	} else if (wp->xoff < ctx->ox &&
75 	    wp->xoff + wp->sx > ctx->ox + ctx->sx) {
76 		/* Both left and right not visible. */
77 		xoff = 0;
78 		sx = ctx->sx;
79 	} else if (wp->xoff < ctx->ox) {
80 		/* Left not visible. */
81 		xoff = 0;
82 		sx = wp->sx - (ctx->ox - wp->xoff);
83 	} else {
84 		/* Right not visible. */
85 		xoff = wp->xoff - ctx->ox;
86 		sx = wp->sx - xoff;
87 	}
88 	if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
89 		/* All visible. */
90 		yoff = wp->yoff - ctx->oy;
91 		sy = wp->sy;
92 	} else if (wp->yoff < ctx->oy &&
93 	    wp->yoff + wp->sy > ctx->oy + ctx->sy) {
94 		/* Both top and bottom not visible. */
95 		yoff = 0;
96 		sy = ctx->sy;
97 	} else if (wp->yoff < ctx->oy) {
98 		/* Top not visible. */
99 		yoff = 0;
100 		sy = wp->sy - (ctx->oy - wp->yoff);
101 	} else {
102 		/* Bottom not visible. */
103 		yoff = wp->yoff - ctx->oy;
104 		sy = wp->sy - yoff;
105 	}
106 
107 	if (ctx->statustop)
108 		yoff += ctx->statuslines;
109 	px = sx / 2;
110 	py = sy / 2;
111 
112 	if (window_pane_index(wp, &idx) != 0)
113 		fatalx("index not found");
114 	len = xsnprintf(buf, sizeof buf, "%u", idx);
115 
116 	if (sx < len)
117 		return;
118 	colour = options_get_number(oo, "display-panes-colour");
119 	active_colour = options_get_number(oo, "display-panes-active-colour");
120 
121 	if (sx < len * 6 || sy < 5) {
122 		tty_cursor(tty, xoff + px - len / 2, yoff + py);
123 		goto draw_text;
124 	}
125 
126 	px -= len * 3;
127 	py -= 2;
128 
129 	memcpy(&gc, &grid_default_cell, sizeof gc);
130 	if (w->active == wp)
131 		gc.bg = active_colour;
132 	else
133 		gc.bg = colour;
134 	gc.flags |= GRID_FLAG_NOPALETTE;
135 
136 	tty_attributes(tty, &gc, wp);
137 	for (ptr = buf; *ptr != '\0'; ptr++) {
138 		if (*ptr < '0' || *ptr > '9')
139 			continue;
140 		idx = *ptr - '0';
141 
142 		for (j = 0; j < 5; j++) {
143 			for (i = px; i < px + 5; i++) {
144 				tty_cursor(tty, xoff + i, yoff + py + j);
145 				if (window_clock_table[idx][j][i - px])
146 					tty_putc(tty, ' ');
147 			}
148 		}
149 		px += 6;
150 	}
151 
152 	len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
153 	if (sx < len || sy < 6)
154 		return;
155 	tty_cursor(tty, xoff + sx - len, yoff);
156 
157 draw_text:
158 	memcpy(&gc, &grid_default_cell, sizeof gc);
159 	if (w->active == wp)
160 		gc.fg = active_colour;
161 	else
162 		gc.fg = colour;
163 	gc.flags |= GRID_FLAG_NOPALETTE;
164 
165 	tty_attributes(tty, &gc, wp);
166 	tty_puts(tty, buf);
167 
168 	tty_cursor(tty, 0, 0);
169 }
170 
171 static void
172 cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
173 {
174 	struct window		*w = c->session->curw->window;
175 	struct window_pane	*wp;
176 
177 	log_debug("%s: %s @%u", __func__, c->name, w->id);
178 
179 	TAILQ_FOREACH(wp, &w->panes, entry) {
180 		if (window_pane_visible(wp))
181 			cmd_display_panes_draw_pane(ctx, wp);
182 	}
183 }
184 
185 static void
186 cmd_display_panes_free(struct client *c)
187 {
188 	struct cmd_display_panes_data	*cdata = c->overlay_data;
189 
190 	if (cdata->item != NULL)
191 		cmdq_continue(cdata->item);
192 	free(cdata->command);
193 	free(cdata);
194 }
195 
196 static int
197 cmd_display_panes_key(struct client *c, struct key_event *event)
198 {
199 	struct cmd_display_panes_data	*cdata = c->overlay_data;
200 	struct cmdq_item		*new_item;
201 	char				*cmd, *expanded;
202 	struct window			*w = c->session->curw->window;
203 	struct window_pane		*wp;
204 	struct cmd_parse_result		*pr;
205 
206 	if (event->key < '0' || event->key > '9')
207 		return (-1);
208 
209 	wp = window_pane_at_index(w, event->key - '0');
210 	if (wp == NULL)
211 		return (1);
212 	window_unzoom(w);
213 
214 	xasprintf(&expanded, "%%%u", wp->id);
215 	cmd = cmd_template_replace(cdata->command, expanded, 1);
216 
217 	pr = cmd_parse_from_string(cmd, NULL);
218 	switch (pr->status) {
219 	case CMD_PARSE_EMPTY:
220 		new_item = NULL;
221 		break;
222 	case CMD_PARSE_ERROR:
223 		new_item = cmdq_get_error(pr->error);
224 		free(pr->error);
225 		cmdq_append(c, new_item);
226 		break;
227 	case CMD_PARSE_SUCCESS:
228 		new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
229 		cmd_list_free(pr->cmdlist);
230 		cmdq_append(c, new_item);
231 		break;
232 	}
233 
234 	free(cmd);
235 	free(expanded);
236 	return (1);
237 }
238 
239 static enum cmd_retval
240 cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
241 {
242 	struct args			*args = self->args;
243 	struct client			*c;
244 	struct session			*s;
245 	u_int		 		 delay;
246 	char				*cause;
247 	struct cmd_display_panes_data	*cdata;
248 
249 	if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
250 		return (CMD_RETURN_ERROR);
251 	s = c->session;
252 
253 	if (c->overlay_draw != NULL)
254 		return (CMD_RETURN_NORMAL);
255 
256 	if (args_has(args, 'd')) {
257 		delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
258 		if (cause != NULL) {
259 			cmdq_error(item, "delay %s", cause);
260 			free(cause);
261 			return (CMD_RETURN_ERROR);
262 		}
263 	} else
264 		delay = options_get_number(s->options, "display-panes-time");
265 
266 	cdata = xmalloc(sizeof *cdata);
267 	if (args->argc != 0)
268 		cdata->command = xstrdup(args->argv[0]);
269 	else
270 		cdata->command = xstrdup("select-pane -t '%%'");
271 	if (args_has(args, 'b'))
272 		cdata->item = NULL;
273 	else
274 		cdata->item = item;
275 
276 	server_client_set_overlay(c, delay, cmd_display_panes_draw,
277 	    cmd_display_panes_key, cmd_display_panes_free, cdata);
278 
279 	if (args_has(args, 'b'))
280 		return (CMD_RETURN_NORMAL);
281 	return (CMD_RETURN_WAIT);
282 }
283