Home | History | Annotate | Line # | Download | only in dist
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include <sys/types.h>
     20 #include <sys/ioctl.h>
     21 
     22 #include <ctype.h>
     23 #include <errno.h>
     24 #include <fcntl.h>
     25 #include <fnmatch.h>
     26 #include <regex.h>
     27 #include <signal.h>
     28 #include <stdint.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <time.h>
     32 #include <unistd.h>
     33 
     34 #include "tmux.h"
     35 
     36 /*
     37  * Each window is attached to a number of panes, each of which is a pty. This
     38  * file contains code to handle them.
     39  *
     40  * A pane has two buffers attached, these are filled and emptied by the main
     41  * server poll loop. Output data is received from pty's in screen format,
     42  * translated and returned as a series of escape sequences and strings via
     43  * input_parse (in input.c). Input data is received as key codes and written
     44  * directly via input_key.
     45  *
     46  * Each pane also has a "virtual" screen (screen.c) which contains the current
     47  * state and is redisplayed when the window is reattached to a client.
     48  *
     49  * Windows are stored directly on a global array and wrapped in any number of
     50  * winlink structs to be linked onto local session RB trees. A reference count
     51  * is maintained and a window removed from the global list and destroyed when
     52  * it reaches zero.
     53  */
     54 
     55 /* Global window list. */
     56 struct windows windows;
     57 
     58 /* Global panes tree. */
     59 struct window_pane_tree all_window_panes;
     60 static u_int	next_window_pane_id;
     61 static u_int	next_window_id;
     62 static u_int	next_active_point;
     63 
     64 struct window_pane_input_data {
     65 	struct cmdq_item	*item;
     66 	u_int			 wp;
     67 	struct client_file	*file;
     68 };
     69 
     70 static struct window_pane *window_pane_create(struct window *, u_int, u_int,
     71 		    u_int);
     72 static void	window_pane_destroy(struct window_pane *);
     73 static void	window_pane_full_size_offset(struct window_pane *wp,
     74 		    u_int *xoff, u_int *yoff, u_int *sx, u_int *sy);
     75 
     76 RB_GENERATE(windows, window, entry, window_cmp);
     77 RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
     78 RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
     79 
     80 int
     81 window_cmp(struct window *w1, struct window *w2)
     82 {
     83 	return (w1->id - w2->id);
     84 }
     85 
     86 int
     87 winlink_cmp(struct winlink *wl1, struct winlink *wl2)
     88 {
     89 	return (wl1->idx - wl2->idx);
     90 }
     91 
     92 int
     93 window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2)
     94 {
     95 	return (wp1->id - wp2->id);
     96 }
     97 
     98 struct winlink *
     99 winlink_find_by_window(struct winlinks *wwl, struct window *w)
    100 {
    101 	struct winlink	*wl;
    102 
    103 	RB_FOREACH(wl, winlinks, wwl) {
    104 		if (wl->window == w)
    105 			return (wl);
    106 	}
    107 
    108 	return (NULL);
    109 }
    110 
    111 struct winlink *
    112 winlink_find_by_index(struct winlinks *wwl, int idx)
    113 {
    114 	struct winlink	wl;
    115 
    116 	if (idx < 0)
    117 		fatalx("bad index");
    118 
    119 	wl.idx = idx;
    120 	return (RB_FIND(winlinks, wwl, &wl));
    121 }
    122 
    123 struct winlink *
    124 winlink_find_by_window_id(struct winlinks *wwl, u_int id)
    125 {
    126 	struct winlink *wl;
    127 
    128 	RB_FOREACH(wl, winlinks, wwl) {
    129 		if (wl->window->id == id)
    130 			return (wl);
    131 	}
    132 	return (NULL);
    133 }
    134 
    135 static int
    136 winlink_next_index(struct winlinks *wwl, int idx)
    137 {
    138 	int	i;
    139 
    140 	i = idx;
    141 	do {
    142 		if (winlink_find_by_index(wwl, i) == NULL)
    143 			return (i);
    144 		if (i == INT_MAX)
    145 			i = 0;
    146 		else
    147 			i++;
    148 	} while (i != idx);
    149 	return (-1);
    150 }
    151 
    152 u_int
    153 winlink_count(struct winlinks *wwl)
    154 {
    155 	struct winlink	*wl;
    156 	u_int		 n;
    157 
    158 	n = 0;
    159 	RB_FOREACH(wl, winlinks, wwl)
    160 		n++;
    161 
    162 	return (n);
    163 }
    164 
    165 struct winlink *
    166 winlink_add(struct winlinks *wwl, int idx)
    167 {
    168 	struct winlink	*wl;
    169 
    170 	if (idx < 0) {
    171 		if ((idx = winlink_next_index(wwl, -idx - 1)) == -1)
    172 			return (NULL);
    173 	} else if (winlink_find_by_index(wwl, idx) != NULL)
    174 		return (NULL);
    175 
    176 	wl = xcalloc(1, sizeof *wl);
    177 	wl->idx = idx;
    178 	RB_INSERT(winlinks, wwl, wl);
    179 
    180 	return (wl);
    181 }
    182 
    183 void
    184 winlink_set_window(struct winlink *wl, struct window *w)
    185 {
    186 	if (wl->window != NULL) {
    187 		TAILQ_REMOVE(&wl->window->winlinks, wl, wentry);
    188 		window_remove_ref(wl->window, __func__);
    189 	}
    190 	TAILQ_INSERT_TAIL(&w->winlinks, wl, wentry);
    191 	wl->window = w;
    192 	window_add_ref(w, __func__);
    193 }
    194 
    195 void
    196 winlink_remove(struct winlinks *wwl, struct winlink *wl)
    197 {
    198 	struct window	*w = wl->window;
    199 
    200 	if (w != NULL) {
    201 		TAILQ_REMOVE(&w->winlinks, wl, wentry);
    202 		window_remove_ref(w, __func__);
    203 	}
    204 
    205 	RB_REMOVE(winlinks, wwl, wl);
    206 	free(wl);
    207 }
    208 
    209 struct winlink *
    210 winlink_next(struct winlink *wl)
    211 {
    212 	return (RB_NEXT(winlinks, wwl, wl));
    213 }
    214 
    215 struct winlink *
    216 winlink_previous(struct winlink *wl)
    217 {
    218 	return (RB_PREV(winlinks, wwl, wl));
    219 }
    220 
    221 struct winlink *
    222 winlink_next_by_number(struct winlink *wl, struct session *s, int n)
    223 {
    224 	for (; n > 0; n--) {
    225 		if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL)
    226 			wl = RB_MIN(winlinks, &s->windows);
    227 	}
    228 
    229 	return (wl);
    230 }
    231 
    232 struct winlink *
    233 winlink_previous_by_number(struct winlink *wl, struct session *s, int n)
    234 {
    235 	for (; n > 0; n--) {
    236 		if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL)
    237 			wl = RB_MAX(winlinks, &s->windows);
    238 	}
    239 
    240 	return (wl);
    241 }
    242 
    243 void
    244 winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
    245 {
    246 	if (wl == NULL)
    247 		return;
    248 
    249 	winlink_stack_remove(stack, wl);
    250 	TAILQ_INSERT_HEAD(stack, wl, sentry);
    251 	wl->flags |= WINLINK_VISITED;
    252 }
    253 
    254 void
    255 winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl)
    256 {
    257 	if (wl != NULL && (wl->flags & WINLINK_VISITED)) {
    258 		TAILQ_REMOVE(stack, wl, sentry);
    259 		wl->flags &= ~WINLINK_VISITED;
    260 	}
    261 }
    262 
    263 struct window *
    264 window_find_by_id_str(const char *s)
    265 {
    266 	const char	*errstr;
    267 	u_int		 id;
    268 
    269 	if (*s != '@')
    270 		return (NULL);
    271 
    272 	id = strtonum(s + 1, 0, UINT_MAX, &errstr);
    273 	if (errstr != NULL)
    274 		return (NULL);
    275 	return (window_find_by_id(id));
    276 }
    277 
    278 struct window *
    279 window_find_by_id(u_int id)
    280 {
    281 	struct window	w;
    282 
    283 	w.id = id;
    284 	return (RB_FIND(windows, &windows, &w));
    285 }
    286 
    287 void
    288 window_update_activity(struct window *w)
    289 {
    290 	gettimeofday(&w->activity_time, NULL);
    291 	alerts_queue(w, WINDOW_ACTIVITY);
    292 }
    293 
    294 struct window *
    295 window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel)
    296 {
    297 	struct window	*w;
    298 
    299 	if (xpixel == 0)
    300 		xpixel = DEFAULT_XPIXEL;
    301 	if (ypixel == 0)
    302 		ypixel = DEFAULT_YPIXEL;
    303 
    304 	w = xcalloc(1, sizeof *w);
    305 	w->name = xstrdup("");
    306 	w->flags = 0;
    307 
    308 	TAILQ_INIT(&w->panes);
    309 	TAILQ_INIT(&w->last_panes);
    310 	w->active = NULL;
    311 
    312 	w->lastlayout = -1;
    313 	w->layout_root = NULL;
    314 
    315 	w->sx = sx;
    316 	w->sy = sy;
    317 	w->manual_sx = sx;
    318 	w->manual_sy = sy;
    319 	w->xpixel = xpixel;
    320 	w->ypixel = ypixel;
    321 
    322 	w->options = options_create(global_w_options);
    323 
    324 	w->references = 0;
    325 	TAILQ_INIT(&w->winlinks);
    326 
    327 	w->id = next_window_id++;
    328 	RB_INSERT(windows, &windows, w);
    329 
    330 	window_set_fill_character(w);
    331 	window_update_activity(w);
    332 
    333 	log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy,
    334 	    w->xpixel, w->ypixel);
    335 	return (w);
    336 }
    337 
    338 static void
    339 window_destroy(struct window *w)
    340 {
    341 	log_debug("window @%u destroyed (%d references)", w->id, w->references);
    342 
    343 	window_unzoom(w, 0);
    344 	RB_REMOVE(windows, &windows, w);
    345 
    346 	if (w->layout_root != NULL)
    347 		layout_free_cell(w->layout_root);
    348 	if (w->saved_layout_root != NULL)
    349 		layout_free_cell(w->saved_layout_root);
    350 	free(w->old_layout);
    351 
    352 	window_destroy_panes(w);
    353 
    354 	if (event_initialized(&w->name_event))
    355 		evtimer_del(&w->name_event);
    356 
    357 	if (event_initialized(&w->alerts_timer))
    358 		evtimer_del(&w->alerts_timer);
    359 	if (event_initialized(&w->offset_timer))
    360 		event_del(&w->offset_timer);
    361 
    362 	options_free(w->options);
    363 	free(w->fill_character);
    364 
    365 	free(w->name);
    366 	free(w);
    367 }
    368 
    369 int
    370 window_pane_destroy_ready(struct window_pane *wp)
    371 {
    372 	int	n;
    373 
    374 	if (wp->pipe_fd != -1) {
    375 		if (EVBUFFER_LENGTH(wp->pipe_event->output) != 0)
    376 			return (0);
    377 		if (ioctl(wp->fd, FIONREAD, &n) != -1 && n > 0)
    378 			return (0);
    379 	}
    380 
    381 	if (~wp->flags & PANE_EXITED)
    382 		return (0);
    383 	return (1);
    384 }
    385 
    386 void
    387 window_add_ref(struct window *w, const char *from)
    388 {
    389 	w->references++;
    390 	log_debug("%s: @%u %s, now %d", __func__, w->id, from, w->references);
    391 }
    392 
    393 void
    394 window_remove_ref(struct window *w, const char *from)
    395 {
    396 	w->references--;
    397 	log_debug("%s: @%u %s, now %d", __func__, w->id, from, w->references);
    398 
    399 	if (w->references == 0)
    400 		window_destroy(w);
    401 }
    402 
    403 void
    404 window_set_name(struct window *w, const char *new_name)
    405 {
    406 	free(w->name);
    407 	utf8_stravis(&w->name, new_name, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
    408 	notify_window("window-renamed", w);
    409 }
    410 
    411 void
    412 window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
    413 {
    414 	if (xpixel == 0)
    415 		xpixel = DEFAULT_XPIXEL;
    416 	if (ypixel == 0)
    417 		ypixel = DEFAULT_YPIXEL;
    418 
    419 	log_debug("%s: @%u resize %ux%u (%ux%u)", __func__, w->id, sx, sy,
    420 	    xpixel == -1 ? w->xpixel : (u_int)xpixel,
    421 	    ypixel == -1 ? w->ypixel : (u_int)ypixel);
    422 	w->sx = sx;
    423 	w->sy = sy;
    424 	if (xpixel != -1)
    425 		w->xpixel = xpixel;
    426 	if (ypixel != -1)
    427 		w->ypixel = ypixel;
    428 }
    429 
    430 void
    431 window_pane_send_resize(struct window_pane *wp, u_int sx, u_int sy)
    432 {
    433 	struct window	*w = wp->window;
    434 	struct winsize	 ws;
    435 
    436 	if (wp->fd == -1)
    437 		return;
    438 
    439 	log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, sx, sy);
    440 
    441 	memset(&ws, 0, sizeof ws);
    442 	ws.ws_col = sx;
    443 	ws.ws_row = sy;
    444 	ws.ws_xpixel = w->xpixel * ws.ws_col;
    445 	ws.ws_ypixel = w->ypixel * ws.ws_row;
    446 	if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
    447 #ifdef __sun
    448 		/*
    449 		 * Some versions of Solaris apparently can return an error when
    450 		 * resizing; don't know why this happens, can't reproduce on
    451 		 * other platforms and ignoring it doesn't seem to cause any
    452 		 * issues.
    453 		 */
    454 		if (errno != EINVAL && errno != ENXIO)
    455 #endif
    456 		fatal("ioctl failed");
    457 }
    458 
    459 int
    460 window_has_pane(struct window *w, struct window_pane *wp)
    461 {
    462 	struct window_pane	*wp1;
    463 
    464 	TAILQ_FOREACH(wp1, &w->panes, entry) {
    465 		if (wp1 == wp)
    466 			return (1);
    467 	}
    468 	return (0);
    469 }
    470 
    471 void
    472 window_update_focus(struct window *w)
    473 {
    474 	if (w != NULL) {
    475 		log_debug("%s: @%u", __func__, w->id);
    476 		window_pane_update_focus(w->active);
    477 	}
    478 }
    479 
    480 void
    481 window_pane_update_focus(struct window_pane *wp)
    482 {
    483 	struct client	*c;
    484 	int		 focused = 0;
    485 
    486 	if (wp != NULL && (~wp->flags & PANE_EXITED)) {
    487 		if (wp != wp->window->active)
    488 			focused = 0;
    489 		else {
    490 			TAILQ_FOREACH(c, &clients, entry) {
    491 				if (c->session != NULL &&
    492 				    c->session->attached != 0 &&
    493 				    (c->flags & CLIENT_FOCUSED) &&
    494 				    c->session->curw->window == wp->window &&
    495 				    c->overlay_draw == NULL) {
    496 					focused = 1;
    497 					break;
    498 				}
    499 			}
    500 		}
    501 		if (!focused && (wp->flags & PANE_FOCUSED)) {
    502 			log_debug("%s: %%%u focus out", __func__, wp->id);
    503 			if (wp->base.mode & MODE_FOCUSON)
    504 				bufferevent_write(wp->event, "\033[O", 3);
    505 			notify_pane("pane-focus-out", wp);
    506 			wp->flags &= ~PANE_FOCUSED;
    507 		} else if (focused && (~wp->flags & PANE_FOCUSED)) {
    508 			log_debug("%s: %%%u focus in", __func__, wp->id);
    509 			if (wp->base.mode & MODE_FOCUSON)
    510 				bufferevent_write(wp->event, "\033[I", 3);
    511 			notify_pane("pane-focus-in", wp);
    512 			wp->flags |= PANE_FOCUSED;
    513 		} else
    514 			log_debug("%s: %%%u focus unchanged", __func__, wp->id);
    515 	}
    516 }
    517 
    518 int
    519 window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
    520 {
    521 	struct window_pane *lastwp;
    522 
    523 	log_debug("%s: pane %%%u", __func__, wp->id);
    524 
    525 	if (wp == w->active)
    526 		return (0);
    527 	lastwp = w->active;
    528 
    529 	window_pane_stack_remove(&w->last_panes, wp);
    530 	window_pane_stack_push(&w->last_panes, lastwp);
    531 
    532 	w->active = wp;
    533 	w->active->active_point = next_active_point++;
    534 	w->active->flags |= PANE_CHANGED;
    535 
    536 	if (options_get_number(global_options, "focus-events")) {
    537 		window_pane_update_focus(lastwp);
    538 		window_pane_update_focus(w->active);
    539 	}
    540 
    541 	tty_update_window_offset(w);
    542 
    543 	if (notify)
    544 		notify_window("window-pane-changed", w);
    545 	return (1);
    546 }
    547 
    548 static int
    549 window_pane_get_palette(struct window_pane *wp, int c)
    550 {
    551 	if (wp == NULL)
    552 		return (-1);
    553 	return (colour_palette_get(&wp->palette, c));
    554 }
    555 
    556 void
    557 window_redraw_active_switch(struct window *w, struct window_pane *wp)
    558 {
    559 	struct grid_cell	*gc1, *gc2;
    560 	int			 c1, c2;
    561 
    562 	if (wp == w->active)
    563 		return;
    564 
    565 	for (;;) {
    566 		/*
    567 		 * If the active and inactive styles or palettes are different,
    568 		 * need to redraw the panes.
    569 		 */
    570 		gc1 = &wp->cached_gc;
    571 		gc2 = &wp->cached_active_gc;
    572 		if (!grid_cells_look_equal(gc1, gc2))
    573 			wp->flags |= PANE_REDRAW;
    574 		else {
    575 			c1 = window_pane_get_palette(wp, gc1->fg);
    576 			c2 = window_pane_get_palette(wp, gc2->fg);
    577 			if (c1 != c2)
    578 				wp->flags |= PANE_REDRAW;
    579 			else {
    580 				c1 = window_pane_get_palette(wp, gc1->bg);
    581 				c2 = window_pane_get_palette(wp, gc2->bg);
    582 				if (c1 != c2)
    583 					wp->flags |= PANE_REDRAW;
    584 			}
    585 		}
    586 		if (wp == w->active)
    587 			break;
    588 		wp = w->active;
    589 	}
    590 }
    591 
    592 struct window_pane *
    593 window_get_active_at(struct window *w, u_int x, u_int y)
    594 {
    595 	struct window_pane	*wp;
    596 	u_int			 xoff, yoff, sx, sy;
    597 
    598 	TAILQ_FOREACH(wp, &w->panes, entry) {
    599 		if (!window_pane_visible(wp))
    600 			continue;
    601 		window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
    602 		if (x < xoff || x > xoff + sx)
    603 			continue;
    604 		if (y < yoff || y > yoff + sy)
    605 			continue;
    606 		return (wp);
    607 	}
    608 	return (NULL);
    609 }
    610 
    611 struct window_pane *
    612 window_find_string(struct window *w, const char *s)
    613 {
    614 	u_int	x, y, top = 0, bottom = w->sy - 1;
    615 	int	status;
    616 
    617 	x = w->sx / 2;
    618 	y = w->sy / 2;
    619 
    620 	status = options_get_number(w->options, "pane-border-status");
    621 	if (status == PANE_STATUS_TOP)
    622 		top++;
    623 	else if (status == PANE_STATUS_BOTTOM)
    624 		bottom--;
    625 
    626 	if (strcasecmp(s, "top") == 0)
    627 		y = top;
    628 	else if (strcasecmp(s, "bottom") == 0)
    629 		y = bottom;
    630 	else if (strcasecmp(s, "left") == 0)
    631 		x = 0;
    632 	else if (strcasecmp(s, "right") == 0)
    633 		x = w->sx - 1;
    634 	else if (strcasecmp(s, "top-left") == 0) {
    635 		x = 0;
    636 		y = top;
    637 	} else if (strcasecmp(s, "top-right") == 0) {
    638 		x = w->sx - 1;
    639 		y = top;
    640 	} else if (strcasecmp(s, "bottom-left") == 0) {
    641 		x = 0;
    642 		y = bottom;
    643 	} else if (strcasecmp(s, "bottom-right") == 0) {
    644 		x = w->sx - 1;
    645 		y = bottom;
    646 	} else
    647 		return (NULL);
    648 
    649 	return (window_get_active_at(w, x, y));
    650 }
    651 
    652 int
    653 window_zoom(struct window_pane *wp)
    654 {
    655 	struct window		*w = wp->window;
    656 	struct window_pane	*wp1;
    657 
    658 	if (w->flags & WINDOW_ZOOMED)
    659 		return (-1);
    660 
    661 	if (window_count_panes(w) == 1)
    662 		return (-1);
    663 
    664 	if (w->active != wp)
    665 		window_set_active_pane(w, wp, 1);
    666 
    667 	TAILQ_FOREACH(wp1, &w->panes, entry) {
    668 		wp1->saved_layout_cell = wp1->layout_cell;
    669 		wp1->layout_cell = NULL;
    670 	}
    671 
    672 	w->saved_layout_root = w->layout_root;
    673 	layout_init(w, wp);
    674 	w->flags |= WINDOW_ZOOMED;
    675 	notify_window("window-layout-changed", w);
    676 
    677 	return (0);
    678 }
    679 
    680 int
    681 window_unzoom(struct window *w, int notify)
    682 {
    683 	struct window_pane	*wp;
    684 
    685 	if (!(w->flags & WINDOW_ZOOMED))
    686 		return (-1);
    687 
    688 	w->flags &= ~WINDOW_ZOOMED;
    689 	layout_free(w);
    690 	w->layout_root = w->saved_layout_root;
    691 	w->saved_layout_root = NULL;
    692 
    693 	TAILQ_FOREACH(wp, &w->panes, entry) {
    694 		wp->layout_cell = wp->saved_layout_cell;
    695 		wp->saved_layout_cell = NULL;
    696 	}
    697 	layout_fix_panes(w, NULL);
    698 
    699 	if (notify)
    700 		notify_window("window-layout-changed", w);
    701 
    702 	return (0);
    703 }
    704 
    705 int
    706 window_push_zoom(struct window *w, int always, int flag)
    707 {
    708 	log_debug("%s: @%u %d", __func__, w->id,
    709 	    flag && (w->flags & WINDOW_ZOOMED));
    710 	if (flag && (always || (w->flags & WINDOW_ZOOMED)))
    711 		w->flags |= WINDOW_WASZOOMED;
    712 	else
    713 		w->flags &= ~WINDOW_WASZOOMED;
    714 	return (window_unzoom(w, 1) == 0);
    715 }
    716 
    717 int
    718 window_pop_zoom(struct window *w)
    719 {
    720 	log_debug("%s: @%u %d", __func__, w->id,
    721 	    !!(w->flags & WINDOW_WASZOOMED));
    722 	if (w->flags & WINDOW_WASZOOMED)
    723 		return (window_zoom(w->active) == 0);
    724 	return (0);
    725 }
    726 
    727 struct window_pane *
    728 window_add_pane(struct window *w, struct window_pane *other, u_int hlimit,
    729     int flags)
    730 {
    731 	struct window_pane	*wp;
    732 
    733 	if (other == NULL)
    734 		other = w->active;
    735 
    736 	wp = window_pane_create(w, w->sx, w->sy, hlimit);
    737 	if (TAILQ_EMPTY(&w->panes)) {
    738 		log_debug("%s: @%u at start", __func__, w->id);
    739 		TAILQ_INSERT_HEAD(&w->panes, wp, entry);
    740 	} else if (flags & SPAWN_BEFORE) {
    741 		log_debug("%s: @%u before %%%u", __func__, w->id, wp->id);
    742 		if (flags & SPAWN_FULLSIZE)
    743 			TAILQ_INSERT_HEAD(&w->panes, wp, entry);
    744 		else
    745 			TAILQ_INSERT_BEFORE(other, wp, entry);
    746 	} else {
    747 		log_debug("%s: @%u after %%%u", __func__, w->id, wp->id);
    748 		if (flags & SPAWN_FULLSIZE)
    749 			TAILQ_INSERT_TAIL(&w->panes, wp, entry);
    750 		else
    751 			TAILQ_INSERT_AFTER(&w->panes, other, wp, entry);
    752 	}
    753 	return (wp);
    754 }
    755 
    756 void
    757 window_lost_pane(struct window *w, struct window_pane *wp)
    758 {
    759 	log_debug("%s: @%u pane %%%u", __func__, w->id, wp->id);
    760 
    761 	if (wp == marked_pane.wp)
    762 		server_clear_marked();
    763 
    764 	window_pane_stack_remove(&w->last_panes, wp);
    765 	if (wp == w->active) {
    766 		w->active = TAILQ_FIRST(&w->last_panes);
    767 		if (w->active == NULL) {
    768 			w->active = TAILQ_PREV(wp, window_panes, entry);
    769 			if (w->active == NULL)
    770 				w->active = TAILQ_NEXT(wp, entry);
    771 		}
    772 		if (w->active != NULL) {
    773 			window_pane_stack_remove(&w->last_panes, w->active);
    774 			w->active->flags |= PANE_CHANGED;
    775 			notify_window("window-pane-changed", w);
    776 			window_update_focus(w);
    777 		}
    778 	}
    779 }
    780 
    781 void
    782 window_remove_pane(struct window *w, struct window_pane *wp)
    783 {
    784 	window_lost_pane(w, wp);
    785 
    786 	TAILQ_REMOVE(&w->panes, wp, entry);
    787 	window_pane_destroy(wp);
    788 }
    789 
    790 struct window_pane *
    791 window_pane_at_index(struct window *w, u_int idx)
    792 {
    793 	struct window_pane	*wp;
    794 	u_int			 n;
    795 
    796 	n = options_get_number(w->options, "pane-base-index");
    797 	TAILQ_FOREACH(wp, &w->panes, entry) {
    798 		if (n == idx)
    799 			return (wp);
    800 		n++;
    801 	}
    802 	return (NULL);
    803 }
    804 
    805 struct window_pane *
    806 window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n)
    807 {
    808 	for (; n > 0; n--) {
    809 		if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
    810 			wp = TAILQ_FIRST(&w->panes);
    811 	}
    812 
    813 	return (wp);
    814 }
    815 
    816 struct window_pane *
    817 window_pane_previous_by_number(struct window *w, struct window_pane *wp,
    818     u_int n)
    819 {
    820 	for (; n > 0; n--) {
    821 		if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL)
    822 			wp = TAILQ_LAST(&w->panes, window_panes);
    823 	}
    824 
    825 	return (wp);
    826 }
    827 
    828 int
    829 window_pane_index(struct window_pane *wp, u_int *i)
    830 {
    831 	struct window_pane	*wq;
    832 	struct window		*w = wp->window;
    833 
    834 	*i = options_get_number(w->options, "pane-base-index");
    835 	TAILQ_FOREACH(wq, &w->panes, entry) {
    836 		if (wp == wq) {
    837 			return (0);
    838 		}
    839 		(*i)++;
    840 	}
    841 
    842 	return (-1);
    843 }
    844 
    845 u_int
    846 window_count_panes(struct window *w)
    847 {
    848 	struct window_pane	*wp;
    849 	u_int			 n;
    850 
    851 	n = 0;
    852 	TAILQ_FOREACH(wp, &w->panes, entry)
    853 		n++;
    854 	return (n);
    855 }
    856 
    857 void
    858 window_destroy_panes(struct window *w)
    859 {
    860 	struct window_pane	*wp;
    861 
    862 	while (!TAILQ_EMPTY(&w->last_panes)) {
    863 		wp = TAILQ_FIRST(&w->last_panes);
    864 		window_pane_stack_remove(&w->last_panes, wp);
    865 	}
    866 
    867 	while (!TAILQ_EMPTY(&w->panes)) {
    868 		wp = TAILQ_FIRST(&w->panes);
    869 		TAILQ_REMOVE(&w->panes, wp, entry);
    870 		window_pane_destroy(wp);
    871 	}
    872 }
    873 
    874 const char *
    875 window_printable_flags(struct winlink *wl, int escape)
    876 {
    877 	struct session	*s = wl->session;
    878 	static char	 flags[32];
    879 	int		 pos;
    880 
    881 	pos = 0;
    882 	if (wl->flags & WINLINK_ACTIVITY) {
    883 		flags[pos++] = '#';
    884 		if (escape)
    885 			flags[pos++] = '#';
    886 	}
    887 	if (wl->flags & WINLINK_BELL)
    888 		flags[pos++] = '!';
    889 	if (wl->flags & WINLINK_SILENCE)
    890 		flags[pos++] = '~';
    891 	if (wl == s->curw)
    892 		flags[pos++] = '*';
    893 	if (wl == TAILQ_FIRST(&s->lastw))
    894 		flags[pos++] = '-';
    895 	if (server_check_marked() && wl == marked_pane.wl)
    896 		flags[pos++] = 'M';
    897 	if (wl->window->flags & WINDOW_ZOOMED)
    898 		flags[pos++] = 'Z';
    899 	flags[pos] = '\0';
    900 	return (flags);
    901 }
    902 
    903 struct window_pane *
    904 window_pane_find_by_id_str(const char *s)
    905 {
    906 	const char	*errstr;
    907 	u_int		 id;
    908 
    909 	if (*s != '%')
    910 		return (NULL);
    911 
    912 	id = strtonum(s + 1, 0, UINT_MAX, &errstr);
    913 	if (errstr != NULL)
    914 		return (NULL);
    915 	return (window_pane_find_by_id(id));
    916 }
    917 
    918 struct window_pane *
    919 window_pane_find_by_id(u_int id)
    920 {
    921 	struct window_pane	wp;
    922 
    923 	wp.id = id;
    924 	return (RB_FIND(window_pane_tree, &all_window_panes, &wp));
    925 }
    926 
    927 static struct window_pane *
    928 window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
    929 {
    930 	struct window_pane	*wp;
    931 	char			 host[HOST_NAME_MAX + 1];
    932 
    933 	wp = xcalloc(1, sizeof *wp);
    934 	wp->window = w;
    935 	wp->options = options_create(w->options);
    936 	wp->flags = (PANE_STYLECHANGED|PANE_THEMECHANGED);
    937 
    938 	wp->id = next_window_pane_id++;
    939 	RB_INSERT(window_pane_tree, &all_window_panes, wp);
    940 
    941 	wp->fd = -1;
    942 
    943 	TAILQ_INIT(&wp->modes);
    944 
    945 	TAILQ_INIT (&wp->resize_queue);
    946 
    947 	wp->sx = sx;
    948 	wp->sy = sy;
    949 
    950 	wp->pipe_fd = -1;
    951 
    952 	wp->control_bg = -1;
    953 	wp->control_fg = -1;
    954 
    955 	style_set_scrollbar_style_from_option(&wp->scrollbar_style,
    956 	    wp->options);
    957 
    958 	colour_palette_init(&wp->palette);
    959 	colour_palette_from_option(&wp->palette, wp->options);
    960 
    961 	screen_init(&wp->base, sx, sy, hlimit);
    962 	wp->screen = &wp->base;
    963 	window_pane_default_cursor(wp);
    964 
    965 	screen_init(&wp->status_screen, 1, 1, 0);
    966 
    967 	if (gethostname(host, sizeof host) == 0)
    968 		screen_set_title(&wp->base, host);
    969 
    970 	return (wp);
    971 }
    972 
    973 static void
    974 window_pane_destroy(struct window_pane *wp)
    975 {
    976 	struct window_pane_resize	*r;
    977 	struct window_pane_resize	*r1;
    978 
    979 	window_pane_reset_mode_all(wp);
    980 	free(wp->searchstr);
    981 
    982 	if (wp->fd != -1) {
    983 #ifdef HAVE_UTEMPTER
    984 		utempter_remove_record(wp->fd);
    985 		kill(getpid(), SIGCHLD);
    986 #endif
    987 		bufferevent_free(wp->event);
    988 		close(wp->fd);
    989 	}
    990 	if (wp->ictx != NULL)
    991 		input_free(wp->ictx);
    992 
    993 	screen_free(&wp->status_screen);
    994 
    995 	screen_free(&wp->base);
    996 
    997 	if (wp->pipe_fd != -1) {
    998 		bufferevent_free(wp->pipe_event);
    999 		close(wp->pipe_fd);
   1000 	}
   1001 
   1002 	if (event_initialized(&wp->resize_timer))
   1003 		event_del(&wp->resize_timer);
   1004 	TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
   1005 		TAILQ_REMOVE(&wp->resize_queue, r, entry);
   1006 		free(r);
   1007 	}
   1008 
   1009 	RB_REMOVE(window_pane_tree, &all_window_panes, wp);
   1010 
   1011 	options_free(wp->options);
   1012 	free(__UNCONST(wp->cwd));
   1013 	free(wp->shell);
   1014 	cmd_free_argv(wp->argc, wp->argv);
   1015 	colour_palette_free(&wp->palette);
   1016 	free(wp);
   1017 }
   1018 
   1019 static void
   1020 window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
   1021 {
   1022 	struct window_pane		*wp = data;
   1023 	struct evbuffer			*evb = wp->event->input;
   1024 	struct window_pane_offset	*wpo = &wp->pipe_offset;
   1025 	size_t				 size = EVBUFFER_LENGTH(evb);
   1026 	char				*new_data;
   1027 	size_t				 new_size;
   1028 	struct client			*c;
   1029 
   1030 	if (wp->pipe_fd != -1) {
   1031 		new_data = window_pane_get_new_data(wp, wpo, &new_size);
   1032 		if (new_size > 0) {
   1033 			bufferevent_write(wp->pipe_event, new_data, new_size);
   1034 			window_pane_update_used_data(wp, wpo, new_size);
   1035 		}
   1036 	}
   1037 
   1038 	log_debug("%%%u has %zu bytes", wp->id, size);
   1039 	TAILQ_FOREACH(c, &clients, entry) {
   1040 		if (c->session != NULL && (c->flags & CLIENT_CONTROL))
   1041 			control_write_output(c, wp);
   1042 	}
   1043 	input_parse_pane(wp);
   1044 	bufferevent_disable(wp->event, EV_READ);
   1045 }
   1046 
   1047 static void
   1048 window_pane_error_callback(__unused struct bufferevent *bufev,
   1049     __unused short what, void *data)
   1050 {
   1051 	struct window_pane *wp = data;
   1052 
   1053 	log_debug("%%%u error", wp->id);
   1054 	wp->flags |= PANE_EXITED;
   1055 
   1056 	if (window_pane_destroy_ready(wp))
   1057 		server_destroy_pane(wp, 1);
   1058 }
   1059 
   1060 void
   1061 window_pane_set_event(struct window_pane *wp)
   1062 {
   1063 	setblocking(wp->fd, 0);
   1064 
   1065 	wp->event = bufferevent_new(wp->fd, window_pane_read_callback,
   1066 	    NULL, window_pane_error_callback, wp);
   1067 	if (wp->event == NULL)
   1068 		fatalx("out of memory");
   1069 	wp->ictx = input_init(wp, wp->event, &wp->palette);
   1070 
   1071 	bufferevent_enable(wp->event, EV_READ|EV_WRITE);
   1072 }
   1073 
   1074 void
   1075 window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
   1076 {
   1077 	struct window_mode_entry	*wme;
   1078 	struct window_pane_resize	*r;
   1079 
   1080 	if (sx == wp->sx && sy == wp->sy)
   1081 		return;
   1082 
   1083 	r = xmalloc(sizeof *r);
   1084 	r->sx = sx;
   1085 	r->sy = sy;
   1086 	r->osx = wp->sx;
   1087 	r->osy = wp->sy;
   1088 	TAILQ_INSERT_TAIL (&wp->resize_queue, r, entry);
   1089 
   1090 	wp->sx = sx;
   1091 	wp->sy = sy;
   1092 
   1093 	log_debug("%s: %%%u resize %ux%u", __func__, wp->id, sx, sy);
   1094 	screen_resize(&wp->base, sx, sy, wp->base.saved_grid == NULL);
   1095 
   1096 	wme = TAILQ_FIRST(&wp->modes);
   1097 	if (wme != NULL && wme->mode->resize != NULL)
   1098 		wme->mode->resize(wme, sx, sy);
   1099 }
   1100 
   1101 int
   1102 window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
   1103     const struct window_mode *mode, struct cmd_find_state *fs,
   1104     struct args *args)
   1105 {
   1106 	struct window_mode_entry	*wme;
   1107 	struct window			*w = wp->window;
   1108 
   1109 	if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode)
   1110 		return (1);
   1111 
   1112 	TAILQ_FOREACH(wme, &wp->modes, entry) {
   1113 		if (wme->mode == mode)
   1114 			break;
   1115 	}
   1116 	if (wme != NULL) {
   1117 		TAILQ_REMOVE(&wp->modes, wme, entry);
   1118 		TAILQ_INSERT_HEAD(&wp->modes, wme, entry);
   1119 	} else {
   1120 		wme = xcalloc(1, sizeof *wme);
   1121 		wme->wp = wp;
   1122 		wme->swp = swp;
   1123 		wme->mode = mode;
   1124 		wme->prefix = 1;
   1125 		TAILQ_INSERT_HEAD(&wp->modes, wme, entry);
   1126 		wme->screen = wme->mode->init(wme, fs, args);
   1127 	}
   1128 	wp->screen = wme->screen;
   1129 
   1130 	wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED);
   1131 	layout_fix_panes(w, NULL);
   1132 
   1133 	server_redraw_window_borders(wp->window);
   1134 	server_status_window(wp->window);
   1135 	notify_pane("pane-mode-changed", wp);
   1136 
   1137 	return (0);
   1138 }
   1139 
   1140 void
   1141 window_pane_reset_mode(struct window_pane *wp)
   1142 {
   1143 	struct window_mode_entry	*wme, *next;
   1144 	struct window			*w = wp->window;
   1145 
   1146 	if (TAILQ_EMPTY(&wp->modes))
   1147 		return;
   1148 
   1149 	wme = TAILQ_FIRST(&wp->modes);
   1150 	TAILQ_REMOVE(&wp->modes, wme, entry);
   1151 	wme->mode->free(wme);
   1152 	free(wme);
   1153 
   1154 	next = TAILQ_FIRST(&wp->modes);
   1155 	if (next == NULL) {
   1156 		wp->flags &= ~PANE_UNSEENCHANGES;
   1157 		log_debug("%s: no next mode", __func__);
   1158 		wp->screen = &wp->base;
   1159 	} else {
   1160 		log_debug("%s: next mode is %s", __func__, next->mode->name);
   1161 		wp->screen = next->screen;
   1162 		if (next->mode->resize != NULL)
   1163 			next->mode->resize(next, wp->sx, wp->sy);
   1164 	}
   1165 
   1166 	wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED);
   1167 	layout_fix_panes(w, NULL);
   1168 
   1169 	server_redraw_window_borders(wp->window);
   1170 	server_status_window(wp->window);
   1171 	notify_pane("pane-mode-changed", wp);
   1172 }
   1173 
   1174 void
   1175 window_pane_reset_mode_all(struct window_pane *wp)
   1176 {
   1177 	while (!TAILQ_EMPTY(&wp->modes))
   1178 		window_pane_reset_mode(wp);
   1179 }
   1180 
   1181 static void
   1182 window_pane_copy_paste(struct window_pane *wp, char *buf, size_t len)
   1183 {
   1184  	struct window_pane	*loop;
   1185 
   1186 	TAILQ_FOREACH(loop, &wp->window->panes, entry) {
   1187 		if (loop != wp &&
   1188 		    TAILQ_EMPTY(&loop->modes) &&
   1189 		    loop->fd != -1 &&
   1190 		    (~loop->flags & PANE_INPUTOFF) &&
   1191 		    window_pane_visible(loop) &&
   1192 		    options_get_number(loop->options, "synchronize-panes")) {
   1193 			log_debug("%s: %.*s", __func__, (int)len, buf);
   1194 			bufferevent_write(loop->event, buf, len);
   1195 		}
   1196 	}
   1197 }
   1198 
   1199 static void
   1200 window_pane_copy_key(struct window_pane *wp, key_code key)
   1201 {
   1202  	struct window_pane	*loop;
   1203 
   1204 	TAILQ_FOREACH(loop, &wp->window->panes, entry) {
   1205 		if (loop != wp &&
   1206 		    TAILQ_EMPTY(&loop->modes) &&
   1207 		    loop->fd != -1 &&
   1208 		    (~loop->flags & PANE_INPUTOFF) &&
   1209 		    window_pane_visible(loop) &&
   1210 		    options_get_number(loop->options, "synchronize-panes"))
   1211 			input_key_pane(loop, key, NULL);
   1212 	}
   1213 }
   1214 
   1215 void
   1216 window_pane_paste(struct window_pane *wp, key_code key, char *buf, size_t len)
   1217 {
   1218 	if (!TAILQ_EMPTY(&wp->modes))
   1219 		return;
   1220 
   1221 	if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
   1222 		return;
   1223 
   1224 	if (KEYC_IS_PASTE(key) && (~wp->screen->mode & MODE_BRACKETPASTE))
   1225 		return;
   1226 
   1227 	log_debug("%s: %.*s", __func__, (int)len, buf);
   1228 	bufferevent_write(wp->event, buf, len);
   1229 
   1230 	if (options_get_number(wp->options, "synchronize-panes"))
   1231 		window_pane_copy_paste(wp, buf, len);
   1232 }
   1233 
   1234 int
   1235 window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
   1236     struct winlink *wl, key_code key, struct mouse_event *m)
   1237 {
   1238 	struct window_mode_entry	*wme;
   1239 
   1240 	if (KEYC_IS_MOUSE(key) && m == NULL)
   1241 		return (-1);
   1242 
   1243 	wme = TAILQ_FIRST(&wp->modes);
   1244 	if (wme != NULL) {
   1245 		if (wme->mode->key != NULL && c != NULL) {
   1246 			key &= ~KEYC_MASK_FLAGS;
   1247 			wme->mode->key(wme, c, s, wl, key, m);
   1248 		}
   1249 		return (0);
   1250 	}
   1251 
   1252 	if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
   1253 		return (0);
   1254 
   1255 	if (input_key_pane(wp, key, m) != 0)
   1256 		return (-1);
   1257 
   1258 	if (KEYC_IS_MOUSE(key))
   1259 		return (0);
   1260 	if (options_get_number(wp->options, "synchronize-panes"))
   1261 		window_pane_copy_key(wp, key);
   1262 	return (0);
   1263 }
   1264 
   1265 int
   1266 window_pane_visible(struct window_pane *wp)
   1267 {
   1268 	if (~wp->window->flags & WINDOW_ZOOMED)
   1269 		return (1);
   1270 	return (wp == wp->window->active);
   1271 }
   1272 
   1273 int
   1274 window_pane_exited(struct window_pane *wp)
   1275 {
   1276 	return (wp->fd == -1 || (wp->flags & PANE_EXITED));
   1277 }
   1278 
   1279 u_int
   1280 window_pane_search(struct window_pane *wp, const char *term, int regex,
   1281     int ignore)
   1282 {
   1283 	struct screen	*s = &wp->base;
   1284 	regex_t		 r;
   1285 	char		*new = NULL, *line;
   1286 	u_int		 i;
   1287 	int		 flags = 0, found;
   1288 	size_t		 n;
   1289 
   1290 	if (!regex) {
   1291 		if (ignore)
   1292 			flags |= FNM_CASEFOLD;
   1293 		xasprintf(&new, "*%s*", term);
   1294 	} else {
   1295 		if (ignore)
   1296 			flags |= REG_ICASE;
   1297 		if (regcomp(&r, term, flags|REG_EXTENDED) != 0)
   1298 			return (0);
   1299 	}
   1300 
   1301 	for (i = 0; i < screen_size_y(s); i++) {
   1302 		line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s));
   1303 		for (n = strlen(line); n > 0; n--) {
   1304 			if (!isspace((u_char)line[n - 1]))
   1305 				break;
   1306 			line[n - 1] = '\0';
   1307 		}
   1308 		log_debug("%s: %s", __func__, line);
   1309 		if (!regex)
   1310 			found = (fnmatch(new, line, flags) == 0);
   1311 		else
   1312 			found = (regexec(&r, line, 0, NULL, 0) == 0);
   1313 		free(line);
   1314 		if (found)
   1315 			break;
   1316 	}
   1317 	if (!regex)
   1318 		free(new);
   1319 	else
   1320 		regfree(&r);
   1321 
   1322 	if (i == screen_size_y(s))
   1323 		return (0);
   1324 	return (i + 1);
   1325 }
   1326 
   1327 /* Get MRU pane from a list. */
   1328 static struct window_pane *
   1329 window_pane_choose_best(struct window_pane **list, u_int size)
   1330 {
   1331 	struct window_pane	*next, *best;
   1332 	u_int			 i;
   1333 
   1334 	if (size == 0)
   1335 		return (NULL);
   1336 
   1337 	best = list[0];
   1338 	for (i = 1; i < size; i++) {
   1339 		next = list[i];
   1340 		if (next->active_point > best->active_point)
   1341 			best = next;
   1342 	}
   1343 	return (best);
   1344 }
   1345 
   1346 /*
   1347  * Get full size and offset of a window pane including the area of the
   1348  * scrollbars if they were visible but not including the border(s).
   1349  */
   1350 static void
   1351 window_pane_full_size_offset(struct window_pane *wp, u_int *xoff, u_int *yoff,
   1352     u_int *sx, u_int *sy)
   1353 {
   1354 	struct window		*w = wp->window;
   1355 	int			 pane_scrollbars;
   1356 	u_int			 sb_w, sb_pos;
   1357 
   1358 	pane_scrollbars = options_get_number(w->options, "pane-scrollbars");
   1359 	sb_pos = options_get_number(w->options, "pane-scrollbars-position");
   1360 
   1361 	if (window_pane_show_scrollbar(wp, pane_scrollbars))
   1362 		sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
   1363 	else
   1364 		sb_w = 0;
   1365 	if (sb_pos == PANE_SCROLLBARS_LEFT) {
   1366 		*xoff = wp->xoff - sb_w;
   1367 		*sx = wp->sx + sb_w;
   1368 	} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
   1369 		*xoff = wp->xoff;
   1370 		*sx = wp->sx + sb_w;
   1371 	}
   1372 	*yoff = wp->yoff;
   1373 	*sy = wp->sy;
   1374 }
   1375 
   1376 /*
   1377  * Find the pane directly above another. We build a list of those adjacent to
   1378  * top edge and then choose the best.
   1379  */
   1380 struct window_pane *
   1381 window_pane_find_up(struct window_pane *wp)
   1382 {
   1383 	struct window		*w;
   1384 	struct window_pane	*next, *best, **list;
   1385 	u_int			 edge, left, right, end, size;
   1386 	int			 status, found;
   1387 	u_int			 xoff, yoff, sx, sy;
   1388 
   1389 	if (wp == NULL)
   1390 		return (NULL);
   1391 	w = wp->window;
   1392 	status = options_get_number(w->options, "pane-border-status");
   1393 
   1394 	list = NULL;
   1395 	size = 0;
   1396 
   1397 	window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
   1398 
   1399 	edge = yoff;
   1400 	if (status == PANE_STATUS_TOP) {
   1401 		if (edge == 1)
   1402 			edge = w->sy + 1;
   1403 	} else if (status == PANE_STATUS_BOTTOM) {
   1404 		if (edge == 0)
   1405 			edge = w->sy;
   1406 	} else {
   1407 		if (edge == 0)
   1408 			edge = w->sy + 1;
   1409 	}
   1410 
   1411 	left = xoff;
   1412 	right = xoff + sx;
   1413 
   1414 	TAILQ_FOREACH(next, &w->panes, entry) {
   1415 		window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
   1416 		if (next == wp)
   1417 			continue;
   1418 		if (yoff + sy + 1 != edge)
   1419 			continue;
   1420 		end = xoff + sx - 1;
   1421 
   1422 		found = 0;
   1423 		if (xoff < left && end > right)
   1424 			found = 1;
   1425 		else if (xoff >= left && xoff <= right)
   1426 			found = 1;
   1427 		else if (end >= left && end <= right)
   1428 			found = 1;
   1429 		if (!found)
   1430 			continue;
   1431 		list = xreallocarray(list, size + 1, sizeof *list);
   1432 		list[size++] = next;
   1433 	}
   1434 
   1435 	best = window_pane_choose_best(list, size);
   1436 	free(list);
   1437 	return (best);
   1438 }
   1439 
   1440 /* Find the pane directly below another. */
   1441 struct window_pane *
   1442 window_pane_find_down(struct window_pane *wp)
   1443 {
   1444 	struct window		*w;
   1445 	struct window_pane	*next, *best, **list;
   1446 	u_int			 edge, left, right, end, size;
   1447 	int			 status, found;
   1448 	u_int			 xoff, yoff, sx, sy;
   1449 
   1450 	if (wp == NULL)
   1451 		return (NULL);
   1452 	w = wp->window;
   1453 	status = options_get_number(w->options, "pane-border-status");
   1454 
   1455 	list = NULL;
   1456 	size = 0;
   1457 
   1458 	window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
   1459 
   1460 	edge = yoff + sy + 1;
   1461 	if (status == PANE_STATUS_TOP) {
   1462 		if (edge >= w->sy)
   1463 			edge = 1;
   1464 	} else if (status == PANE_STATUS_BOTTOM) {
   1465 		if (edge >= w->sy - 1)
   1466 			edge = 0;
   1467 	} else {
   1468 		if (edge >= w->sy)
   1469 			edge = 0;
   1470 	}
   1471 
   1472 	left = wp->xoff;
   1473 	right = wp->xoff + wp->sx;
   1474 
   1475 	TAILQ_FOREACH(next, &w->panes, entry) {
   1476 		window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
   1477 		if (next == wp)
   1478 			continue;
   1479 		if (yoff != edge)
   1480 			continue;
   1481 		end = xoff + sx - 1;
   1482 
   1483 		found = 0;
   1484 		if (xoff < left && end > right)
   1485 			found = 1;
   1486 		else if (xoff >= left && xoff <= right)
   1487 			found = 1;
   1488 		else if (end >= left && end <= right)
   1489 			found = 1;
   1490 		if (!found)
   1491 			continue;
   1492 		list = xreallocarray(list, size + 1, sizeof *list);
   1493 		list[size++] = next;
   1494 	}
   1495 
   1496 	best = window_pane_choose_best(list, size);
   1497 	free(list);
   1498 	return (best);
   1499 }
   1500 
   1501 /* Find the pane directly to the left of another. */
   1502 struct window_pane *
   1503 window_pane_find_left(struct window_pane *wp)
   1504 {
   1505 	struct window		*w;
   1506 	struct window_pane	*next, *best, **list;
   1507 	u_int			 edge, top, bottom, end, size;
   1508 	int			 found;
   1509 	u_int			 xoff, yoff, sx, sy;
   1510 
   1511 	if (wp == NULL)
   1512 		return (NULL);
   1513 	w = wp->window;
   1514 
   1515 	list = NULL;
   1516 	size = 0;
   1517 
   1518 	window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
   1519 
   1520 	edge = xoff;
   1521 	if (edge == 0)
   1522 		edge = w->sx + 1;
   1523 
   1524 	top = yoff;
   1525 	bottom = yoff + sy;
   1526 
   1527 	TAILQ_FOREACH(next, &w->panes, entry) {
   1528 		window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
   1529 		if (next == wp)
   1530 			continue;
   1531 		if (xoff + sx + 1 != edge)
   1532 			continue;
   1533 		end = yoff + sy - 1;
   1534 
   1535 		found = 0;
   1536 		if (yoff < top && end > bottom)
   1537 			found = 1;
   1538 		else if (yoff >= top && yoff <= bottom)
   1539 			found = 1;
   1540 		else if (end >= top && end <= bottom)
   1541 			found = 1;
   1542 		if (!found)
   1543 			continue;
   1544 		list = xreallocarray(list, size + 1, sizeof *list);
   1545 		list[size++] = next;
   1546 	}
   1547 
   1548 	best = window_pane_choose_best(list, size);
   1549 	free(list);
   1550 	return (best);
   1551 }
   1552 
   1553 /* Find the pane directly to the right of another. */
   1554 struct window_pane *
   1555 window_pane_find_right(struct window_pane *wp)
   1556 {
   1557 	struct window		*w;
   1558 	struct window_pane	*next, *best, **list;
   1559 	u_int			 edge, top, bottom, end, size;
   1560 	int			 found;
   1561 	u_int			 xoff, yoff, sx, sy;
   1562 
   1563 	if (wp == NULL)
   1564 		return (NULL);
   1565 	w = wp->window;
   1566 
   1567 	list = NULL;
   1568 	size = 0;
   1569 
   1570 	window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
   1571 
   1572 	edge = xoff + sx + 1;
   1573 	if (edge >= w->sx)
   1574 		edge = 0;
   1575 
   1576 	top = wp->yoff;
   1577 	bottom = wp->yoff + wp->sy;
   1578 
   1579 	TAILQ_FOREACH(next, &w->panes, entry) {
   1580 		window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
   1581 		if (next == wp)
   1582 			continue;
   1583 		if (xoff != edge)
   1584 			continue;
   1585 		end = yoff + sy - 1;
   1586 
   1587 		found = 0;
   1588 		if (yoff < top && end > bottom)
   1589 			found = 1;
   1590 		else if (yoff >= top && yoff <= bottom)
   1591 			found = 1;
   1592 		else if (end >= top && end <= bottom)
   1593 			found = 1;
   1594 		if (!found)
   1595 			continue;
   1596 		list = xreallocarray(list, size + 1, sizeof *list);
   1597 		list[size++] = next;
   1598 	}
   1599 
   1600 	best = window_pane_choose_best(list, size);
   1601 	free(list);
   1602 	return (best);
   1603 }
   1604 
   1605 void
   1606 window_pane_stack_push(struct window_panes *stack, struct window_pane *wp)
   1607 {
   1608 	if (wp != NULL) {
   1609 		window_pane_stack_remove(stack, wp);
   1610 		TAILQ_INSERT_HEAD(stack, wp, sentry);
   1611 		wp->flags |= PANE_VISITED;
   1612 	}
   1613 }
   1614 
   1615 void
   1616 window_pane_stack_remove(struct window_panes *stack, struct window_pane *wp)
   1617 {
   1618 	if (wp != NULL && (wp->flags & PANE_VISITED)) {
   1619 		TAILQ_REMOVE(stack, wp, sentry);
   1620 		wp->flags &= ~PANE_VISITED;
   1621 	}
   1622 }
   1623 
   1624 /* Clear alert flags for a winlink */
   1625 void
   1626 winlink_clear_flags(struct winlink *wl)
   1627 {
   1628 	struct winlink	*loop;
   1629 
   1630 	wl->window->flags &= ~WINDOW_ALERTFLAGS;
   1631 	TAILQ_FOREACH(loop, &wl->window->winlinks, wentry) {
   1632 		if ((loop->flags & WINLINK_ALERTFLAGS) != 0) {
   1633 			loop->flags &= ~WINLINK_ALERTFLAGS;
   1634 			server_status_session(loop->session);
   1635 		}
   1636 	}
   1637 }
   1638 
   1639 /* Shuffle window indexes up. */
   1640 int
   1641 winlink_shuffle_up(struct session *s, struct winlink *wl, int before)
   1642 {
   1643 	int	 idx, last;
   1644 
   1645 	if (wl == NULL)
   1646 		return (-1);
   1647 	if (before)
   1648 		idx = wl->idx;
   1649 	else
   1650 		idx = wl->idx + 1;
   1651 
   1652 	/* Find the next free index. */
   1653 	for (last = idx; last < INT_MAX; last++) {
   1654 		if (winlink_find_by_index(&s->windows, last) == NULL)
   1655 			break;
   1656 	}
   1657 	if (last == INT_MAX)
   1658 		return (-1);
   1659 
   1660 	/* Move everything from last - 1 to idx up a bit. */
   1661 	for (; last > idx; last--) {
   1662 		wl = winlink_find_by_index(&s->windows, last - 1);
   1663 		RB_REMOVE(winlinks, &s->windows, wl);
   1664 		wl->idx++;
   1665 		RB_INSERT(winlinks, &s->windows, wl);
   1666 	}
   1667 
   1668 	return (idx);
   1669 }
   1670 
   1671 static void
   1672 window_pane_input_callback(struct client *c, __unused const char *path,
   1673     int error, int closed, struct evbuffer *buffer, void *data)
   1674 {
   1675 	struct window_pane_input_data	*cdata = data;
   1676 	struct window_pane		*wp;
   1677 	u_char				*buf = EVBUFFER_DATA(buffer);
   1678 	size_t				 len = EVBUFFER_LENGTH(buffer);
   1679 
   1680 	wp = window_pane_find_by_id(cdata->wp);
   1681 	if (cdata->file != NULL && (wp == NULL || c->flags & CLIENT_DEAD)) {
   1682 		if (wp == NULL) {
   1683 			c->retval = 1;
   1684 			c->flags |= CLIENT_EXIT;
   1685 		}
   1686 		file_cancel(cdata->file);
   1687 	} else if (cdata->file == NULL || closed || error != 0) {
   1688 		cmdq_continue(cdata->item);
   1689 		server_client_unref(c);
   1690 		free(cdata);
   1691 	} else
   1692 		input_parse_buffer(wp, buf, len);
   1693 	evbuffer_drain(buffer, len);
   1694 }
   1695 
   1696 int
   1697 window_pane_start_input(struct window_pane *wp, struct cmdq_item *item,
   1698     char **cause)
   1699 {
   1700 	struct client			*c = cmdq_get_client(item);
   1701 	struct window_pane_input_data	*cdata;
   1702 
   1703 	if (~wp->flags & PANE_EMPTY) {
   1704 		*cause = xstrdup("pane is not empty");
   1705 		return (-1);
   1706 	}
   1707 	if (c->flags & (CLIENT_DEAD|CLIENT_EXITED))
   1708 		return (1);
   1709 	if (c->session != NULL)
   1710 		return (1);
   1711 
   1712 	cdata = xmalloc(sizeof *cdata);
   1713 	cdata->item = item;
   1714 	cdata->wp = wp->id;
   1715 	cdata->file = file_read(c, "-", window_pane_input_callback, cdata);
   1716 	c->references++;
   1717 
   1718 	return (0);
   1719 }
   1720 
   1721 void *
   1722 window_pane_get_new_data(struct window_pane *wp,
   1723     struct window_pane_offset *wpo, size_t *size)
   1724 {
   1725 	size_t	used = wpo->used - wp->base_offset;
   1726 
   1727 	*size = EVBUFFER_LENGTH(wp->event->input) - used;
   1728 	return (EVBUFFER_DATA(wp->event->input) + used);
   1729 }
   1730 
   1731 void
   1732 window_pane_update_used_data(struct window_pane *wp,
   1733     struct window_pane_offset *wpo, size_t size)
   1734 {
   1735 	size_t	used = wpo->used - wp->base_offset;
   1736 
   1737 	if (size > EVBUFFER_LENGTH(wp->event->input) - used)
   1738 		size = EVBUFFER_LENGTH(wp->event->input) - used;
   1739 	wpo->used += size;
   1740 }
   1741 
   1742 void
   1743 window_set_fill_character(struct window *w)
   1744 {
   1745 	const char		*value;
   1746 	struct utf8_data	*ud;
   1747 
   1748 	free(w->fill_character);
   1749 	w->fill_character = NULL;
   1750 
   1751 	value = options_get_string(w->options, "fill-character");
   1752 	if (*value != '\0' && utf8_isvalid(value)) {
   1753 		ud = utf8_fromcstr(value);
   1754 		if (ud != NULL && ud[0].width == 1)
   1755 			w->fill_character = ud;
   1756 		else
   1757 			free(ud);
   1758 	}
   1759 }
   1760 
   1761 void
   1762 window_pane_default_cursor(struct window_pane *wp)
   1763 {
   1764 	screen_set_default_cursor(wp->screen, wp->options);
   1765 }
   1766 
   1767 int
   1768 window_pane_mode(struct window_pane *wp)
   1769 {
   1770 	if (TAILQ_FIRST(&wp->modes) != NULL) {
   1771 		if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode)
   1772 			return (WINDOW_PANE_COPY_MODE);
   1773 		if (TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
   1774 			return (WINDOW_PANE_VIEW_MODE);
   1775 	}
   1776 	return (WINDOW_PANE_NO_MODE);
   1777 }
   1778 
   1779 /* Return 1 if scrollbar is or should be displayed. */
   1780 int
   1781 window_pane_show_scrollbar(struct window_pane *wp, int sb_option)
   1782 {
   1783 	if (SCREEN_IS_ALTERNATE(wp->screen))
   1784 		return (0);
   1785 	if (sb_option == PANE_SCROLLBARS_ALWAYS ||
   1786 	    (sb_option == PANE_SCROLLBARS_MODAL &&
   1787 	    window_pane_mode(wp) != WINDOW_PANE_NO_MODE))
   1788 		return (1);
   1789 	return (0);
   1790 }
   1791 
   1792 int
   1793 window_pane_get_bg(struct window_pane *wp)
   1794 {
   1795 	int			c;
   1796 	struct grid_cell	defaults;
   1797 
   1798 	c = window_pane_get_bg_control_client(wp);
   1799 	if (c == -1) {
   1800 		tty_default_colours(&defaults, wp);
   1801 		if (COLOUR_DEFAULT(defaults.bg))
   1802 			c = window_get_bg_client(wp);
   1803 		else
   1804 			c = defaults.bg;
   1805 	}
   1806 	return (c);
   1807 }
   1808 
   1809 /* Get a client with a background for the pane. */
   1810 int
   1811 window_get_bg_client(struct window_pane *wp)
   1812 {
   1813 	struct window	*w = wp->window;
   1814 	struct client	*loop;
   1815 
   1816 	TAILQ_FOREACH(loop, &clients, entry) {
   1817 		if (loop->flags & CLIENT_UNATTACHEDFLAGS)
   1818 			continue;
   1819 		if (loop->session == NULL || !session_has(loop->session, w))
   1820 			continue;
   1821 		if (loop->tty.bg == -1)
   1822 			continue;
   1823 		return (loop->tty.bg);
   1824 	}
   1825 	return (-1);
   1826 }
   1827 
   1828 /*
   1829  * If any control mode client exists that has provided a bg color, return it.
   1830  * Otherwise, return -1.
   1831  */
   1832 int
   1833 window_pane_get_bg_control_client(struct window_pane *wp)
   1834 {
   1835 	struct client	*c;
   1836 
   1837 	if (wp->control_bg == -1)
   1838 		return (-1);
   1839 
   1840 	TAILQ_FOREACH(c, &clients, entry) {
   1841 		if (c->flags & CLIENT_CONTROL)
   1842 			return (wp->control_bg);
   1843 	}
   1844 	return (-1);
   1845 }
   1846 
   1847 /*
   1848  * Get a client with a foreground for the pane. There isn't much to choose
   1849  * between them so just use the first.
   1850  */
   1851 int
   1852 window_pane_get_fg(struct window_pane *wp)
   1853 {
   1854 	struct window	*w = wp->window;
   1855 	struct client	*loop;
   1856 
   1857 	TAILQ_FOREACH(loop, &clients, entry) {
   1858 		if (loop->flags & CLIENT_UNATTACHEDFLAGS)
   1859 			continue;
   1860 		if (loop->session == NULL || !session_has(loop->session, w))
   1861 			continue;
   1862 		if (loop->tty.fg == -1)
   1863 			continue;
   1864 		return (loop->tty.fg);
   1865 	}
   1866 	return (-1);
   1867 }
   1868 
   1869 /*
   1870  * If any control mode client exists that has provided a fg color, return it.
   1871  * Otherwise, return -1.
   1872  */
   1873 int
   1874 window_pane_get_fg_control_client(struct window_pane *wp)
   1875 {
   1876 	struct client	*c;
   1877 
   1878 	if (wp->control_fg == -1)
   1879 		return (-1);
   1880 
   1881 	TAILQ_FOREACH(c, &clients, entry) {
   1882 		if (c->flags & CLIENT_CONTROL)
   1883 			return (wp->control_fg);
   1884 	}
   1885 	return (-1);
   1886 }
   1887 
   1888 enum client_theme
   1889 window_pane_get_theme(struct window_pane *wp)
   1890 {
   1891 	struct window		*w;
   1892 	struct client		*loop;
   1893 	enum client_theme	 theme;
   1894 	int			 found_light = 0, found_dark = 0;
   1895 
   1896 	if (wp == NULL)
   1897 		return (THEME_UNKNOWN);
   1898 	w = wp->window;
   1899 
   1900 	/*
   1901 	 * Derive theme from pane background color, if it's not the default
   1902 	 * colour.
   1903 	 */
   1904 	theme = colour_totheme(window_pane_get_bg(wp));
   1905 	if (theme != THEME_UNKNOWN)
   1906 		return (theme);
   1907 
   1908 	/* Try to find a client that has a theme. */
   1909 	TAILQ_FOREACH(loop, &clients, entry) {
   1910 		if (loop->flags & CLIENT_UNATTACHEDFLAGS)
   1911 			continue;
   1912 		if (loop->session == NULL || !session_has(loop->session, w))
   1913 			continue;
   1914 		switch (loop->theme) {
   1915 		case THEME_LIGHT:
   1916 			found_light = 1;
   1917 			break;
   1918 		case THEME_DARK:
   1919 			found_dark = 1;
   1920 			break;
   1921 		case THEME_UNKNOWN:
   1922 			break;
   1923 		}
   1924 	}
   1925 
   1926 	if (found_dark && !found_light)
   1927 		return (THEME_DARK);
   1928 	if (found_light && !found_dark)
   1929 		return (THEME_LIGHT);
   1930 	return (THEME_UNKNOWN);
   1931 }
   1932 
   1933 void
   1934 window_pane_send_theme_update(struct window_pane *wp)
   1935 {
   1936 	if (wp == NULL || window_pane_exited(wp))
   1937 		return;
   1938 	if (~wp->flags & PANE_THEMECHANGED)
   1939 		return;
   1940 	if (~wp->screen->mode & MODE_THEME_UPDATES)
   1941 		return;
   1942 
   1943 	switch (window_pane_get_theme(wp)) {
   1944 	case THEME_LIGHT:
   1945 		input_key_pane(wp, KEYC_REPORT_LIGHT_THEME, NULL);
   1946 		break;
   1947 	case THEME_DARK:
   1948 		input_key_pane(wp, KEYC_REPORT_DARK_THEME, NULL);
   1949 		break;
   1950 	case THEME_UNKNOWN:
   1951 		break;
   1952 	}
   1953 
   1954 	wp->flags &= ~PANE_THEMECHANGED;
   1955 }
   1956