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