Do not crash if in buffer mode and the last buffer is deleted using the
[tmux.git] / cmd-display-panes.c
blob06f6dc277a987d99e2ea65bcef5df4d7be297ebf
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "tmux.h"
27 * Display panes on a client.
30 static enum args_parse_type cmd_display_panes_args_parse(struct args *,
31 u_int, char **);
32 static enum cmd_retval cmd_display_panes_exec(struct cmd *,
33 struct cmdq_item *);
35 const struct cmd_entry cmd_display_panes_entry = {
36 .name = "display-panes",
37 .alias = "displayp",
39 .args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse },
40 .usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
42 .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
43 .exec = cmd_display_panes_exec
46 struct cmd_display_panes_data {
47 struct cmdq_item *item;
48 struct args_command_state *state;
51 static enum args_parse_type
52 cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
53 __unused char **cause)
55 return (ARGS_PARSE_COMMANDS_OR_STRING);
58 static void
59 cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
60 struct window_pane *wp)
62 struct client *c = ctx->c;
63 struct tty *tty = &c->tty;
64 struct session *s = c->session;
65 struct options *oo = s->options;
66 struct window *w = wp->window;
67 struct grid_cell fgc, bgc;
68 u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
69 int colour, active_colour;
70 char buf[16], lbuf[16], rbuf[16], *ptr;
71 size_t len, llen, rlen;
73 if (wp->xoff + wp->sx <= ctx->ox ||
74 wp->xoff >= ctx->ox + ctx->sx ||
75 wp->yoff + wp->sy <= ctx->oy ||
76 wp->yoff >= ctx->oy + ctx->sy)
77 return;
79 if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
80 /* All visible. */
81 xoff = wp->xoff - ctx->ox;
82 sx = wp->sx;
83 } else if (wp->xoff < ctx->ox &&
84 wp->xoff + wp->sx > ctx->ox + ctx->sx) {
85 /* Both left and right not visible. */
86 xoff = 0;
87 sx = ctx->sx;
88 } else if (wp->xoff < ctx->ox) {
89 /* Left not visible. */
90 xoff = 0;
91 sx = wp->sx - (ctx->ox - wp->xoff);
92 } else {
93 /* Right not visible. */
94 xoff = wp->xoff - ctx->ox;
95 sx = wp->sx - xoff;
97 if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
98 /* All visible. */
99 yoff = wp->yoff - ctx->oy;
100 sy = wp->sy;
101 } else if (wp->yoff < ctx->oy &&
102 wp->yoff + wp->sy > ctx->oy + ctx->sy) {
103 /* Both top and bottom not visible. */
104 yoff = 0;
105 sy = ctx->sy;
106 } else if (wp->yoff < ctx->oy) {
107 /* Top not visible. */
108 yoff = 0;
109 sy = wp->sy - (ctx->oy - wp->yoff);
110 } else {
111 /* Bottom not visible. */
112 yoff = wp->yoff - ctx->oy;
113 sy = wp->sy - yoff;
116 if (ctx->statustop)
117 yoff += ctx->statuslines;
118 px = sx / 2;
119 py = sy / 2;
121 if (window_pane_index(wp, &pane) != 0)
122 fatalx("index not found");
123 len = xsnprintf(buf, sizeof buf, "%u", pane);
125 if (sx < len)
126 return;
127 colour = options_get_number(oo, "display-panes-colour");
128 active_colour = options_get_number(oo, "display-panes-active-colour");
130 memcpy(&fgc, &grid_default_cell, sizeof fgc);
131 memcpy(&bgc, &grid_default_cell, sizeof bgc);
132 if (w->active == wp) {
133 fgc.fg = active_colour;
134 bgc.bg = active_colour;
135 } else {
136 fgc.fg = colour;
137 bgc.bg = colour;
140 rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
141 if (pane > 9 && pane < 35)
142 llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
143 else
144 llen = 0;
146 if (sx < len * 6 || sy < 5) {
147 tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
148 if (sx >= len + llen + 1) {
149 len += llen + 1;
150 tty_cursor(tty, xoff + px - len / 2, yoff + py);
151 tty_putn(tty, buf, len, len);
152 tty_putn(tty, " ", 1, 1);
153 tty_putn(tty, lbuf, llen, llen);
154 } else {
155 tty_cursor(tty, xoff + px - len / 2, yoff + py);
156 tty_putn(tty, buf, len, len);
158 goto out;
161 px -= len * 3;
162 py -= 2;
164 tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL);
165 for (ptr = buf; *ptr != '\0'; ptr++) {
166 if (*ptr < '0' || *ptr > '9')
167 continue;
168 idx = *ptr - '0';
170 for (j = 0; j < 5; j++) {
171 for (i = px; i < px + 5; i++) {
172 tty_cursor(tty, xoff + i, yoff + py + j);
173 if (window_clock_table[idx][j][i - px])
174 tty_putc(tty, ' ');
177 px += 6;
180 if (sy <= 6)
181 goto out;
182 tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
183 if (rlen != 0 && sx >= rlen) {
184 tty_cursor(tty, xoff + sx - rlen, yoff);
185 tty_putn(tty, rbuf, rlen, rlen);
187 if (llen != 0) {
188 tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
189 yoff + py + 5);
190 tty_putn(tty, lbuf, llen, llen);
193 out:
194 tty_cursor(tty, 0, 0);
197 static void
198 cmd_display_panes_draw(struct client *c, __unused void *data,
199 struct screen_redraw_ctx *ctx)
201 struct window *w = c->session->curw->window;
202 struct window_pane *wp;
204 log_debug("%s: %s @%u", __func__, c->name, w->id);
206 TAILQ_FOREACH(wp, &w->panes, entry) {
207 if (window_pane_visible(wp))
208 cmd_display_panes_draw_pane(ctx, wp);
212 static void
213 cmd_display_panes_free(__unused struct client *c, void *data)
215 struct cmd_display_panes_data *cdata = data;
217 if (cdata->item != NULL)
218 cmdq_continue(cdata->item);
219 args_make_commands_free(cdata->state);
220 free(cdata);
223 static int
224 cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
226 struct cmd_display_panes_data *cdata = data;
227 char *expanded, *error;
228 struct cmdq_item *item = cdata->item, *new_item;
229 struct cmd_list *cmdlist;
230 struct window *w = c->session->curw->window;
231 struct window_pane *wp;
232 u_int index;
233 key_code key;
235 if (event->key >= '0' && event->key <= '9')
236 index = event->key - '0';
237 else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
238 key = (event->key & KEYC_MASK_KEY);
239 if (key >= 'a' && key <= 'z')
240 index = 10 + (key - 'a');
241 else
242 return (-1);
243 } else
244 return (-1);
246 wp = window_pane_at_index(w, index);
247 if (wp == NULL)
248 return (1);
249 window_unzoom(w);
251 xasprintf(&expanded, "%%%u", wp->id);
253 cmdlist = args_make_commands(cdata->state, 1, &expanded, &error);
254 if (cmdlist == NULL) {
255 cmdq_append(c, cmdq_get_error(error));
256 free(error);
257 } else if (item == NULL) {
258 new_item = cmdq_get_command(cmdlist, NULL);
259 cmdq_append(c, new_item);
260 } else {
261 new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
262 cmdq_insert_after(item, new_item);
265 free(expanded);
266 return (1);
269 static enum cmd_retval
270 cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
272 struct args *args = cmd_get_args(self);
273 struct client *tc = cmdq_get_target_client(item);
274 struct session *s = tc->session;
275 u_int delay;
276 char *cause;
277 struct cmd_display_panes_data *cdata;
278 int wait = !args_has(args, 'b');
280 if (tc->overlay_draw != NULL)
281 return (CMD_RETURN_NORMAL);
283 if (args_has(args, 'd')) {
284 delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
285 if (cause != NULL) {
286 cmdq_error(item, "delay %s", cause);
287 free(cause);
288 return (CMD_RETURN_ERROR);
290 } else
291 delay = options_get_number(s->options, "display-panes-time");
293 cdata = xcalloc(1, sizeof *cdata);
294 if (wait)
295 cdata->item = item;
296 cdata->state = args_make_commands_prepare(self, item, 0,
297 "select-pane -t \"%%%\"", wait, 0);
299 if (args_has(args, 'N')) {
300 server_client_set_overlay(tc, delay, NULL, NULL,
301 cmd_display_panes_draw, NULL, cmd_display_panes_free, NULL,
302 cdata);
303 } else {
304 server_client_set_overlay(tc, delay, NULL, NULL,
305 cmd_display_panes_draw, cmd_display_panes_key,
306 cmd_display_panes_free, NULL, cdata);
309 if (!wait)
310 return (CMD_RETURN_NORMAL);
311 return (CMD_RETURN_WAIT);