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