1/* $OpenBSD$ */ 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 30static enum args_parse_type cmd_display_panes_args_parse(struct args *, 31 u_int, char **); 32static enum cmd_retval cmd_display_panes_exec(struct cmd *, 33 struct cmdq_item *); 34 35const struct cmd_entry cmd_display_panes_entry = { 36 .name = "display-panes", 37 .alias = "displayp", 38 39 .args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse }, 40 .usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]", 41 42 .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, 43 .exec = cmd_display_panes_exec 44}; 45 46struct cmd_display_panes_data { 47 struct cmdq_item *item; 48 struct args_command_state *state; 49}; 50 51static enum args_parse_type 52cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx, 53 __unused char **cause) 54{ 55 return (ARGS_PARSE_COMMANDS_OR_STRING); 56} 57 58static void 59cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx, 60 struct window_pane *wp) 61{ 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; 72 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; 78 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; 96 } 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; 114 } 115 116 if (ctx->statustop) 117 yoff += ctx->statuslines; 118 px = sx / 2; 119 py = sy / 2; 120 121 if (window_pane_index(wp, &pane) != 0) 122 fatalx("index not found"); 123 len = xsnprintf(buf, sizeof buf, "%u", pane); 124 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"); 129 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; 138 } 139 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; 145 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); 157 } 158 goto out; 159 } 160 161 px -= len * 3; 162 py -= 2; 163 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'; 169 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, ' '); 175 } 176 } 177 px += 6; 178 } 179 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); 186 } 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); 191 } 192 193out: 194 tty_cursor(tty, 0, 0); 195} 196 197static void 198cmd_display_panes_draw(struct client *c, __unused void *data, 199 struct screen_redraw_ctx *ctx) 200{ 201 struct window *w = c->session->curw->window; 202 struct window_pane *wp; 203 204 log_debug("%s: %s @%u", __func__, c->name, w->id); 205 206 TAILQ_FOREACH(wp, &w->panes, entry) { 207 if (window_pane_visible(wp)) 208 cmd_display_panes_draw_pane(ctx, wp); 209 } 210} 211 212static void 213cmd_display_panes_free(__unused struct client *c, void *data) 214{ 215 struct cmd_display_panes_data *cdata = data; 216 217 if (cdata->item != NULL) 218 cmdq_continue(cdata->item); 219 args_make_commands_free(cdata->state); 220 free(cdata); 221} 222 223static int 224cmd_display_panes_key(struct client *c, void *data, struct key_event *event) 225{ 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; 234 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); 245 246 wp = window_pane_at_index(w, index); 247 if (wp == NULL) 248 return (1); 249 window_unzoom(w); 250 251 xasprintf(&expanded, "%%%u", wp->id); 252 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); 263 } 264 265 free(expanded); 266 return (1); 267} 268 269static enum cmd_retval 270cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) 271{ 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'); 279 280 if (tc->overlay_draw != NULL) 281 return (CMD_RETURN_NORMAL); 282 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); 289 } 290 } else 291 delay = options_get_number(s->options, "display-panes-time"); 292 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); 298 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); 307 } 308 309 if (!wait) 310 return (CMD_RETURN_NORMAL); 311 return (CMD_RETURN_WAIT); 312} 313