1 /* $OpenBSD: cmd-display-panes.c,v 1.35 2020/05/16 15:34:08 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|CMD_CLIENT_TFLAG, 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 tty_attributes(tty, &gc, &grid_default_cell, NULL); 135 for (ptr = buf; *ptr != '\0'; ptr++) { 136 if (*ptr < '0' || *ptr > '9') 137 continue; 138 idx = *ptr - '0'; 139 140 for (j = 0; j < 5; j++) { 141 for (i = px; i < px + 5; i++) { 142 tty_cursor(tty, xoff + i, yoff + py + j); 143 if (window_clock_table[idx][j][i - px]) 144 tty_putc(tty, ' '); 145 } 146 } 147 px += 6; 148 } 149 150 len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy); 151 if (sx < len || sy < 6) 152 return; 153 tty_cursor(tty, xoff + sx - len, yoff); 154 155 draw_text: 156 memcpy(&gc, &grid_default_cell, sizeof gc); 157 if (w->active == wp) 158 gc.fg = active_colour; 159 else 160 gc.fg = colour; 161 tty_attributes(tty, &gc, &grid_default_cell, NULL); 162 tty_puts(tty, buf); 163 164 tty_cursor(tty, 0, 0); 165 } 166 167 static void 168 cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx) 169 { 170 struct window *w = c->session->curw->window; 171 struct window_pane *wp; 172 173 log_debug("%s: %s @%u", __func__, c->name, w->id); 174 175 TAILQ_FOREACH(wp, &w->panes, entry) { 176 if (window_pane_visible(wp)) 177 cmd_display_panes_draw_pane(ctx, wp); 178 } 179 } 180 181 static void 182 cmd_display_panes_free(struct client *c) 183 { 184 struct cmd_display_panes_data *cdata = c->overlay_data; 185 186 if (cdata->item != NULL) 187 cmdq_continue(cdata->item); 188 free(cdata->command); 189 free(cdata); 190 } 191 192 static int 193 cmd_display_panes_key(struct client *c, struct key_event *event) 194 { 195 struct cmd_display_panes_data *cdata = c->overlay_data; 196 char *cmd, *expanded, *error; 197 struct window *w = c->session->curw->window; 198 struct window_pane *wp; 199 enum cmd_parse_status status; 200 201 if (event->key < '0' || event->key > '9') 202 return (-1); 203 204 wp = window_pane_at_index(w, event->key - '0'); 205 if (wp == NULL) 206 return (1); 207 window_unzoom(w); 208 209 xasprintf(&expanded, "%%%u", wp->id); 210 cmd = cmd_template_replace(cdata->command, expanded, 1); 211 212 status = cmd_parse_and_append(cmd, NULL, c, NULL, &error); 213 if (status == CMD_PARSE_ERROR) { 214 cmdq_append(c, cmdq_get_error(error)); 215 free(error); 216 } 217 218 free(cmd); 219 free(expanded); 220 return (1); 221 } 222 223 static enum cmd_retval 224 cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) 225 { 226 struct args *args = cmd_get_args(self); 227 struct client *tc = cmdq_get_target_client(item); 228 struct session *s = tc->session; 229 u_int delay; 230 char *cause; 231 struct cmd_display_panes_data *cdata; 232 233 if (tc->overlay_draw != NULL) 234 return (CMD_RETURN_NORMAL); 235 236 if (args_has(args, 'd')) { 237 delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause); 238 if (cause != NULL) { 239 cmdq_error(item, "delay %s", cause); 240 free(cause); 241 return (CMD_RETURN_ERROR); 242 } 243 } else 244 delay = options_get_number(s->options, "display-panes-time"); 245 246 cdata = xmalloc(sizeof *cdata); 247 if (args->argc != 0) 248 cdata->command = xstrdup(args->argv[0]); 249 else 250 cdata->command = xstrdup("select-pane -t '%%'"); 251 if (args_has(args, 'b')) 252 cdata->item = NULL; 253 else 254 cdata->item = item; 255 256 server_client_set_overlay(tc, delay, NULL, NULL, cmd_display_panes_draw, 257 cmd_display_panes_key, cmd_display_panes_free, cdata); 258 259 if (args_has(args, 'b')) 260 return (CMD_RETURN_NORMAL); 261 return (CMD_RETURN_WAIT); 262 } 263