mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Improved layout code.
Each window now has a tree of layout cells associated with it. In this tree, each node is either a horizontal or vertical cell containing a list of other cells running from left-to-right or top-to-bottom, or a leaf cell which is associated with a pane. The major functional changes are: - panes may now be split arbitrarily both horizontally (splitw -h, C-b %) and vertically (splitw -v, C-b "); - panes may be resized both horizontally and vertically (resizep -L/-R/-U/-D, bound to C-b left/right/up/down and C-b M-left/right/up/down); - layouts are now applied and then may be modified by resizing or splitting panes, rather than being fixed and reapplied when the window is resized or panes are added; - manual-vertical layout is no longer necessary, and active-only layout is gone (but may return in future); - the main-pane layouts now reduce the size of the main pane to fit all panes if possible. Thanks to all who tested.
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -27,7 +27,7 @@ SRCS=	attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ | |||||||
| 	cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ | 	cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \ | ||||||
| 	cmd-up-pane.c cmd-display-message.c cmd.c \ | 	cmd-up-pane.c cmd-display-message.c cmd.c \ | ||||||
| 	colour.c grid-view.c grid.c input-keys.c \ | 	colour.c grid-view.c grid.c input-keys.c \ | ||||||
| 	input.c key-bindings.c key-string.c layout-manual.c layout.c log.c \ | 	input.c key-bindings.c key-string.c layout-set.c layout.c log.c \ | ||||||
| 	mode-key.c names.c options-cmd.c options.c paste.c procname.c \ | 	mode-key.c names.c options-cmd.c options.c paste.c procname.c \ | ||||||
| 	resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ | 	resize.c screen-redraw.c screen-write.c screen.c server-fn.c \ | ||||||
| 	server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ | 	server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \ | ||||||
|   | |||||||
| @@ -74,17 +74,17 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		if (wl->window->active == NULL) | 		if (wl->window->active == NULL) | ||||||
| 			wl->window->active = TAILQ_NEXT(wp, entry); | 			wl->window->active = TAILQ_NEXT(wp, entry); | ||||||
| 	} | 	} | ||||||
|  	layout_refresh(wl->window, 0); |  	layout_close_pane(wp); | ||||||
|  |  | ||||||
|  	w = wp->window = window_create1(s->sx, s->sy); |  	w = wp->window = window_create1(s->sx, s->sy); | ||||||
|  	TAILQ_INSERT_HEAD(&w->panes, wp, entry); |  	TAILQ_INSERT_HEAD(&w->panes, wp, entry); | ||||||
|  	w->active = wp; |  	w->active = wp; | ||||||
|  	w->name = default_window_name(w); |  	w->name = default_window_name(w); | ||||||
|  | 	layout_init(w); | ||||||
|  |  | ||||||
|  	wl = session_attach(s, w, -1, &cause); /* can't fail */ |  	wl = session_attach(s, w, -1, &cause); /* can't fail */ | ||||||
|  	if (!(data->chflags & CMD_CHFLAG('d'))) |  	if (!(data->chflags & CMD_CHFLAG('d'))) | ||||||
|  		session_select(s, wl->idx); |  		session_select(s, wl->idx); | ||||||
|  	layout_refresh(w, 0); |  | ||||||
|  |  | ||||||
| 	server_redraw_session(s); | 	server_redraw_session(s); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -76,8 +76,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		idx++; | 		idx++; | ||||||
|  |  | ||||||
| 		window_choose_add(wl->window->active, | 		window_choose_add(wl->window->active, | ||||||
| 		    wm->idx, "%3d: %s [%ux%u %s] (%u panes)", wm->idx, w->name, | 		    wm->idx, "%3d: %s [%ux%u] (%u panes)", | ||||||
| 		    w->sx, w->sy, layout_name(w), window_count_panes(w)); | 		    wm->idx, w->name, w->sx, w->sy, window_count_panes(w)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cdata = xmalloc(sizeof *cdata); | 	cdata = xmalloc(sizeof *cdata); | ||||||
|   | |||||||
| @@ -54,7 +54,6 @@ cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		w->active = TAILQ_NEXT(w->active, entry); | 		w->active = TAILQ_NEXT(w->active, entry); | ||||||
| 		if (w->active == NULL) | 		if (w->active == NULL) | ||||||
| 			w->active = TAILQ_FIRST(&w->panes); | 			w->active = TAILQ_FIRST(&w->panes); | ||||||
| 		layout_refresh(w, 1); |  | ||||||
| 	} while (!window_pane_visible(w->active)); | 	} while (!window_pane_visible(w->active)); | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
|   | |||||||
| @@ -66,8 +66,8 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		return (0); | 		return (0); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	layout_close_pane(wp); | ||||||
| 	window_remove_pane(wl->window, wp); | 	window_remove_pane(wl->window, wp); | ||||||
| 	server_redraw_window(wl->window); | 	server_redraw_window(wl->window); | ||||||
| 	layout_refresh(wl->window, 0); |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -78,9 +78,8 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 			else | 			else | ||||||
| 				name = "unknown"; | 				name = "unknown"; | ||||||
| 			ctx->print(ctx, | 			ctx->print(ctx, | ||||||
| 			    "     %s [%ux%u %s] [history %u/%u, %llu bytes]", | 			    "     %s [%ux%u] [history %u/%u, %llu bytes]", | ||||||
| 			    name, wp->sx, wp->sy, layout_name(w), gd->hsize, | 			    name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); | ||||||
| 			    gd->hlimit, size); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -44,12 +44,13 @@ cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| { | { | ||||||
| 	struct cmd_target_data	*data = self->data; | 	struct cmd_target_data	*data = self->data; | ||||||
| 	struct winlink		*wl; | 	struct winlink		*wl; | ||||||
|  | 	u_int			 layout; | ||||||
|  |  | ||||||
| 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | ||||||
| 		return (-1); | 		return (-1); | ||||||
|  |  | ||||||
| 	layout_next(wl->window); | 	layout = layout_set_next(wl->window); | ||||||
| 	ctx->info(ctx, "layout now: %s", layout_name(wl->window)); | 	ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -44,12 +44,13 @@ cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| { | { | ||||||
| 	struct cmd_target_data	*data = self->data; | 	struct cmd_target_data	*data = self->data; | ||||||
| 	struct winlink		*wl; | 	struct winlink		*wl; | ||||||
|  | 	u_int			 layout; | ||||||
| 	 | 	 | ||||||
| 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | ||||||
| 		return (-1); | 		return (-1); | ||||||
|  |  | ||||||
| 	layout_previous(wl->window); | 	layout = layout_set_previous(wl->window); | ||||||
| 	ctx->info(ctx, "layout now: %s", layout_name(wl->window)); | 	ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -32,7 +32,8 @@ int	cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); | |||||||
| const struct cmd_entry cmd_resize_pane_entry = { | const struct cmd_entry cmd_resize_pane_entry = { | ||||||
| 	"resize-pane", "resizep", | 	"resize-pane", "resizep", | ||||||
| 	CMD_PANE_WINDOW_USAGE "[-DU] [adjustment]", | 	CMD_PANE_WINDOW_USAGE "[-DU] [adjustment]", | ||||||
| 	CMD_ARG01, CMD_CHFLAG('D')|CMD_CHFLAG('U'), | 	CMD_ARG01, | ||||||
|  | 	CMD_CHFLAG('D')|CMD_CHFLAG('L')|CMD_CHFLAG('R')|CMD_CHFLAG('U'), | ||||||
| 	cmd_resize_pane_init, | 	cmd_resize_pane_init, | ||||||
| 	cmd_pane_parse, | 	cmd_pane_parse, | ||||||
| 	cmd_resize_pane_exec, | 	cmd_resize_pane_exec, | ||||||
| @@ -50,15 +51,31 @@ cmd_resize_pane_init(struct cmd *self, int key) | |||||||
| 	cmd_pane_init(self, key); | 	cmd_pane_init(self, key); | ||||||
| 	data = self->data; | 	data = self->data; | ||||||
|  |  | ||||||
|  | 	if (key == KEYC_ADDCTL(KEYC_UP)) | ||||||
|  | 		data->chflags |= CMD_CHFLAG('U'); | ||||||
| 	if (key == KEYC_ADDCTL(KEYC_DOWN)) | 	if (key == KEYC_ADDCTL(KEYC_DOWN)) | ||||||
| 		data->chflags |= CMD_CHFLAG('D'); | 		data->chflags |= CMD_CHFLAG('D'); | ||||||
|  | 	if (key == KEYC_ADDCTL(KEYC_LEFT)) | ||||||
|  | 		data->chflags |= CMD_CHFLAG('L'); | ||||||
|  | 	if (key == KEYC_ADDCTL(KEYC_RIGHT)) | ||||||
|  | 		data->chflags |= CMD_CHFLAG('R'); | ||||||
|  |  | ||||||
| 	if (key == KEYC_ADDESC(KEYC_UP)) | 	if (key == KEYC_ADDESC(KEYC_UP)) { | ||||||
|  | 		data->chflags |= CMD_CHFLAG('U'); | ||||||
| 		data->arg = xstrdup("5"); | 		data->arg = xstrdup("5"); | ||||||
|  | 	} | ||||||
| 	if (key == KEYC_ADDESC(KEYC_DOWN)) { | 	if (key == KEYC_ADDESC(KEYC_DOWN)) { | ||||||
| 		data->chflags |= CMD_CHFLAG('D'); | 		data->chflags |= CMD_CHFLAG('D'); | ||||||
| 		data->arg = xstrdup("5"); | 		data->arg = xstrdup("5"); | ||||||
| 	} | 	} | ||||||
|  | 	if (key == KEYC_ADDESC(KEYC_LEFT)) { | ||||||
|  | 		data->chflags |= CMD_CHFLAG('L'); | ||||||
|  | 		data->arg = xstrdup("5"); | ||||||
|  | 	} | ||||||
|  | 	if (key == KEYC_ADDESC(KEYC_RIGHT)) { | ||||||
|  | 		data->chflags |= CMD_CHFLAG('R'); | ||||||
|  | 		data->arg = xstrdup("5"); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| int | int | ||||||
| @@ -92,12 +109,14 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (!(data->chflags & CMD_CHFLAG('D'))) | 	if (data->chflags & (CMD_CHFLAG('L')|CMD_CHFLAG('R'))) { | ||||||
| 		adjust = -adjust; | 		if (data->chflags & CMD_CHFLAG('L')) | ||||||
| 	if (layout_resize(wp, adjust) != 0) { | 			adjust = -adjust; | ||||||
| 		ctx->error(ctx, "layout %s " | 		layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust); | ||||||
| 		    "does not support resizing", layout_name(wp->window)); | 	} else { | ||||||
| 		return (-1); | 		if (data->chflags & CMD_CHFLAG('U')) | ||||||
|  | 			adjust = -adjust; | ||||||
|  | 		layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust); | ||||||
| 	} | 	} | ||||||
| 	server_redraw_window(wl->window); | 	server_redraw_window(wl->window); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -70,6 +70,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
|  |  | ||||||
| 	wp = TAILQ_FIRST(&w->panes); | 	wp = TAILQ_FIRST(&w->panes); | ||||||
| 	TAILQ_REMOVE(&w->panes, wp, entry); | 	TAILQ_REMOVE(&w->panes, wp, entry); | ||||||
|  | 	layout_free(w); | ||||||
|  	window_destroy_panes(w); |  	window_destroy_panes(w); | ||||||
| 	TAILQ_INSERT_HEAD(&w->panes, wp, entry); | 	TAILQ_INSERT_HEAD(&w->panes, wp, entry); | ||||||
| 	window_pane_resize(wp, w->sx, w->sy); | 	window_pane_resize(wp, w->sx, w->sy); | ||||||
| @@ -78,6 +79,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		xfree(cause); | 		xfree(cause); | ||||||
| 		return (-1); | 		return (-1); | ||||||
| 	} | 	} | ||||||
|  | 	layout_init(w); | ||||||
| 	screen_reinit(&wp->base); | 	screen_reinit(&wp->base); | ||||||
|  |  | ||||||
| 	recalculate_sizes(); | 	recalculate_sizes(); | ||||||
|   | |||||||
| @@ -59,6 +59,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	struct winlink		*wl; | 	struct winlink		*wl; | ||||||
| 	struct window		*w; | 	struct window		*w; | ||||||
| 	struct window_pane	*wp, *wp2; | 	struct window_pane	*wp, *wp2; | ||||||
|  | 	struct layout_cell	*lc; | ||||||
| 	u_int			 sx, sy, xoff, yoff; | 	u_int			 sx, sy, xoff, yoff; | ||||||
|  |  | ||||||
| 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | ||||||
| @@ -70,42 +71,56 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		TAILQ_REMOVE(&w->panes, wp, entry); | 		TAILQ_REMOVE(&w->panes, wp, entry); | ||||||
| 		TAILQ_INSERT_HEAD(&w->panes, wp, entry); | 		TAILQ_INSERT_HEAD(&w->panes, wp, entry); | ||||||
|  |  | ||||||
|  | 		lc = wp->layout_cell; | ||||||
| 		xoff = wp->xoff; yoff = wp->yoff; | 		xoff = wp->xoff; yoff = wp->yoff; | ||||||
| 		sx = wp->sx; sy = wp->sy; | 		sx = wp->sx; sy = wp->sy; | ||||||
| 		TAILQ_FOREACH(wp, &w->panes, entry) { | 		TAILQ_FOREACH(wp, &w->panes, entry) { | ||||||
| 			if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) | 			if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) | ||||||
| 				break; | 				break; | ||||||
|  | 			wp->layout_cell = wp2->layout_cell; | ||||||
|  | 			if (wp->layout_cell != NULL) | ||||||
|  | 				wp->layout_cell->wp = wp; | ||||||
| 			wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; | 			wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; | ||||||
| 			window_pane_resize(wp, wp2->sx, wp2->sy); | 			window_pane_resize(wp, wp2->sx, wp2->sy); | ||||||
| 		} | 		} | ||||||
|  | 		wp->layout_cell = lc; | ||||||
|  | 		if (wp->layout_cell != NULL) | ||||||
|  | 			wp->layout_cell->wp = wp; | ||||||
| 		wp->xoff = xoff; wp->yoff = yoff; | 		wp->xoff = xoff; wp->yoff = yoff; | ||||||
| 		window_pane_resize(wp, sx, sy); | 		window_pane_resize(wp, sx, sy); | ||||||
|  |  | ||||||
| 		if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) | 		if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) | ||||||
| 			wp = TAILQ_LAST(&w->panes, window_panes); | 			wp = TAILQ_LAST(&w->panes, window_panes); | ||||||
| 		window_set_active_pane(w, wp); | 		window_set_active_pane(w, wp); | ||||||
|  | 		server_redraw_window(w); | ||||||
| 	} else { | 	} else { | ||||||
| 		wp = TAILQ_FIRST(&w->panes); | 		wp = TAILQ_FIRST(&w->panes); | ||||||
| 		TAILQ_REMOVE(&w->panes, wp, entry); | 		TAILQ_REMOVE(&w->panes, wp, entry); | ||||||
| 		TAILQ_INSERT_TAIL(&w->panes, wp, entry); | 		TAILQ_INSERT_TAIL(&w->panes, wp, entry); | ||||||
|  |  | ||||||
|  | 		lc = wp->layout_cell; | ||||||
| 		xoff = wp->xoff; yoff = wp->yoff; | 		xoff = wp->xoff; yoff = wp->yoff; | ||||||
| 		sx = wp->sx; sy = wp->sy; | 		sx = wp->sx; sy = wp->sy; | ||||||
| 		TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { | 		TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { | ||||||
| 			if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL) | 			if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL) | ||||||
| 				break; | 				break; | ||||||
|  | 			wp->layout_cell = wp2->layout_cell; | ||||||
|  | 			if (wp->layout_cell != NULL) | ||||||
|  | 				wp->layout_cell->wp = wp; | ||||||
| 			wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; | 			wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; | ||||||
| 			window_pane_resize(wp, wp2->sx, wp2->sy); | 			window_pane_resize(wp, wp2->sx, wp2->sy); | ||||||
| 		} | 		} | ||||||
|  | 		wp->layout_cell = lc; | ||||||
|  | 		if (wp->layout_cell != NULL) | ||||||
|  | 			wp->layout_cell->wp = wp; | ||||||
| 		wp->xoff = xoff; wp->yoff = yoff; | 		wp->xoff = xoff; wp->yoff = yoff; | ||||||
| 		window_pane_resize(wp, sx, sy); | 		window_pane_resize(wp, sx, sy); | ||||||
|  |  | ||||||
| 		if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) | 		if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) | ||||||
| 			wp = TAILQ_FIRST(&w->panes); | 			wp = TAILQ_FIRST(&w->panes); | ||||||
| 		window_set_active_pane(w, wp); | 		window_set_active_pane(w, wp); | ||||||
|  | 		server_redraw_window(w); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	layout_refresh(w, 0); |  | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -49,17 +49,17 @@ cmd_select_layout_init(struct cmd *self, int key) | |||||||
| 	data = self->data; | 	data = self->data; | ||||||
|  |  | ||||||
| 	switch (key) { | 	switch (key) { | ||||||
| 	case KEYC_ADDESC('0'): |  | ||||||
| 		data->arg = xstrdup("manual-vertical"); |  | ||||||
| 		break; |  | ||||||
| 	case KEYC_ADDESC('1'): | 	case KEYC_ADDESC('1'): | ||||||
| 		data->arg = xstrdup("even-horizontal"); | 		data->arg = xstrdup("even-horizontal"); | ||||||
| 		break; | 		break; | ||||||
| 	case KEYC_ADDESC('2'): | 	case KEYC_ADDESC('2'): | ||||||
| 		data->arg = xstrdup("even-vertical"); | 		data->arg = xstrdup("even-vertical"); | ||||||
| 		break; | 		break; | ||||||
| 	case KEYC_ADDESC('9'): | 	case KEYC_ADDESC('3'): | ||||||
| 		data->arg = xstrdup("active-only"); | 		data->arg = xstrdup("main-horizontal"); | ||||||
|  | 		break; | ||||||
|  | 	case KEYC_ADDESC('4'): | ||||||
|  | 		data->arg = xstrdup("main-vertical"); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -74,13 +74,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | ||||||
| 		return (-1); | 		return (-1); | ||||||
|  |  | ||||||
| 	if ((layout = layout_lookup(data->arg)) == -1) { | 	if ((layout = layout_set_lookup(data->arg)) == -1) { | ||||||
| 		ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg); |  		ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg); | ||||||
| 		return (-1); |  		return (-1); | ||||||
| 	} |  	} | ||||||
|  |  | ||||||
| 	if (layout_select(wl->window, layout) == 0) | 	layout = layout_set_select(wl->window, layout); | ||||||
| 		ctx->info(ctx, "layout now: %s", layout_name(wl->window)); | 	ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -63,7 +63,6 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		return (-1); | 		return (-1); | ||||||
| 	} | 	} | ||||||
| 	window_set_active_pane(wl->window, wp); | 	window_set_active_pane(wl->window, wp); | ||||||
| 	layout_refresh(wl->window, 1); |  | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -39,13 +39,14 @@ struct cmd_split_window_data { | |||||||
| 	char	*target; | 	char	*target; | ||||||
| 	char	*cmd; | 	char	*cmd; | ||||||
| 	int	 flag_detached; | 	int	 flag_detached; | ||||||
|  | 	int	 flag_horizontal; | ||||||
| 	int	 percentage; | 	int	 percentage; | ||||||
| 	int	 lines; | 	int	 size; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const struct cmd_entry cmd_split_window_entry = { | const struct cmd_entry cmd_split_window_entry = { | ||||||
| 	"split-window", "splitw", | 	"split-window", "splitw", | ||||||
| 	"[-d] [-p percentage|-l lines] [-t target-window] [command]", | 	"[-dhv] [-p percentage|-l size] [-t target-window] [command]", | ||||||
| 	0, 0, | 	0, 0, | ||||||
| 	cmd_split_window_init, | 	cmd_split_window_init, | ||||||
| 	cmd_split_window_parse, | 	cmd_split_window_parse, | ||||||
| @@ -57,7 +58,7 @@ const struct cmd_entry cmd_split_window_entry = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| void | void | ||||||
| cmd_split_window_init(struct cmd *self, unused int arg) | cmd_split_window_init(struct cmd *self, int key) | ||||||
| { | { | ||||||
| 	struct cmd_split_window_data	 *data; | 	struct cmd_split_window_data	 *data; | ||||||
|  |  | ||||||
| @@ -65,50 +66,63 @@ cmd_split_window_init(struct cmd *self, unused int arg) | |||||||
| 	data->target = NULL; | 	data->target = NULL; | ||||||
| 	data->cmd = NULL; | 	data->cmd = NULL; | ||||||
| 	data->flag_detached = 0; | 	data->flag_detached = 0; | ||||||
|  | 	data->flag_horizontal = 0; | ||||||
| 	data->percentage = -1; | 	data->percentage = -1; | ||||||
| 	data->lines = -1; | 	data->size = -1; | ||||||
|  |  | ||||||
|  | 	switch (key) { | ||||||
|  | 	case '%': | ||||||
|  | 		data->flag_horizontal = 1; | ||||||
|  | 		break;		 | ||||||
|  | 	case '"': | ||||||
|  | 		data->flag_horizontal = 0; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| int | int | ||||||
| cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) | cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) | ||||||
| { | { | ||||||
| 	struct cmd_split_window_data	*data; | 	struct cmd_split_window_data	*data; | ||||||
| 	int				 opt, n; | 	int				 opt; | ||||||
| 	const char			*errstr; | 	const char			*errstr; | ||||||
|  |  | ||||||
| 	self->entry->init(self, 0); | 	self->entry->init(self, 0); | ||||||
| 	data = self->data; | 	data = self->data; | ||||||
|  |  | ||||||
| 	while ((opt = getopt(argc, argv, "dl:p:t:")) != -1) { | 	while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) { | ||||||
| 		switch (opt) { | 		switch (opt) { | ||||||
| 		case 'd': | 		case 'd': | ||||||
| 			data->flag_detached = 1; | 			data->flag_detached = 1; | ||||||
| 			break; | 			break; | ||||||
|  | 		case 'h': | ||||||
|  | 			data->flag_horizontal = 1; | ||||||
|  | 			break; | ||||||
| 		case 't': | 		case 't': | ||||||
| 			if (data->target == NULL) | 			if (data->target == NULL) | ||||||
| 				data->target = xstrdup(optarg); | 				data->target = xstrdup(optarg); | ||||||
| 			break; | 			break; | ||||||
| 		case 'l': | 		case 'l': | ||||||
| 			if (data->percentage == -1 && data->lines == -1) { | 			if (data->percentage != -1 || data->size != -1) | ||||||
| 				n = strtonum(optarg, 1, INT_MAX, &errstr); | 				break; | ||||||
| 				if (errstr != NULL) { | 			data->size = strtonum(optarg, 1, INT_MAX, &errstr); | ||||||
| 					xasprintf(cause, "lines %s", errstr); | 			if (errstr != NULL) { | ||||||
| 					goto error; | 				xasprintf(cause, "size %s", errstr); | ||||||
| 				} | 				goto error; | ||||||
| 				data->lines = n; |  | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 		case 'p': | 		case 'p': | ||||||
| 			if (data->lines == -1 && data->percentage == -1) { | 			if (data->size != -1 || data->percentage != -1) | ||||||
| 				n = strtonum(optarg, 1, 100, &errstr); | 				break; | ||||||
| 				if (errstr != NULL) { | 			data->percentage = strtonum(optarg, 1, 100, &errstr); | ||||||
| 					xasprintf( | 			if (errstr != NULL) { | ||||||
| 					    cause, "percentage %s", errstr); | 				xasprintf(cause, "percentage %s", errstr); | ||||||
| 					goto error; | 				goto error; | ||||||
| 				} |  | ||||||
| 				data->percentage = n; |  | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
|  | 		case 'v': | ||||||
|  | 			data->flag_horizontal = 0; | ||||||
|  | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			goto usage; | 			goto usage; | ||||||
| 		} | 		} | ||||||
| @@ -142,7 +156,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	const char		       **env; | 	const char		       **env; | ||||||
| 	char		 		*cmd, *cwd, *cause; | 	char		 		*cmd, *cwd, *cause; | ||||||
| 	u_int				 hlimit; | 	u_int				 hlimit; | ||||||
| 	int				 lines; | 	int				 size; | ||||||
|  | 	enum layout_type		 type; | ||||||
|  |  | ||||||
| 	if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) | 	if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) | ||||||
| 		return (-1); | 		return (-1); | ||||||
| @@ -158,19 +173,27 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	else | 	else | ||||||
| 		cwd = ctx->cmdclient->cwd; | 		cwd = ctx->cmdclient->cwd; | ||||||
|  |  | ||||||
| 	lines = -1; | 	size = -1; | ||||||
| 	if (data->lines != -1) | 	if (data->size != -1) | ||||||
| 		lines = data->lines; | 		size = data->size; | ||||||
| 	else if (data->percentage != -1) | 	else if (data->percentage != -1) | ||||||
| 		lines = (w->active->sy * data->percentage) / 100; | 		size = (w->active->sy * data->percentage) / 100; | ||||||
|  |  | ||||||
| 	hlimit = options_get_number(&s->options, "history-limit"); | 	hlimit = options_get_number(&s->options, "history-limit"); | ||||||
| 	wp = window_add_pane(w, lines, cmd, cwd, env, hlimit, &cause); |  | ||||||
| 	if (wp == NULL) { | 	type = LAYOUT_TOPBOTTOM; | ||||||
| 		ctx->error(ctx, "create pane failed: %s", cause); | 	if (data->flag_horizontal) | ||||||
| 		xfree(cause); | 		type = LAYOUT_LEFTRIGHT; | ||||||
| 		return (-1); |  | ||||||
|  | 	wp = window_add_pane(w, hlimit, &cause); | ||||||
|  | 	if (wp == NULL) | ||||||
|  | 		goto error; | ||||||
|  | 	if (window_pane_spawn(wp, cmd, cwd, env, &cause) != 0) | ||||||
|  | 		goto error; | ||||||
|  | 	if (layout_split_pane(w->active, type, size, wp) != 0) { | ||||||
|  | 		cause = xstrdup("pane too small"); | ||||||
|  | 		goto error; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	server_redraw_window(w); | 	server_redraw_window(w); | ||||||
|  |  | ||||||
| 	if (!data->flag_detached) { | 	if (!data->flag_detached) { | ||||||
| @@ -179,9 +202,15 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		server_redraw_session(s); | 		server_redraw_session(s); | ||||||
| 	} else | 	} else | ||||||
| 		server_status_session(s); | 		server_status_session(s); | ||||||
| 	layout_refresh(w, 0); |  | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
|  |  | ||||||
|  | error: | ||||||
|  | 	if (wp != NULL) | ||||||
|  | 		window_remove_pane(w, wp); | ||||||
|  | 	ctx->error(ctx, "create pane failed: %s", cause); | ||||||
|  | 	xfree(cause); | ||||||
|  | 	return (-1); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| @@ -228,6 +257,8 @@ cmd_split_window_print(struct cmd *self, char *buf, size_t len) | |||||||
| 		return (off); | 		return (off); | ||||||
| 	if (off < len && data->flag_detached) | 	if (off < len && data->flag_detached) | ||||||
| 		off += xsnprintf(buf + off, len - off, " -d"); | 		off += xsnprintf(buf + off, len - off, " -d"); | ||||||
|  | 	if (off < len && data->flag_horizontal) | ||||||
|  | 		off += xsnprintf(buf + off, len - off, " -h"); | ||||||
| 	if (off < len && data->target != NULL) | 	if (off < len && data->target != NULL) | ||||||
| 		off += cmd_prarg(buf + off, len - off, " -t ", data->target); | 		off += cmd_prarg(buf + off, len - off, " -t ", data->target); | ||||||
| 	if (off < len && data->cmd != NULL) | 	if (off < len && data->cmd != NULL) | ||||||
|   | |||||||
| @@ -157,6 +157,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	struct winlink			*wl; | 	struct winlink			*wl; | ||||||
| 	struct window			*w; | 	struct window			*w; | ||||||
| 	struct window_pane		*tmp_wp, *src_wp, *dst_wp; | 	struct window_pane		*tmp_wp, *src_wp, *dst_wp; | ||||||
|  | 	struct layout_cell		*lc; | ||||||
| 	u_int				 xx, yy; | 	u_int				 xx, yy; | ||||||
|  |  | ||||||
| 	if (data == NULL) | 	if (data == NULL) | ||||||
| @@ -207,12 +208,15 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 	else | 	else | ||||||
| 		TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); | 		TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); | ||||||
|  |  | ||||||
|  | 	lc = src_wp->layout_cell; | ||||||
| 	xx = src_wp->xoff; | 	xx = src_wp->xoff; | ||||||
| 	yy = src_wp->yoff; | 	yy = src_wp->yoff; | ||||||
|  	src_wp->xoff = dst_wp->xoff; | 	src_wp->layout_cell = dst_wp->layout_cell; | ||||||
|  	src_wp->yoff = dst_wp->yoff; | 	if (src_wp->layout_cell != NULL) | ||||||
|  	dst_wp->xoff = xx; | 		src_wp->layout_cell->wp = src_wp; | ||||||
|  	dst_wp->yoff = yy; | 	dst_wp->layout_cell = lc; | ||||||
|  | 	if (dst_wp->layout_cell != NULL) | ||||||
|  | 		dst_wp->layout_cell->wp = dst_wp; | ||||||
|  |  | ||||||
| 	xx = src_wp->sx; | 	xx = src_wp->sx; | ||||||
| 	yy = src_wp->sy; | 	yy = src_wp->sy; | ||||||
| @@ -224,8 +228,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		if (!window_pane_visible(tmp_wp)) | 		if (!window_pane_visible(tmp_wp)) | ||||||
| 			tmp_wp = src_wp; | 			tmp_wp = src_wp; | ||||||
| 		window_set_active_pane(w, tmp_wp); | 		window_set_active_pane(w, tmp_wp); | ||||||
| 		layout_refresh(w, 0); |  | ||||||
| 	} | 	} | ||||||
|  | 	server_redraw_window(w); | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -54,7 +54,6 @@ cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		w->active = TAILQ_PREV(w->active, window_panes, entry); | 		w->active = TAILQ_PREV(w->active, window_panes, entry); | ||||||
| 		if (w->active == NULL) | 		if (w->active == NULL) | ||||||
| 			w->active = TAILQ_LAST(&w->panes, window_panes); | 			w->active = TAILQ_LAST(&w->panes, window_panes); | ||||||
| 		layout_refresh(w, 1); |  | ||||||
| 	} while (!window_pane_visible(w->active)); | 	} while (!window_pane_visible(w->active)); | ||||||
|  |  | ||||||
| 	return (0); | 	return (0); | ||||||
|   | |||||||
| @@ -94,6 +94,7 @@ key_bindings_init(void) | |||||||
| 		{ ' ',			  0, &cmd_next_layout_entry }, | 		{ ' ',			  0, &cmd_next_layout_entry }, | ||||||
| 		{ '!', 			  0, &cmd_break_pane_entry }, | 		{ '!', 			  0, &cmd_break_pane_entry }, | ||||||
| 		{ '"', 			  0, &cmd_split_window_entry },	 | 		{ '"', 			  0, &cmd_split_window_entry },	 | ||||||
|  | 		{ '%', 			  0, &cmd_split_window_entry },	 | ||||||
| 		{ '#', 			  0, &cmd_list_buffers_entry }, | 		{ '#', 			  0, &cmd_list_buffers_entry }, | ||||||
| 		{ '&', 			  0, &cmd_confirm_before_entry }, | 		{ '&', 			  0, &cmd_confirm_before_entry }, | ||||||
| 		{ ',', 			  0, &cmd_command_prompt_entry }, | 		{ ',', 			  0, &cmd_command_prompt_entry }, | ||||||
| @@ -132,10 +133,10 @@ key_bindings_init(void) | |||||||
| 		{ '{',			  0, &cmd_swap_pane_entry }, | 		{ '{',			  0, &cmd_swap_pane_entry }, | ||||||
| 		{ '}',			  0, &cmd_swap_pane_entry }, | 		{ '}',			  0, &cmd_swap_pane_entry }, | ||||||
| 		{ '\002', 		  0, &cmd_send_prefix_entry }, | 		{ '\002', 		  0, &cmd_send_prefix_entry }, | ||||||
| 		{ KEYC_ADDESC('0'),	  0, &cmd_select_layout_entry }, |  | ||||||
| 		{ KEYC_ADDESC('1'),	  0, &cmd_select_layout_entry }, | 		{ KEYC_ADDESC('1'),	  0, &cmd_select_layout_entry }, | ||||||
| 		{ KEYC_ADDESC('2'),	  0, &cmd_select_layout_entry }, | 		{ KEYC_ADDESC('2'),	  0, &cmd_select_layout_entry }, | ||||||
| 		{ KEYC_ADDESC('9'),	  0, &cmd_select_layout_entry }, | 		{ KEYC_ADDESC('3'),	  0, &cmd_select_layout_entry }, | ||||||
|  | 		{ KEYC_ADDESC('4'),	  0, &cmd_select_layout_entry }, | ||||||
| 		{ KEYC_PPAGE, 		  0, &cmd_scroll_mode_entry }, | 		{ KEYC_PPAGE, 		  0, &cmd_scroll_mode_entry }, | ||||||
| 		{ KEYC_ADDESC('n'), 	  0, &cmd_next_window_entry }, | 		{ KEYC_ADDESC('n'), 	  0, &cmd_next_window_entry }, | ||||||
| 		{ KEYC_ADDESC('p'), 	  0, &cmd_previous_window_entry }, | 		{ KEYC_ADDESC('p'), 	  0, &cmd_previous_window_entry }, | ||||||
| @@ -143,8 +144,12 @@ key_bindings_init(void) | |||||||
| 		{ KEYC_DOWN, 		  0, &cmd_down_pane_entry }, | 		{ KEYC_DOWN, 		  0, &cmd_down_pane_entry }, | ||||||
| 		{ KEYC_ADDESC(KEYC_UP),   1, &cmd_resize_pane_entry }, | 		{ KEYC_ADDESC(KEYC_UP),   1, &cmd_resize_pane_entry }, | ||||||
| 		{ KEYC_ADDESC(KEYC_DOWN), 1, &cmd_resize_pane_entry }, | 		{ KEYC_ADDESC(KEYC_DOWN), 1, &cmd_resize_pane_entry }, | ||||||
|  | 		{ KEYC_ADDESC(KEYC_LEFT), 1, &cmd_resize_pane_entry }, | ||||||
|  | 		{ KEYC_ADDESC(KEYC_RIGHT),1, &cmd_resize_pane_entry }, | ||||||
| 		{ KEYC_ADDCTL(KEYC_UP),   1, &cmd_resize_pane_entry }, | 		{ KEYC_ADDCTL(KEYC_UP),   1, &cmd_resize_pane_entry }, | ||||||
| 		{ KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry },	 | 		{ KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry },	 | ||||||
|  | 		{ KEYC_ADDCTL(KEYC_LEFT), 1, &cmd_resize_pane_entry }, | ||||||
|  | 		{ KEYC_ADDCTL(KEYC_RIGHT),1, &cmd_resize_pane_entry }, | ||||||
| 		{ KEYC_ADDESC('o'),	  0, &cmd_rotate_window_entry }, | 		{ KEYC_ADDESC('o'),	  0, &cmd_rotate_window_entry }, | ||||||
| 		{ '\017',	          0, &cmd_rotate_window_entry }, | 		{ '\017',	          0, &cmd_rotate_window_entry }, | ||||||
| 	}; | 	}; | ||||||
|   | |||||||
							
								
								
									
										172
									
								
								layout-manual.c
									
									
									
									
									
								
							
							
						
						
									
										172
									
								
								layout-manual.c
									
									
									
									
									
								
							| @@ -1,172 +0,0 @@ | |||||||
| /* $OpenBSD$ */ |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> |  | ||||||
|  * |  | ||||||
|  * Permission to use, copy, modify, and distribute this software for any |  | ||||||
|  * purpose with or without fee is hereby granted, provided that the above |  | ||||||
|  * copyright notice and this permission notice appear in all copies. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |  | ||||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |  | ||||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |  | ||||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |  | ||||||
|  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |  | ||||||
|  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |  | ||||||
|  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include <sys/types.h> |  | ||||||
|  |  | ||||||
| #include "tmux.h" |  | ||||||
|  |  | ||||||
| void	layout_manual_v_update_offsets(struct window *); |  | ||||||
|  |  | ||||||
| void |  | ||||||
| layout_manual_v_refresh(struct window *w, unused int active_only) |  | ||||||
| { |  | ||||||
| 	struct window_pane	*wp; |  | ||||||
| 	u_int			 npanes, total, height; |  | ||||||
| 	int			 left; |  | ||||||
|  |  | ||||||
| 	if (active_only) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	if (TAILQ_EMPTY(&w->panes)) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	/* Check the new size. */ |  | ||||||
| 	npanes = window_count_panes(w); |  | ||||||
| 	if (w->sy <= PANE_MINIMUM * npanes) { |  | ||||||
| 		/*  |  | ||||||
| 		 * Make the first pane the smaller of the minimum and total (it |  | ||||||
| 		 * must fit to be visible) and the rest the minimum size. |  | ||||||
| 		 */ |  | ||||||
| 		height = PANE_MINIMUM; |  | ||||||
| 		if (height > w->sy) |  | ||||||
| 			height = w->sy + 1; |  | ||||||
| 		TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 			if (wp == TAILQ_FIRST(&w->panes)) |  | ||||||
| 				wp->sy = height - 1; |  | ||||||
| 			else |  | ||||||
| 				wp->sy = PANE_MINIMUM - 1; |  | ||||||
| 		} |  | ||||||
| 		/* And increase the first by the rest if possible. */ |  | ||||||
| 		if (w->sy >= PANE_MINIMUM) |  | ||||||
| 			TAILQ_FIRST(&w->panes)->sy += 1 + w->sy % PANE_MINIMUM; |  | ||||||
| 	} else { |  | ||||||
| 		/* In theory they will all fit. Find the current total. */ |  | ||||||
| 		total = 0; |  | ||||||
| 		TAILQ_FOREACH(wp, &w->panes, entry) |  | ||||||
| 			total += wp->sy; |  | ||||||
| 		total += npanes - 1; |  | ||||||
|  |  | ||||||
| 		/* Growing or shrinking? */ |  | ||||||
| 		left = w->sy - total; |  | ||||||
| 		if (left > 0) { |  | ||||||
| 			/* Growing. Expand evenly. */ |  | ||||||
| 			while (left > 0) { |  | ||||||
| 				TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 					wp->sy++; |  | ||||||
| 					if (--left == 0) |  | ||||||
| 						break; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			/* Shrinking. Reduce evenly down to minimum. */ |  | ||||||
| 			while (left < 0) { |  | ||||||
| 				TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 					if (wp->sy <= PANE_MINIMUM - 1) |  | ||||||
| 						continue; |  | ||||||
| 					wp->sy--; |  | ||||||
| 					if (++left == 0) |  | ||||||
| 						break; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Now do the resize. */ |  | ||||||
| 	TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 		wp->sy--; |  | ||||||
| 	    	window_pane_resize(wp, w->sx, wp->sy + 1); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Fill in the offsets. */ |  | ||||||
| 	layout_manual_v_update_offsets(w); |  | ||||||
|  |  | ||||||
| 	/* Switch the active window if necessary. */ |  | ||||||
| 	window_set_active_pane(w, w->active); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| layout_manual_v_resize(struct window_pane *wp, int adjust) |  | ||||||
| { |  | ||||||
| 	struct window		*w = wp->window; |  | ||||||
| 	struct window_pane	*wq; |  | ||||||
|  |  | ||||||
| 	if (adjust > 0) { |  | ||||||
| 		/* |  | ||||||
| 		 * If this is not the last pane, keep trying to increase size |  | ||||||
| 		 * and remove it from the next panes. If it is the last, do |  | ||||||
| 		 * so on the previous pane. |  | ||||||
| 		 */ |  | ||||||
| 		if (TAILQ_NEXT(wp, entry) == NULL) { |  | ||||||
| 			if (wp == TAILQ_FIRST(&w->panes)) { |  | ||||||
| 				/* Only one pane. */ |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 			wp = TAILQ_PREV(wp, window_panes, entry); |  | ||||||
| 		} |  | ||||||
| 		while (adjust-- > 0) { |  | ||||||
| 			wq = wp; |  | ||||||
| 			while ((wq = TAILQ_NEXT(wq, entry)) != NULL) { |  | ||||||
| 				if (wq->sy <= PANE_MINIMUM) |  | ||||||
| 					continue; |  | ||||||
| 				window_pane_resize(wq, wq->sx, wq->sy - 1); |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 			if (wq == NULL) |  | ||||||
| 				break; |  | ||||||
| 			window_pane_resize(wp, wp->sx, wp->sy + 1); |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		adjust = -adjust; |  | ||||||
| 		/* |  | ||||||
| 		 * If this is not the last pane, keep trying to reduce size |  | ||||||
| 		 * and add to the following pane. If it is the last, do so on |  | ||||||
| 		 * the previous pane. |  | ||||||
| 		 */ |  | ||||||
| 		wq = TAILQ_NEXT(wp, entry); |  | ||||||
| 		if (wq == NULL) { |  | ||||||
| 			if (wp == TAILQ_FIRST(&w->panes)) { |  | ||||||
| 				/* Only one pane. */ |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 			wq = wp; |  | ||||||
| 			wp = TAILQ_PREV(wq, window_panes, entry); |  | ||||||
| 		} |  | ||||||
| 		while (adjust-- > 0) { |  | ||||||
| 			if (wp->sy <= PANE_MINIMUM) |  | ||||||
| 				break; |  | ||||||
| 			window_pane_resize(wq, wq->sx, wq->sy + 1); |  | ||||||
| 			window_pane_resize(wp, wp->sx, wp->sy - 1); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	layout_manual_v_update_offsets(w); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| layout_manual_v_update_offsets(struct window *w) |  | ||||||
| { |  | ||||||
| 	struct window_pane     *wp; |  | ||||||
| 	u_int			yoff; |  | ||||||
|  |  | ||||||
| 	yoff = 0; |  | ||||||
| 	TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 		wp->xoff = 0; |  | ||||||
| 		wp->yoff = yoff; |  | ||||||
| 		yoff += wp->sy + 1; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										436
									
								
								layout-set.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								layout-set.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,436 @@ | |||||||
|  | /* $OpenBSD$ */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> | ||||||
|  |  * | ||||||
|  |  * Permission to use, copy, modify, and distribute this software for any | ||||||
|  |  * purpose with or without fee is hereby granted, provided that the above | ||||||
|  |  * copyright notice and this permission notice appear in all copies. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||||
|  |  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||||
|  |  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||||
|  |  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||||
|  |  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | ||||||
|  |  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <sys/types.h> | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #include "tmux.h" | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Set window layouts - predefined methods to arrange windows. These are one-off | ||||||
|  |  * and generate a layout tree. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | void	layout_set_even_h(struct window *); | ||||||
|  | void	layout_set_even_v(struct window *); | ||||||
|  | void	layout_set_main_h(struct window *); | ||||||
|  | void	layout_set_main_v(struct window *); | ||||||
|  |  | ||||||
|  | const struct { | ||||||
|  | 	const char	*name; | ||||||
|  | 	void	      	(*arrange)(struct window *); | ||||||
|  | } layout_sets[] = { | ||||||
|  | 	{ "even-horizontal", layout_set_even_h }, | ||||||
|  | 	{ "even-vertical", layout_set_even_v }, | ||||||
|  | 	{ "main-horizontal", layout_set_main_h }, | ||||||
|  | 	{ "main-vertical", layout_set_main_v }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const char * | ||||||
|  | layout_set_name(u_int layout) | ||||||
|  | { | ||||||
|  | 	return (layout_sets[layout].name); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | layout_set_lookup(const char *name) | ||||||
|  | { | ||||||
|  | 	u_int	i; | ||||||
|  | 	int	matched = -1; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < nitems(layout_sets); i++) { | ||||||
|  | 		if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) { | ||||||
|  | 			if (matched != -1)	/* ambiguous */ | ||||||
|  | 				return (-1); | ||||||
|  | 			matched = i; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return (matched); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | u_int | ||||||
|  | layout_set_select(struct window *w, u_int layout) | ||||||
|  | { | ||||||
|  | 	if (layout > nitems(layout_sets) - 1) | ||||||
|  | 		layout = nitems(layout_sets) - 1; | ||||||
|  |  | ||||||
|  | 	if (layout_sets[layout].arrange != NULL) | ||||||
|  | 		layout_sets[layout].arrange(w); | ||||||
|  |  | ||||||
|  | 	w->layout = layout; | ||||||
|  | 	return (layout); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | u_int | ||||||
|  | layout_set_next(struct window *w) | ||||||
|  | { | ||||||
|  | 	u_int	layout = w->layout; | ||||||
|  |  | ||||||
|  | 	if (layout_sets[layout].arrange != NULL) | ||||||
|  | 		layout_sets[layout].arrange(w); | ||||||
|  |  | ||||||
|  | 	w->layout++; | ||||||
|  | 	if (w->layout > nitems(layout_sets) - 1) | ||||||
|  | 		w->layout = 0; | ||||||
|  | 	return (layout); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | u_int | ||||||
|  | layout_set_previous(struct window *w) | ||||||
|  | { | ||||||
|  | 	u_int	layout = w->layout; | ||||||
|  |  | ||||||
|  | 	if (layout_sets[layout].arrange != NULL) | ||||||
|  | 		layout_sets[layout].arrange(w); | ||||||
|  |  | ||||||
|  | 	if (w->layout == 0) | ||||||
|  | 		w->layout = nitems(layout_sets) - 1; | ||||||
|  | 	else | ||||||
|  | 		w->layout--; | ||||||
|  | 	return (layout); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | layout_set_even_h(struct window *w) | ||||||
|  | { | ||||||
|  | 	struct window_pane	*wp; | ||||||
|  | 	struct layout_cell	*lc, *lcnew; | ||||||
|  | 	u_int			 i, n, width, xoff; | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	/* Get number of panes. */ | ||||||
|  | 	n = window_count_panes(w); | ||||||
|  | 	if (n <= 1) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	/* How many can we fit? */ | ||||||
|  | 	if (w->sx / n < PANE_MINIMUM + 1) { | ||||||
|  | 		width = PANE_MINIMUM + 1; | ||||||
|  | 		n = UINT_MAX; | ||||||
|  | 	} else | ||||||
|  | 		width = w->sx / n; | ||||||
|  |  | ||||||
|  | 	/* Free the old root and construct a new. */ | ||||||
|  | 	layout_free(w); | ||||||
|  | 	lc = w->layout_root = layout_create_cell(NULL); | ||||||
|  | 	layout_set_size(lc, w->sx, w->sy, 0, 0); | ||||||
|  | 	layout_make_node(lc, LAYOUT_LEFTRIGHT); | ||||||
|  |  | ||||||
|  | 	/* Build new leaf cells. */ | ||||||
|  | 	i = xoff = 0; | ||||||
|  | 	TAILQ_FOREACH(wp, &w->panes, entry) { | ||||||
|  | 		/* Create child cell. */ | ||||||
|  | 		lcnew = layout_create_cell(lc); | ||||||
|  | 		layout_set_size(lcnew, width - 1, w->sy, xoff, 0); | ||||||
|  | 		layout_make_leaf(lcnew, wp); | ||||||
|  | 		TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); | ||||||
|  |  | ||||||
|  | 		i++; | ||||||
|  | 		xoff += width; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Allocate any remaining space. */ | ||||||
|  | 	if (w->sx > xoff - 1) { | ||||||
|  | 		lc = TAILQ_LAST(&lc->cells, layout_cells); | ||||||
|  | 		layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, w->sx - (xoff - 1)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Fix cell offsets. */ | ||||||
|  | 	layout_fix_offsets(lc); | ||||||
|  | 	layout_fix_panes(w, w->sx, w->sy); | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	server_redraw_window(w); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | layout_set_even_v(struct window *w) | ||||||
|  | { | ||||||
|  | 	struct window_pane	*wp; | ||||||
|  | 	struct layout_cell	*lc, *lcnew; | ||||||
|  | 	u_int			 i, n, height, yoff; | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	/* Get number of panes. */ | ||||||
|  | 	n = window_count_panes(w); | ||||||
|  | 	if (n <= 1) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	/* How many can we fit? */ | ||||||
|  | 	if (w->sy / n < PANE_MINIMUM + 1) { | ||||||
|  | 		height = PANE_MINIMUM + 1; | ||||||
|  | 		n = UINT_MAX; | ||||||
|  | 	} else | ||||||
|  | 		height = w->sy / n; | ||||||
|  |  | ||||||
|  | 	/* Free the old root and construct a new. */ | ||||||
|  | 	layout_free(w); | ||||||
|  | 	lc = w->layout_root = layout_create_cell(NULL); | ||||||
|  | 	layout_set_size(lc, w->sx, w->sy, 0, 0); | ||||||
|  | 	layout_make_node(lc, LAYOUT_TOPBOTTOM); | ||||||
|  |  | ||||||
|  | 	/* Build new leaf cells. */ | ||||||
|  | 	i = yoff = 0; | ||||||
|  | 	TAILQ_FOREACH(wp, &w->panes, entry) { | ||||||
|  | 		/* Create child cell. */ | ||||||
|  | 		lcnew = layout_create_cell(lc); | ||||||
|  | 		layout_set_size(lcnew, w->sx, height - 1, 0, yoff); | ||||||
|  | 		layout_make_leaf(lcnew, wp); | ||||||
|  | 		TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); | ||||||
|  |  | ||||||
|  | 		i++; | ||||||
|  | 		yoff += height; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Allocate any remaining space. */ | ||||||
|  | 	if (w->sy > yoff - 1) { | ||||||
|  | 		lc = TAILQ_LAST(&lc->cells, layout_cells); | ||||||
|  | 		layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, w->sy - (yoff - 1)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Fix cell offsets. */ | ||||||
|  | 	layout_fix_offsets(lc); | ||||||
|  | 	layout_fix_panes(w, w->sx, w->sy); | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	server_redraw_window(w); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | layout_set_main_h(struct window *w) | ||||||
|  | { | ||||||
|  | 	struct window_pane	*wp; | ||||||
|  | 	struct layout_cell	*lc, *lcmain, *lcrow, *lcchild; | ||||||
|  | 	u_int			 n, mainheight, width, height, used; | ||||||
|  | 	u_int			 i, j, columns, rows, totalrows; | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	/* Get number of panes. */ | ||||||
|  | 	n = window_count_panes(w); | ||||||
|  | 	if (n <= 1) | ||||||
|  | 		return; | ||||||
|  | 	n--;	/* take off main pane */ | ||||||
|  |  | ||||||
|  | 	/* How many rows and columns will be needed? */ | ||||||
|  | 	columns = w->sx / (PANE_MINIMUM + 1);	/* maximum columns */ | ||||||
|  | 	rows = 1 + (n - 1) / columns; | ||||||
|  | 	columns = 1 + (n - 1) / rows; | ||||||
|  | 	width = w->sx / columns; | ||||||
|  |  | ||||||
|  | 	/* Get the main pane height and add one for separator line. */ | ||||||
|  | 	mainheight = options_get_number(&w->options, "main-pane-height") + 1; | ||||||
|  | 	if (mainheight < PANE_MINIMUM + 1) | ||||||
|  | 		mainheight = PANE_MINIMUM + 1; | ||||||
|  |  | ||||||
|  | 	/* Try and make everything fit. */ | ||||||
|  | 	totalrows = rows * (PANE_MINIMUM + 1) - 1; | ||||||
|  | 	if (mainheight + totalrows > w->sy) { | ||||||
|  | 		if (totalrows + PANE_MINIMUM + 1 > w->sy) | ||||||
|  | 			mainheight = PANE_MINIMUM + 2; | ||||||
|  | 		else | ||||||
|  | 			mainheight = w->sy - totalrows; | ||||||
|  | 		height = PANE_MINIMUM + 1; | ||||||
|  | 	} else | ||||||
|  | 		height = (w->sy - mainheight) / rows; | ||||||
|  |  | ||||||
|  | 	/* Free old tree and create a new root. */ | ||||||
|  | 	layout_free(w); | ||||||
|  | 	lc = w->layout_root = layout_create_cell(NULL); | ||||||
|  | 	layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0); | ||||||
|  | 	layout_make_node(lc, LAYOUT_TOPBOTTOM); | ||||||
|  |  | ||||||
|  | 	/* Create the main pane. */ | ||||||
|  | 	lcmain = layout_create_cell(lc); | ||||||
|  | 	layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0); | ||||||
|  | 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); | ||||||
|  | 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); | ||||||
|  |  | ||||||
|  | 	/* Create a grid of the remaining cells. */ | ||||||
|  | 	wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); | ||||||
|  | 	for (j = 0; j < rows; j++) { | ||||||
|  | 		/* If this is the last cell, all done. */ | ||||||
|  | 		if (wp == NULL) | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		/* Create the new row. */ | ||||||
|  | 		lcrow = layout_create_cell(lc); | ||||||
|  | 		layout_set_size(lcrow, w->sx, height - 1, 0, 0); | ||||||
|  | 		TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); | ||||||
|  |  | ||||||
|  | 		/* If only one column, just use the row directly. */ | ||||||
|  | 		if (columns == 1) { | ||||||
|  | 			layout_make_leaf(lcrow, wp); | ||||||
|  | 			wp = TAILQ_NEXT(wp, entry); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  		/* Add in the columns. */ | ||||||
|  | 		layout_make_node(lcrow, LAYOUT_LEFTRIGHT); | ||||||
|  | 		for (i = 0; i < columns; i++) { | ||||||
|  | 			/* Create and add a pane cell. */ | ||||||
|  | 			lcchild = layout_create_cell(lcrow); | ||||||
|  | 			layout_set_size(lcchild, width - 1, height - 1, 0, 0); | ||||||
|  | 			layout_make_leaf(lcchild, wp); | ||||||
|  | 			TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); | ||||||
|  |  | ||||||
|  | 			/* Move to the next cell. */ | ||||||
|  | 			if ((wp = TAILQ_NEXT(wp, entry)) == NULL) | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		/* Adjust the row to fit the full width if necessary. */ | ||||||
|  | 		if (i == columns) | ||||||
|  | 			i--; | ||||||
|  |  		used = ((i + 1) * width) - 1; | ||||||
|  |  		if (w->sx <= used) | ||||||
|  |  			continue; | ||||||
|  |  		lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); | ||||||
|  |  		layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Adjust the last row height to fit if necessary. */ | ||||||
|  | 	used = mainheight + (rows * height) - 1; | ||||||
|  | 	if (w->sy > used) { | ||||||
|  | 		lcrow = TAILQ_LAST(&lc->cells, layout_cells); | ||||||
|  | 		layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Fix cell offsets. */ | ||||||
|  | 	layout_fix_offsets(lc); | ||||||
|  | 	layout_fix_panes(w, w->sx, w->sy); | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	server_redraw_window(w); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | layout_set_main_v(struct window *w) | ||||||
|  | { | ||||||
|  | 	struct window_pane	*wp; | ||||||
|  | 	struct layout_cell	*lc, *lcmain, *lccolumn, *lcchild; | ||||||
|  | 	u_int			 n, mainwidth, width, height, used; | ||||||
|  | 	u_int			 i, j, columns, rows, totalcolumns; | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	/* Get number of panes. */ | ||||||
|  | 	n = window_count_panes(w); | ||||||
|  | 	if (n <= 1) | ||||||
|  | 		return; | ||||||
|  | 	n--;	/* take off main pane */ | ||||||
|  |  | ||||||
|  | 	/* How many rows and columns will be needed? */ | ||||||
|  | 	rows = w->sy / (PANE_MINIMUM + 1);	/* maximum rows */ | ||||||
|  | 	columns = 1 + (n - 1) / rows; | ||||||
|  | 	rows = 1 + (n - 1) / columns; | ||||||
|  | 	height = w->sy / rows; | ||||||
|  |  | ||||||
|  | 	/* Get the main pane width and add one for separator line. */ | ||||||
|  | 	mainwidth = options_get_number(&w->options, "main-pane-width") + 1; | ||||||
|  | 	if (mainwidth < PANE_MINIMUM + 1) | ||||||
|  | 		mainwidth = PANE_MINIMUM + 1; | ||||||
|  |  | ||||||
|  | 	/* Try and make everything fit. */ | ||||||
|  | 	totalcolumns = columns * (PANE_MINIMUM + 1) - 1; | ||||||
|  | 	if (mainwidth + totalcolumns > w->sx) { | ||||||
|  | 		if (totalcolumns + PANE_MINIMUM + 1 > w->sx) | ||||||
|  | 			mainwidth = PANE_MINIMUM + 2; | ||||||
|  | 		else | ||||||
|  | 			mainwidth = w->sx - totalcolumns; | ||||||
|  | 		width = PANE_MINIMUM + 1; | ||||||
|  | 	} else | ||||||
|  | 		width = (w->sx - mainwidth) / columns; | ||||||
|  |  | ||||||
|  | 	/* Free old tree and create a new root. */ | ||||||
|  | 	layout_free(w); | ||||||
|  | 	lc = w->layout_root = layout_create_cell(NULL); | ||||||
|  | 	layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0); | ||||||
|  | 	layout_make_node(lc, LAYOUT_LEFTRIGHT); | ||||||
|  |  | ||||||
|  | 	/* Create the main pane. */ | ||||||
|  | 	lcmain = layout_create_cell(lc); | ||||||
|  | 	layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0); | ||||||
|  | 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); | ||||||
|  | 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); | ||||||
|  |  | ||||||
|  | 	/* Create a grid of the remaining cells. */ | ||||||
|  | 	wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); | ||||||
|  | 	for (j = 0; j < columns; j++) { | ||||||
|  | 		/* If this is the last cell, all done. */ | ||||||
|  | 		if (wp == NULL) | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		/* Create the new column. */ | ||||||
|  | 		lccolumn = layout_create_cell(lc); | ||||||
|  | 		layout_set_size(lccolumn, width - 1, w->sy, 0, 0); | ||||||
|  | 		TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry); | ||||||
|  |  | ||||||
|  | 		/* If only one row, just use the row directly. */ | ||||||
|  | 		if (rows == 1) { | ||||||
|  | 			layout_make_leaf(lccolumn, wp); | ||||||
|  | 			wp = TAILQ_NEXT(wp, entry); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		/* Add in the rows. */ | ||||||
|  | 		layout_make_node(lccolumn, LAYOUT_TOPBOTTOM); | ||||||
|  | 		for (i = 0; i < rows; i++) { | ||||||
|  | 			/* Create and add a pane cell. */ | ||||||
|  | 			lcchild = layout_create_cell(lccolumn); | ||||||
|  | 			layout_set_size(lcchild, width - 1, height - 1, 0, 0); | ||||||
|  | 			layout_make_leaf(lcchild, wp); | ||||||
|  | 			TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry); | ||||||
|  |  | ||||||
|  | 			/* Move to the next cell. */ | ||||||
|  | 			if ((wp = TAILQ_NEXT(wp, entry)) == NULL) | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		/* Adjust the column to fit the full height if necessary. */ | ||||||
|  | 		if (i == rows) | ||||||
|  | 			i--; | ||||||
|  | 		used = ((i + 1) * height) - 1; | ||||||
|  |  		if (w->sy <= used) | ||||||
|  |  			continue; | ||||||
|  |  		lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells); | ||||||
|  |  		layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Adjust the last column width to fit if necessary. */ | ||||||
|  | 	used = mainwidth + (columns * width) - 1; | ||||||
|  | 	if (w->sx > used) { | ||||||
|  | 		lccolumn = TAILQ_LAST(&lc->cells, layout_cells); | ||||||
|  | 		layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Fix cell offsets. */ | ||||||
|  | 	layout_fix_offsets(lc); | ||||||
|  | 	layout_fix_panes(w, w->sx, w->sy); | ||||||
|  |  | ||||||
|  | 	layout_print_cell(w->layout_root, __func__, 1); | ||||||
|  |  | ||||||
|  | 	server_redraw_window(w); | ||||||
|  | } | ||||||
							
								
								
									
										869
									
								
								layout.c
									
									
									
									
									
								
							
							
						
						
									
										869
									
								
								layout.c
									
									
									
									
									
								
							| @@ -18,349 +18,632 @@ | |||||||
|  |  | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
|  |  | ||||||
| #include <string.h> | #include <stdlib.h> | ||||||
|  |  | ||||||
| #include "tmux.h" | #include "tmux.h" | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Each layout has two functions, _refresh to relayout the panes and _resize to |  * The window layout is a tree of cells each of which can be one of: a | ||||||
|  * resize a single pane. |  * left-right container for a list of cells, a top-bottom container for a list | ||||||
|  |  * of cells, or a container for a window pane. | ||||||
|  * |  * | ||||||
|  * Second argument (int) to _refresh is 1 if the only change has been that the |  * Each window has a pointer to the root of its layout tree (containing its | ||||||
|  * active pane has changed. If 0 then panes, active pane or both may have |  * panes), every pane has a pointer back to the cell containing it, and each | ||||||
|  * changed. |  * cell a pointer to its parent cell. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| void	layout_active_only_refresh(struct window *, int); | int	layout_resize_pane_grow(struct layout_cell *, enum layout_type, int); | ||||||
| void	layout_even_h_refresh(struct window *, int); | int	layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int); | ||||||
| void	layout_even_v_refresh(struct window *, int); |  | ||||||
| void	layout_main_h_refresh(struct window *, int); |  | ||||||
| void	layout_main_v_refresh(struct window *, int); |  | ||||||
|  |  | ||||||
| const struct { | struct layout_cell * | ||||||
| 	const char     *name; | layout_create_cell(struct layout_cell *lcparent) | ||||||
| 	void		(*refresh)(struct window *, int); |  | ||||||
| 	void		(*resize)(struct window_pane *, int); |  | ||||||
| } layouts[] = { |  | ||||||
| 	{ "manual-vertical", layout_manual_v_refresh, layout_manual_v_resize }, |  | ||||||
| 	{ "active-only", layout_active_only_refresh, NULL }, |  | ||||||
| 	{ "even-horizontal", layout_even_h_refresh, NULL }, |  | ||||||
| 	{ "even-vertical", layout_even_v_refresh, NULL }, |  | ||||||
| 	{ "main-horizontal", layout_main_h_refresh, NULL }, |  | ||||||
| 	{ "main-vertical", layout_main_v_refresh, NULL }, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const char * |  | ||||||
| layout_name(struct window *w) |  | ||||||
| { | { | ||||||
| 	return (layouts[w->layout].name); | 	struct layout_cell	*lc; | ||||||
|  |  | ||||||
|  | 	lc = xmalloc(sizeof *lc); | ||||||
|  | 	lc->type = LAYOUT_WINDOWPANE; | ||||||
|  | 	lc->parent = lcparent; | ||||||
|  |  | ||||||
|  | 	TAILQ_INIT(&lc->cells); | ||||||
|  | 	 | ||||||
|  | 	lc->sx = UINT_MAX; | ||||||
|  | 	lc->sy = UINT_MAX; | ||||||
|  | 	 | ||||||
|  | 	lc->xoff = UINT_MAX; | ||||||
|  | 	lc->yoff = UINT_MAX; | ||||||
|  | 	 | ||||||
|  | 	lc->wp = NULL; | ||||||
|  |  | ||||||
|  | 	return (lc); | ||||||
| } | } | ||||||
|  |  | ||||||
| int | void | ||||||
| layout_lookup(const char *name) | layout_free_cell(struct layout_cell *lc) | ||||||
| { | { | ||||||
| 	u_int	i; | 	struct layout_cell	*lcchild; | ||||||
| 	int	matched = -1; |  | ||||||
|  |  | ||||||
| 	for (i = 0; i < nitems(layouts); i++) { | 	switch (lc->type) { | ||||||
| 		if (strncmp(layouts[i].name, name, strlen(name)) == 0) { | 	case LAYOUT_LEFTRIGHT: | ||||||
| 			if (matched != -1)	/* ambiguous */ | 	case LAYOUT_TOPBOTTOM: | ||||||
| 				return (-1); | 		while (!TAILQ_EMPTY(&lc->cells)) { | ||||||
| 			matched = i; | 			lcchild = TAILQ_FIRST(&lc->cells); | ||||||
|  | 			TAILQ_REMOVE(&lc->cells, lcchild, entry); | ||||||
|  | 			layout_free_cell(lcchild); | ||||||
| 		} | 		} | ||||||
|  | 		break; | ||||||
|  | 	case LAYOUT_WINDOWPANE: | ||||||
|  | 		if (lc->wp != NULL) | ||||||
|  | 			lc->wp->layout_cell = NULL; | ||||||
|  | 		break; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return (matched); | 	xfree(lc); | ||||||
| } |  | ||||||
|  |  | ||||||
| int |  | ||||||
| layout_select(struct window *w, u_int layout) |  | ||||||
| { |  | ||||||
| 	if (layout > nitems(layouts) - 1 || layout == w->layout) |  | ||||||
| 		return (-1); |  | ||||||
| 	w->layout = layout; |  | ||||||
|  |  | ||||||
| 	layout_refresh(w, 0); |  | ||||||
| 	return (0); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| layout_next(struct window *w) | layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) | ||||||
| { | { | ||||||
| 	w->layout++; | 	struct layout_cell	*lcchild; | ||||||
| 	if (w->layout > nitems(layouts) - 1) |  | ||||||
| 		w->layout = 0; | 	log_debug( | ||||||
| 	layout_refresh(w, 0); | 	    "%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n, " ", lc, | ||||||
|  | 	    lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx, lc->sy); | ||||||
|  | 	switch (lc->type) { | ||||||
|  | 	case LAYOUT_LEFTRIGHT: | ||||||
|  | 	case LAYOUT_TOPBOTTOM: | ||||||
|  | 		TAILQ_FOREACH(lcchild, &lc->cells, entry) | ||||||
|  | 		    	layout_print_cell(lcchild, hdr, n + 1); | ||||||
|  | 		break; | ||||||
|  | 	case LAYOUT_WINDOWPANE: | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| layout_previous(struct window *w) | layout_set_size( | ||||||
|  |     struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, u_int yoff) | ||||||
| { | { | ||||||
| 	if (w->layout == 0) | 	lc->sx = sx; | ||||||
| 		w->layout = nitems(layouts) - 1; | 	lc->sy = sy; | ||||||
| 	else |  | ||||||
| 		w->layout--; | 	lc->xoff = xoff; | ||||||
| 	layout_refresh(w, 0); | 	lc->yoff = yoff; | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| layout_refresh(struct window *w, int active_only) | layout_make_leaf(struct layout_cell *lc, struct window_pane *wp) | ||||||
| { | { | ||||||
| 	layouts[w->layout].refresh(w, active_only); | 	lc->type = LAYOUT_WINDOWPANE; | ||||||
| 	server_redraw_window(w); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int | 	TAILQ_INIT(&lc->cells); | ||||||
| layout_resize(struct window_pane *wp, int adjust) |  | ||||||
| { |  | ||||||
| 	struct window	*w = wp->window; |  | ||||||
|  |  | ||||||
| 	if (layouts[w->layout].resize == NULL) | 	wp->layout_cell = lc; | ||||||
| 		return (-1); | 	lc->wp = wp; | ||||||
| 	layouts[w->layout].resize(wp, adjust); |  | ||||||
| 	return (0); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| layout_active_only_refresh(struct window *w, unused int active_only) | layout_make_node(struct layout_cell *lc, enum layout_type type) | ||||||
|  | { | ||||||
|  | 	if (type == LAYOUT_WINDOWPANE) | ||||||
|  | 		fatalx("bad layout type"); | ||||||
|  | 	lc->type = type; | ||||||
|  |  | ||||||
|  | 	TAILQ_INIT(&lc->cells); | ||||||
|  |  | ||||||
|  | 	if (lc->wp != NULL) | ||||||
|  | 		lc->wp->layout_cell = NULL; | ||||||
|  | 	lc->wp = NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Fix cell offsets based on their sizes. */ | ||||||
|  | void | ||||||
|  | layout_fix_offsets(struct layout_cell *lc) | ||||||
|  | { | ||||||
|  | 	struct layout_cell	*lcchild; | ||||||
|  | 	u_int			 xoff, yoff; | ||||||
|  |  | ||||||
|  | 	if (lc->type == LAYOUT_LEFTRIGHT) { | ||||||
|  | 		xoff = lc->xoff; | ||||||
|  | 		TAILQ_FOREACH(lcchild, &lc->cells, entry) { | ||||||
|  | 			lcchild->xoff = xoff; | ||||||
|  | 			lcchild->yoff = lc->yoff; | ||||||
|  | 			if (lcchild->type != LAYOUT_WINDOWPANE) | ||||||
|  | 				layout_fix_offsets(lcchild); | ||||||
|  | 			xoff += lcchild->sx + 1; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		yoff = lc->yoff; | ||||||
|  | 		TAILQ_FOREACH(lcchild, &lc->cells, entry) { | ||||||
|  | 			lcchild->xoff = lc->xoff; | ||||||
|  | 			lcchild->yoff = yoff; | ||||||
|  | 			if (lcchild->type != LAYOUT_WINDOWPANE) | ||||||
|  | 				layout_fix_offsets(lcchild); | ||||||
|  | 			yoff += lcchild->sy + 1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Update pane offsets and sizes based on their cells. */ | ||||||
|  | void | ||||||
|  | layout_fix_panes(struct window *w, u_int wsx, u_int wsy) | ||||||
| { | { | ||||||
| 	struct window_pane	*wp; | 	struct window_pane	*wp; | ||||||
| 	u_int			 xoff; | 	struct layout_cell	*lc; | ||||||
|  | 	u_int			 sx, sy; | ||||||
|  |  | ||||||
| 	xoff = w->sx; |  | ||||||
| 	TAILQ_FOREACH(wp, &w->panes, entry) { | 	TAILQ_FOREACH(wp, &w->panes, entry) { | ||||||
| 		/* Put the active pane on screen and the rest to the right. */ | 		if ((lc = wp->layout_cell) == NULL) | ||||||
| 		if (wp == w->active) | 			continue; | ||||||
| 			wp->xoff = 0; | 		wp->xoff = lc->xoff; | ||||||
|  | 		wp->yoff = lc->yoff; | ||||||
|  |  | ||||||
|  | 		/* | ||||||
|  | 		 * Layout cells are limited by the smallest size of other cells | ||||||
|  | 		 * within the same row or column; if this isn't the case | ||||||
|  | 		 * resizing becomes difficult. | ||||||
|  | 		 * | ||||||
|  | 		 * However, panes do not have to take up their entire cell, so | ||||||
|  | 		 * they can be cropped to the window edge if the layout | ||||||
|  | 		 * overflows and they are partly visible. | ||||||
|  | 		 * | ||||||
|  | 		 * This stops cells being hidden unnecessarily. | ||||||
|  | 		 */ | ||||||
|  |  | ||||||
|  | 		/* | ||||||
|  | 		 * Work out the horizontal size. If the pane is actually | ||||||
|  | 		 * outside the window or the entire pane is already visible, | ||||||
|  | 		 * don't crop. | ||||||
|  | 		 */ | ||||||
|  | 		if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx) | ||||||
|  | 			sx = lc->sx; | ||||||
| 		else { | 		else { | ||||||
| 			wp->xoff = xoff; | 			sx = wsx - lc->xoff; | ||||||
| 			xoff += w->sx; | 			if (sx < 1) | ||||||
| 		} | 				sx = lc->sx; | ||||||
| 		wp->yoff = 0; |  | ||||||
| 		window_pane_resize(wp, w->sx, w->sy); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| layout_even_h_refresh(struct window *w, int active_only) |  | ||||||
| { |  | ||||||
| 	struct window_pane	*wp; |  | ||||||
| 	u_int			 i, n, width, xoff; |  | ||||||
|  |  | ||||||
| 	if (active_only) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	/* If the screen is too small, show active only. */ |  | ||||||
| 	if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) { |  | ||||||
| 		layout_active_only_refresh(w, active_only); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Get number of panes. */ |  | ||||||
| 	n = window_count_panes(w); |  | ||||||
| 	if (n == 0) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	/* How many can we fit? */ |  | ||||||
| 	if (w->sx / n < PANE_MINIMUM) { |  | ||||||
| 		width = PANE_MINIMUM; |  | ||||||
| 		n = UINT_MAX; |  | ||||||
| 	} else |  | ||||||
| 		width = w->sx / n; |  | ||||||
|  |  | ||||||
| 	/* Fit the panes. */ |  | ||||||
| 	i = xoff = 0; |  | ||||||
| 	TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 		wp->xoff = xoff; |  | ||||||
| 		wp->yoff = 0; |  | ||||||
| 		if (i != n - 1) |  | ||||||
|  			window_pane_resize(wp, width - 1, w->sy); |  | ||||||
| 		else |  | ||||||
|  			window_pane_resize(wp, width, w->sy); |  | ||||||
|  |  | ||||||
| 		i++; |  | ||||||
| 		xoff += width; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Any space left? */ |  | ||||||
| 	while (xoff++ < w->sx) { |  | ||||||
| 		wp = TAILQ_LAST(&w->panes, window_panes); |  | ||||||
| 		window_pane_resize(wp, wp->sx + 1, wp->sy); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| layout_even_v_refresh(struct window *w, int active_only) |  | ||||||
| { |  | ||||||
| 	struct window_pane	*wp; |  | ||||||
| 	u_int			 i, n, height, yoff; |  | ||||||
|  |  | ||||||
| 	if (active_only) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	/* If the screen is too small, show active only. */ |  | ||||||
| 	if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) { |  | ||||||
| 		layout_active_only_refresh(w, active_only); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Get number of panes. */ |  | ||||||
| 	n = window_count_panes(w); |  | ||||||
| 	if (n == 0) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	/* How many can we fit? */ |  | ||||||
| 	if (w->sy / n < PANE_MINIMUM) { |  | ||||||
| 		height = PANE_MINIMUM; |  | ||||||
| 		n = UINT_MAX; |  | ||||||
| 	} else |  | ||||||
| 		height = w->sy / n; |  | ||||||
|  |  | ||||||
| 	/* Fit the panes. */ |  | ||||||
| 	i = yoff = 0; |  | ||||||
| 	TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 		wp->xoff = 0; |  | ||||||
| 		wp->yoff = yoff; |  | ||||||
| 		if (i != n - 1) |  | ||||||
|  			window_pane_resize(wp, w->sx, height - 1); |  | ||||||
| 		else |  | ||||||
|  			window_pane_resize(wp, w->sx, height); |  | ||||||
|  |  | ||||||
| 		i++; |  | ||||||
| 		yoff += height; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Any space left? */ |  | ||||||
| 	while (yoff++ < w->sy) { |  | ||||||
| 		wp = TAILQ_LAST(&w->panes, window_panes); |  | ||||||
| 		window_pane_resize(wp, wp->sx, wp->sy + 1); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| layout_main_v_refresh(struct window *w, int active_only) |  | ||||||
| { |  | ||||||
| 	struct window_pane	*wp; |  | ||||||
| 	u_int			 i, n, mainwidth, height, yoff; |  | ||||||
|  |  | ||||||
| 	if (active_only) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	/* Get number of panes. */ |  | ||||||
| 	n = window_count_panes(w); |  | ||||||
| 	if (n == 0) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	/* Get the main pane width and add one for separator line. */ |  | ||||||
| 	mainwidth = options_get_number(&w->options, "main-pane-width") + 1; |  | ||||||
|  |  | ||||||
| 	/* Need >1 pane and minimum columns; if fewer, display active only. */ |  | ||||||
| 	if (n == 1 || |  | ||||||
| 	    w->sx < mainwidth + PANE_MINIMUM || w->sy < PANE_MINIMUM) { |  | ||||||
| 		layout_active_only_refresh(w, active_only); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	n--; |  | ||||||
|  |  | ||||||
| 	/* How many can we fit, not including first? */ |  | ||||||
| 	if (w->sy / n < PANE_MINIMUM) { |  | ||||||
| 		height = PANE_MINIMUM; |  | ||||||
| 		n = w->sy / PANE_MINIMUM; |  | ||||||
| 	} else |  | ||||||
| 		height = w->sy / n; |  | ||||||
|  |  | ||||||
| 	/* Fit the panes. */ |  | ||||||
| 	i = yoff = 0; |  | ||||||
| 	TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 		if (wp == TAILQ_FIRST(&w->panes)) { |  | ||||||
| 			wp->xoff = 0; |  | ||||||
| 			wp->yoff = 0; |  | ||||||
| 			window_pane_resize(wp, mainwidth - 1, w->sy); |  | ||||||
| 			continue; |  | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		wp->xoff = mainwidth; | 		/*  | ||||||
| 		wp->yoff = yoff; | 		 * Similarly for the vertical size; the minimum vertical size | ||||||
| 		if (i != n - 1) | 		 * is two because scroll regions cannot be one line. | ||||||
|  			window_pane_resize(wp, w->sx - mainwidth, height - 1); | 		 */ | ||||||
| 		else | 		if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy) | ||||||
|  			window_pane_resize(wp, w->sx - mainwidth, height); | 			sy = lc->sy; | ||||||
|  | 		else { | ||||||
|  | 			sy = wsy - lc->yoff; | ||||||
|  | 			if (sy < 2) | ||||||
|  | 				sy = lc->sy; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		i++; | 		window_pane_resize(wp, sx, sy); | ||||||
| 		yoff += height; | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Calculate how much size is available to be removed from a cell. */ | ||||||
|  | u_int | ||||||
|  | layout_resize_check(struct layout_cell *lc, enum layout_type type) | ||||||
|  | { | ||||||
|  | 	struct layout_cell	*lcchild; | ||||||
|  | 	u_int			 available, minimum; | ||||||
|  |  | ||||||
|  | 	if (lc->type == LAYOUT_WINDOWPANE) { | ||||||
|  | 		/* Space available in this cell only. */ | ||||||
|  | 		if (type == LAYOUT_LEFTRIGHT) | ||||||
|  | 			available = lc->sx; | ||||||
|  | 		else | ||||||
|  | 			available = lc->sy; | ||||||
|  | 		 | ||||||
|  | 		if (available > PANE_MINIMUM) | ||||||
|  | 			available -= PANE_MINIMUM; | ||||||
|  | 		else | ||||||
|  | 			available = 0; | ||||||
|  | 	} else if (lc->type == type) { | ||||||
|  | 		/* Same type: total of available space in all child cells. */ | ||||||
|  | 		available = 0; | ||||||
|  | 		TAILQ_FOREACH(lcchild, &lc->cells, entry) | ||||||
|  | 			available += layout_resize_check(lcchild, type); | ||||||
|  | 	} else { | ||||||
|  | 		/* Different type: minimum of available space in child cells. */ | ||||||
|  | 		minimum = UINT_MAX; | ||||||
|  | 		TAILQ_FOREACH(lcchild, &lc->cells, entry) { | ||||||
|  | 			available = layout_resize_check(lcchild, type); | ||||||
|  | 			if (available < minimum) | ||||||
|  | 				minimum = available; | ||||||
|  | 		} | ||||||
|  | 		available = minimum; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Any space left? */ | 	return (available); | ||||||
| 	while (yoff++ < w->sy) { | } | ||||||
| 		wp = TAILQ_LAST(&w->panes, window_panes); |  | ||||||
| 		while (wp != NULL && wp == TAILQ_FIRST(&w->panes)) | /* | ||||||
| 			wp = TAILQ_PREV(wp, window_panes, entry); |  * Adjust cell size evenly, including altering its children. This function | ||||||
| 		if (wp == NULL) |  * expects the change to have already been bounded to the space available. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change) | ||||||
|  | { | ||||||
|  | 	struct layout_cell	*lcchild; | ||||||
|  |  | ||||||
|  | 	/* Adjust the cell size. */ | ||||||
|  | 	if (type == LAYOUT_LEFTRIGHT) | ||||||
|  | 		lc->sx += change; | ||||||
|  | 	else | ||||||
|  | 		lc->sy += change; | ||||||
|  | 	 | ||||||
|  | 	/* If this is a leaf cell, that is all that is necessary. */ | ||||||
|  | 	if (type == LAYOUT_WINDOWPANE) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	/* Child cell runs in a different direction. */ | ||||||
|  | 	if (lc->type != type) { | ||||||
|  | 		TAILQ_FOREACH(lcchild, &lc->cells, entry) | ||||||
|  | 			layout_resize_adjust(lcchild, type, change); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/*  | ||||||
|  | 	 * Child cell runs in the same direction. Adjust each child equally  | ||||||
|  | 	 * until no further change is possible. | ||||||
|  | 	 */ | ||||||
|  | 	while (change != 0) { | ||||||
|  | 		TAILQ_FOREACH(lcchild, &lc->cells, entry) { | ||||||
|  | 			if (change == 0) | ||||||
|  | 				break; | ||||||
|  | 			if (change > 0) { | ||||||
|  | 				layout_resize_adjust(lcchild, type, 1); | ||||||
|  | 				change--; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (layout_resize_check(lcchild, type) > 0) { | ||||||
|  | 				layout_resize_adjust(lcchild, type, -1); | ||||||
|  | 				change++; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | layout_init(struct window *w) | ||||||
|  | { | ||||||
|  | 	struct layout_cell	*lc; | ||||||
|  |  | ||||||
|  | 	lc = w->layout_root = layout_create_cell(NULL); | ||||||
|  | 	layout_set_size(lc, w->sx, w->sy, 0, 0); | ||||||
|  | 	layout_make_leaf(lc, TAILQ_FIRST(&w->panes)); | ||||||
|  |  | ||||||
|  | 	layout_fix_panes(w, w->sx, w->sy); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | layout_free(struct window *w) | ||||||
|  | { | ||||||
|  | 	layout_free_cell(w->layout_root); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Resize the entire layout after window resize. */ | ||||||
|  | void | ||||||
|  | layout_resize(struct window *w, u_int sx, u_int sy) | ||||||
|  | { | ||||||
|  | 	struct layout_cell	*lc = w->layout_root; | ||||||
|  | 	int			 xlimit, ylimit, xchange, ychange; | ||||||
|  |  | ||||||
|  | 	/*  | ||||||
|  | 	 * Adjust horizontally. Do not attempt to reduce the layout lower than | ||||||
|  | 	 * the minimum (more than the amount returned by layout_resize_check). | ||||||
|  | 	 *  | ||||||
|  | 	 * This can mean that the window size is smaller than the total layout | ||||||
|  | 	 * size: redrawing this is handled at a higher level, but it does leave | ||||||
|  | 	 * a problem with growing the window size here: if the current size is | ||||||
|  | 	 * < the minimum, growing proportionately by adding to each pane is | ||||||
|  | 	 * wrong as it would keep the layout size larger than the window size. | ||||||
|  | 	 * Instead, spread the difference between the minimum and the new size | ||||||
|  | 	 * out proportionately - this should leave the layout fitting the new | ||||||
|  | 	 * window size. | ||||||
|  | 	 */ | ||||||
|  | 	xchange = sx - w->sx; | ||||||
|  | 	xlimit = layout_resize_check(lc, LAYOUT_LEFTRIGHT); | ||||||
|  | 	if (xchange < 0 && xchange < -xlimit) | ||||||
|  | 		xchange = -xlimit; | ||||||
|  | 	if (xlimit == 0) { | ||||||
|  | 		if (sx <= lc->sx)	/* lc->sx is minimum possible */ | ||||||
|  | 			xchange = 0; | ||||||
|  | 		else | ||||||
|  | 			xchange = sx - lc->sx; | ||||||
|  | 	} | ||||||
|  | 	if (xchange != 0) | ||||||
|  | 		layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, xchange); | ||||||
|  |  | ||||||
|  | 	/* Adjust vertically in a similar fashion. */ | ||||||
|  | 	ychange = sy - w->sy; | ||||||
|  | 	ylimit = layout_resize_check(lc, LAYOUT_TOPBOTTOM); | ||||||
|  | 	if (ychange < 0 && ychange < -ylimit) | ||||||
|  | 		ychange = -ylimit; | ||||||
|  | 	if (ylimit == 0) { | ||||||
|  | 		if (sy <= lc->sy)	/* lc->sy is minimum possible */ | ||||||
|  | 			ychange = 0; | ||||||
|  | 		else | ||||||
|  | 			ychange = sy - lc->sy; | ||||||
|  | 	} | ||||||
|  | 	if (ychange != 0) | ||||||
|  | 		layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange); | ||||||
|  | 	 | ||||||
|  | 	/* Fix cell offsets. */ | ||||||
|  | 	layout_fix_offsets(lc); | ||||||
|  | 	layout_fix_panes(w, sx, sy); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Resize a single pane within the layout. */ | ||||||
|  | void | ||||||
|  | layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) | ||||||
|  | { | ||||||
|  | 	struct layout_cell     *lc, *lcparent; | ||||||
|  | 	int			needed, size; | ||||||
|  |  | ||||||
|  | 	lc = wp->layout_cell; | ||||||
|  |  | ||||||
|  | 	/* Find next parent of the same type. */ | ||||||
|  | 	lcparent = lc->parent; | ||||||
|  | 	while (lcparent != NULL && lcparent->type != type) { | ||||||
|  | 		lc = lcparent; | ||||||
|  | 		lcparent = lc->parent; | ||||||
|  | 	} | ||||||
|  | 	if (lcparent == NULL) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	/* If this is the last cell, move back one. */ | ||||||
|  | 	if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)) | ||||||
|  | 		lc = TAILQ_PREV(lc, layout_cells, entry); | ||||||
|  |  | ||||||
|  | 	/* Grow or shrink the cell. */ | ||||||
|  | 	needed = change; | ||||||
|  | 	while (needed != 0) { | ||||||
|  | 		if (change > 0) { | ||||||
|  | 			size = layout_resize_pane_grow(lc, type, needed); | ||||||
|  | 			needed -= size; | ||||||
|  | 		} else { | ||||||
|  | 			size = layout_resize_pane_shrink(lc, type, needed); | ||||||
|  | 			needed += size; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (size == 0)	/* no more change possible */ | ||||||
| 			break; | 			break; | ||||||
| 		window_pane_resize(wp, wp->sx, wp->sy + 1); |  | ||||||
| 	} | 	} | ||||||
|  | 	 | ||||||
|  | 	/* Fix cell offsets. */ | ||||||
|  | 	layout_fix_offsets(wp->window->layout_root); | ||||||
|  | 	layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | int | ||||||
| layout_main_h_refresh(struct window *w, int active_only) | layout_resize_pane_grow( | ||||||
|  |     struct layout_cell *lc, enum layout_type type, int needed) | ||||||
| { | { | ||||||
| 	struct window_pane	*wp; | 	struct layout_cell	*lcadd, *lcremove; | ||||||
| 	u_int			 i, n, mainheight, width, xoff; | 	u_int			 size; | ||||||
|  |  | ||||||
| 	if (active_only) | 	/* Growing. Always add to the current cell. */ | ||||||
| 		return; | 	lcadd = lc; | ||||||
| 			 | 			 | ||||||
| 	/* Get number of panes. */ | 	/* Look towards the tail for a suitable cell for reduction. */ | ||||||
| 	n = window_count_panes(w); | 	lcremove = TAILQ_NEXT(lc, entry); | ||||||
| 	if (n == 0) | 	while (lcremove != NULL) { | ||||||
| 		return; | 		size = layout_resize_check(lcremove, type); | ||||||
|  | 		if (size > 0) | ||||||
| 	/* Get the main pane height and add one for separator line. */ |  | ||||||
| 	mainheight = options_get_number(&w->options, "main-pane-height") + 1; |  | ||||||
|  |  | ||||||
| 	/* Need >1 pane and minimum rows; if fewer, display active only. */ |  | ||||||
| 	if (n == 1 || |  | ||||||
| 	    w->sy < mainheight + PANE_MINIMUM || w->sx < PANE_MINIMUM) { |  | ||||||
| 		layout_active_only_refresh(w, active_only); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	n--; |  | ||||||
|  |  | ||||||
| 	/* How many can we fit, not including first? */ |  | ||||||
| 	if (w->sx / n < PANE_MINIMUM) { |  | ||||||
| 		width = PANE_MINIMUM; |  | ||||||
| 		n = w->sx / PANE_MINIMUM; |  | ||||||
| 	} else |  | ||||||
| 		width = w->sx / n; |  | ||||||
|  |  | ||||||
| 	/* Fit the panes. */ |  | ||||||
| 	i = xoff = 0; |  | ||||||
| 	TAILQ_FOREACH(wp, &w->panes, entry) { |  | ||||||
| 		if (wp == TAILQ_FIRST(&w->panes)) { |  | ||||||
| 			wp->xoff = 0; |  | ||||||
| 			wp->yoff = 0; |  | ||||||
| 			window_pane_resize(wp, w->sx, mainheight - 1); |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		wp->xoff = xoff; |  | ||||||
| 		wp->yoff = mainheight; |  | ||||||
| 		if (i != n - 1) |  | ||||||
|  			window_pane_resize(wp, width - 1, w->sy - mainheight); |  | ||||||
| 		else |  | ||||||
|  			window_pane_resize(wp, width - 1, w->sy - mainheight); |  | ||||||
|  |  | ||||||
| 		i++; |  | ||||||
| 		xoff += width; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Any space left? */ |  | ||||||
| 	while (xoff++ < w->sx + 1) { |  | ||||||
| 		wp = TAILQ_LAST(&w->panes, window_panes); |  | ||||||
| 		while (wp != NULL && wp == TAILQ_FIRST(&w->panes)) |  | ||||||
| 			wp = TAILQ_PREV(wp, window_panes, entry); |  | ||||||
| 		if (wp == NULL) |  | ||||||
| 			break; | 			break; | ||||||
| 		window_pane_resize(wp, wp->sx + 1, wp->sy); | 		lcremove = TAILQ_NEXT(lcremove, entry);	 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/* If none found, look towards the head. */ | ||||||
|  | 	if (lcremove == NULL) { | ||||||
|  | 		lcremove = TAILQ_PREV(lc, layout_cells, entry); | ||||||
|  | 		while (lcremove != NULL) { | ||||||
|  | 			size = layout_resize_check(lcremove, type); | ||||||
|  | 			if (size > 0) | ||||||
|  | 				break; | ||||||
|  | 			lcremove = TAILQ_PREV(lcremove, layout_cells, entry); | ||||||
|  | 		} | ||||||
|  | 		if (lcremove == NULL) | ||||||
|  | 			return (0); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Change the cells. */ | ||||||
|  | 	if (size > (u_int) needed) | ||||||
|  | 		size = needed; | ||||||
|  | 	layout_resize_adjust(lcadd, type, size); | ||||||
|  | 	layout_resize_adjust(lcremove, type, -size); | ||||||
|  | 	return (size); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | layout_resize_pane_shrink( | ||||||
|  |     struct layout_cell *lc, enum layout_type type, int needed) | ||||||
|  | { | ||||||
|  | 	struct layout_cell	*lcadd, *lcremove; | ||||||
|  | 	u_int			 size; | ||||||
|  |  | ||||||
|  | 	/* Shrinking. Find cell to remove from by walking towards head. */ | ||||||
|  | 	lcremove = lc; | ||||||
|  | 	do { | ||||||
|  | 		size = layout_resize_check(lcremove, type); | ||||||
|  | 		if (size != 0) | ||||||
|  | 			break; | ||||||
|  | 		lcremove = TAILQ_PREV(lcremove, layout_cells, entry); | ||||||
|  | 	} while (lcremove != NULL); | ||||||
|  | 	if (lcremove == NULL) | ||||||
|  | 		return (0); | ||||||
|  |  | ||||||
|  | 	/* And add onto the next cell (from the original cell). */ | ||||||
|  | 	lcadd = TAILQ_NEXT(lc, entry); | ||||||
|  | 	if (lcadd == NULL) | ||||||
|  | 		return (0); | ||||||
|  |  | ||||||
|  | 	/* Change the cells. */ | ||||||
|  | 	if (size > (u_int) -needed) | ||||||
|  | 		size = -needed; | ||||||
|  | 	layout_resize_adjust(lcadd, type, size); | ||||||
|  | 	layout_resize_adjust(lcremove, type, -size); | ||||||
|  | 	return (size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Split a pane into two. size is a hint, or -1 for default half/half split. */ | ||||||
|  | int | ||||||
|  | layout_split_pane(struct window_pane *wp, | ||||||
|  |     enum layout_type type, int size, struct window_pane *new_wp) | ||||||
|  | { | ||||||
|  | 	struct layout_cell     *lc, *lcparent, *lcnew; | ||||||
|  | 	u_int			sx, sy, xoff, yoff, size1, size2; | ||||||
|  |  | ||||||
|  | 	lc = wp->layout_cell; | ||||||
|  |  | ||||||
|  | 	/* Copy the old cell size. */ | ||||||
|  | 	sx = lc->sx; | ||||||
|  | 	sy = lc->sy; | ||||||
|  | 	xoff = lc->xoff; | ||||||
|  | 	yoff = lc->yoff; | ||||||
|  |  | ||||||
|  | 	/* Check there is enough space for the two new panes. */ | ||||||
|  | 	switch (type) { | ||||||
|  | 	case LAYOUT_LEFTRIGHT: | ||||||
|  | 		if (sx < PANE_MINIMUM * 2 + 1) | ||||||
|  | 			return (-1); | ||||||
|  | 		break; | ||||||
|  | 	case LAYOUT_TOPBOTTOM: | ||||||
|  | 		if (sy < PANE_MINIMUM * 2 + 1) | ||||||
|  | 			return (-1); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		fatalx("bad layout type"); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (lc->parent != NULL && lc->parent->type == type) { | ||||||
|  | 		/* | ||||||
|  | 		 * If the parent exists and is of the same type as the split, | ||||||
|  | 		 * create a new cell and insert it after this one. | ||||||
|  | 		 */ | ||||||
|  |  | ||||||
|  | 		/* Create the new child cell. */ | ||||||
|  | 		lcnew = layout_create_cell(lc->parent); | ||||||
|  | 		TAILQ_INSERT_AFTER(&lc->parent->cells, lc, lcnew, entry); | ||||||
|  | 	} else { | ||||||
|  | 		/* | ||||||
|  | 		 * Otherwise create a new parent and insert it. | ||||||
|  | 		 */ | ||||||
|  | 		 | ||||||
|  | 		/* Create and insert the replacement parent. */ | ||||||
|  | 		lcparent = layout_create_cell(lc->parent); | ||||||
|  | 		layout_make_node(lcparent, type); | ||||||
|  | 		layout_set_size(lcparent, sx, sy, xoff, yoff); | ||||||
|  | 		if (lc->parent == NULL) | ||||||
|  | 			wp->window->layout_root = lcparent; | ||||||
|  | 		else | ||||||
|  | 			TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry); | ||||||
|  | 		 | ||||||
|  | 		/* Insert the old cell. */ | ||||||
|  | 		lc->parent = lcparent; | ||||||
|  | 		TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry); | ||||||
|  | 		 | ||||||
|  | 		/* Create the new child cell. */ | ||||||
|  | 		lcnew = layout_create_cell(lcparent); | ||||||
|  | 		TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Set new cell sizes.  size is the target size or -1 for middle split, | ||||||
|  | 	 * size1 is the size of the top/left and size2 the bottom/right. | ||||||
|  | 	 */ | ||||||
|  | 	switch (type) { | ||||||
|  | 	case LAYOUT_LEFTRIGHT: | ||||||
|  | 		if (size < 0) | ||||||
|  | 			size2 = ((sx + 1) / 2) - 1; | ||||||
|  |  		else | ||||||
|  | 			size2 = size; | ||||||
|  | 		if (size2 < PANE_MINIMUM) | ||||||
|  | 			size2 = PANE_MINIMUM; | ||||||
|  | 		else if (size2 > sx - 2) | ||||||
|  | 			size2 = sx - 2; | ||||||
|  | 		size1 = sx - 1 - size2; | ||||||
|  | 		layout_set_size(lc, size1, sy, xoff, yoff); | ||||||
|  | 		layout_set_size(lcnew, size2, sy, xoff + lc->sx + 1, yoff); | ||||||
|  | 		break; | ||||||
|  | 	case LAYOUT_TOPBOTTOM: | ||||||
|  | 		if (size < 0) | ||||||
|  | 			size2 = ((sy + 1) / 2) - 1; | ||||||
|  | 		else | ||||||
|  | 			size2 = size; | ||||||
|  | 		if (size2 < PANE_MINIMUM) | ||||||
|  | 			size2 = PANE_MINIMUM; | ||||||
|  | 		else if (size2 > sy - 2) | ||||||
|  | 			size2 = sy - 2; | ||||||
|  | 		size1 = sy - 1 - size2; | ||||||
|  | 		layout_set_size(lc, sx, size1, xoff, yoff); | ||||||
|  | 		layout_set_size(lcnew, sx, size2, xoff, yoff + lc->sy + 1); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		fatalx("bad layout type"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Assign the panes. */ | ||||||
|  | 	layout_make_leaf(lc, wp); | ||||||
|  | 	layout_make_leaf(lcnew, new_wp); | ||||||
|  |  | ||||||
|  | 	/* Fix pane offsets and sizes. */ | ||||||
|  | 	layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); | ||||||
|  |  | ||||||
|  | 	return (0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Destroy the layout associated with a pane and redistribute the space. */ | ||||||
|  | void | ||||||
|  | layout_close_pane(struct window_pane *wp) | ||||||
|  | { | ||||||
|  | 	struct layout_cell     *lc, *lcother, *lcparent; | ||||||
|  |  | ||||||
|  | 	lc = wp->layout_cell; | ||||||
|  | 	lcparent = lc->parent; | ||||||
|  |  | ||||||
|  | 	/*  | ||||||
|  | 	 * If no parent, this is the last pane so window close is imminent and | ||||||
|  | 	 * there is no need to resize anything. | ||||||
|  | 	 */ | ||||||
|  | 	if (lcparent == NULL) { | ||||||
|  | 		layout_free_cell(lc); | ||||||
|  | 		wp->window->layout_root = NULL; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Merge the space into the previous or next cell. */ | ||||||
|  | 	if (lc == TAILQ_FIRST(&lcparent->cells)) | ||||||
|  | 		lcother = TAILQ_NEXT(lc, entry); | ||||||
|  | 	else | ||||||
|  | 		lcother = TAILQ_PREV(lc, layout_cells, entry); | ||||||
|  | 	if (lcparent->type == LAYOUT_LEFTRIGHT) | ||||||
|  | 		layout_resize_adjust(lcother, lcparent->type, lc->sx + 1); | ||||||
|  | 	else | ||||||
|  | 		layout_resize_adjust(lcother, lcparent->type, lc->sy + 1); | ||||||
|  |  | ||||||
|  | 	/* Remove this from the parent's list. */ | ||||||
|  | 	TAILQ_REMOVE(&lcparent->cells, lc, entry); | ||||||
|  | 	layout_free_cell(lc); | ||||||
|  | 	 | ||||||
|  | 	/*  | ||||||
|  | 	 * If the parent now has one cell, remove the parent from the tree and | ||||||
|  | 	 * replace it by that cell. | ||||||
|  | 	 */ | ||||||
|  | 	lc = TAILQ_FIRST(&lcparent->cells); | ||||||
|  | 	if (TAILQ_NEXT(lc, entry) == NULL) { | ||||||
|  | 		TAILQ_REMOVE(&lcparent->cells, lc, entry); | ||||||
|  |  | ||||||
|  | 		lc->parent = lcparent->parent; | ||||||
|  | 		if (lc->parent == NULL) { | ||||||
|  | 			lc->xoff = 0; lc->yoff = 0; | ||||||
|  | 			wp->window->layout_root = lc; | ||||||
|  | 		} else | ||||||
|  | 			TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); | ||||||
|  |  | ||||||
|  | 		layout_free_cell(lcparent); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Fix pane offsets and sizes. */ | ||||||
|  | 	layout_fix_offsets(wp->window->layout_root); | ||||||
|  | 	layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								resize.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								resize.c
									
									
									
									
									
								
							| @@ -132,6 +132,7 @@ recalculate_sizes(void) | |||||||
| 		log_debug( | 		log_debug( | ||||||
| 		    "window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); | 		    "window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); | ||||||
|  |  | ||||||
|  | 		layout_resize(w, ssx, ssy); | ||||||
| 		window_resize(w, ssx, ssy); | 		window_resize(w, ssx, ssy); | ||||||
|  |  | ||||||
| 		/* | 		/* | ||||||
| @@ -148,6 +149,5 @@ recalculate_sizes(void) | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		server_redraw_window(w); | 		server_redraw_window(w); | ||||||
| 		layout_refresh(w, 0); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								server.c
									
									
									
									
									
								
							| @@ -840,7 +840,9 @@ server_handle_client(struct client *c) | |||||||
|  |  | ||||||
| 	/* Ensure cursor position and mode settings. */ | 	/* Ensure cursor position and mode settings. */ | ||||||
| 	status = options_get_number(&c->session->options, "status"); | 	status = options_get_number(&c->session->options, "status"); | ||||||
| 	if (wp->yoff + s->cy < c->tty.sy - status) | 	if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) | ||||||
|  | 		tty_cursor(&c->tty, 0, 0, 0, 0); | ||||||
|  | 	else | ||||||
| 		tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); | 		tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); | ||||||
|  |  | ||||||
| 	mode = s->mode; | 	mode = s->mode; | ||||||
| @@ -1072,9 +1074,9 @@ server_check_window(struct window *w) | |||||||
| 		 * pane dies). | 		 * pane dies). | ||||||
| 		 */ | 		 */ | ||||||
| 		if (wp->fd == -1 && !flag) { | 		if (wp->fd == -1 && !flag) { | ||||||
|  | 			layout_close_pane(wp); | ||||||
| 			window_remove_pane(w, wp); | 			window_remove_pane(w, wp); | ||||||
| 			server_redraw_window(w); | 			server_redraw_window(w); | ||||||
| 			layout_refresh(w, 0); |  | ||||||
| 		} else  | 		} else  | ||||||
| 			destroyed = 0; | 			destroyed = 0; | ||||||
| 		wp = wq; | 		wp = wq; | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -393,15 +393,17 @@ each pane takes up a certain area of the display and is a separate terminal. | |||||||
| A window may be split into panes using the | A window may be split into panes using the | ||||||
| .Ic split-window | .Ic split-window | ||||||
| command. | command. | ||||||
| .Pp | Windows may be split horizontally (with the | ||||||
| Panes are numbered beginning from zero; in horizontal layouts zero is the | .Fl h | ||||||
| leftmost pane and in vertical the topmost. | flag) or vertically. | ||||||
| .Pp | Panes may be resized with the | ||||||
| Panes may be arranged using several layouts. | .Ic resize-pane | ||||||
| The layout may be cycled with the |  | ||||||
| .Ic next-layout |  | ||||||
| command (bound to | command (bound to | ||||||
| .Ql C-space | .Ql C-up , | ||||||
|  | .Ql C-down | ||||||
|  | .Ql C-left | ||||||
|  | and | ||||||
|  | .Ql C-right | ||||||
| by default), the current pane may be changed with the | by default), the current pane may be changed with the | ||||||
| .Ic up-pane | .Ic up-pane | ||||||
| and | and | ||||||
| @@ -410,12 +412,22 @@ commands and the | |||||||
| .Ic rotate-window | .Ic rotate-window | ||||||
| and | and | ||||||
| .Ic swap-pane | .Ic swap-pane | ||||||
| commands may be used to swap panes without changing the window layout. | commands may be used to swap panes without changing their position. | ||||||
|  | Panes are numbered beginning from zero in the order they are created. | ||||||
|  | .Pp | ||||||
|  | A number of preset | ||||||
|  | .Em layouts | ||||||
|  | are available. | ||||||
|  | These may be selected with the | ||||||
|  | .Ic select-layout | ||||||
|  | command or cycled with | ||||||
|  | .Ic next-layout | ||||||
|  | (bound to | ||||||
|  | .Ql C-space | ||||||
|  | by default); once a layout is chosen, panes within it may be moved and resized as normal. | ||||||
| .Pp | .Pp | ||||||
| The following layouts are supported: | The following layouts are supported: | ||||||
| .Bl -tag -width Ds | .Bl -tag -width Ds | ||||||
| .It Ic active-only |  | ||||||
| Only the active pane is shown \(en all other panes are hidden. |  | ||||||
| .It Ic even-horizontal | .It Ic even-horizontal | ||||||
| Panes are spread out evenly from left to right across the window. | Panes are spread out evenly from left to right across the window. | ||||||
| .It Ic even-vertical | .It Ic even-vertical | ||||||
| @@ -434,11 +446,6 @@ bottom along the right. | |||||||
| See the | See the | ||||||
| .Em main-pane-width | .Em main-pane-width | ||||||
| window option. | window option. | ||||||
| .It Ic manual |  | ||||||
| Manual layout splits windows vertically (running across); only with this layout |  | ||||||
| may panes be resized using the |  | ||||||
| .Ic resize-pane |  | ||||||
| command. |  | ||||||
| .El | .El | ||||||
| .Sh STATUS LINE | .Sh STATUS LINE | ||||||
| .Nm | .Nm | ||||||
| @@ -980,7 +987,7 @@ Rename the current window, or the window at | |||||||
| if specified, to | if specified, to | ||||||
| .Ar new-name . | .Ar new-name . | ||||||
| .It Xo Ic resize-pane | .It Xo Ic resize-pane | ||||||
| .Op Fl DU | .Op Fl DLUR | ||||||
| .Op Fl p Ar pane-index | .Op Fl p Ar pane-index | ||||||
| .Op Fl t Ar target-window | .Op Fl t Ar target-window | ||||||
| .Op Ar adjustment | .Op Ar adjustment | ||||||
| @@ -988,11 +995,15 @@ if specified, to | |||||||
| .D1 (alias: Ic resizep ) | .D1 (alias: Ic resizep ) | ||||||
| Resize a pane, upward with | Resize a pane, upward with | ||||||
| .Fl U | .Fl U | ||||||
| (the default) or downward with | (the default), downward with | ||||||
| .Fl D . | .Fl D , | ||||||
|  | to the left with | ||||||
|  | .Fl L | ||||||
|  | and to the right with | ||||||
|  | .Fl R. | ||||||
| The | The | ||||||
| .Ar adjustment | .Ar adjustment | ||||||
| is given in lines (the default is 1). | is given in lines or cells (the default is 1). | ||||||
| .It Xo Ic respawn-window | .It Xo Ic respawn-window | ||||||
| .Op Fl k | .Op Fl k | ||||||
| .Op Fl t Ar target-window | .Op Fl t Ar target-window | ||||||
| @@ -1520,38 +1531,30 @@ is used. | |||||||
| Execute commands from | Execute commands from | ||||||
| .Ar path . | .Ar path . | ||||||
| .It Xo Ic split-window | .It Xo Ic split-window | ||||||
| .Op Fl d | .Op Fl dhv | ||||||
| .Oo Fl l | .Oo Fl l | ||||||
| .Ar lines | | .Ar size | | ||||||
| .Fl p Ar percentage Oc | .Fl p Ar percentage Oc | ||||||
| .Op Fl t Ar target-window | .Op Fl t Ar target-window | ||||||
| .Op Ar command | .Op Ar command | ||||||
| .Xc | .Xc | ||||||
| .D1 (alias: splitw ) | .D1 (alias: splitw ) | ||||||
| Creates a new window by splitting it vertically. | Creates a new pane by splitting the active pane: | ||||||
|  | .Fl h | ||||||
|  | does a horizontal split and | ||||||
|  | .Fl v | ||||||
|  | a vertical split; if neither is specified, | ||||||
|  | .Fl v | ||||||
|  | is assumed. | ||||||
| The | The | ||||||
| .Fl l | .Fl l | ||||||
| and | and | ||||||
| .Fl p | .Fl p | ||||||
| options specify the size of the new window in lines, or as a percentage, | options specify the size of the new window in lines (for vertical split) or in | ||||||
| respectively. | cells (for horizontal split), or as a percentage, respectively. | ||||||
| All other options have the same meaning as in the | All other options have the same meaning as in the | ||||||
| .Ic new-window | .Ic new-window | ||||||
| command. | command. | ||||||
| .Pp |  | ||||||
| A few notes with regard to panes: |  | ||||||
| .Bl -enum -compact |  | ||||||
| .It |  | ||||||
| If attempting to split a window with less than eight lines, an error will be |  | ||||||
| shown. |  | ||||||
| .It |  | ||||||
| If the window is resized, as many panes are shown as can fit without reducing |  | ||||||
| them below four lines. |  | ||||||
| .It |  | ||||||
| The minimum pane size is four lines (including the separator line). |  | ||||||
| .It |  | ||||||
| The panes are indexed from top (0) to bottom, with no numbers skipped. |  | ||||||
| .El |  | ||||||
| .It Xo Ic start-server | .It Xo Ic start-server | ||||||
| .Xc | .Xc | ||||||
| .D1 (alias: Ic start ) | .D1 (alias: Ic start ) | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -47,8 +47,11 @@ extern const char    *__progname; | |||||||
| /* Default prompt history length. */ | /* Default prompt history length. */ | ||||||
| #define PROMPT_HISTORY 100 | #define PROMPT_HISTORY 100 | ||||||
|  |  | ||||||
| /* Minimum pane size. */ | /*  | ||||||
| #define PANE_MINIMUM 5	/* includes separator line */ |  * Minimum layout cell size, NOT including separator line. The scroll region | ||||||
|  |  * cannot be one line in height so this must be at least two. | ||||||
|  |  */ | ||||||
|  | #define PANE_MINIMUM 2 | ||||||
|  |  | ||||||
| /* Automatic name refresh interval, in milliseconds. */ | /* Automatic name refresh interval, in milliseconds. */ | ||||||
| #define NAME_INTERVAL 500 | #define NAME_INTERVAL 500 | ||||||
| @@ -592,6 +595,7 @@ struct window_mode { | |||||||
| /* Child window structure. */ | /* Child window structure. */ | ||||||
| struct window_pane { | struct window_pane { | ||||||
| 	struct window	*window; | 	struct window	*window; | ||||||
|  | 	struct layout_cell *layout_cell; | ||||||
|  |  | ||||||
| 	u_int		 sx; | 	u_int		 sx; | ||||||
| 	u_int		 sy; | 	u_int		 sy; | ||||||
| @@ -635,7 +639,9 @@ struct window { | |||||||
|  |  | ||||||
| 	struct window_pane *active; | 	struct window_pane *active; | ||||||
| 	struct window_panes panes; | 	struct window_panes panes; | ||||||
|  |  | ||||||
| 	u_int		 layout; | 	u_int		 layout; | ||||||
|  | 	struct layout_cell *layout_root; | ||||||
|  |  | ||||||
| 	u_int		 sx; | 	u_int		 sx; | ||||||
| 	u_int		 sy; | 	u_int		 sy; | ||||||
| @@ -664,6 +670,34 @@ struct winlink { | |||||||
| RB_HEAD(winlinks, winlink); | RB_HEAD(winlinks, winlink); | ||||||
| SLIST_HEAD(winlink_stack, winlink); | SLIST_HEAD(winlink_stack, winlink); | ||||||
|  |  | ||||||
|  | /* Layout direction. */ | ||||||
|  | enum layout_type { | ||||||
|  | 	LAYOUT_LEFTRIGHT, | ||||||
|  | 	LAYOUT_TOPBOTTOM, | ||||||
|  | 	LAYOUT_WINDOWPANE | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* Layout cells queue. */ | ||||||
|  | TAILQ_HEAD(layout_cells, layout_cell); | ||||||
|  |  | ||||||
|  | /* Layout cell. */ | ||||||
|  | struct layout_cell { | ||||||
|  | 	enum layout_type type; | ||||||
|  |  | ||||||
|  | 	struct layout_cell *parent; | ||||||
|  |  | ||||||
|  | 	u_int		 sx; | ||||||
|  | 	u_int		 sy; | ||||||
|  |  | ||||||
|  | 	u_int		 xoff; | ||||||
|  | 	u_int		 yoff; | ||||||
|  |  | ||||||
|  | 	struct window_pane *wp; | ||||||
|  | 	struct layout_cells cells; | ||||||
|  |  | ||||||
|  | 	TAILQ_ENTRY(layout_cell) entry; | ||||||
|  | }; | ||||||
|  |  | ||||||
| /* Paste buffer. */ | /* Paste buffer. */ | ||||||
| struct paste_buffer { | struct paste_buffer { | ||||||
|      	char		*data; |      	char		*data; | ||||||
| @@ -1446,8 +1480,7 @@ struct window	*window_create(const char *, const char *, | |||||||
| void		 window_destroy(struct window *); | void		 window_destroy(struct window *); | ||||||
| int		 window_resize(struct window *, u_int, u_int); | int		 window_resize(struct window *, u_int, u_int); | ||||||
| void		 window_set_active_pane(struct window *, struct window_pane *); | void		 window_set_active_pane(struct window *, struct window_pane *); | ||||||
| struct window_pane *window_add_pane(struct window *, int, | struct window_pane *window_add_pane(struct window *, u_int, char **); | ||||||
| 		     const char *, const char *, const char **, u_int, char **); |  | ||||||
| void		 window_remove_pane(struct window *, struct window_pane *); | void		 window_remove_pane(struct window *, struct window_pane *); | ||||||
| struct window_pane *window_pane_at_index(struct window *, u_int); | struct window_pane *window_pane_at_index(struct window *, u_int); | ||||||
| u_int		 window_pane_index(struct window *, struct window_pane *); | u_int		 window_pane_index(struct window *, struct window_pane *); | ||||||
| @@ -1467,20 +1500,38 @@ void		 window_pane_mouse(struct window_pane *, | |||||||
|     		     struct client *, u_char, u_char, u_char); |     		     struct client *, u_char, u_char, u_char); | ||||||
| int		 window_pane_visible(struct window_pane *); | int		 window_pane_visible(struct window_pane *); | ||||||
| char		*window_pane_search( | char		*window_pane_search( | ||||||
| 		     struct window_pane *, const char *, u_int *); |     		     struct window_pane *, const char *, u_int *); | ||||||
|  |  | ||||||
| /* layout.c */ | /* layout.c */ | ||||||
| const char * 	 layout_name(struct window *); | struct layout_cell *layout_create_cell(struct layout_cell *); | ||||||
| int		 layout_lookup(const char *); | void		 layout_free_cell(struct layout_cell *); | ||||||
| void		 layout_refresh(struct window *, int); | void		 layout_print_cell(struct layout_cell *, const char *, u_int); | ||||||
| int		 layout_resize(struct window_pane *, int); | void		 layout_set_size( | ||||||
| int		 layout_select(struct window *, u_int); | 		     struct layout_cell *, u_int, u_int, u_int, u_int); | ||||||
| void		 layout_next(struct window *); | void		 layout_make_leaf( | ||||||
| void		 layout_previous(struct window *); | 		     struct layout_cell *, struct window_pane *); | ||||||
|  | void		 layout_make_node(struct layout_cell *, enum layout_type); | ||||||
|  | void		 layout_fix_offsets(struct layout_cell *); | ||||||
|  | void		 layout_fix_panes(struct window *, u_int, u_int); | ||||||
|  | u_int		 layout_resize_check(struct layout_cell *, enum layout_type); | ||||||
|  | void		 layout_resize_adjust( | ||||||
|  | 		     struct layout_cell *, enum layout_type, int); | ||||||
|  | void		 layout_init(struct window *); | ||||||
|  | void		 layout_free(struct window *); | ||||||
|  | void		 layout_resize(struct window *, u_int, u_int); | ||||||
|  | void		 layout_resize_pane( | ||||||
|  |     		     struct window_pane *, enum layout_type, int); | ||||||
|  | int		 layout_split_pane(struct window_pane *, | ||||||
|  | 		     enum layout_type, int, struct window_pane *); | ||||||
|  | void		 layout_close_pane(struct window_pane *); | ||||||
|  |  | ||||||
| /* layout-manual.c */ | /* layout-set.c */ | ||||||
| void		 layout_manual_v_refresh(struct window *, int); | const char	*layout_set_name(u_int); | ||||||
| void		 layout_manual_v_resize(struct window_pane *, int); | int		 layout_set_lookup(const char *); | ||||||
|  | u_int		 layout_set_select(struct window *, u_int); | ||||||
|  | u_int		 layout_set_next(struct window *); | ||||||
|  | u_int		 layout_set_previous(struct window *); | ||||||
|  | void		 layout_set_active_changed(struct window *); | ||||||
|  |  | ||||||
| /* window-clock.c */ | /* window-clock.c */ | ||||||
| extern const struct window_mode window_clock_mode; | extern const struct window_mode window_clock_mode; | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								window.c
									
									
									
									
									
								
							| @@ -35,7 +35,7 @@ | |||||||
| #include "tmux.h" | #include "tmux.h" | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Each window is attached to one or two panes, each of which is a pty. This |  * Each window is attached to a number of panes, each of which is a pty. This | ||||||
|  * file contains code to handle them. |  * file contains code to handle them. | ||||||
|  * |  * | ||||||
|  * A pane has two buffers attached, these are filled and emptied by the main |  * A pane has two buffers attached, these are filled and emptied by the main | ||||||
| @@ -230,7 +230,9 @@ window_create1(u_int sx, u_int sy) | |||||||
|  |  | ||||||
| 	TAILQ_INIT(&w->panes); | 	TAILQ_INIT(&w->panes); | ||||||
| 	w->active = NULL; | 	w->active = NULL; | ||||||
|  |  | ||||||
| 	w->layout = 0; | 	w->layout = 0; | ||||||
|  | 	w->layout_root = NULL; | ||||||
| 	 | 	 | ||||||
| 	w->sx = sx; | 	w->sx = sx; | ||||||
| 	w->sy = sy; | 	w->sy = sy; | ||||||
| @@ -254,15 +256,20 @@ struct window * | |||||||
| window_create(const char *name, const char *cmd, const char *cwd, | window_create(const char *name, const char *cmd, const char *cwd, | ||||||
|     const char **envp, u_int sx, u_int sy, u_int hlimit, char **cause) |     const char **envp, u_int sx, u_int sy, u_int hlimit, char **cause) | ||||||
| { | { | ||||||
| 	struct window	*w; | 	struct window		*w; | ||||||
|  | 	struct window_pane	*wp; | ||||||
|  |  | ||||||
| 	w = window_create1(sx, sy); | 	w = window_create1(sx, sy); | ||||||
| 	if (window_add_pane(w, -1, cmd, cwd, envp, hlimit, cause) == NULL) { | 	if ((wp = window_add_pane(w, hlimit, cause)) == NULL) { | ||||||
|  | 		window_destroy(w); | ||||||
|  | 		return (NULL); | ||||||
|  | 	} | ||||||
|  | 	layout_init(w); | ||||||
|  | 	if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) { | ||||||
| 		window_destroy(w); | 		window_destroy(w); | ||||||
| 		return (NULL); | 		return (NULL); | ||||||
| 	} | 	} | ||||||
| 	w->active = TAILQ_FIRST(&w->panes); | 	w->active = TAILQ_FIRST(&w->panes); | ||||||
|  |  | ||||||
| 	if (name != NULL) { | 	if (name != NULL) { | ||||||
| 		w->name = xstrdup(name); | 		w->name = xstrdup(name); | ||||||
| 		options_set_number(&w->options, "automatic-rename", 0); | 		options_set_number(&w->options, "automatic-rename", 0); | ||||||
| @@ -282,6 +289,9 @@ window_destroy(struct window *w) | |||||||
| 	while (!ARRAY_EMPTY(&windows) && ARRAY_LAST(&windows) == NULL) | 	while (!ARRAY_EMPTY(&windows) && ARRAY_LAST(&windows) == NULL) | ||||||
| 		ARRAY_TRUNC(&windows, 1); | 		ARRAY_TRUNC(&windows, 1); | ||||||
|  |  | ||||||
|  | 	if (w->layout_root != NULL) | ||||||
|  | 		layout_free(w); | ||||||
|  |  | ||||||
| 	options_free(&w->options); | 	options_free(&w->options); | ||||||
|  |  | ||||||
| 	window_destroy_panes(w); | 	window_destroy_panes(w); | ||||||
| @@ -304,7 +314,6 @@ void | |||||||
| window_set_active_pane(struct window *w, struct window_pane *wp) | window_set_active_pane(struct window *w, struct window_pane *wp) | ||||||
| { | { | ||||||
| 	w->active = wp; | 	w->active = wp; | ||||||
|  |  | ||||||
| 	while (!window_pane_visible(w->active)) { | 	while (!window_pane_visible(w->active)) { | ||||||
| 		w->active = TAILQ_PREV(w->active, window_panes, entry); | 		w->active = TAILQ_PREV(w->active, window_panes, entry); | ||||||
| 		if (w->active == NULL) | 		if (w->active == NULL) | ||||||
| @@ -315,41 +324,15 @@ window_set_active_pane(struct window *w, struct window_pane *wp) | |||||||
| } | } | ||||||
|  |  | ||||||
| struct window_pane * | struct window_pane * | ||||||
| window_add_pane(struct window *w, int wanty, const char *cmd, | window_add_pane(struct window *w, u_int hlimit, unused char **cause) | ||||||
|     const char *cwd, const char **envp, u_int hlimit, char **cause) |  | ||||||
| { | { | ||||||
| 	struct window_pane	*wp; | 	struct window_pane	*wp; | ||||||
| 	u_int			 sizey; |  | ||||||
|  |  | ||||||
| 	if (TAILQ_EMPTY(&w->panes)) | 	wp = window_pane_create(w, w->sx, w->sy, hlimit); | ||||||
| 		wanty = w->sy; |  | ||||||
| 	else { |  | ||||||
| 		sizey = w->active->sy - 1; /* for separator */ |  | ||||||
| 		if (sizey < PANE_MINIMUM * 2) { |  | ||||||
| 			*cause = xstrdup("pane too small"); |  | ||||||
| 			return (NULL); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|   		if (wanty == -1) |  | ||||||
| 			wanty = sizey / 2; |  | ||||||
|  |  | ||||||
| 		if (wanty < PANE_MINIMUM) |  | ||||||
| 			wanty = PANE_MINIMUM; |  | ||||||
| 		if ((u_int) wanty > sizey - PANE_MINIMUM) |  | ||||||
| 			wanty = sizey - PANE_MINIMUM; |  | ||||||
|  |  | ||||||
| 		window_pane_resize(w->active, w->sx, sizey - wanty); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	wp = window_pane_create(w, w->sx, wanty, hlimit); |  | ||||||
| 	if (TAILQ_EMPTY(&w->panes)) | 	if (TAILQ_EMPTY(&w->panes)) | ||||||
| 		TAILQ_INSERT_HEAD(&w->panes, wp, entry); | 		TAILQ_INSERT_HEAD(&w->panes, wp, entry); | ||||||
| 	else | 	else | ||||||
| 		TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry); | 		TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry); | ||||||
| 	if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) { |  | ||||||
| 		window_remove_pane(w, wp); |  | ||||||
| 		return (NULL); |  | ||||||
| 	} |  | ||||||
| 	return (wp); | 	return (wp); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -435,6 +418,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) | |||||||
|  |  | ||||||
| 	wp->mode = NULL; | 	wp->mode = NULL; | ||||||
|  |  | ||||||
|  | 	wp->layout_cell = NULL; | ||||||
|  |  | ||||||
| 	wp->xoff = 0; | 	wp->xoff = 0; | ||||||
|  	wp->yoff = 0; |  	wp->yoff = 0; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Nicholas Marriott
					Nicholas Marriott