1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2009 Nicholas Marriott <[email protected]>
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
30static enum cmd_retval cmd_display_panes_exec(struct cmd *,
31 struct cmdq_item *);
32
33const 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
44struct cmd_display_panes_data {
45 struct cmdq_item *item;
46 char *command;
47};
48
49static void
50cmd_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
157draw_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
171static void
172cmd_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
185static void
186cmd_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
196static int
197cmd_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
239static enum cmd_retval
240cmd_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