Home | History | Annotate | Line # | Download | only in dist
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott (at) 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  * Refresh client.
     28  */
     29 
     30 static enum cmd_retval	cmd_refresh_client_exec(struct cmd *,
     31 			    struct cmdq_item *);
     32 
     33 const struct cmd_entry cmd_refresh_client_entry = {
     34 	.name = "refresh-client",
     35 	.alias = "refresh",
     36 
     37 	.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL },
     38 	.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
     39 		 "[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE
     40 		 " [adjustment]",
     41 
     42 	.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
     43 	.exec = cmd_refresh_client_exec
     44 };
     45 
     46 static void
     47 cmd_refresh_client_update_subscription(struct client *tc, const char *value)
     48 {
     49 	char			*copy, *split, *name, *what;
     50 	enum control_sub_type	 subtype;
     51 	int			 subid = -1;
     52 
     53 	copy = name = xstrdup(value);
     54 	if ((split = strchr(copy, ':')) == NULL) {
     55 		control_remove_sub(tc, copy);
     56 		goto out;
     57 	}
     58 	*split++ = '\0';
     59 
     60 	what = split;
     61 	if ((split = strchr(what, ':')) == NULL)
     62 		goto out;
     63 	*split++ = '\0';
     64 
     65 	if (strcmp(what, "%*") == 0)
     66 		subtype = CONTROL_SUB_ALL_PANES;
     67 	else if (sscanf(what, "%%%d", &subid) == 1 && subid >= 0)
     68 		subtype = CONTROL_SUB_PANE;
     69 	else if (strcmp(what, "@*") == 0)
     70 		subtype = CONTROL_SUB_ALL_WINDOWS;
     71 	else if (sscanf(what, "@%d", &subid) == 1 && subid >= 0)
     72 		subtype = CONTROL_SUB_WINDOW;
     73 	else
     74 		subtype = CONTROL_SUB_SESSION;
     75 	control_add_sub(tc, name, subtype, subid, split);
     76 
     77 out:
     78 	free(copy);
     79 }
     80 
     81 static enum cmd_retval
     82 cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
     83 {
     84 	struct args		*args = cmd_get_args(self);
     85 	struct client		*tc = cmdq_get_target_client(item);
     86 	const char		*size = args_get(args, 'C');
     87 	u_int			 w, x, y;
     88 	struct client_window	*cw;
     89 
     90 	if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) {
     91 		if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
     92 		    y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
     93 			cmdq_error(item, "size too small or too big");
     94 			return (CMD_RETURN_ERROR);
     95 		}
     96 		log_debug("%s: client %s window @%u: size %ux%u", __func__,
     97 		    tc->name, w, x, y);
     98 		cw = server_client_add_client_window(tc, w);
     99 		cw->sx = x;
    100 		cw->sy = y;
    101 		tc->flags |= CLIENT_WINDOWSIZECHANGED;
    102 		recalculate_sizes_now(1);
    103 		return (CMD_RETURN_NORMAL);
    104 	}
    105 	if (sscanf(size, "@%u:", &w) == 1) {
    106 		cw = server_client_get_client_window(tc, w);
    107 		if (cw != NULL) {
    108 			log_debug("%s: client %s window @%u: no size", __func__,
    109 			    tc->name, w);
    110 			cw->sx = 0;
    111 			cw->sy = 0;
    112 			recalculate_sizes_now(1);
    113 		}
    114 		return (CMD_RETURN_NORMAL);
    115 	}
    116 
    117 	if (sscanf(size, "%u,%u", &x, &y) != 2 &&
    118 	    sscanf(size, "%ux%u", &x, &y) != 2) {
    119 		cmdq_error(item, "bad size argument");
    120 		return (CMD_RETURN_ERROR);
    121 	}
    122 	if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
    123 	    y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
    124 		cmdq_error(item, "size too small or too big");
    125 		return (CMD_RETURN_ERROR);
    126 	}
    127 	tty_set_size(&tc->tty, x, y, 0, 0);
    128 	tc->flags |= CLIENT_SIZECHANGED;
    129 	recalculate_sizes_now(1);
    130 	return (CMD_RETURN_NORMAL);
    131 }
    132 
    133 static void
    134 cmd_refresh_client_update_offset(struct client *tc, const char *value)
    135 {
    136 	struct window_pane	*wp;
    137 	char			*copy, *split;
    138 	u_int			 pane;
    139 
    140 	if (*value != '%')
    141 		return;
    142 	copy = xstrdup(value);
    143 	if ((split = strchr(copy, ':')) == NULL)
    144 		goto out;
    145 	*split++ = '\0';
    146 
    147 	if (sscanf(copy, "%%%u", &pane) != 1)
    148 		goto out;
    149 	wp = window_pane_find_by_id(pane);
    150 	if (wp == NULL)
    151 		goto out;
    152 
    153 	if (strcmp(split, "on") == 0)
    154 		control_set_pane_on(tc, wp);
    155 	else if (strcmp(split, "off") == 0)
    156 		control_set_pane_off(tc, wp);
    157 	else if (strcmp(split, "continue") == 0)
    158 		control_continue_pane(tc, wp);
    159 	else if (strcmp(split, "pause") == 0)
    160 		control_pause_pane(tc, wp);
    161 
    162 out:
    163 	free(copy);
    164 }
    165 
    166 static enum cmd_retval
    167 cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
    168 {
    169 	struct args		*args = cmd_get_args(self);
    170 	struct client		*tc = cmdq_get_target_client(item);
    171 	const char		*p;
    172 	u_int			 i;
    173 	struct cmd_find_state	 fs;
    174 
    175 	p = args_get(args, 'l');
    176 	if (p == NULL) {
    177 		if (tc->flags & CLIENT_CLIPBOARDBUFFER)
    178 			return (CMD_RETURN_NORMAL);
    179 		tc->flags |= CLIENT_CLIPBOARDBUFFER;
    180 	} else {
    181 		if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0)
    182 			return (CMD_RETURN_ERROR);
    183 		for (i = 0; i < tc->clipboard_npanes; i++) {
    184 			if (tc->clipboard_panes[i] == fs.wp->id)
    185 				break;
    186 		}
    187 		if (i != tc->clipboard_npanes)
    188 			return (CMD_RETURN_NORMAL);
    189 		tc->clipboard_panes = xreallocarray(tc->clipboard_panes,
    190 		    tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes);
    191 		tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id;
    192 	}
    193 	tty_clipboard_query(&tc->tty);
    194 	return (CMD_RETURN_NORMAL);
    195 }
    196 
    197 static void
    198 cmd_refresh_report(struct tty *tty, const char *value)
    199 {
    200 	struct window_pane	*wp;
    201 	u_int			 pane;
    202 	size_t			 size = 0;
    203 	char			*copy, *split;
    204 
    205 	if (*value != '%')
    206 		return;
    207 	copy = xstrdup(value);
    208 	if ((split = strchr(copy, ':')) == NULL)
    209 		goto out;
    210 	*split++ = '\0';
    211 
    212 	if (sscanf(copy, "%%%u", &pane) != 1)
    213 		goto out;
    214 	wp = window_pane_find_by_id(pane);
    215 	if (wp == NULL)
    216 		goto out;
    217 
    218 	tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg,
    219 	    &wp->control_bg);
    220 
    221 out:
    222 	free(copy);
    223 }
    224 
    225 static enum cmd_retval
    226 cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
    227 {
    228 	struct args		*args = cmd_get_args(self);
    229 	struct client		*tc = cmdq_get_target_client(item);
    230 	struct tty		*tty = &tc->tty;
    231 	struct window		*w;
    232 	const char		*errstr;
    233 	u_int			 adjust;
    234 	struct args_value	*av;
    235 
    236 	if (args_has(args, 'c') ||
    237 	    args_has(args, 'L') ||
    238 	    args_has(args, 'R') ||
    239 	    args_has(args, 'U') ||
    240 	    args_has(args, 'D'))
    241 	{
    242 		if (args_count(args) == 0)
    243 			adjust = 1;
    244 		else {
    245 			adjust = strtonum(args_string(args, 0), 1, INT_MAX,
    246 			    &errstr);
    247 			if (errstr != NULL) {
    248 				cmdq_error(item, "adjustment %s", errstr);
    249 				return (CMD_RETURN_ERROR);
    250 			}
    251 		}
    252 
    253 		if (args_has(args, 'c'))
    254 			tc->pan_window = NULL;
    255 		else {
    256 			w = tc->session->curw->window;
    257 			if (tc->pan_window != w) {
    258 				tc->pan_window = w;
    259 				tc->pan_ox = tty->oox;
    260 				tc->pan_oy = tty->ooy;
    261 			}
    262 			if (args_has(args, 'L')) {
    263 				if (tc->pan_ox > adjust)
    264 					tc->pan_ox -= adjust;
    265 				else
    266 					tc->pan_ox = 0;
    267 			} else if (args_has(args, 'R')) {
    268 				tc->pan_ox += adjust;
    269 				if (tc->pan_ox > w->sx - tty->osx)
    270 					tc->pan_ox = w->sx - tty->osx;
    271 			} else if (args_has(args, 'U')) {
    272 				if (tc->pan_oy > adjust)
    273 					tc->pan_oy -= adjust;
    274 				else
    275 					tc->pan_oy = 0;
    276 			} else if (args_has(args, 'D')) {
    277 				tc->pan_oy += adjust;
    278 				if (tc->pan_oy > w->sy - tty->osy)
    279 					tc->pan_oy = w->sy - tty->osy;
    280 			}
    281 		}
    282 		tty_update_client_offset(tc);
    283 		server_redraw_client(tc);
    284 		return (CMD_RETURN_NORMAL);
    285 	}
    286 
    287 	if (args_has(args, 'l'))
    288 		return (cmd_refresh_client_clipboard(self, item));
    289 
    290 	if (args_has(args, 'F')) /* -F is an alias for -f */
    291 		server_client_set_flags(tc, args_get(args, 'F'));
    292 	if (args_has(args, 'f'))
    293 		server_client_set_flags(tc, args_get(args, 'f'));
    294 	if (args_has(args, 'r'))
    295 		cmd_refresh_report(tty, args_get(args, 'r'));
    296 
    297 	if (args_has(args, 'A')) {
    298 		if (~tc->flags & CLIENT_CONTROL)
    299 			goto not_control_client;
    300 		av = args_first_value(args, 'A');
    301 		while (av != NULL) {
    302 			cmd_refresh_client_update_offset(tc, av->string);
    303 			av = args_next_value(av);
    304 		}
    305 		return (CMD_RETURN_NORMAL);
    306 	}
    307 	if (args_has(args, 'B')) {
    308 		if (~tc->flags & CLIENT_CONTROL)
    309 			goto not_control_client;
    310 		av = args_first_value(args, 'B');
    311 		while (av != NULL) {
    312 			cmd_refresh_client_update_subscription(tc, av->string);
    313 			av = args_next_value(av);
    314 		}
    315 		return (CMD_RETURN_NORMAL);
    316 	}
    317 	if (args_has(args, 'C')) {
    318 		if (~tc->flags & CLIENT_CONTROL)
    319 			goto not_control_client;
    320 		return (cmd_refresh_client_control_client_size(self, item));
    321 	}
    322 
    323 	if (args_has(args, 'S')) {
    324 		tc->flags |= CLIENT_STATUSFORCE;
    325 		server_status_client(tc);
    326 	} else {
    327 		tc->flags |= CLIENT_STATUSFORCE;
    328 		server_redraw_client(tc);
    329 	}
    330 	return (CMD_RETURN_NORMAL);
    331 
    332 not_control_client:
    333 	cmdq_error(item, "not a control client");
    334 	return (CMD_RETURN_ERROR);
    335 }
    336