Beispiel #1
0
char *
format_window_name(struct window *w)
{
	struct format_tree	*ft;
	char			*fmt, *name;

	ft = format_create(NULL, 0);
	format_defaults_window(ft, w);
	format_defaults_pane(ft, w->active);

	fmt = options_get_string(w->options, "automatic-rename-format");
	name = format_expand(ft, fmt);

	format_free(ft);
	return (name);
}
Beispiel #2
0
enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args			*args = self->args;
	struct cmd_run_shell_data	*cdata;
	char				*shellcmd;
	struct client			*c;
	struct session			*s = NULL;
	struct winlink			*wl = NULL;
	struct window_pane		*wp = NULL;
	struct format_tree		*ft;

	if (args_has(args, 't'))
		wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
	else {
		c = cmd_find_client(cmdq, NULL, 1);
		if (c != NULL && c->session != NULL) {
			s = c->session;
			wl = s->curw;
			wp = wl->window->active;
		}
	}

	ft = format_create();
	if (s != NULL)
		format_session(ft, s);
	if (s != NULL && wl != NULL)
		format_winlink(ft, s, wl);
	if (wp != NULL)
		format_window_pane(ft, wp);
	shellcmd = format_expand(ft, args->argv[0]);
	format_free(ft);

	cdata = xmalloc(sizeof *cdata);
	cdata->cmd = shellcmd;
	cdata->bflag = args_has(args, 'b');
	cdata->wp_id = wp != NULL ? (int) wp->id : -1;

	cdata->cmdq = cmdq;
	cmdq->references++;

	job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata);

	if (cdata->bflag)
		return (CMD_RETURN_NORMAL);
	return (CMD_RETURN_WAIT);
}
Beispiel #3
0
unsigned int
get_python_format_unnamed_arg_count (const char *string)
{
  /* Parse the format string.  */
  char *invalid_reason = NULL;
  struct spec *descr =
    (struct spec *) format_parse (string, false, &invalid_reason);

  if (descr != NULL)
    {
      unsigned int result = descr->unnamed_arg_count;

      format_free (descr);
      return result;
    }
  else
    {
      free (invalid_reason);
      return 0;
    }
}
Beispiel #4
0
enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args		*args = self->args;
	struct session		*s;
	struct winlink		*wl;
	struct client		*c;
	const char		*cmd, *template;
	char			*cause, *cp;
	int			 idx, last, detached, cwd, fd = -1;
	struct format_tree	*ft;

	if (args_has(args, 'a')) {
		wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
		if (wl == NULL)
			return (CMD_RETURN_ERROR);
		idx = wl->idx + 1;

		/* Find the next free index. */
		for (last = idx; last < INT_MAX; last++) {
			if (winlink_find_by_index(&s->windows, last) == NULL)
				break;
		}
		if (last == INT_MAX) {
			cmdq_error(cmdq, "no free window indexes");
			return (CMD_RETURN_ERROR);
		}

		/* Move everything from last - 1 to idx up a bit. */
		for (; last > idx; last--) {
			wl = winlink_find_by_index(&s->windows, last - 1);
			server_link_window(s, wl, s, last, 0, 0, NULL);
			server_unlink_window(s, wl);
		}
	} else {
		if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2)
			return (CMD_RETURN_ERROR);
	}
	detached = args_has(args, 'd');

	wl = NULL;
	if (idx != -1)
		wl = winlink_find_by_index(&s->windows, idx);
	if (wl != NULL && args_has(args, 'k')) {
		/*
		 * Can't use session_detach as it will destroy session if this
		 * makes it empty.
		 */
		notify_window_unlinked(s, wl->window);
		wl->flags &= ~WINLINK_ALERTFLAGS;
		winlink_stack_remove(&s->lastw, wl);
		winlink_remove(&s->windows, wl);

		/* Force select/redraw if current. */
		if (wl == s->curw) {
			detached = 0;
			s->curw = NULL;
		}
	}

	if (args->argc == 0)
		cmd = options_get_string(&s->options, "default-command");
	else
		cmd = args->argv[0];

	if (args_has(args, 'c')) {
		ft = format_create();
		if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
			format_client(ft, c);
		format_session(ft, s);
		format_winlink(ft, s, s->curw);
		format_window_pane(ft, s->curw->window->active);
		cp = format_expand(ft, args_get(args, 'c'));
		format_free(ft);

		fd = open(cp, O_RDONLY|O_DIRECTORY);
		free(cp);
		if (fd == -1) {
			cmdq_error(cmdq, "bad working directory: %s",
			    strerror(errno));
			return (CMD_RETURN_ERROR);
		}
		cwd = fd;
	} else if (cmdq->client != NULL && cmdq->client->session == NULL)
		cwd = cmdq->client->cwd;
	else
		cwd = s->cwd;

	if (idx == -1)
		idx = -1 - options_get_number(&s->options, "base-index");
	wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
	if (wl == NULL) {
		cmdq_error(cmdq, "create window failed: %s", cause);
		free(cause);
		goto error;
	}
	if (!detached) {
		session_select(s, wl->idx);
		server_redraw_session_group(s);
	} else
		server_status_session_group(s);

	if (args_has(args, 'P')) {
		if ((template = args_get(args, 'F')) == NULL)
Beispiel #5
0
enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args		*args = self->args;
	struct client		*c = cmdq->state.c;
	struct window_pane	*wp = cmdq->state.tflag.wp;
	struct session		*s = cmdq->state.tflag.s;
	struct winlink		*wl = cmdq->state.tflag.wl;
	char			*cmd;
	int			 old_fd, pipe_fd[2], null_fd;
	struct format_tree	*ft;

	/* Destroy the old pipe. */
	old_fd = wp->pipe_fd;
	if (wp->pipe_fd != -1) {
		bufferevent_free(wp->pipe_event);
		close(wp->pipe_fd);
		wp->pipe_fd = -1;
	}

	/* If no pipe command, that is enough. */
	if (args->argc == 0 || *args->argv[0] == '\0')
		return (CMD_RETURN_NORMAL);

	/*
	 * With -o, only open the new pipe if there was no previous one. This
	 * allows a pipe to be toggled with a single key, for example:
	 *
	 *	bind ^p pipep -o 'cat >>~/output'
	 */
	if (args_has(self->args, 'o') && old_fd != -1)
		return (CMD_RETURN_NORMAL);

	/* Open the new pipe. */
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
		cmdq_error(cmdq, "socketpair error: %s", strerror(errno));
		return (CMD_RETURN_ERROR);
	}

	/* Expand the command. */
	ft = format_create(cmdq, 0);
	format_defaults(ft, c, s, wl, wp);
	cmd = format_expand_time(ft, args->argv[0], time(NULL));
	format_free(ft);

	/* Fork the child. */
	switch (fork()) {
	case -1:
		cmdq_error(cmdq, "fork error: %s", strerror(errno));

		free(cmd);
		return (CMD_RETURN_ERROR);
	case 0:
		/* Child process. */
		close(pipe_fd[0]);
		clear_signals(1);

		if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
			_exit(1);
		if (pipe_fd[1] != STDIN_FILENO)
			close(pipe_fd[1]);

		null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
		if (dup2(null_fd, STDOUT_FILENO) == -1)
			_exit(1);
		if (dup2(null_fd, STDERR_FILENO) == -1)
			_exit(1);
		if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
			close(null_fd);

		closefrom(STDERR_FILENO + 1);

		execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
		_exit(1);
	default:
		/* Parent process. */
		close(pipe_fd[1]);

		wp->pipe_fd = pipe_fd[0];
		wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);

		wp->pipe_event = bufferevent_new(wp->pipe_fd,
		    NULL, NULL, cmd_pipe_pane_error_callback, wp);
		bufferevent_enable(wp->pipe_event, EV_WRITE);

		setblocking(wp->pipe_fd, 0);

		free(cmd);
		return (CMD_RETURN_NORMAL);
	}
}
Beispiel #6
0
enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args		*args = self->args;
	struct session		*s;
	struct winlink		*wl;
	struct window		*w;
	struct window_pane	*wp, *new_wp = NULL;
	struct environ		 env;
	const char		*cmd, *shell, *template;
	char			*cause, *new_cause, *cp;
	u_int			 hlimit;
	int			 size, percentage, cwd, fd = -1;
	enum layout_type	 type;
	struct layout_cell	*lc;
	struct client		*c;
	struct format_tree	*ft;

	if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
		return (CMD_RETURN_ERROR);
	w = wl->window;
	server_unzoom_window(w);

	environ_init(&env);
	environ_copy(&global_environ, &env);
	environ_copy(&s->environ, &env);
	server_fill_environ(s, &env);

	if (args->argc == 0)
		cmd = options_get_string(&s->options, "default-command");
	else
		cmd = args->argv[0];

	if (args_has(args, 'c')) {
		ft = format_create();
		if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
			format_client(ft, c);
		format_session(ft, s);
		format_winlink(ft, s, s->curw);
		format_window_pane(ft, s->curw->window->active);
		cp = format_expand(ft, args_get(args, 'c'));
		format_free(ft);

		fd = open(cp, O_RDONLY|O_DIRECTORY);
		free(cp);
		if (fd == -1) {
			cmdq_error(cmdq, "bad working directory: %s",
			    strerror(errno));
			return (CMD_RETURN_ERROR);
		}
		cwd = fd;
	} else if (cmdq->client != NULL && cmdq->client->session == NULL)
		cwd = cmdq->client->cwd;
	else
		cwd = s->cwd;

	type = LAYOUT_TOPBOTTOM;
	if (args_has(args, 'h'))
		type = LAYOUT_LEFTRIGHT;

	size = -1;
	if (args_has(args, 'l')) {
		size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
		if (cause != NULL) {
			xasprintf(&new_cause, "size %s", cause);
			free(cause);
			cause = new_cause;
			goto error;
		}
	} else if (args_has(args, 'p')) {
		percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
		if (cause != NULL) {
			xasprintf(&new_cause, "percentage %s", cause);
			free(cause);
			cause = new_cause;
			goto error;
		}
		if (type == LAYOUT_TOPBOTTOM)
			size = (wp->sy * percentage) / 100;
		else
			size = (wp->sx * percentage) / 100;
	}
	hlimit = options_get_number(&s->options, "history-limit");

	shell = options_get_string(&s->options, "default-shell");
	if (*shell == '\0' || areshell(shell))
		shell = _PATH_BSHELL;

	if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) {
		cause = xstrdup("pane too small");
		goto error;
	}
	new_wp = window_add_pane(w, hlimit);
	if (window_pane_spawn(
	    new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
		goto error;
	layout_assign_pane(lc, new_wp);

	server_redraw_window(w);

	if (!args_has(args, 'd')) {
		window_set_active_pane(w, new_wp);
		session_select(s, wl->idx);
		server_redraw_session(s);
	} else
		server_status_session(s);

	environ_free(&env);

	if (args_has(args, 'P')) {
		if ((template = args_get(args, 'F')) == NULL)
Beispiel #7
0
enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args		*args = self->args;
	struct client		*c = cmdq->client, *c0;
	struct session		*s, *groupwith;
	struct window		*w;
	struct environ		 env;
	struct termios		 tio, *tiop;
	const char		*newname, *target, *update, *errstr, *template;
	const char		*path;
	char		       **argv, *cmd, *cause, *cp;
	int			 detached, already_attached, idx, cwd, fd = -1;
	int			 argc;
	u_int			 sx, sy;
	struct format_tree	*ft;
	struct environ_entry	*envent;

	if (self->entry == &cmd_has_session_entry) {
		if (cmd_find_session(cmdq, args_get(args, 't'), 0) == NULL)
			return (CMD_RETURN_ERROR);
		return (CMD_RETURN_NORMAL);
	}

	if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
		cmdq_error(cmdq, "command or window name given with target");
		return (CMD_RETURN_ERROR);
	}

	newname = args_get(args, 's');
	if (newname != NULL) {
		if (!session_check_name(newname)) {
			cmdq_error(cmdq, "bad session name: %s", newname);
			return (CMD_RETURN_ERROR);
		}
		if (session_find(newname) != NULL) {
			if (args_has(args, 'A')) {
				return (cmd_attach_session(cmdq, newname,
				    args_has(args, 'D'), 0, NULL,
				    args_has(args, 'E')));
			}
			cmdq_error(cmdq, "duplicate session: %s", newname);
			return (CMD_RETURN_ERROR);
		}
	}

	target = args_get(args, 't');
	if (target != NULL) {
		groupwith = cmd_find_session(cmdq, target, 0);
		if (groupwith == NULL)
			return (CMD_RETURN_ERROR);
	} else
		groupwith = NULL;

	/* Set -d if no client. */
	detached = args_has(args, 'd');
	if (c == NULL)
		detached = 1;

	/* Is this client already attached? */
	already_attached = 0;
	if (c != NULL && c->session != NULL)
		already_attached = 1;

	/* Get the new session working directory. */
	if (args_has(args, 'c')) {
		ft = format_create();
		format_defaults(ft, cmd_find_client(cmdq, NULL, 1), NULL, NULL,
		    NULL);
		cp = format_expand(ft, args_get(args, 'c'));
		format_free(ft);

		if (cp != NULL && *cp != '\0') {
			fd = open(cp, O_RDONLY|O_DIRECTORY);
			free(cp);
			if (fd == -1) {
				cmdq_error(cmdq, "bad working directory: %s",
				    strerror(errno));
				return (CMD_RETURN_ERROR);
			}
		} else if (cp != NULL)
			free(cp);
		cwd = fd;
	} else if (c != NULL && c->session == NULL)
		cwd = c->cwd;
	else if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL)
		cwd = c0->session->cwd;
	else {
		fd = open(".", O_RDONLY);
		cwd = fd;
	}

	/*
	 * If this is a new client, check for nesting and save the termios
	 * settings (part of which is used for new windows in this session).
	 *
	 * tcgetattr() is used rather than using tty.tio since if the client is
	 * detached, tty_open won't be called. It must be done before opening
	 * the terminal as that calls tcsetattr() to prepare for tmux taking
	 * over.
	 */
	if (!detached && !already_attached && c->tty.fd != -1) {
		if (server_client_check_nested(cmdq->client)) {
			cmdq_error(cmdq, "sessions should be nested with care, "
			    "unset $TMUX to force");
			return (CMD_RETURN_ERROR);
		}
		if (tcgetattr(c->tty.fd, &tio) != 0)
			fatal("tcgetattr failed");
		tiop = &tio;
	} else
		tiop = NULL;

	/* Open the terminal if necessary. */
	if (!detached && !already_attached) {
		if (server_client_open(c, &cause) != 0) {
			cmdq_error(cmdq, "open terminal failed: %s", cause);
			free(cause);
			goto error;
		}
	}

	/* Find new session size. */
	if (c != NULL) {
		sx = c->tty.sx;
		sy = c->tty.sy;
	} else {
		sx = 80;
		sy = 24;
	}
	if (detached && args_has(args, 'x')) {
		sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
		if (errstr != NULL) {
			cmdq_error(cmdq, "width %s", errstr);
			goto error;
		}
	}
	if (detached && args_has(args, 'y')) {
		sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
		if (errstr != NULL) {
			cmdq_error(cmdq, "height %s", errstr);
			goto error;
		}
	}
	if (sy > 0 && options_get_number(&global_s_options, "status"))
		sy--;
	if (sx == 0)
		sx = 1;
	if (sy == 0)
		sy = 1;

	/* Figure out the command for the new window. */
	argc = -1;
	argv = NULL;
	if (target == NULL && args->argc != 0) {
		argc = args->argc;
		argv = args->argv;
	} else if (target == NULL) {
		cmd = options_get_string(&global_s_options, "default-command");
		if (cmd != NULL && *cmd != '\0') {
			argc = 1;
			argv = &cmd;
		} else {
			argc = 0;
			argv = NULL;
		}
	}

	path = NULL;
	if (c != NULL && c->session == NULL)
		envent = environ_find(&c->environ, "PATH");
	else
		envent = environ_find(&global_environ, "PATH");
	if (envent != NULL)
		path = envent->value;

	/* Construct the environment. */
	environ_init(&env);
	if (c != NULL && !args_has(args, 'E')) {
		update = options_get_string(&global_s_options,
		    "update-environment");
		environ_update(update, &c->environ, &env);
	}

	/* Create the new session. */
	idx = -1 - options_get_number(&global_s_options, "base-index");
	s = session_create(newname, argc, argv, path, cwd, &env, tiop, idx, sx,
	    sy, &cause);
	if (s == NULL) {
		cmdq_error(cmdq, "create session failed: %s", cause);
		free(cause);
		goto error;
	}
	environ_free(&env);

	/* Set the initial window name if one given. */
	if (argc >= 0 && args_has(args, 'n')) {
		w = s->curw->window;
		window_set_name(w, args_get(args, 'n'));
		options_set_number(&w->options, "automatic-rename", 0);
	}

	/*
	 * If a target session is given, this is to be part of a session group,
	 * so add it to the group and synchronize.
	 */
	if (groupwith != NULL) {
		session_group_add(groupwith, s);
		session_group_synchronize_to(s);
		session_select(s, RB_MIN(winlinks, &s->windows)->idx);
	}

	/*
	 * Set the client to the new session. If a command client exists, it is
	 * taking this session and needs to get MSG_READY and stay around.
	 */
	if (!detached) {
		if (!already_attached)
			server_write_ready(c);
		else if (c->session != NULL)
			c->last_session = c->session;
		c->session = s;
		status_timer_start(c);
		notify_attached_session_changed(c);
		session_update_activity(s);
		server_redraw_client(c);
	}
	recalculate_sizes();
	server_update_socket();

	/*
	 * If there are still configuration file errors to display, put the new
	 * session's current window into more mode and display them now.
	 */
	if (cfg_finished)
		cfg_show_causes(s);

	/* Print if requested. */
	if (args_has(args, 'P')) {
		if ((template = args_get(args, 'F')) == NULL)
Beispiel #8
0
int set_axisgrid_data(AGridUI *ui, Quark *q, void *caller)
{
    tickmarks *t = axisgrid_get_data(q);

    if (t && ui) {
        AMem *amem = quark_get_amem(q);
        int i;
        
        if (!caller || caller == ui->type) {
            t->type = GetOptionChoice(ui->type);
        }

        if (!caller || caller == ui->tmajor) {
            if (xv_evalexpr(ui->tmajor, &t->tmajor) != RETURN_SUCCESS) {
                errmsg("Specify major tick spacing");
                return RETURN_FAILURE;
            }
        }
        if (!caller || caller == ui->nminor) {
            t->nminor = (int) SpinChoiceGetValue(ui->nminor);
        }
        if (!caller || caller == ui->tlform) {
            Format *format = GetFormatChoice(ui->tlform);
            AMem *amem = quark_get_amem(q);
            amem_free(amem, t->tl_format.fstring);
            t->tl_format = *format;
            t->tl_format.fstring = amem_strdup(amem, format->fstring);
            format_free(format);
        }
        if (!caller || caller == ui->tlfont) {
            t->tl_tprops.font = GetOptionChoice(ui->tlfont);
        }
        if (!caller || caller == ui->tlcolor) {
            t->tl_tprops.color = GetOptionChoice(ui->tlcolor);
        }
        if (!caller || caller == ui->barpen) {
            GetPenChoice(ui->barpen, &t->bar.pen);
        }
        if (!caller || caller == ui->barlinew) {
            t->bar.width = SpinChoiceGetValue(ui->barlinew);
        }
        if (!caller || caller == ui->barlines) {
            t->bar.style = GetOptionChoice(ui->barlines);
        }
        if (!caller || caller == ui->tlcharsize) {
            t->tl_tprops.charsize = SpinChoiceGetValue(ui->tlcharsize);
        }
        if (!caller || caller == ui->tlangle) {
            t->tl_tprops.angle = GetAngleChoice(ui->tlangle);
        }
        if (!caller || caller == ui->tlstagger) {
            t->tl_staggered = GetOptionChoice(ui->tlstagger);
        }
        if (!caller || caller == ui->tlstarttype) {
            t->tl_starttype = GetOptionChoice(ui->tlstarttype) == 0 ?
                TYPE_AUTO : TYPE_SPEC;
        }
        if (!caller || caller == ui->tlstart) {
            if (t->tl_starttype == TYPE_SPEC) {
                if (xv_evalexpr(ui->tlstart, &t->tl_start) != RETURN_SUCCESS) {
                errmsg("Specify tick label start");
                    return RETURN_FAILURE;
                }
            }
        }
        if (!caller || caller == ui->tlstoptype) {
            t->tl_stoptype = GetOptionChoice(ui->tlstoptype) == 0 ?
                TYPE_AUTO : TYPE_SPEC;
        }
        if (!caller || caller == ui->tlstop) {
            if (t->tl_stoptype == TYPE_SPEC) {
                if (xv_evalexpr(ui->tlstop, &t->tl_stop) != RETURN_SUCCESS) {
                    errmsg("Specify tick label stop");
                    return RETURN_FAILURE;
                }
            }
        }
        if (!caller || caller == ui->tlskip) {
            t->tl_skip = GetOptionChoice(ui->tlskip);
        }
        if (!caller || caller == ui->tlformula) {
            char *s = TextGetString(ui->tlformula);
            t->tl_formula = amem_strcpy(amem, t->tl_formula, s);
            xfree(s);
        }
        if (!caller || caller == ui->tlprestr) {
            char *s = TextGetString(ui->tlprestr);
            t->tl_prestr = amem_strcpy(amem, t->tl_prestr, s);
            xfree(s);
        }
        if (!caller || caller == ui->tlappstr) {
            char *s = TextGetString(ui->tlappstr);
            t->tl_appstr = amem_strcpy(amem, t->tl_appstr, s);
            xfree(s);
        }
        if (!caller || caller == ui->tlgap_para) {
            xv_evalexpr(ui->tlgap_para, &t->tl_gap.x);
        }
        if (!caller || caller == ui->tlgap_perp) {
            xv_evalexpr(ui->tlgap_perp, &t->tl_gap.y);
        }
        if (!caller || caller == ui->tround) {
            t->t_round = ToggleButtonGetState(ui->tround);
        }
        if (!caller || caller == ui->autonum) {
            t->t_autonum = GetOptionChoice(ui->autonum) + 2;
        }


        if (!caller || caller == ui->tgrid) {
            t->gprops.onoff = ToggleButtonGetState(ui->tgrid);
        }
        if (!caller || caller == ui->tgridpen) {
            GetPenChoice(ui->tgridpen, &t->gprops.line.pen);
        }
        if (!caller || caller == ui->tgridlinew) {
            t->gprops.line.width = SpinChoiceGetValue(ui->tgridlinew);
        }
        if (!caller || caller == ui->tgridlines) {
            t->gprops.line.style = GetOptionChoice(ui->tgridlines);
        }

        if (!caller || caller == ui->tmgrid) {
            t->mgprops.onoff = ToggleButtonGetState(ui->tmgrid);
        }
        if (!caller || caller == ui->tmgridpen) {
            GetPenChoice(ui->tmgridpen, &t->mgprops.line.pen);
        }
        if (!caller || caller == ui->tmgridlinew) {
            t->mgprops.line.width = SpinChoiceGetValue(ui->tmgridlinew);
        }
        if (!caller || caller == ui->tmgridlines) {
            t->mgprops.line.style = GetOptionChoice(ui->tmgridlines);
        }


        if (!caller || caller == ui->tinout) {
            t->props.inout = GetOptionChoice(ui->tinout);
        }
        if (!caller || caller == ui->tlen) {
            t->props.size = SpinChoiceGetValue(ui->tlen);
        }
        if (!caller || caller == ui->tpen) {
            GetPenChoice(ui->tpen, &t->props.line.pen);
        }
        if (!caller || caller == ui->tgridlinew) {
            t->props.line.width = SpinChoiceGetValue(ui->tlinew);
        }
        if (!caller || caller == ui->tgridlines) {
            t->props.line.style = GetOptionChoice(ui->tlines);
        }
        if (!caller || caller == ui->tminout) {
            t->mprops.inout = GetOptionChoice(ui->tminout);
        }
        if (!caller || caller == ui->tmlen) {
            t->mprops.size = SpinChoiceGetValue(ui->tmlen);
        }
        if (!caller || caller == ui->tmpen) {
            GetPenChoice(ui->tmpen, &t->mprops.line.pen);
        }
        if (!caller || caller == ui->tmgridlinew) {
            t->mprops.line.width = SpinChoiceGetValue(ui->tmlinew);
        }
        if (!caller || caller == ui->tmgridlines) {
            t->mprops.line.style = GetOptionChoice(ui->tmlines);
        }
        if (!caller ||
            caller == ui->specticks || caller == ui->nspec || caller == ui->specloc) {
            t->t_spec = GetOptionChoice(ui->specticks);
            /* only read special info if special ticks used */
            if (t->t_spec != TICKS_SPEC_NONE) {
                t->nticks = (int) SpinChoiceGetValue(ui->nspec);
                /* ensure that enough tick positions have been specified */
                for (i = 0; i < t->nticks; i++) {
                    if (xv_evalexpr(ui->specloc[i], &t->tloc[i].wtpos) ==
                                                        RETURN_SUCCESS) {
                        char *cp, *s;
                        cp = TextGetString(ui->speclabel[i]);
                        if (cp[0] == '\0') {
                            t->tloc[i].type = TICK_TYPE_MINOR;
                        } else {
                            t->tloc[i].type = TICK_TYPE_MAJOR;
                        }
                        if (t->t_spec == TICKS_SPEC_BOTH) {
                            s = cp;
                        } else {
                            s = NULL;
                        }
                        t->tloc[i].label =
                            amem_strcpy(amem, t->tloc[i].label, s);
                        xfree(cp);
                    }
                } 
            }
        }
        
        quark_dirtystate_set(q, TRUE);
        
        return RETURN_SUCCESS;
    } else {
        return RETURN_FAILURE;
    }
}
Beispiel #9
0
static void
window_buffer_build(void *modedata, u_int sort_type, __unused uint64_t *tag,
    const char *filter)
{
	struct window_buffer_modedata	*data = modedata;
	struct window_buffer_itemdata	*item;
	u_int				 i;
	struct paste_buffer		*pb;
	char				*text, *cp;
	struct format_tree		*ft;
	struct session			*s = NULL;
	struct winlink			*wl = NULL;
	struct window_pane		*wp = NULL;

	for (i = 0; i < data->item_size; i++)
		window_buffer_free_item(data->item_list[i]);
	free(data->item_list);
	data->item_list = NULL;
	data->item_size = 0;

	pb = NULL;
	while ((pb = paste_walk(pb)) != NULL) {
		item = window_buffer_add_item(data);
		item->name = xstrdup(paste_buffer_name(pb));
		paste_buffer_data(pb, &item->size);
		item->order = paste_buffer_order(pb);
	}

	switch (sort_type) {
	case WINDOW_BUFFER_BY_NAME:
		qsort(data->item_list, data->item_size, sizeof *data->item_list,
		    window_buffer_cmp_name);
		break;
	case WINDOW_BUFFER_BY_TIME:
		qsort(data->item_list, data->item_size, sizeof *data->item_list,
		    window_buffer_cmp_time);
		break;
	case WINDOW_BUFFER_BY_SIZE:
		qsort(data->item_list, data->item_size, sizeof *data->item_list,
		    window_buffer_cmp_size);
		break;
	}

	if (cmd_find_valid_state(&data->fs)) {
		s = data->fs.s;
		wl = data->fs.wl;
		wp = data->fs.wp;
	}

	for (i = 0; i < data->item_size; i++) {
		item = data->item_list[i];

		pb = paste_get_name(item->name);
		if (pb == NULL)
			continue;
		ft = format_create(NULL, NULL, FORMAT_NONE, 0);
		format_defaults(ft, NULL, s, wl, wp);
		format_defaults_paste_buffer(ft, pb);

		if (filter != NULL) {
			cp = format_expand(ft, filter);
			if (!format_true(cp)) {
				free(cp);
				format_free(ft);
				continue;
			}
			free(cp);
		}

		text = format_expand(ft, data->format);
		mode_tree_add(data->data, NULL, item, item->order, item->name,
		    text, -1);
		free(text);

		format_free(ft);
	}

}
Beispiel #10
0
enum cmd_retval
cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
    const char *cflag)
{
	struct session		*s;
	struct client		*c;
	struct winlink		*wl = NULL;
	struct window		*w = NULL;
	struct window_pane	*wp = NULL;
	const char		*update;
	char			*cause;
	u_int			 i;
	int			 fd;
	struct format_tree	*ft;
	char			*cp;

	if (RB_EMPTY(&sessions)) {
		cmdq_error(cmdq, "no sessions");
		return (CMD_RETURN_ERROR);
	}

	if (tflag == NULL) {
		if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL)
			return (CMD_RETURN_ERROR);
	} else if (tflag[strcspn(tflag, ":.")] != '\0') {
		if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL)
			return (CMD_RETURN_ERROR);
	} else {
		if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL)
			return (CMD_RETURN_ERROR);
		w = cmd_lookup_windowid(tflag);
		if (w == NULL && (wp = cmd_lookup_paneid(tflag)) != NULL)
			w = wp->window;
		if (w != NULL)
			wl = winlink_find_by_window(&s->windows, w);
	}

	if (cmdq->client == NULL)
		return (CMD_RETURN_NORMAL);

	if (wl != NULL) {
		if (wp != NULL)
			window_set_active_pane(wp->window, wp);
		session_set_current(s, wl);
	}

	if (cmdq->client->session != NULL) {
		if (dflag) {
			/*
			 * Can't use server_write_session in case attaching to
			 * the same session as currently attached to.
			 */
			for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
				c = ARRAY_ITEM(&clients, i);
				if (c == NULL || c->session != s)
					continue;
				if (c == cmdq->client)
					continue;
				server_write_client(c, MSG_DETACH,
				    c->session->name,
				    strlen(c->session->name) + 1);
			}
		}

		if (cflag != NULL) {
			ft = format_create();
			if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
				format_client(ft, c);
			format_session(ft, s);
			format_winlink(ft, s, s->curw);
			format_window_pane(ft, s->curw->window->active);
			cp = format_expand(ft, cflag);
			format_free(ft);

			fd = open(cp, O_RDONLY|O_DIRECTORY);
			free(cp);
			if (fd == -1) {
				cmdq_error(cmdq, "bad working directory: %s",
				    strerror(errno));
				return (CMD_RETURN_ERROR);
			}
			close(s->cwd);
			s->cwd = fd;
		}

		cmdq->client->session = s;
		notify_attached_session_changed(cmdq->client);
		session_update_activity(s);
		server_redraw_client(cmdq->client);
		s->curw->flags &= ~WINLINK_ALERTFLAGS;
	} else {
		if (server_client_open(cmdq->client, s, &cause) != 0) {
			cmdq_error(cmdq, "open terminal failed: %s", cause);
			free(cause);
			return (CMD_RETURN_ERROR);
		}

		if (cflag != NULL) {
			ft = format_create();
			if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
				format_client(ft, c);
			format_session(ft, s);
			format_winlink(ft, s, s->curw);
			format_window_pane(ft, s->curw->window->active);
			cp = format_expand(ft, cflag);
			format_free(ft);

			fd = open(cp, O_RDONLY|O_DIRECTORY);
			free(cp);
			if (fd == -1) {
				cmdq_error(cmdq, "bad working directory: %s",
				    strerror(errno));
				return (CMD_RETURN_ERROR);
			}
			close(s->cwd);
			s->cwd = fd;
		}

		if (rflag)
			cmdq->client->flags |= CLIENT_READONLY;

		if (dflag) {
			server_write_session(s, MSG_DETACH, s->name,
			    strlen(s->name) + 1);
		}

		update = options_get_string(&s->options, "update-environment");
		environ_update(update, &cmdq->client->environ, &s->environ);

		cmdq->client->session = s;
		notify_attached_session_changed(cmdq->client);
		session_update_activity(s);
		server_redraw_client(cmdq->client);
		s->curw->flags &= ~WINLINK_ALERTFLAGS;

		server_write_ready(cmdq->client);
		cmdq->client_exit = 0;
	}
	recalculate_sizes();
	server_update_socket();

	return (CMD_RETURN_NORMAL);
}
Beispiel #11
0
static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{
	struct args		*args = self->args;
	struct client		*c = cmd_find_client(item, NULL, 1);
	struct window_pane	*wp = item->target.wp;
	struct session		*s = item->target.s;
	struct winlink		*wl = item->target.wl;
	char			*cmd;
	int			 old_fd, pipe_fd[2], null_fd, in, out;
	struct format_tree	*ft;
	sigset_t		 set, oldset;

	/* Destroy the old pipe. */
	old_fd = wp->pipe_fd;
	if (wp->pipe_fd != -1) {
		bufferevent_free(wp->pipe_event);
		close(wp->pipe_fd);
		wp->pipe_fd = -1;

		if (window_pane_destroy_ready(wp)) {
			server_destroy_pane(wp, 1);
			return (CMD_RETURN_NORMAL);
		}
	}

	/* If no pipe command, that is enough. */
	if (args->argc == 0 || *args->argv[0] == '\0')
		return (CMD_RETURN_NORMAL);

	/*
	 * With -o, only open the new pipe if there was no previous one. This
	 * allows a pipe to be toggled with a single key, for example:
	 *
	 *	bind ^p pipep -o 'cat >>~/output'
	 */
	if (args_has(self->args, 'o') && old_fd != -1)
		return (CMD_RETURN_NORMAL);

	/* What do we want to do? Neither -I or -O is -O. */
	if (args_has(self->args, 'I')) {
		in = 1;
		out = args_has(self->args, 'O');
	} else {
		in = 0;
		out = 1;
	}

	/* Open the new pipe. */
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
		cmdq_error(item, "socketpair error: %s", strerror(errno));
		return (CMD_RETURN_ERROR);
	}

	/* Expand the command. */
	ft = format_create(item->client, item, FORMAT_NONE, 0);
	format_defaults(ft, c, s, wl, wp);
	cmd = format_expand_time(ft, args->argv[0]);
	format_free(ft);

	/* Fork the child. */
	sigfillset(&set);
	sigprocmask(SIG_BLOCK, &set, &oldset);
	switch (fork()) {
	case -1:
		sigprocmask(SIG_SETMASK, &oldset, NULL);
		cmdq_error(item, "fork error: %s", strerror(errno));

		free(cmd);
		return (CMD_RETURN_ERROR);
	case 0:
		/* Child process. */
		proc_clear_signals(server_proc, 1);
		sigprocmask(SIG_SETMASK, &oldset, NULL);
		close(pipe_fd[0]);

		null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
		if (out) {
			if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
				_exit(1);
		} else {
			if (dup2(null_fd, STDIN_FILENO) == -1)
				_exit(1);
		}
		if (in) {
			if (dup2(pipe_fd[1], STDOUT_FILENO) == -1)
				_exit(1);
			if (pipe_fd[1] != STDOUT_FILENO)
				close(pipe_fd[1]);
		} else {
			if (dup2(null_fd, STDOUT_FILENO) == -1)
				_exit(1);
		}
		if (dup2(null_fd, STDERR_FILENO) == -1)
			_exit(1);
		closefrom(STDERR_FILENO + 1);

		execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
		_exit(1);
	default:
		/* Parent process. */
		sigprocmask(SIG_SETMASK, &oldset, NULL);
		close(pipe_fd[1]);

		wp->pipe_fd = pipe_fd[0];
		if (wp->fd != -1)
			wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
		else
			wp->pipe_off = 0;

		setblocking(wp->pipe_fd, 0);
		wp->pipe_event = bufferevent_new(wp->pipe_fd,
		    cmd_pipe_pane_read_callback,
		    cmd_pipe_pane_write_callback,
		    cmd_pipe_pane_error_callback,
		    wp);
		if (wp->pipe_event == NULL)
			fatalx("out of memory");
		if (out)
			bufferevent_enable(wp->pipe_event, EV_WRITE);
		if (in)
			bufferevent_enable(wp->pipe_event, EV_READ);

		free(cmd);
		return (CMD_RETURN_NORMAL);
	}
}
Beispiel #12
0
enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args			*args = self->args;
	struct cmd_if_shell_data	*cdata;
	char				*shellcmd, *cmd, *cause;
	struct cmd_list			*cmdlist;
	struct client			*c;
	struct session			*s = NULL;
	struct winlink			*wl = NULL;
	struct window_pane		*wp = NULL;
	struct format_tree		*ft;
	int				 cwd;

	if (args_has(args, 't')) {
		wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
		cwd = wp->cwd;
	} else {
		c = cmd_find_client(cmdq, NULL, 1);
		if (c != NULL && c->session != NULL) {
			s = c->session;
			wl = s->curw;
			wp = wl->window->active;
		}
		if (cmdq->client != NULL && cmdq->client->session == NULL)
			cwd = cmdq->client->cwd;
		else if (s != NULL)
			cwd = s->cwd;
		else
			cwd = -1;
	}

	ft = format_create();
	format_defaults(ft, NULL, s, wl, wp);
	shellcmd = format_expand(ft, args->argv[0]);
	format_free(ft);

	if (args_has(args, 'F')) {
		cmd = NULL;
		if (*shellcmd != '0' && *shellcmd != '\0')
			cmd = args->argv[1];
		else if (args->argc == 3)
			cmd = args->argv[2];
		if (cmd == NULL)
			return (CMD_RETURN_NORMAL);
		if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
			if (cause != NULL) {
				cmdq_error(cmdq, "%s", cause);
				free(cause);
			}
			return (CMD_RETURN_ERROR);
		}
		cmdq_run(cmdq, cmdlist, &cmdq->item->mouse);
		cmd_list_free(cmdlist);
		return (CMD_RETURN_NORMAL);
	}

	cdata = xmalloc(sizeof *cdata);

	cdata->cmd_if = xstrdup(args->argv[1]);
	if (args->argc == 3)
		cdata->cmd_else = xstrdup(args->argv[2]);
	else
		cdata->cmd_else = NULL;

	cdata->bflag = args_has(args, 'b');

	cdata->cmdq = cmdq;
	memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
	cmdq->references++;

	cdata->references = 1;
	job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
	    cdata);
	free(shellcmd);

	if (cdata->bflag)
		return (CMD_RETURN_NORMAL);
	return (CMD_RETURN_WAIT);
}
Beispiel #13
0
int graph_set_data(GraphUI *ui, Quark *q, void *caller)
{
    if (quark_fid_get(q) == QFlavorGraph) {
        double axislim, znorm;
        world w;
        GLocator *locator;

        graph_get_world(q, &w);
        locator = graph_get_locator(q);

        if (!caller || caller == ui->graph_type) {
            graph_set_type(q, GetOptionChoice(ui->graph_type));
        }
        if (!caller || caller == ui->stacked) {
            graph_set_stacked(q, GetToggleButtonState(ui->stacked));
        }
        if (!caller || caller == ui->flip_xy) {
            graph_set_xyflip(q, GetToggleButtonState(ui->flip_xy));
        }

        if (!caller || caller == ui->start_x) {
            if (xv_evalexpr(ui->start_x, &axislim) != RETURN_SUCCESS) {
                errmsg("Axis start/stop values undefined");
                return RETURN_FAILURE;
            }
            w.xg1 = axislim;
        }
        if (!caller || caller == ui->stop_x) {
            if (xv_evalexpr(ui->stop_x, &axislim) != RETURN_SUCCESS) {
                errmsg("Axis start/stop values undefined");
                return RETURN_FAILURE;
            }
            w.xg2 = axislim;
        }

        if (!caller || caller == ui->start_y) {
            if (xv_evalexpr(ui->start_y, &axislim) != RETURN_SUCCESS) {
                errmsg("Axis start/stop values undefined");
                return RETURN_FAILURE;
            }
            w.yg1 = axislim;
        }
        if (!caller || caller == ui->stop_y) {
            if (xv_evalexpr(ui->stop_y, &axislim) != RETURN_SUCCESS) {
                errmsg("Axis start/stop values undefined");
                return RETURN_FAILURE;
            }
            w.yg2 = axislim;
        }

        if (!caller ||
            caller == ui->start_x || caller == ui->stop_x ||
            caller == ui->start_y || caller == ui->stop_y) {
            graph_set_world(q, &w);
        }

        if (!caller || caller == ui->scale_x) {
            graph_set_xscale(q, GetOptionChoice(ui->scale_x));
        }
        if (!caller || caller == ui->invert_x)  {
            graph_set_xinvert(q, GetToggleButtonState(ui->invert_x));
        }

        if (!caller || caller == ui->scale_y) {
            graph_set_yscale(q, GetOptionChoice(ui->scale_y));
        }
        if (!caller || caller == ui->invert_y)  {
            graph_set_yinvert(q, GetToggleButtonState(ui->invert_y));
        }

        if (!caller || caller == ui->bargap) {
            graph_set_bargap(q, GetSpinChoice(ui->bargap));
        }
        if (!caller || caller == ui->znorm) {
            xv_evalexpr(ui->znorm, &znorm);
            graph_set_znorm(q, znorm);
        }


        if (!caller || caller == ui->loc_type) {
            locator->type = GetOptionChoice(ui->loc_type);
            quark_dirtystate_set(q, TRUE);
        }
        if (!caller || caller == ui->loc_fx) {
            Format *format = GetFormatChoice(ui->loc_fx);
            AMem *amem = quark_get_amem(q);
            amem_free(amem, locator->fx.fstring);
            locator->fx = *format;
            locator->fx.fstring = amem_strdup(amem, format->fstring);
            format_free(format);
            quark_dirtystate_set(q, TRUE);
        }
        if (!caller || caller == ui->loc_fy) {
            Format *format = GetFormatChoice(ui->loc_fy);
            AMem *amem = quark_get_amem(q);
            amem_free(amem, locator->fy.fstring);
            locator->fy = *format;
            locator->fy.fstring = amem_strdup(amem, format->fstring);
            format_free(format);
            quark_dirtystate_set(q, TRUE);
        }
        if (!caller || caller == ui->fixedp) {
            locator->pointset = GetToggleButtonState(ui->fixedp);
            quark_dirtystate_set(q, TRUE);
        }
        if (!caller || caller == ui->locx) {
            xv_evalexpr(ui->locx, &locator->origin.x); 
            quark_dirtystate_set(q, TRUE);
        }
        if (!caller || caller == ui->locy) {
            xv_evalexpr(ui->locy, &locator->origin.y); 
            quark_dirtystate_set(q, TRUE);
        }

        return RETURN_SUCCESS;
    } else {
        return RETURN_FAILURE;
    }
}
Beispiel #14
0
static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{
	struct args		*args = self->args;
	struct client		*c = item->client;
	struct session		*s, *as;
	struct session		*groupwith = item->state.tflag.s;
	struct window		*w;
	struct environ		*env;
	struct termios		 tio, *tiop;
	const char		*newname, *target, *update, *errstr, *template;
	const char		*path, *cwd, *to_free = NULL;
	char		       **argv, *cmd, *cause, *cp;
	int			 detached, already_attached, idx, argc;
	u_int			 sx, sy;
	struct format_tree	*ft;
	struct environ_entry	*envent;
	struct cmd_find_state	 fs;

	if (self->entry == &cmd_has_session_entry) {
		/*
		 * cmd_prepare() will fail if the session cannot be found,
		 * hence always return success here.
		 */
		return (CMD_RETURN_NORMAL);
	}

	if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
		cmdq_error(item, "command or window name given with target");
		return (CMD_RETURN_ERROR);
	}

	newname = args_get(args, 's');
	if (newname != NULL) {
		if (!session_check_name(newname)) {
			cmdq_error(item, "bad session name: %s", newname);
			return (CMD_RETURN_ERROR);
		}
		if ((as = session_find(newname)) != NULL) {
			if (args_has(args, 'A')) {
				/*
				 * This item is now destined for
				 * attach-session. Because attach-session will
				 * have already been prepared, copy this
				 * session into its tflag so it can be used.
				 */
				cmd_find_from_session(&item->state.tflag, as);
				return (cmd_attach_session(item,
				    args_has(args, 'D'), 0, NULL,
				    args_has(args, 'E')));
			}
			cmdq_error(item, "duplicate session: %s", newname);
			return (CMD_RETURN_ERROR);
		}
	}

	if ((target = args_get(args, 't')) != NULL) {
		if (groupwith == NULL) {
			cmdq_error(item, "no such session: %s", target);
			goto error;
		}
	} else
		groupwith = NULL;

	/* Set -d if no client. */
	detached = args_has(args, 'd');
	if (c == NULL)
		detached = 1;

	/* Is this client already attached? */
	already_attached = 0;
	if (c != NULL && c->session != NULL)
		already_attached = 1;

	/* Get the new session working directory. */
	if (args_has(args, 'c')) {
		ft = format_create(item, 0);
		format_defaults(ft, c, NULL, NULL, NULL);
		to_free = cwd = format_expand(ft, args_get(args, 'c'));
		format_free(ft);
	} else if (c != NULL && c->session == NULL && c->cwd != NULL)
		cwd = c->cwd;
	else
		cwd = ".";

	/*
	 * If this is a new client, check for nesting and save the termios
	 * settings (part of which is used for new windows in this session).
	 *
	 * tcgetattr() is used rather than using tty.tio since if the client is
	 * detached, tty_open won't be called. It must be done before opening
	 * the terminal as that calls tcsetattr() to prepare for tmux taking
	 * over.
	 */
	if (!detached && !already_attached && c->tty.fd != -1) {
		if (server_client_check_nested(item->client)) {
			cmdq_error(item, "sessions should be nested with care, "
			    "unset $TMUX to force");
			return (CMD_RETURN_ERROR);
		}
		if (tcgetattr(c->tty.fd, &tio) != 0)
			fatal("tcgetattr failed");
		tiop = &tio;
	} else
		tiop = NULL;

	/* Open the terminal if necessary. */
	if (!detached && !already_attached) {
		if (server_client_open(c, &cause) != 0) {
			cmdq_error(item, "open terminal failed: %s", cause);
			free(cause);
			goto error;
		}
	}

	/* Find new session size. */
	if (c != NULL) {
		sx = c->tty.sx;
		sy = c->tty.sy;
	} else {
		sx = 80;
		sy = 24;
	}
	if (detached && args_has(args, 'x')) {
		sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
		if (errstr != NULL) {
			cmdq_error(item, "width %s", errstr);
			goto error;
		}
	}
	if (detached && args_has(args, 'y')) {
		sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
		if (errstr != NULL) {
			cmdq_error(item, "height %s", errstr);
			goto error;
		}
	}
	if (sy > 0 && options_get_number(global_s_options, "status"))
		sy--;
	if (sx == 0)
		sx = 1;
	if (sy == 0)
		sy = 1;

	/* Figure out the command for the new window. */
	argc = -1;
	argv = NULL;
	if (!args_has(args, 't') && args->argc != 0) {
		argc = args->argc;
		argv = args->argv;
	} else if (groupwith == NULL) {
		cmd = options_get_string(global_s_options, "default-command");
		if (cmd != NULL && *cmd != '\0') {
			argc = 1;
			argv = &cmd;
		} else {
			argc = 0;
			argv = NULL;
		}
	}

	path = NULL;
	if (c != NULL && c->session == NULL)
		envent = environ_find(c->environ, "PATH");
	else
		envent = environ_find(global_environ, "PATH");
	if (envent != NULL)
		path = envent->value;

	/* Construct the environment. */
	env = environ_create();
	if (c != NULL && !args_has(args, 'E')) {
		update = options_get_string(global_s_options,
		    "update-environment");
		environ_update(update, c->environ, env);
	}

	/* Create the new session. */
	idx = -1 - options_get_number(global_s_options, "base-index");
	s = session_create(newname, argc, argv, path, cwd, env, tiop, idx, sx,
	    sy, &cause);
	environ_free(env);
	if (s == NULL) {
		cmdq_error(item, "create session failed: %s", cause);
		free(cause);
		goto error;
	}

	/* Set the initial window name if one given. */
	if (argc >= 0 && args_has(args, 'n')) {
		w = s->curw->window;
		window_set_name(w, args_get(args, 'n'));
		options_set_number(w->options, "automatic-rename", 0);
	}

	/*
	 * If a target session is given, this is to be part of a session group,
	 * so add it to the group and synchronize.
	 */
	if (groupwith != NULL) {
		session_group_add(groupwith, s);
		session_group_synchronize_to(s);
		session_select(s, RB_MIN(winlinks, &s->windows)->idx);
	}
	notify_session("session-created", s);

	/*
	 * Set the client to the new session. If a command client exists, it is
	 * taking this session and needs to get MSG_READY and stay around.
	 */
	if (!detached) {
		if (!already_attached) {
			if (~c->flags & CLIENT_CONTROL)
				proc_send(c->peer, MSG_READY, -1, NULL, 0);
		} else if (c->session != NULL)
			c->last_session = c->session;
		c->session = s;
		server_client_set_key_table(c, NULL);
		status_timer_start(c);
		notify_client("client-session-changed", c);
		session_update_activity(s, NULL);
		gettimeofday(&s->last_attached_time, NULL);
		server_redraw_client(c);
	}
	recalculate_sizes();
	server_update_socket();

	/*
	 * If there are still configuration file errors to display, put the new
	 * session's current window into more mode and display them now.
	 */
	if (cfg_finished)
		cfg_show_causes(s);

	/* Print if requested. */
	if (args_has(args, 'P')) {
		if ((template = args_get(args, 'F')) == NULL)