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