xref: /openbsd-src/usr.bin/tmux/window.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: window.c,v 1.166 2016/09/16 13:43:41 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 <errno.h>
23 #include <fcntl.h>
24 #include <fnmatch.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <termios.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <util.h>
32 
33 #include "tmux.h"
34 
35 /*
36  * Each window is attached to a number of panes, each of which is a pty. This
37  * file contains code to handle them.
38  *
39  * A pane has two buffers attached, these are filled and emptied by the main
40  * server poll loop. Output data is received from pty's in screen format,
41  * translated and returned as a series of escape sequences and strings via
42  * input_parse (in input.c). Input data is received as key codes and written
43  * directly via input_key.
44  *
45  * Each pane also has a "virtual" screen (screen.c) which contains the current
46  * state and is redisplayed when the window is reattached to a client.
47  *
48  * Windows are stored directly on a global array and wrapped in any number of
49  * winlink structs to be linked onto local session RB trees. A reference count
50  * is maintained and a window removed from the global list and destroyed when
51  * it reaches zero.
52  */
53 
54 /* Global window list. */
55 struct windows windows;
56 
57 /* Global panes tree. */
58 struct window_pane_tree all_window_panes;
59 static u_int	next_window_pane_id;
60 static u_int	next_window_id;
61 static u_int	next_active_point;
62 
63 static void	window_pane_set_watermark(struct window_pane *, size_t);
64 
65 static void	window_pane_read_callback(struct bufferevent *, void *);
66 static void	window_pane_error_callback(struct bufferevent *, short, void *);
67 
68 static struct window_pane *window_pane_choose_best(struct window_pane **,
69 		    u_int);
70 
71 RB_GENERATE(windows, window, entry, window_cmp);
72 
73 int
74 window_cmp(struct window *w1, struct window *w2)
75 {
76 	return (w1->id - w2->id);
77 }
78 
79 RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
80 
81 int
82 winlink_cmp(struct winlink *wl1, struct winlink *wl2)
83 {
84 	return (wl1->idx - wl2->idx);
85 }
86 
87 RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
88 
89 int
90 window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2)
91 {
92 	return (wp1->id - wp2->id);
93 }
94 
95 struct winlink *
96 winlink_find_by_window(struct winlinks *wwl, struct window *w)
97 {
98 	struct winlink	*wl;
99 
100 	RB_FOREACH(wl, winlinks, wwl) {
101 		if (wl->window == w)
102 			return (wl);
103 	}
104 
105 	return (NULL);
106 }
107 
108 struct winlink *
109 winlink_find_by_index(struct winlinks *wwl, int idx)
110 {
111 	struct winlink	wl;
112 
113 	if (idx < 0)
114 		fatalx("bad index");
115 
116 	wl.idx = idx;
117 	return (RB_FIND(winlinks, wwl, &wl));
118 }
119 
120 struct winlink *
121 winlink_find_by_window_id(struct winlinks *wwl, u_int id)
122 {
123 	struct winlink *wl;
124 
125 	RB_FOREACH(wl, winlinks, wwl) {
126 		if (wl->window->id == id)
127 			return (wl);
128 	}
129 	return (NULL);
130 }
131 
132 int
133 winlink_next_index(struct winlinks *wwl, int idx)
134 {
135 	int	i;
136 
137 	i = idx;
138 	do {
139 		if (winlink_find_by_index(wwl, i) == NULL)
140 			return (i);
141 		if (i == INT_MAX)
142 			i = 0;
143 		else
144 			i++;
145 	} while (i != idx);
146 	return (-1);
147 }
148 
149 u_int
150 winlink_count(struct winlinks *wwl)
151 {
152 	struct winlink	*wl;
153 	u_int		 n;
154 
155 	n = 0;
156 	RB_FOREACH(wl, winlinks, wwl)
157 		n++;
158 
159 	return (n);
160 }
161 
162 struct winlink *
163 winlink_add(struct winlinks *wwl, int idx)
164 {
165 	struct winlink	*wl;
166 
167 	if (idx < 0) {
168 		if ((idx = winlink_next_index(wwl, -idx - 1)) == -1)
169 			return (NULL);
170 	} else if (winlink_find_by_index(wwl, idx) != NULL)
171 		return (NULL);
172 
173 	wl = xcalloc(1, sizeof *wl);
174 	wl->idx = idx;
175 	RB_INSERT(winlinks, wwl, wl);
176 
177 	return (wl);
178 }
179 
180 void
181 winlink_set_window(struct winlink *wl, struct window *w)
182 {
183 	wl->window = w;
184 	w->references++;
185 }
186 
187 void
188 winlink_remove(struct winlinks *wwl, struct winlink *wl)
189 {
190 	struct window	*w = wl->window;
191 
192 	RB_REMOVE(winlinks, wwl, wl);
193 	free(wl->status_text);
194 	free(wl);
195 
196 	if (w != NULL)
197 		window_remove_ref(w);
198 }
199 
200 struct winlink *
201 winlink_next(struct winlink *wl)
202 {
203 	return (RB_NEXT(winlinks, wwl, wl));
204 }
205 
206 struct winlink *
207 winlink_previous(struct winlink *wl)
208 {
209 	return (RB_PREV(winlinks, wwl, wl));
210 }
211 
212 struct winlink *
213 winlink_next_by_number(struct winlink *wl, struct session *s, int n)
214 {
215 	for (; n > 0; n--) {
216 		if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL)
217 			wl = RB_MIN(winlinks, &s->windows);
218 	}
219 
220 	return (wl);
221 }
222 
223 struct winlink *
224 winlink_previous_by_number(struct winlink *wl, struct session *s, int n)
225 {
226 	for (; n > 0; n--) {
227 		if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL)
228 			wl = RB_MAX(winlinks, &s->windows);
229 	}
230 
231 	return (wl);
232 }
233 
234 void
235 winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
236 {
237 	if (wl == NULL)
238 		return;
239 
240 	winlink_stack_remove(stack, wl);
241 	TAILQ_INSERT_HEAD(stack, wl, sentry);
242 }
243 
244 void
245 winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl)
246 {
247 	struct winlink	*wl2;
248 
249 	if (wl == NULL)
250 		return;
251 
252 	TAILQ_FOREACH(wl2, stack, sentry) {
253 		if (wl2 == wl) {
254 			TAILQ_REMOVE(stack, wl, sentry);
255 			return;
256 		}
257 	}
258 }
259 
260 struct window *
261 window_find_by_id_str(const char *s)
262 {
263 	const char	*errstr;
264 	u_int		 id;
265 
266 	if (*s != '@')
267 		return (NULL);
268 
269 	id = strtonum(s + 1, 0, UINT_MAX, &errstr);
270 	if (errstr != NULL)
271 		return (NULL);
272 	return (window_find_by_id(id));
273 }
274 
275 struct window *
276 window_find_by_id(u_int id)
277 {
278 	struct window	w;
279 
280 	w.id = id;
281 	return (RB_FIND(windows, &windows, &w));
282 }
283 
284 void
285 window_update_activity(struct window *w)
286 {
287 	gettimeofday(&w->activity_time, NULL);
288 	alerts_queue(w, WINDOW_ACTIVITY);
289 }
290 
291 struct window *
292 window_create1(u_int sx, u_int sy)
293 {
294 	struct window	*w;
295 
296 	w = xcalloc(1, sizeof *w);
297 	w->name = NULL;
298 	w->flags = WINDOW_STYLECHANGED;
299 
300 	TAILQ_INIT(&w->panes);
301 	w->active = NULL;
302 
303 	w->lastlayout = -1;
304 	w->layout_root = NULL;
305 
306 	w->sx = sx;
307 	w->sy = sy;
308 
309 	w->options = options_create(global_w_options);
310 
311 	w->references = 0;
312 
313 	w->id = next_window_id++;
314 	RB_INSERT(windows, &windows, w);
315 
316 	window_update_activity(w);
317 
318 	return (w);
319 }
320 
321 struct window *
322 window_create(const char *name, int argc, char **argv, const char *path,
323     const char *shell, const char *cwd, struct environ *env,
324     struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause)
325 {
326 	struct window		*w;
327 	struct window_pane	*wp;
328 
329 	w = window_create1(sx, sy);
330 	wp = window_add_pane(w, NULL, hlimit);
331 	layout_init(w, wp);
332 
333 	if (window_pane_spawn(wp, argc, argv, path, shell, cwd, env, tio,
334 	    cause) != 0) {
335 		window_destroy(w);
336 		return (NULL);
337 	}
338 
339 	w->active = TAILQ_FIRST(&w->panes);
340 	if (name != NULL) {
341 		w->name = xstrdup(name);
342 		options_set_number(w->options, "automatic-rename", 0);
343 	} else
344 		w->name = default_window_name(w);
345 
346 	return (w);
347 }
348 
349 void
350 window_destroy(struct window *w)
351 {
352 	RB_REMOVE(windows, &windows, w);
353 
354 	if (w->layout_root != NULL)
355 		layout_free_cell(w->layout_root);
356 	if (w->saved_layout_root != NULL)
357 		layout_free_cell(w->saved_layout_root);
358 	free(w->old_layout);
359 
360 	if (event_initialized(&w->name_event))
361 		evtimer_del(&w->name_event);
362 
363 	if (event_initialized(&w->alerts_timer))
364 		evtimer_del(&w->alerts_timer);
365 
366 	options_free(w->options);
367 
368 	window_destroy_panes(w);
369 
370 	free(w->name);
371 	free(w);
372 }
373 
374 void
375 window_remove_ref(struct window *w)
376 {
377 	if (w->references == 0)
378 		fatal("bad reference count");
379 	w->references--;
380 	if (w->references == 0)
381 		window_destroy(w);
382 }
383 
384 void
385 window_set_name(struct window *w, const char *new_name)
386 {
387 	free(w->name);
388 	w->name = xstrdup(new_name);
389 	notify_window_renamed(w);
390 }
391 
392 void
393 window_resize(struct window *w, u_int sx, u_int sy)
394 {
395 	w->sx = sx;
396 	w->sy = sy;
397 }
398 
399 int
400 window_has_pane(struct window *w, struct window_pane *wp)
401 {
402 	struct window_pane	*wp1;
403 
404 	TAILQ_FOREACH(wp1, &w->panes, entry) {
405 		if (wp1 == wp)
406 			return (1);
407 	}
408 	return (0);
409 }
410 
411 int
412 window_set_active_pane(struct window *w, struct window_pane *wp)
413 {
414 	if (wp == w->active)
415 		return (0);
416 	w->last = w->active;
417 	w->active = wp;
418 	while (!window_pane_visible(w->active)) {
419 		w->active = TAILQ_PREV(w->active, window_panes, entry);
420 		if (w->active == NULL)
421 			w->active = TAILQ_LAST(&w->panes, window_panes);
422 		if (w->active == wp)
423 			return (1);
424 	}
425 	w->active->active_point = next_active_point++;
426 	w->active->flags |= PANE_CHANGED;
427 	return (1);
428 }
429 
430 void
431 window_redraw_active_switch(struct window *w, struct window_pane *wp)
432 {
433 	const struct grid_cell	*agc, *wgc;
434 
435 	if (wp == w->active)
436 		return;
437 
438 	/*
439 	 * If window-style and window-active-style are the same, we don't need
440 	 * to redraw panes when switching active panes. Otherwise, if the
441 	 * active or inactive pane do not have a custom style, they will need
442 	 * to be redrawn.
443 	 */
444 	agc = options_get_style(w->options, "window-active-style");
445 	wgc = options_get_style(w->options, "window-style");
446 	if (style_equal(agc, wgc))
447 		return;
448 	if (style_equal(&grid_default_cell, &w->active->colgc))
449 		w->active->flags |= PANE_REDRAW;
450 	if (style_equal(&grid_default_cell, &wp->colgc))
451 		wp->flags |= PANE_REDRAW;
452 }
453 
454 struct window_pane *
455 window_get_active_at(struct window *w, u_int x, u_int y)
456 {
457 	struct window_pane	*wp;
458 
459 	TAILQ_FOREACH(wp, &w->panes, entry) {
460 		if (!window_pane_visible(wp))
461 			continue;
462 		if (x < wp->xoff || x > wp->xoff + wp->sx)
463 			continue;
464 		if (y < wp->yoff || y > wp->yoff + wp->sy)
465 			continue;
466 		return (wp);
467 	}
468 	return (NULL);
469 }
470 
471 struct window_pane *
472 window_find_string(struct window *w, const char *s)
473 {
474 	u_int	x, y;
475 
476 	x = w->sx / 2;
477 	y = w->sy / 2;
478 
479 	if (strcasecmp(s, "top") == 0)
480 		y = 0;
481 	else if (strcasecmp(s, "bottom") == 0)
482 		y = w->sy - 1;
483 	else if (strcasecmp(s, "left") == 0)
484 		x = 0;
485 	else if (strcasecmp(s, "right") == 0)
486 		x = w->sx - 1;
487 	else if (strcasecmp(s, "top-left") == 0) {
488 		x = 0;
489 		y = 0;
490 	} else if (strcasecmp(s, "top-right") == 0) {
491 		x = w->sx - 1;
492 		y = 0;
493 	} else if (strcasecmp(s, "bottom-left") == 0) {
494 		x = 0;
495 		y = w->sy - 1;
496 	} else if (strcasecmp(s, "bottom-right") == 0) {
497 		x = w->sx - 1;
498 		y = w->sy - 1;
499 	} else
500 		return (NULL);
501 
502 	return (window_get_active_at(w, x, y));
503 }
504 
505 int
506 window_zoom(struct window_pane *wp)
507 {
508 	struct window		*w = wp->window;
509 	struct window_pane	*wp1;
510 
511 	if (w->flags & WINDOW_ZOOMED)
512 		return (-1);
513 
514 	if (!window_pane_visible(wp))
515 		return (-1);
516 
517 	if (window_count_panes(w) == 1)
518 		return (-1);
519 
520 	if (w->active != wp)
521 		window_set_active_pane(w, wp);
522 
523 	TAILQ_FOREACH(wp1, &w->panes, entry) {
524 		wp1->saved_layout_cell = wp1->layout_cell;
525 		wp1->layout_cell = NULL;
526 	}
527 
528 	w->saved_layout_root = w->layout_root;
529 	layout_init(w, wp);
530 	w->flags |= WINDOW_ZOOMED;
531 	notify_window_layout_changed(w);
532 
533 	return (0);
534 }
535 
536 int
537 window_unzoom(struct window *w)
538 {
539 	struct window_pane	*wp;
540 
541 	if (!(w->flags & WINDOW_ZOOMED))
542 		return (-1);
543 
544 	w->flags &= ~WINDOW_ZOOMED;
545 	layout_free(w);
546 	w->layout_root = w->saved_layout_root;
547 	w->saved_layout_root = NULL;
548 
549 	TAILQ_FOREACH(wp, &w->panes, entry) {
550 		wp->layout_cell = wp->saved_layout_cell;
551 		wp->saved_layout_cell = NULL;
552 	}
553 	layout_fix_panes(w, w->sx, w->sy);
554 	notify_window_layout_changed(w);
555 
556 	return (0);
557 }
558 
559 struct window_pane *
560 window_add_pane(struct window *w, struct window_pane *after, u_int hlimit)
561 {
562 	struct window_pane	*wp;
563 
564 	wp = window_pane_create(w, w->sx, w->sy, hlimit);
565 	if (TAILQ_EMPTY(&w->panes))
566 		TAILQ_INSERT_HEAD(&w->panes, wp, entry);
567 	else {
568 		if (after == NULL)
569 			TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry);
570 		else
571 			TAILQ_INSERT_AFTER(&w->panes, after, wp, entry);
572 	}
573 	return (wp);
574 }
575 
576 void
577 window_lost_pane(struct window *w, struct window_pane *wp)
578 {
579 	if (wp == marked_pane.wp)
580 		server_clear_marked();
581 
582 	if (wp == w->active) {
583 		w->active = w->last;
584 		w->last = NULL;
585 		if (w->active == NULL) {
586 			w->active = TAILQ_PREV(wp, window_panes, entry);
587 			if (w->active == NULL)
588 				w->active = TAILQ_NEXT(wp, entry);
589 		}
590 		if (w->active != NULL)
591 			w->active->flags |= PANE_CHANGED;
592 	} else if (wp == w->last)
593 		w->last = NULL;
594 }
595 
596 void
597 window_remove_pane(struct window *w, struct window_pane *wp)
598 {
599 	window_lost_pane(w, wp);
600 
601 	TAILQ_REMOVE(&w->panes, wp, entry);
602 	window_pane_destroy(wp);
603 }
604 
605 struct window_pane *
606 window_pane_at_index(struct window *w, u_int idx)
607 {
608 	struct window_pane	*wp;
609 	u_int			 n;
610 
611 	n = options_get_number(w->options, "pane-base-index");
612 	TAILQ_FOREACH(wp, &w->panes, entry) {
613 		if (n == idx)
614 			return (wp);
615 		n++;
616 	}
617 	return (NULL);
618 }
619 
620 struct window_pane *
621 window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n)
622 {
623 	for (; n > 0; n--) {
624 		if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
625 			wp = TAILQ_FIRST(&w->panes);
626 	}
627 
628 	return (wp);
629 }
630 
631 struct window_pane *
632 window_pane_previous_by_number(struct window *w, struct window_pane *wp,
633     u_int n)
634 {
635 	for (; n > 0; n--) {
636 		if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL)
637 			wp = TAILQ_LAST(&w->panes, window_panes);
638 	}
639 
640 	return (wp);
641 }
642 
643 int
644 window_pane_index(struct window_pane *wp, u_int *i)
645 {
646 	struct window_pane	*wq;
647 	struct window		*w = wp->window;
648 
649 	*i = options_get_number(w->options, "pane-base-index");
650 	TAILQ_FOREACH(wq, &w->panes, entry) {
651 		if (wp == wq) {
652 			return (0);
653 		}
654 		(*i)++;
655 	}
656 
657 	return (-1);
658 }
659 
660 u_int
661 window_count_panes(struct window *w)
662 {
663 	struct window_pane	*wp;
664 	u_int			 n;
665 
666 	n = 0;
667 	TAILQ_FOREACH(wp, &w->panes, entry)
668 		n++;
669 	return (n);
670 }
671 
672 void
673 window_destroy_panes(struct window *w)
674 {
675 	struct window_pane	*wp;
676 
677 	while (!TAILQ_EMPTY(&w->panes)) {
678 		wp = TAILQ_FIRST(&w->panes);
679 		TAILQ_REMOVE(&w->panes, wp, entry);
680 		window_pane_destroy(wp);
681 	}
682 }
683 
684 /* Retuns the printable flags on a window, empty string if no flags set. */
685 char *
686 window_printable_flags(struct session *s, struct winlink *wl)
687 {
688 	char	flags[32];
689 	int	pos;
690 
691 	pos = 0;
692 	if (wl->flags & WINLINK_ACTIVITY)
693 		flags[pos++] = '#';
694 	if (wl->flags & WINLINK_BELL)
695 		flags[pos++] = '!';
696 	if (wl->flags & WINLINK_SILENCE)
697 		flags[pos++] = '~';
698 	if (wl == s->curw)
699 		flags[pos++] = '*';
700 	if (wl == TAILQ_FIRST(&s->lastw))
701 		flags[pos++] = '-';
702 	if (server_check_marked() && wl == marked_pane.wl)
703 		flags[pos++] = 'M';
704 	if (wl->window->flags & WINDOW_ZOOMED)
705 		flags[pos++] = 'Z';
706 	flags[pos] = '\0';
707 	return (xstrdup(flags));
708 }
709 
710 struct window_pane *
711 window_pane_find_by_id_str(const char *s)
712 {
713 	const char	*errstr;
714 	u_int		 id;
715 
716 	if (*s != '%')
717 		return (NULL);
718 
719 	id = strtonum(s + 1, 0, UINT_MAX, &errstr);
720 	if (errstr != NULL)
721 		return (NULL);
722 	return (window_pane_find_by_id(id));
723 }
724 
725 struct window_pane *
726 window_pane_find_by_id(u_int id)
727 {
728 	struct window_pane	wp;
729 
730 	wp.id = id;
731 	return (RB_FIND(window_pane_tree, &all_window_panes, &wp));
732 }
733 
734 struct window_pane *
735 window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
736 {
737 	struct window_pane	*wp;
738 	char			 host[HOST_NAME_MAX + 1];
739 
740 	wp = xcalloc(1, sizeof *wp);
741 	wp->window = w;
742 
743 	wp->id = next_window_pane_id++;
744 	RB_INSERT(window_pane_tree, &all_window_panes, wp);
745 
746 	wp->argc = 0;
747 	wp->argv = NULL;
748 	wp->shell = NULL;
749 	wp->cwd = NULL;
750 
751 	wp->fd = -1;
752 	wp->event = NULL;
753 
754 	wp->mode = NULL;
755 
756 	wp->layout_cell = NULL;
757 
758 	wp->xoff = 0;
759 	wp->yoff = 0;
760 
761 	wp->sx = sx;
762 	wp->sy = sy;
763 
764 	wp->pipe_fd = -1;
765 	wp->pipe_off = 0;
766 	wp->pipe_event = NULL;
767 
768 	wp->saved_grid = NULL;
769 
770 	memcpy(&wp->colgc, &grid_default_cell, sizeof wp->colgc);
771 
772 	screen_init(&wp->base, sx, sy, hlimit);
773 	wp->screen = &wp->base;
774 
775 	screen_init(&wp->status_screen, 1, 1, 0);
776 
777 	if (gethostname(host, sizeof host) == 0)
778 		screen_set_title(&wp->base, host);
779 
780 	input_init(wp);
781 
782 	return (wp);
783 }
784 
785 void
786 window_pane_destroy(struct window_pane *wp)
787 {
788 	window_pane_reset_mode(wp);
789 
790 	if (wp->fd != -1) {
791 		bufferevent_free(wp->event);
792 		close(wp->fd);
793 	}
794 
795 	input_free(wp);
796 
797 	screen_free(&wp->base);
798 	if (wp->saved_grid != NULL)
799 		grid_destroy(wp->saved_grid);
800 
801 	if (wp->pipe_fd != -1) {
802 		bufferevent_free(wp->pipe_event);
803 		close(wp->pipe_fd);
804 	}
805 
806 	RB_REMOVE(window_pane_tree, &all_window_panes, wp);
807 
808 	free((void *)wp->cwd);
809 	free(wp->shell);
810 	cmd_free_argv(wp->argc, wp->argv);
811 	free(wp);
812 }
813 
814 static void
815 window_pane_set_watermark(struct window_pane *wp, size_t size)
816 {
817 	wp->wmark_hits = 0;
818 	wp->wmark_size = size;
819 	bufferevent_setwatermark(wp->event, EV_READ, 0, size);
820 }
821 
822 int
823 window_pane_spawn(struct window_pane *wp, int argc, char **argv,
824     const char *path, const char *shell, const char *cwd, struct environ *env,
825     struct termios *tio, char **cause)
826 {
827 	struct winsize	 ws;
828 	char		*argv0, *cmd, **argvp;
829 	const char	*ptr, *first, *home;
830 	struct termios	 tio2;
831 	int		 i;
832 
833 	if (wp->fd != -1) {
834 		bufferevent_free(wp->event);
835 		close(wp->fd);
836 	}
837 	if (argc > 0) {
838 		cmd_free_argv(wp->argc, wp->argv);
839 		wp->argc = argc;
840 		wp->argv = cmd_copy_argv(argc, argv);
841 	}
842 	if (shell != NULL) {
843 		free(wp->shell);
844 		wp->shell = xstrdup(shell);
845 	}
846 	if (cwd != NULL) {
847 		free((void *)wp->cwd);
848 		wp->cwd = xstrdup(cwd);
849 	}
850 
851 	cmd = cmd_stringify_argv(wp->argc, wp->argv);
852 	log_debug("spawn: %s -- %s", wp->shell, cmd);
853 	for (i = 0; i < wp->argc; i++)
854 		log_debug("spawn: argv[%d] = %s", i, wp->argv[i]);
855 	environ_log(env, "spawn: ");
856 
857 	memset(&ws, 0, sizeof ws);
858 	ws.ws_col = screen_size_x(&wp->base);
859 	ws.ws_row = screen_size_y(&wp->base);
860 
861 	switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) {
862 	case -1:
863 		wp->fd = -1;
864 		xasprintf(cause, "%s: %s", cmd, strerror(errno));
865 		free(cmd);
866 		return (-1);
867 	case 0:
868 		if (chdir(wp->cwd) != 0) {
869 			if ((home = find_home()) == NULL || chdir(home) != 0)
870 				chdir("/");
871 		}
872 
873 		if (tcgetattr(STDIN_FILENO, &tio2) != 0)
874 			fatal("tcgetattr failed");
875 		if (tio != NULL)
876 			memcpy(tio2.c_cc, tio->c_cc, sizeof tio2.c_cc);
877 		tio2.c_cc[VERASE] = '\177';
878 		if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
879 			fatal("tcgetattr failed");
880 
881 		closefrom(STDERR_FILENO + 1);
882 
883 		if (path != NULL)
884 			environ_set(env, "PATH", "%s", path);
885 		environ_set(env, "TMUX_PANE", "%%%u", wp->id);
886 		environ_push(env);
887 
888 		clear_signals(1);
889 		log_close();
890 
891 		setenv("SHELL", wp->shell, 1);
892 		ptr = strrchr(wp->shell, '/');
893 
894 		/*
895 		 * If given one argument, assume it should be passed to sh -c;
896 		 * with more than one argument, use execvp(). If there is no
897 		 * arguments, create a login shell.
898 		 */
899 		if (wp->argc > 0) {
900 			if (wp->argc != 1) {
901 				/* Copy to ensure argv ends in NULL. */
902 				argvp = cmd_copy_argv(wp->argc, wp->argv);
903 				execvp(argvp[0], argvp);
904 				fatal("execvp failed");
905 			}
906 			first = wp->argv[0];
907 
908 			if (ptr != NULL && *(ptr + 1) != '\0')
909 				xasprintf(&argv0, "%s", ptr + 1);
910 			else
911 				xasprintf(&argv0, "%s", wp->shell);
912 			execl(wp->shell, argv0, "-c", first, (char *)NULL);
913 			fatal("execl failed");
914 		}
915 		if (ptr != NULL && *(ptr + 1) != '\0')
916 			xasprintf(&argv0, "-%s", ptr + 1);
917 		else
918 			xasprintf(&argv0, "-%s", wp->shell);
919 		execl(wp->shell, argv0, (char *)NULL);
920 		fatal("execl failed");
921 	}
922 
923 	setblocking(wp->fd, 0);
924 
925 	wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
926 	    window_pane_error_callback, wp);
927 
928 	window_pane_set_watermark(wp, READ_FAST_SIZE);
929 	bufferevent_enable(wp->event, EV_READ|EV_WRITE);
930 
931 	free(cmd);
932 	return (0);
933 }
934 
935 static void
936 window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
937 {
938 	struct window_pane	*wp = data;
939 	struct evbuffer		*evb = wp->event->input;
940 	size_t			 size = EVBUFFER_LENGTH(evb);
941 	char			*new_data;
942 	size_t			 new_size;
943 
944 	if (wp->wmark_size == READ_FAST_SIZE) {
945 		if (size > READ_FULL_SIZE)
946 			wp->wmark_hits++;
947 		if (wp->wmark_hits == READ_CHANGE_HITS)
948 			window_pane_set_watermark(wp, READ_SLOW_SIZE);
949 	} else if (wp->wmark_size == READ_SLOW_SIZE) {
950 		if (size < READ_EMPTY_SIZE)
951 			wp->wmark_hits++;
952 		if (wp->wmark_hits == READ_CHANGE_HITS)
953 			window_pane_set_watermark(wp, READ_FAST_SIZE);
954 	}
955 	log_debug("%%%u has %zu bytes (of %u, %u hits)", wp->id, size,
956 	    wp->wmark_size, wp->wmark_hits);
957 
958 	new_size = size - wp->pipe_off;
959 	if (wp->pipe_fd != -1 && new_size > 0) {
960 		new_data = EVBUFFER_DATA(evb) + wp->pipe_off;
961 		bufferevent_write(wp->pipe_event, new_data, new_size);
962 	}
963 
964 	input_parse(wp);
965 
966 	wp->pipe_off = size;
967 }
968 
969 static void
970 window_pane_error_callback(__unused struct bufferevent *bufev,
971     __unused short what, void *data)
972 {
973 	struct window_pane *wp = data;
974 
975 	server_destroy_pane(wp, 1);
976 }
977 
978 void
979 window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
980 {
981 	if (sx == wp->sx && sy == wp->sy)
982 		return;
983 	wp->sx = sx;
984 	wp->sy = sy;
985 
986 	screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL);
987 	if (wp->mode != NULL)
988 		wp->mode->resize(wp, sx, sy);
989 
990 	wp->flags |= PANE_RESIZE;
991 }
992 
993 /*
994  * Enter alternative screen mode. A copy of the visible screen is saved and the
995  * history is not updated
996  */
997 void
998 window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc,
999     int cursor)
1000 {
1001 	struct screen	*s = &wp->base;
1002 	u_int		 sx, sy;
1003 
1004 	if (wp->saved_grid != NULL)
1005 		return;
1006 	if (!options_get_number(wp->window->options, "alternate-screen"))
1007 		return;
1008 	sx = screen_size_x(s);
1009 	sy = screen_size_y(s);
1010 
1011 	wp->saved_grid = grid_create(sx, sy, 0);
1012 	grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
1013 	if (cursor) {
1014 		wp->saved_cx = s->cx;
1015 		wp->saved_cy = s->cy;
1016 	}
1017 	memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell);
1018 
1019 	grid_view_clear(s->grid, 0, 0, sx, sy);
1020 
1021 	wp->base.grid->flags &= ~GRID_HISTORY;
1022 
1023 	wp->flags |= PANE_REDRAW;
1024 }
1025 
1026 /* Exit alternate screen mode and restore the copied grid. */
1027 void
1028 window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc,
1029     int cursor)
1030 {
1031 	struct screen	*s = &wp->base;
1032 	u_int		 sx, sy;
1033 
1034 	if (wp->saved_grid == NULL)
1035 		return;
1036 	if (!options_get_number(wp->window->options, "alternate-screen"))
1037 		return;
1038 	sx = screen_size_x(s);
1039 	sy = screen_size_y(s);
1040 
1041 	/*
1042 	 * If the current size is bigger, temporarily resize to the old size
1043 	 * before copying back.
1044 	 */
1045 	if (sy > wp->saved_grid->sy)
1046 		screen_resize(s, sx, wp->saved_grid->sy, 1);
1047 
1048 	/* Restore the grid, cursor position and cell. */
1049 	grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
1050 	if (cursor)
1051 		s->cx = wp->saved_cx;
1052 	if (s->cx > screen_size_x(s) - 1)
1053 		s->cx = screen_size_x(s) - 1;
1054 	if (cursor)
1055 		s->cy = wp->saved_cy;
1056 	if (s->cy > screen_size_y(s) - 1)
1057 		s->cy = screen_size_y(s) - 1;
1058 	memcpy(gc, &wp->saved_cell, sizeof *gc);
1059 
1060 	/*
1061 	 * Turn history back on (so resize can use it) and then resize back to
1062 	 * the current size.
1063 	 */
1064 	wp->base.grid->flags |= GRID_HISTORY;
1065 	if (sy > wp->saved_grid->sy || sx != wp->saved_grid->sx)
1066 		screen_resize(s, sx, sy, 1);
1067 
1068 	grid_destroy(wp->saved_grid);
1069 	wp->saved_grid = NULL;
1070 
1071 	wp->flags |= PANE_REDRAW;
1072 }
1073 
1074 static void
1075 window_pane_mode_timer(__unused int fd, __unused short events, void *arg)
1076 {
1077 	struct window_pane	*wp = arg;
1078 	struct timeval		 tv = { .tv_sec = 10 };
1079 	int			 n = 0;
1080 
1081 	evtimer_del(&wp->modetimer);
1082 	evtimer_add(&wp->modetimer, &tv);
1083 
1084 	log_debug("%%%u in mode: last=%ld", wp->id, (long)wp->modelast);
1085 
1086 	if (wp->modelast < time(NULL) - WINDOW_MODE_TIMEOUT) {
1087 		if (ioctl(wp->fd, FIONREAD, &n) == -1 || n > 0)
1088 			window_pane_reset_mode(wp);
1089 	}
1090 }
1091 
1092 int
1093 window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
1094 {
1095 	struct screen	*s;
1096 	struct timeval	 tv = { .tv_sec = 10 };
1097 
1098 	if (wp->mode != NULL)
1099 		return (1);
1100 	wp->mode = mode;
1101 
1102 	wp->modelast = time(NULL);
1103 	evtimer_set(&wp->modetimer, window_pane_mode_timer, wp);
1104 	evtimer_add(&wp->modetimer, &tv);
1105 
1106 	if ((s = wp->mode->init(wp)) != NULL)
1107 		wp->screen = s;
1108 	wp->flags |= (PANE_REDRAW|PANE_CHANGED);
1109 
1110 	server_status_window(wp->window);
1111 	return (0);
1112 }
1113 
1114 void
1115 window_pane_reset_mode(struct window_pane *wp)
1116 {
1117 	if (wp->mode == NULL)
1118 		return;
1119 
1120 	evtimer_del(&wp->modetimer);
1121 
1122 	wp->mode->free(wp);
1123 	wp->mode = NULL;
1124 
1125 	wp->screen = &wp->base;
1126 	wp->flags |= (PANE_REDRAW|PANE_CHANGED);
1127 
1128 	server_status_window(wp->window);
1129 }
1130 
1131 void
1132 window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
1133     key_code key, struct mouse_event *m)
1134 {
1135 	struct window_pane	*wp2;
1136 
1137 	if (KEYC_IS_MOUSE(key) && m == NULL)
1138 		return;
1139 
1140 	if (wp->mode != NULL) {
1141 		wp->modelast = time(NULL);
1142 		if (wp->mode->key != NULL)
1143 			wp->mode->key(wp, c, s, key, m);
1144 		return;
1145 	}
1146 
1147 	if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
1148 		return;
1149 
1150 	input_key(wp, key, m);
1151 
1152 	if (KEYC_IS_MOUSE(key))
1153 		return;
1154 	if (options_get_number(wp->window->options, "synchronize-panes")) {
1155 		TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
1156 			if (wp2 == wp || wp2->mode != NULL)
1157 				continue;
1158 			if (wp2->fd == -1 || wp2->flags & PANE_INPUTOFF)
1159 				continue;
1160 			if (window_pane_visible(wp2))
1161 				input_key(wp2, key, NULL);
1162 		}
1163 	}
1164 }
1165 
1166 int
1167 window_pane_visible(struct window_pane *wp)
1168 {
1169 	struct window	*w = wp->window;
1170 
1171 	if (wp->layout_cell == NULL)
1172 		return (0);
1173 	if (wp->xoff >= w->sx || wp->yoff >= w->sy)
1174 		return (0);
1175 	if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
1176 		return (0);
1177 	return (1);
1178 }
1179 
1180 char *
1181 window_pane_search(struct window_pane *wp, const char *searchstr,
1182     u_int *lineno)
1183 {
1184 	struct screen	*s = &wp->base;
1185 	char		*newsearchstr, *line, *msg;
1186 	u_int	 	 i;
1187 
1188 	msg = NULL;
1189 	xasprintf(&newsearchstr, "*%s*", searchstr);
1190 
1191 	for (i = 0; i < screen_size_y(s); i++) {
1192 		line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s));
1193 		if (fnmatch(newsearchstr, line, 0) == 0) {
1194 			msg = line;
1195 			if (lineno != NULL)
1196 				*lineno = i;
1197 			break;
1198 		}
1199 		free(line);
1200 	}
1201 
1202 	free(newsearchstr);
1203 	return (msg);
1204 }
1205 
1206 /* Get MRU pane from a list. */
1207 static struct window_pane *
1208 window_pane_choose_best(struct window_pane **list, u_int size)
1209 {
1210 	struct window_pane	*next, *best;
1211 	u_int			 i;
1212 
1213 	if (size == 0)
1214 		return (NULL);
1215 
1216 	best = list[0];
1217 	for (i = 1; i < size; i++) {
1218 		next = list[i];
1219 		if (next->active_point > best->active_point)
1220 			best = next;
1221 	}
1222 	return (best);
1223 }
1224 
1225 /*
1226  * Find the pane directly above another. We build a list of those adjacent to
1227  * top edge and then choose the best.
1228  */
1229 struct window_pane *
1230 window_pane_find_up(struct window_pane *wp)
1231 {
1232 	struct window_pane	*next, *best, **list;
1233 	u_int			 edge, left, right, end, size;
1234 	int			 found;
1235 
1236 	if (wp == NULL || !window_pane_visible(wp))
1237 		return (NULL);
1238 
1239 	list = NULL;
1240 	size = 0;
1241 
1242 	edge = wp->yoff;
1243 	if (edge == 0)
1244 		edge = wp->window->sy + 1;
1245 
1246 	left = wp->xoff;
1247 	right = wp->xoff + wp->sx;
1248 
1249 	TAILQ_FOREACH(next, &wp->window->panes, entry) {
1250 		if (next == wp || !window_pane_visible(next))
1251 			continue;
1252 		if (next->yoff + next->sy + 1 != edge)
1253 			continue;
1254 		end = next->xoff + next->sx - 1;
1255 
1256 		found = 0;
1257 		if (next->xoff < left && end > right)
1258 			found = 1;
1259 		else if (next->xoff >= left && next->xoff <= right)
1260 			found = 1;
1261 		else if (end >= left && end <= right)
1262 			found = 1;
1263 		if (!found)
1264 			continue;
1265 		list = xreallocarray(list, size + 1, sizeof *list);
1266 		list[size++] = next;
1267 	}
1268 
1269 	best = window_pane_choose_best(list, size);
1270 	free(list);
1271 	return (best);
1272 }
1273 
1274 /* Find the pane directly below another. */
1275 struct window_pane *
1276 window_pane_find_down(struct window_pane *wp)
1277 {
1278 	struct window_pane	*next, *best, **list;
1279 	u_int			 edge, left, right, end, size;
1280 	int			 found;
1281 
1282 	if (wp == NULL || !window_pane_visible(wp))
1283 		return (NULL);
1284 
1285 	list = NULL;
1286 	size = 0;
1287 
1288 	edge = wp->yoff + wp->sy + 1;
1289 	if (edge >= wp->window->sy)
1290 		edge = 0;
1291 
1292 	left = wp->xoff;
1293 	right = wp->xoff + wp->sx;
1294 
1295 	TAILQ_FOREACH(next, &wp->window->panes, entry) {
1296 		if (next == wp || !window_pane_visible(next))
1297 			continue;
1298 		if (next->yoff != 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 to the left of another. */
1321 struct window_pane *
1322 window_pane_find_left(struct window_pane *wp)
1323 {
1324 	struct window_pane	*next, *best, **list;
1325 	u_int			 edge, top, bottom, end, size;
1326 	int			 found;
1327 
1328 	if (wp == NULL || !window_pane_visible(wp))
1329 		return (NULL);
1330 
1331 	list = NULL;
1332 	size = 0;
1333 
1334 	edge = wp->xoff;
1335 	if (edge == 0)
1336 		edge = wp->window->sx + 1;
1337 
1338 	top = wp->yoff;
1339 	bottom = wp->yoff + wp->sy;
1340 
1341 	TAILQ_FOREACH(next, &wp->window->panes, entry) {
1342 		if (next == wp || !window_pane_visible(next))
1343 			continue;
1344 		if (next->xoff + next->sx + 1 != edge)
1345 			continue;
1346 		end = next->yoff + next->sy - 1;
1347 
1348 		found = 0;
1349 		if (next->yoff < top && end > bottom)
1350 			found = 1;
1351 		else if (next->yoff >= top && next->yoff <= bottom)
1352 			found = 1;
1353 		else if (end >= top && end <= bottom)
1354 			found = 1;
1355 		if (!found)
1356 			continue;
1357 		list = xreallocarray(list, size + 1, sizeof *list);
1358 		list[size++] = next;
1359 	}
1360 
1361 	best = window_pane_choose_best(list, size);
1362 	free(list);
1363 	return (best);
1364 }
1365 
1366 /* Find the pane directly to the right of another. */
1367 struct window_pane *
1368 window_pane_find_right(struct window_pane *wp)
1369 {
1370 	struct window_pane	*next, *best, **list;
1371 	u_int			 edge, top, bottom, end, size;
1372 	int			 found;
1373 
1374 	if (wp == NULL || !window_pane_visible(wp))
1375 		return (NULL);
1376 
1377 	list = NULL;
1378 	size = 0;
1379 
1380 	edge = wp->xoff + wp->sx + 1;
1381 	if (edge >= wp->window->sx)
1382 		edge = 0;
1383 
1384 	top = wp->yoff;
1385 	bottom = wp->yoff + wp->sy;
1386 
1387 	TAILQ_FOREACH(next, &wp->window->panes, entry) {
1388 		if (next == wp || !window_pane_visible(next))
1389 			continue;
1390 		if (next->xoff != edge)
1391 			continue;
1392 		end = next->yoff + next->sy - 1;
1393 
1394 		found = 0;
1395 		if (next->yoff < top && end > bottom)
1396 			found = 1;
1397 		else if (next->yoff >= top && next->yoff <= bottom)
1398 			found = 1;
1399 		else if (end >= top && end <= bottom)
1400 			found = 1;
1401 		if (!found)
1402 			continue;
1403 		list = xreallocarray(list, size + 1, sizeof *list);
1404 		list[size++] = next;
1405 	}
1406 
1407 	best = window_pane_choose_best(list, size);
1408 	free(list);
1409 	return (best);
1410 }
1411 
1412 /* Clear alert flags for a winlink */
1413 void
1414 winlink_clear_flags(struct winlink *wl)
1415 {
1416 	struct session	*s;
1417 	struct winlink	*wl_loop;
1418 
1419 	RB_FOREACH(s, sessions, &sessions) {
1420 		RB_FOREACH(wl_loop, winlinks, &s->windows) {
1421 			if (wl_loop->window != wl->window)
1422 				continue;
1423 			if ((wl_loop->flags & WINLINK_ALERTFLAGS) == 0)
1424 				continue;
1425 
1426 			wl_loop->flags &= ~WINLINK_ALERTFLAGS;
1427 			wl_loop->window->flags &= ~WINDOW_ALERTFLAGS;
1428 			server_status_session(s);
1429 		}
1430 	}
1431 }
1432 
1433 int
1434 winlink_shuffle_up(struct session *s, struct winlink *wl)
1435 {
1436 	int	 idx, last;
1437 
1438 	idx = wl->idx + 1;
1439 
1440 	/* Find the next free index. */
1441 	for (last = idx; last < INT_MAX; last++) {
1442 		if (winlink_find_by_index(&s->windows, last) == NULL)
1443 			break;
1444 	}
1445 	if (last == INT_MAX)
1446 		return (-1);
1447 
1448 	/* Move everything from last - 1 to idx up a bit. */
1449 	for (; last > idx; last--) {
1450 		wl = winlink_find_by_index(&s->windows, last - 1);
1451 		server_link_window(s, wl, s, last, 0, 0, NULL);
1452 		server_unlink_window(s, wl);
1453 	}
1454 
1455 	return (idx);
1456 }
1457