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