Home | History | Annotate | Line # | Download | only in dist
      1   1.1  christos /* $OpenBSD$ */
      2   1.1  christos 
      3   1.1  christos /*
      4   1.1  christos  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5   1.1  christos  *
      6   1.1  christos  * Permission to use, copy, modify, and distribute this software for any
      7   1.1  christos  * purpose with or without fee is hereby granted, provided that the above
      8   1.1  christos  * copyright notice and this permission notice appear in all copies.
      9   1.1  christos  *
     10   1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11   1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12   1.1  christos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13   1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14   1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15   1.1  christos  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16   1.1  christos  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17   1.1  christos  */
     18   1.1  christos 
     19   1.1  christos #include <sys/types.h>
     20   1.1  christos 
     21   1.3  christos #include <ctype.h>
     22   1.1  christos #include <stdlib.h>
     23   1.1  christos #include <string.h>
     24   1.1  christos 
     25   1.1  christos #include "tmux.h"
     26   1.1  christos 
     27   1.5  christos static struct screen	*window_tree_init(struct window_mode_entry *,
     28   1.1  christos 			     struct cmd_find_state *, struct args *);
     29   1.5  christos static void		 window_tree_free(struct window_mode_entry *);
     30   1.5  christos static void		 window_tree_resize(struct window_mode_entry *, u_int,
     31   1.5  christos 			     u_int);
     32   1.8  christos static void		 window_tree_update(struct window_mode_entry *);
     33   1.5  christos static void		 window_tree_key(struct window_mode_entry *,
     34   1.5  christos 			     struct client *, struct session *,
     35   1.5  christos 			     struct winlink *, key_code, struct mouse_event *);
     36   1.1  christos 
     37   1.7  christos #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -Zt '%%'"
     38   1.1  christos 
     39   1.1  christos #define WINDOW_TREE_DEFAULT_FORMAT \
     40   1.1  christos 	"#{?pane_format," \
     41   1.8  christos 		"#{?pane_marked,#[reverse],}" \
     42   1.8  christos 		"#{pane_current_command}#{?pane_active,*,}#{?pane_marked,M,}" \
     43   1.8  christos 		"#{?#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}},: \"#{pane_title}\",}" \
     44  1.12       wiz 	",window_format," \
     45  1.12       wiz 		"#{?window_marked_flag,#[reverse],}" \
     46  1.12       wiz 		"#{window_name}#{window_flags}" \
     47  1.12       wiz 		"#{?#{&&:#{==:#{window_panes},1},#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}}},: \"#{pane_title}\",}" \
     48   1.1  christos 	"," \
     49  1.12       wiz 		"#{session_windows} windows" \
     50  1.12       wiz 		"#{?session_grouped, " \
     51  1.12       wiz 			"(group #{session_group}: " \
     52  1.12       wiz 			"#{session_group_list})," \
     53   1.1  christos 		"}" \
     54  1.12       wiz 		"#{?session_attached, (attached),}" \
     55   1.1  christos 	"}"
     56   1.1  christos 
     57   1.8  christos #define WINDOW_TREE_DEFAULT_KEY_FORMAT \
     58   1.8  christos 	"#{?#{e|<:#{line},10}," \
     59   1.8  christos 		"#{line}" \
     60  1.12       wiz 	",#{e|<:#{line},36},"	\
     61  1.12       wiz 	        "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
     62   1.8  christos 	"}"
     63   1.8  christos 
     64   1.6  christos static const struct menu_item window_tree_menu_items[] = {
     65   1.8  christos 	{ "Select", '\r', NULL },
     66   1.8  christos 	{ "Expand", KEYC_RIGHT, NULL },
     67   1.8  christos 	{ "Mark", 'm', NULL },
     68   1.6  christos 	{ "", KEYC_NONE, NULL },
     69   1.6  christos 	{ "Tag", 't', NULL },
     70   1.6  christos 	{ "Tag All", '\024', NULL },
     71   1.6  christos 	{ "Tag None", 'T', NULL },
     72   1.6  christos 	{ "", KEYC_NONE, NULL },
     73   1.6  christos 	{ "Kill", 'x', NULL },
     74   1.6  christos 	{ "Kill Tagged", 'X', NULL },
     75   1.6  christos 	{ "", KEYC_NONE, NULL },
     76   1.6  christos 	{ "Cancel", 'q', NULL },
     77   1.6  christos 
     78   1.6  christos 	{ NULL, KEYC_NONE, NULL }
     79   1.6  christos };
     80   1.6  christos 
     81   1.1  christos const struct window_mode window_tree_mode = {
     82   1.1  christos 	.name = "tree-mode",
     83   1.5  christos 	.default_format = WINDOW_TREE_DEFAULT_FORMAT,
     84   1.1  christos 
     85   1.1  christos 	.init = window_tree_init,
     86   1.1  christos 	.free = window_tree_free,
     87   1.1  christos 	.resize = window_tree_resize,
     88   1.8  christos 	.update = window_tree_update,
     89   1.1  christos 	.key = window_tree_key,
     90   1.1  christos };
     91   1.1  christos 
     92   1.1  christos enum window_tree_sort_type {
     93   1.1  christos 	WINDOW_TREE_BY_INDEX,
     94   1.1  christos 	WINDOW_TREE_BY_NAME,
     95   1.1  christos 	WINDOW_TREE_BY_TIME,
     96   1.1  christos };
     97   1.1  christos static const char *window_tree_sort_list[] = {
     98   1.1  christos 	"index",
     99   1.1  christos 	"name",
    100   1.1  christos 	"time"
    101   1.1  christos };
    102   1.7  christos static struct mode_tree_sort_criteria *window_tree_sort;
    103   1.1  christos 
    104   1.1  christos enum window_tree_type {
    105   1.1  christos 	WINDOW_TREE_NONE,
    106   1.1  christos 	WINDOW_TREE_SESSION,
    107   1.1  christos 	WINDOW_TREE_WINDOW,
    108   1.1  christos 	WINDOW_TREE_PANE,
    109   1.1  christos };
    110   1.1  christos 
    111   1.1  christos struct window_tree_itemdata {
    112   1.1  christos 	enum window_tree_type	type;
    113   1.1  christos 	int			session;
    114   1.1  christos 	int			winlink;
    115   1.1  christos 	int			pane;
    116   1.1  christos };
    117   1.1  christos 
    118   1.1  christos struct window_tree_modedata {
    119   1.1  christos 	struct window_pane		 *wp;
    120   1.1  christos 	int				  dead;
    121   1.1  christos 	int				  references;
    122   1.1  christos 
    123   1.1  christos 	struct mode_tree_data		 *data;
    124   1.1  christos 	char				 *format;
    125   1.8  christos 	char				 *key_format;
    126   1.1  christos 	char				 *command;
    127   1.3  christos 	int				  squash_groups;
    128  1.12       wiz 	int				  prompt_flags;
    129   1.1  christos 
    130   1.1  christos 	struct window_tree_itemdata	**item_list;
    131   1.1  christos 	u_int				  item_size;
    132   1.1  christos 
    133   1.1  christos 	const char			 *entered;
    134   1.1  christos 
    135   1.1  christos 	struct cmd_find_state		  fs;
    136   1.1  christos 	enum window_tree_type		  type;
    137   1.1  christos 
    138   1.1  christos 	int				  offset;
    139   1.3  christos 
    140   1.3  christos 	int				  left;
    141   1.3  christos 	int				  right;
    142   1.3  christos 	u_int				  start;
    143   1.3  christos 	u_int				  end;
    144   1.3  christos 	u_int				  each;
    145   1.1  christos };
    146   1.1  christos 
    147   1.1  christos static void
    148   1.1  christos window_tree_pull_item(struct window_tree_itemdata *item, struct session **sp,
    149   1.1  christos     struct winlink **wlp, struct window_pane **wp)
    150   1.1  christos {
    151   1.1  christos 	*wp = NULL;
    152   1.1  christos 	*wlp = NULL;
    153   1.1  christos 	*sp = session_find_by_id(item->session);
    154   1.1  christos 	if (*sp == NULL)
    155   1.1  christos 		return;
    156   1.1  christos 	if (item->type == WINDOW_TREE_SESSION) {
    157   1.1  christos 		*wlp = (*sp)->curw;
    158   1.1  christos 		*wp = (*wlp)->window->active;
    159   1.1  christos 		return;
    160   1.1  christos 	}
    161   1.1  christos 
    162   1.1  christos 	*wlp = winlink_find_by_index(&(*sp)->windows, item->winlink);
    163   1.1  christos 	if (*wlp == NULL) {
    164   1.1  christos 		*sp = NULL;
    165   1.1  christos 		return;
    166   1.1  christos 	}
    167   1.1  christos 	if (item->type == WINDOW_TREE_WINDOW) {
    168   1.1  christos 		*wp = (*wlp)->window->active;
    169   1.1  christos 		return;
    170   1.1  christos 	}
    171   1.1  christos 
    172   1.1  christos 	*wp = window_pane_find_by_id(item->pane);
    173   1.1  christos 	if (!window_has_pane((*wlp)->window, *wp))
    174   1.1  christos 		*wp = NULL;
    175   1.1  christos 	if (*wp == NULL) {
    176   1.1  christos 		*sp = NULL;
    177   1.1  christos 		*wlp = NULL;
    178   1.1  christos 		return;
    179   1.1  christos 	}
    180   1.1  christos }
    181   1.1  christos 
    182   1.1  christos static struct window_tree_itemdata *
    183   1.1  christos window_tree_add_item(struct window_tree_modedata *data)
    184   1.1  christos {
    185   1.1  christos 	struct window_tree_itemdata	*item;
    186   1.1  christos 
    187   1.1  christos 	data->item_list = xreallocarray(data->item_list, data->item_size + 1,
    188   1.1  christos 	    sizeof *data->item_list);
    189   1.1  christos 	item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
    190   1.1  christos 	return (item);
    191   1.1  christos }
    192   1.1  christos 
    193   1.1  christos static void
    194   1.1  christos window_tree_free_item(struct window_tree_itemdata *item)
    195   1.1  christos {
    196   1.1  christos 	free(item);
    197   1.1  christos }
    198   1.1  christos 
    199   1.1  christos static int
    200   1.7  christos window_tree_cmp_session(const void *a0, const void *b0)
    201   1.1  christos {
    202   1.7  christos 	const struct session *const	*a = a0;
    203   1.7  christos 	const struct session *const	*b = b0;
    204   1.7  christos 	const struct session		*sa = *a;
    205   1.7  christos 	const struct session		*sb = *b;
    206   1.7  christos 	int				 result = 0;
    207   1.1  christos 
    208   1.7  christos 	switch (window_tree_sort->field) {
    209   1.7  christos 	case WINDOW_TREE_BY_INDEX:
    210   1.7  christos 		result = sa->id - sb->id;
    211   1.7  christos 		break;
    212   1.7  christos 	case WINDOW_TREE_BY_TIME:
    213   1.7  christos 		if (timercmp(&sa->activity_time, &sb->activity_time, >)) {
    214   1.7  christos 			result = -1;
    215   1.7  christos 			break;
    216   1.7  christos 		}
    217   1.7  christos 		if (timercmp(&sa->activity_time, &sb->activity_time, <)) {
    218   1.7  christos 			result = 1;
    219   1.7  christos 			break;
    220   1.7  christos 		}
    221   1.7  christos 		/* FALLTHROUGH */
    222   1.7  christos 	case WINDOW_TREE_BY_NAME:
    223   1.7  christos 		result = strcmp(sa->name, sb->name);
    224   1.7  christos 		break;
    225   1.7  christos 	}
    226   1.1  christos 
    227   1.7  christos 	if (window_tree_sort->reversed)
    228   1.7  christos 		result = -result;
    229   1.7  christos 	return (result);
    230   1.1  christos }
    231   1.1  christos 
    232   1.1  christos static int
    233   1.7  christos window_tree_cmp_window(const void *a0, const void *b0)
    234   1.1  christos {
    235   1.7  christos 	const struct winlink *const	*a = a0;
    236   1.7  christos 	const struct winlink *const	*b = b0;
    237   1.7  christos 	const struct winlink		*wla = *a;
    238   1.7  christos 	const struct winlink		*wlb = *b;
    239   1.7  christos 	struct window			*wa = wla->window;
    240   1.7  christos 	struct window			*wb = wlb->window;
    241   1.7  christos 	int				 result = 0;
    242   1.1  christos 
    243   1.7  christos 	switch (window_tree_sort->field) {
    244   1.7  christos 	case WINDOW_TREE_BY_INDEX:
    245   1.7  christos 		result = wla->idx - wlb->idx;
    246   1.7  christos 		break;
    247   1.7  christos 	case WINDOW_TREE_BY_TIME:
    248   1.7  christos 		if (timercmp(&wa->activity_time, &wb->activity_time, >)) {
    249   1.7  christos 			result = -1;
    250   1.7  christos 			break;
    251   1.7  christos 		}
    252   1.7  christos 		if (timercmp(&wa->activity_time, &wb->activity_time, <)) {
    253   1.7  christos 			result = 1;
    254   1.7  christos 			break;
    255   1.7  christos 		}
    256   1.7  christos 		/* FALLTHROUGH */
    257   1.7  christos 	case WINDOW_TREE_BY_NAME:
    258   1.7  christos 		result = strcmp(wa->name, wb->name);
    259   1.7  christos 		break;
    260   1.7  christos 	}
    261   1.1  christos 
    262   1.7  christos 	if (window_tree_sort->reversed)
    263   1.7  christos 		result = -result;
    264   1.7  christos 	return (result);
    265   1.1  christos }
    266   1.1  christos 
    267   1.1  christos static int
    268   1.7  christos window_tree_cmp_pane(const void *a0, const void *b0)
    269   1.1  christos {
    270  1.11       wiz 	struct window_pane	**a = (struct window_pane **)__UNCONST(a0);
    271  1.11       wiz 	struct window_pane	**b = (struct window_pane **)__UNCONST(b0);
    272  1.11       wiz 	int			  result;
    273  1.11       wiz 	u_int			  ai, bi;
    274   1.1  christos 
    275   1.7  christos 	if (window_tree_sort->field == WINDOW_TREE_BY_TIME)
    276   1.7  christos 		result = (*a)->active_point - (*b)->active_point;
    277   1.7  christos 	else {
    278   1.7  christos 		/*
    279   1.7  christos 		 * Panes don't have names, so use number order for any other
    280   1.7  christos 		 * sort field.
    281   1.7  christos 		 */
    282  1.11       wiz 		window_pane_index(*a, &ai);
    283  1.11       wiz 		window_pane_index(*b, &bi);
    284  1.11       wiz 		result = ai - bi;
    285   1.7  christos 	}
    286   1.7  christos 	if (window_tree_sort->reversed)
    287   1.7  christos 		result = -result;
    288   1.7  christos 	return (result);
    289   1.1  christos }
    290   1.1  christos 
    291   1.1  christos static void
    292   1.1  christos window_tree_build_pane(struct session *s, struct winlink *wl,
    293   1.1  christos     struct window_pane *wp, void *modedata, struct mode_tree_item *parent)
    294   1.1  christos {
    295   1.1  christos 	struct window_tree_modedata	*data = modedata;
    296   1.1  christos 	struct window_tree_itemdata	*item;
    297  1.12       wiz 	struct mode_tree_item		*mti;
    298   1.1  christos 	char				*name, *text;
    299   1.1  christos 	u_int				 idx;
    300  1.12       wiz 	struct format_tree		*ft;
    301   1.1  christos 
    302   1.1  christos 	window_pane_index(wp, &idx);
    303   1.1  christos 
    304   1.1  christos 	item = window_tree_add_item(data);
    305   1.1  christos 	item->type = WINDOW_TREE_PANE;
    306   1.1  christos 	item->session = s->id;
    307   1.1  christos 	item->winlink = wl->idx;
    308   1.1  christos 	item->pane = wp->id;
    309   1.1  christos 
    310  1.12       wiz 	ft = format_create(NULL, NULL, FORMAT_PANE|wp->id, 0);
    311  1.12       wiz 	format_defaults(ft, NULL, s, wl, wp);
    312  1.12       wiz 	text = format_expand(ft, data->format);
    313   1.1  christos 	xasprintf(&name, "%u", idx);
    314  1.12       wiz 	format_free(ft);
    315   1.1  christos 
    316  1.12       wiz 	mti = mode_tree_add(data->data, parent, item, (uintptr_t)wp, name, text,
    317  1.12       wiz 	    -1);
    318   1.1  christos 	free(text);
    319   1.1  christos 	free(name);
    320  1.12       wiz 	mode_tree_align(mti, 1);
    321   1.1  christos }
    322   1.1  christos 
    323   1.1  christos static int
    324   1.1  christos window_tree_filter_pane(struct session *s, struct winlink *wl,
    325   1.1  christos     struct window_pane *wp, const char *filter)
    326   1.1  christos {
    327   1.1  christos 	char	*cp;
    328   1.1  christos 	int	 result;
    329   1.1  christos 
    330   1.1  christos 	if (filter == NULL)
    331   1.1  christos 		return (1);
    332   1.1  christos 
    333   1.1  christos 	cp = format_single(NULL, filter, NULL, s, wl, wp);
    334   1.1  christos 	result = format_true(cp);
    335   1.1  christos 	free(cp);
    336   1.1  christos 
    337   1.1  christos 	return (result);
    338   1.1  christos }
    339   1.1  christos 
    340   1.1  christos static int
    341   1.7  christos window_tree_build_window(struct session *s, struct winlink *wl,
    342   1.7  christos     void *modedata, struct mode_tree_sort_criteria *sort_crit,
    343   1.7  christos     struct mode_tree_item *parent, const char *filter)
    344   1.1  christos {
    345   1.1  christos 	struct window_tree_modedata	*data = modedata;
    346   1.1  christos 	struct window_tree_itemdata	*item;
    347   1.1  christos 	struct mode_tree_item		*mti;
    348   1.1  christos 	char				*name, *text;
    349   1.1  christos 	struct window_pane		*wp, **l;
    350   1.1  christos 	u_int				 n, i;
    351   1.1  christos 	int				 expanded;
    352  1.12       wiz 	struct format_tree		*ft;
    353   1.1  christos 
    354   1.1  christos 	item = window_tree_add_item(data);
    355   1.1  christos 	item->type = WINDOW_TREE_WINDOW;
    356   1.1  christos 	item->session = s->id;
    357   1.1  christos 	item->winlink = wl->idx;
    358   1.1  christos 	item->pane = -1;
    359   1.1  christos 
    360  1.12       wiz 	ft = format_create(NULL, NULL, FORMAT_PANE|wl->window->active->id, 0);
    361  1.12       wiz 	format_defaults(ft, NULL, s, wl, NULL);
    362  1.12       wiz 	text = format_expand(ft, data->format);
    363   1.1  christos 	xasprintf(&name, "%u", wl->idx);
    364  1.12       wiz 	format_free(ft);
    365   1.1  christos 
    366   1.1  christos 	if (data->type == WINDOW_TREE_SESSION ||
    367   1.1  christos 	    data->type == WINDOW_TREE_WINDOW)
    368   1.1  christos 		expanded = 0;
    369   1.1  christos 	else
    370   1.1  christos 		expanded = 1;
    371   1.2       kre 	mti = mode_tree_add(data->data, parent, item, (uintptr_t)wl, name, text,
    372   1.1  christos 	    expanded);
    373   1.1  christos 	free(text);
    374   1.1  christos 	free(name);
    375  1.12       wiz 	mode_tree_align(mti, 1);
    376   1.1  christos 
    377   1.3  christos 	if ((wp = TAILQ_FIRST(&wl->window->panes)) == NULL)
    378   1.3  christos 		goto empty;
    379   1.1  christos 	if (TAILQ_NEXT(wp, entry) == NULL) {
    380   1.1  christos 		if (!window_tree_filter_pane(s, wl, wp, filter))
    381   1.1  christos 			goto empty;
    382   1.1  christos 	}
    383   1.1  christos 
    384   1.1  christos 	l = NULL;
    385   1.1  christos 	n = 0;
    386   1.1  christos 
    387   1.1  christos 	TAILQ_FOREACH(wp, &wl->window->panes, entry) {
    388   1.1  christos 		if (!window_tree_filter_pane(s, wl, wp, filter))
    389   1.1  christos 			continue;
    390   1.1  christos 		l = xreallocarray(l, n + 1, sizeof *l);
    391   1.1  christos 		l[n++] = wp;
    392   1.1  christos 	}
    393   1.1  christos 	if (n == 0)
    394   1.1  christos 		goto empty;
    395   1.1  christos 
    396   1.7  christos 	window_tree_sort = sort_crit;
    397   1.7  christos 	qsort(l, n, sizeof *l, window_tree_cmp_pane);
    398   1.1  christos 
    399   1.1  christos 	for (i = 0; i < n; i++)
    400   1.1  christos 		window_tree_build_pane(s, wl, l[i], modedata, mti);
    401   1.1  christos 	free(l);
    402   1.1  christos 	return (1);
    403   1.1  christos 
    404   1.1  christos empty:
    405   1.1  christos 	window_tree_free_item(item);
    406   1.1  christos 	data->item_size--;
    407   1.1  christos 	mode_tree_remove(data->data, mti);
    408   1.1  christos 	return (0);
    409   1.1  christos }
    410   1.1  christos 
    411   1.1  christos static void
    412   1.7  christos window_tree_build_session(struct session *s, void *modedata,
    413   1.7  christos     struct mode_tree_sort_criteria *sort_crit, const char *filter)
    414   1.1  christos {
    415   1.1  christos 	struct window_tree_modedata	*data = modedata;
    416   1.1  christos 	struct window_tree_itemdata	*item;
    417   1.1  christos 	struct mode_tree_item		*mti;
    418   1.1  christos 	char				*text;
    419  1.12       wiz 	struct winlink			*wl = s->curw, **l;
    420   1.1  christos 	u_int				 n, i, empty;
    421   1.1  christos 	int				 expanded;
    422  1.12       wiz 	struct format_tree		*ft;
    423   1.1  christos 
    424   1.1  christos 	item = window_tree_add_item(data);
    425   1.1  christos 	item->type = WINDOW_TREE_SESSION;
    426   1.1  christos 	item->session = s->id;
    427   1.1  christos 	item->winlink = -1;
    428   1.1  christos 	item->pane = -1;
    429   1.1  christos 
    430  1.12       wiz 	ft = format_create(NULL, NULL, FORMAT_PANE|wl->window->active->id, 0);
    431  1.12       wiz 	format_defaults(ft, NULL, s, NULL, NULL);
    432  1.12       wiz 	text = format_expand(ft, data->format);
    433  1.12       wiz 	format_free(ft);
    434   1.1  christos 
    435   1.1  christos 	if (data->type == WINDOW_TREE_SESSION)
    436   1.1  christos 		expanded = 0;
    437   1.1  christos 	else
    438   1.1  christos 		expanded = 1;
    439   1.2       kre 	mti = mode_tree_add(data->data, NULL, item, (uintptr_t)s, s->name, text,
    440   1.1  christos 	    expanded);
    441   1.1  christos 	free(text);
    442   1.1  christos 
    443   1.1  christos 	l = NULL;
    444   1.1  christos 	n = 0;
    445   1.1  christos 	RB_FOREACH(wl, winlinks, &s->windows) {
    446   1.1  christos 		l = xreallocarray(l, n + 1, sizeof *l);
    447   1.1  christos 		l[n++] = wl;
    448   1.1  christos 	}
    449   1.7  christos 	window_tree_sort = sort_crit;
    450   1.7  christos 	qsort(l, n, sizeof *l, window_tree_cmp_window);
    451   1.1  christos 
    452   1.1  christos 	empty = 0;
    453   1.1  christos 	for (i = 0; i < n; i++) {
    454   1.7  christos 		if (!window_tree_build_window(s, l[i], modedata, sort_crit, mti,
    455   1.1  christos 		    filter))
    456   1.1  christos 			empty++;
    457   1.1  christos 	}
    458   1.1  christos 	if (empty == n) {
    459   1.1  christos 		window_tree_free_item(item);
    460   1.1  christos 		data->item_size--;
    461   1.1  christos 		mode_tree_remove(data->data, mti);
    462   1.1  christos 	}
    463   1.1  christos 	free(l);
    464   1.1  christos }
    465   1.1  christos 
    466   1.1  christos static void
    467   1.7  christos window_tree_build(void *modedata, struct mode_tree_sort_criteria *sort_crit,
    468   1.7  christos     uint64_t *tag, const char *filter)
    469   1.1  christos {
    470   1.1  christos 	struct window_tree_modedata	*data = modedata;
    471   1.1  christos 	struct session			*s, **l;
    472   1.3  christos 	struct session_group		*sg, *current;
    473   1.1  christos 	u_int				 n, i;
    474   1.1  christos 
    475   1.3  christos 	current = session_group_contains(data->fs.s);
    476   1.3  christos 
    477   1.1  christos 	for (i = 0; i < data->item_size; i++)
    478   1.1  christos 		window_tree_free_item(data->item_list[i]);
    479   1.1  christos 	free(data->item_list);
    480   1.1  christos 	data->item_list = NULL;
    481   1.1  christos 	data->item_size = 0;
    482   1.1  christos 
    483   1.1  christos 	l = NULL;
    484   1.1  christos 	n = 0;
    485   1.1  christos 	RB_FOREACH(s, sessions, &sessions) {
    486   1.3  christos 		if (data->squash_groups &&
    487   1.3  christos 		    (sg = session_group_contains(s)) != NULL) {
    488   1.3  christos 			if ((sg == current && s != data->fs.s) ||
    489   1.3  christos 			    (sg != current && s != TAILQ_FIRST(&sg->sessions)))
    490   1.3  christos 				continue;
    491   1.3  christos 		}
    492   1.1  christos 		l = xreallocarray(l, n + 1, sizeof *l);
    493   1.1  christos 		l[n++] = s;
    494   1.1  christos 	}
    495   1.7  christos 	window_tree_sort = sort_crit;
    496   1.7  christos 	qsort(l, n, sizeof *l, window_tree_cmp_session);
    497   1.1  christos 
    498   1.1  christos 	for (i = 0; i < n; i++)
    499   1.7  christos 		window_tree_build_session(l[i], modedata, sort_crit, filter);
    500   1.1  christos 	free(l);
    501   1.1  christos 
    502   1.1  christos 	switch (data->type) {
    503   1.1  christos 	case WINDOW_TREE_NONE:
    504   1.1  christos 		break;
    505   1.1  christos 	case WINDOW_TREE_SESSION:
    506   1.2       kre 		*tag = (uintptr_t)data->fs.s;
    507   1.1  christos 		break;
    508   1.1  christos 	case WINDOW_TREE_WINDOW:
    509   1.2       kre 		*tag = (uintptr_t)data->fs.wl;
    510   1.1  christos 		break;
    511   1.1  christos 	case WINDOW_TREE_PANE:
    512   1.3  christos 		if (window_count_panes(data->fs.wl->window) == 1)
    513   1.4  christos 			*tag = (uintptr_t)data->fs.wl;
    514   1.3  christos 		else
    515   1.4  christos 			*tag = (uintptr_t)data->fs.wp;
    516   1.1  christos 		break;
    517   1.1  christos 	}
    518   1.1  christos }
    519   1.1  christos 
    520   1.3  christos static void
    521   1.3  christos window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
    522   1.3  christos     u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
    523   1.3  christos {
    524   1.3  christos 	size_t	 len;
    525   1.3  christos 	u_int	 ox, oy;
    526   1.3  christos 
    527   1.3  christos 	len = strlen(label);
    528   1.3  christos 	if (sx == 0 || sy == 1 || len > sx)
    529   1.3  christos 		return;
    530   1.3  christos 	ox = (sx - len + 1) / 2;
    531   1.3  christos 	oy = (sy + 1) / 2;
    532   1.3  christos 
    533   1.3  christos 	if (ox > 1 && ox + len < sx - 1 && sy >= 3) {
    534   1.5  christos 		screen_write_cursormove(ctx, px + ox - 1, py + oy - 1, 0);
    535  1.10       wiz 		screen_write_box(ctx, len + 2, 3, BOX_LINES_DEFAULT, NULL,
    536  1.10       wiz 		    NULL);
    537   1.3  christos 	}
    538   1.5  christos 	screen_write_cursormove(ctx, px + ox, py + oy, 0);
    539   1.3  christos 	screen_write_puts(ctx, gc, "%s", label);
    540   1.3  christos }
    541   1.3  christos 
    542   1.1  christos static void
    543   1.1  christos window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
    544   1.1  christos     struct screen_write_ctx *ctx, u_int sx, u_int sy)
    545   1.1  christos {
    546   1.1  christos 	struct options		*oo = s->options;
    547   1.1  christos 	struct winlink		*wl;
    548   1.1  christos 	struct window		*w;
    549   1.3  christos 	u_int			 cx = ctx->s->cx, cy = ctx->s->cy;
    550   1.1  christos 	u_int			 loop, total, visible, each, width, offset;
    551   1.1  christos 	u_int			 current, start, end, remaining, i;
    552   1.1  christos 	struct grid_cell	 gc;
    553   1.1  christos 	int			 colour, active_colour, left, right;
    554   1.1  christos 	char			*label;
    555   1.1  christos 
    556   1.1  christos 	total = winlink_count(&s->windows);
    557   1.1  christos 
    558   1.1  christos 	memcpy(&gc, &grid_default_cell, sizeof gc);
    559   1.1  christos 	colour = options_get_number(oo, "display-panes-colour");
    560   1.1  christos 	active_colour = options_get_number(oo, "display-panes-active-colour");
    561   1.1  christos 
    562   1.1  christos 	if (sx / total < 24) {
    563   1.1  christos 		visible = sx / 24;
    564   1.1  christos 		if (visible == 0)
    565   1.1  christos 			visible = 1;
    566   1.1  christos 	} else
    567   1.1  christos 		visible = total;
    568   1.1  christos 
    569   1.1  christos 	current = 0;
    570   1.1  christos 	RB_FOREACH(wl, winlinks, &s->windows) {
    571   1.1  christos 		if (wl == s->curw)
    572   1.1  christos 			break;
    573   1.1  christos 		current++;
    574   1.1  christos 	}
    575   1.1  christos 
    576   1.1  christos 	if (current < visible) {
    577   1.1  christos 		start = 0;
    578   1.1  christos 		end = visible;
    579   1.1  christos 	} else if (current >= total - visible) {
    580   1.1  christos 		start = total - visible;
    581   1.1  christos 		end = total;
    582   1.1  christos 	} else {
    583   1.1  christos 		start = current - (visible / 2);
    584   1.1  christos 		end = start + visible;
    585   1.1  christos 	}
    586   1.1  christos 
    587   1.1  christos 	if (data->offset < -(int)start)
    588   1.1  christos 		data->offset = -(int)start;
    589   1.1  christos 	if (data->offset > (int)(total - end))
    590   1.1  christos 		data->offset = (int)(total - end);
    591   1.1  christos 	start += data->offset;
    592   1.1  christos 	end += data->offset;
    593   1.1  christos 
    594   1.1  christos 	left = (start != 0);
    595   1.1  christos 	right = (end != total);
    596   1.1  christos 	if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
    597   1.1  christos 		left = right = 0;
    598   1.1  christos 	if (left && right) {
    599   1.1  christos 		each = (sx - 6) / visible;
    600   1.1  christos 		remaining = (sx - 6) - (visible * each);
    601   1.1  christos 	} else if (left || right) {
    602   1.1  christos 		each = (sx - 3) / visible;
    603   1.1  christos 		remaining = (sx - 3) - (visible * each);
    604   1.1  christos 	} else {
    605   1.1  christos 		each = sx / visible;
    606   1.1  christos 		remaining = sx - (visible * each);
    607   1.1  christos 	}
    608   1.1  christos 	if (each == 0)
    609   1.1  christos 		return;
    610   1.1  christos 
    611   1.1  christos 	if (left) {
    612   1.3  christos 		data->left = cx + 2;
    613   1.5  christos 		screen_write_cursormove(ctx, cx + 2, cy, 0);
    614   1.1  christos 		screen_write_vline(ctx, sy, 0, 0);
    615   1.5  christos 		screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
    616   1.1  christos 		screen_write_puts(ctx, &grid_default_cell, "<");
    617   1.3  christos 	} else
    618   1.3  christos 		data->left = -1;
    619   1.1  christos 	if (right) {
    620   1.3  christos 		data->right = cx + sx - 3;
    621   1.5  christos 		screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
    622   1.1  christos 		screen_write_vline(ctx, sy, 0, 0);
    623   1.5  christos 		screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
    624   1.1  christos 		screen_write_puts(ctx, &grid_default_cell, ">");
    625   1.3  christos 	} else
    626   1.3  christos 		data->right = -1;
    627   1.3  christos 
    628   1.3  christos 	data->start = start;
    629   1.3  christos 	data->end = end;
    630   1.3  christos 	data->each = each;
    631   1.1  christos 
    632   1.1  christos 	i = loop = 0;
    633   1.1  christos 	RB_FOREACH(wl, winlinks, &s->windows) {
    634   1.1  christos 		if (loop == end)
    635   1.1  christos 			break;
    636   1.1  christos 		if (loop < start) {
    637   1.1  christos 			loop++;
    638   1.1  christos 			continue;
    639   1.1  christos 		}
    640   1.1  christos 		w = wl->window;
    641   1.1  christos 
    642   1.1  christos 		if (wl == s->curw)
    643   1.1  christos 			gc.fg = active_colour;
    644   1.1  christos 		else
    645   1.1  christos 			gc.fg = colour;
    646   1.1  christos 
    647   1.1  christos 		if (left)
    648   1.1  christos 			offset = 3 + (i * each);
    649   1.1  christos 		else
    650   1.1  christos 			offset = (i * each);
    651   1.1  christos 		if (loop == end - 1)
    652   1.1  christos 			width = each + remaining;
    653   1.1  christos 		else
    654   1.1  christos 			width = each - 1;
    655   1.1  christos 
    656   1.5  christos 		screen_write_cursormove(ctx, cx + offset, cy, 0);
    657   1.1  christos 		screen_write_preview(ctx, &w->active->base, width, sy);
    658   1.1  christos 
    659   1.1  christos 		xasprintf(&label, " %u:%s ", wl->idx, w->name);
    660  1.12       wiz 		if (strlen(label) > width) {
    661  1.12       wiz 			free(label);
    662   1.1  christos 			xasprintf(&label, " %u ", wl->idx);
    663  1.12       wiz 		}
    664   1.3  christos 		window_tree_draw_label(ctx, cx + offset, cy, width, sy, &gc,
    665   1.3  christos 		    label);
    666   1.1  christos 		free(label);
    667   1.1  christos 
    668   1.1  christos 		if (loop != end - 1) {
    669   1.5  christos 			screen_write_cursormove(ctx, cx + offset + width, cy, 0);
    670   1.1  christos 			screen_write_vline(ctx, sy, 0, 0);
    671   1.1  christos 		}
    672   1.1  christos 		loop++;
    673   1.1  christos 
    674   1.1  christos 		i++;
    675   1.1  christos 	}
    676   1.1  christos }
    677   1.1  christos 
    678   1.1  christos static void
    679   1.1  christos window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
    680   1.1  christos     struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy)
    681   1.1  christos {
    682   1.1  christos 	struct options		*oo = s->options;
    683   1.1  christos 	struct window_pane	*wp;
    684   1.3  christos 	u_int			 cx = ctx->s->cx, cy = ctx->s->cy;
    685   1.1  christos 	u_int			 loop, total, visible, each, width, offset;
    686  1.11       wiz 	u_int			 current, start, end, remaining, i, pane_idx;
    687   1.1  christos 	struct grid_cell	 gc;
    688   1.1  christos 	int			 colour, active_colour, left, right;
    689   1.1  christos 	char			*label;
    690   1.1  christos 
    691   1.1  christos 	total = window_count_panes(w);
    692   1.1  christos 
    693   1.1  christos 	memcpy(&gc, &grid_default_cell, sizeof gc);
    694   1.1  christos 	colour = options_get_number(oo, "display-panes-colour");
    695   1.1  christos 	active_colour = options_get_number(oo, "display-panes-active-colour");
    696   1.1  christos 
    697   1.1  christos 	if (sx / total < 24) {
    698   1.1  christos 		visible = sx / 24;
    699   1.1  christos 		if (visible == 0)
    700   1.1  christos 			visible = 1;
    701   1.1  christos 	} else
    702   1.1  christos 		visible = total;
    703   1.1  christos 
    704   1.1  christos 	current = 0;
    705   1.1  christos 	TAILQ_FOREACH(wp, &w->panes, entry) {
    706   1.1  christos 		if (wp == w->active)
    707   1.1  christos 			break;
    708   1.1  christos 		current++;
    709   1.1  christos 	}
    710   1.1  christos 
    711   1.1  christos 	if (current < visible) {
    712   1.1  christos 		start = 0;
    713   1.1  christos 		end = visible;
    714   1.1  christos 	} else if (current >= total - visible) {
    715   1.1  christos 		start = total - visible;
    716   1.1  christos 		end = total;
    717   1.1  christos 	} else {
    718   1.1  christos 		start = current - (visible / 2);
    719   1.1  christos 		end = start + visible;
    720   1.1  christos 	}
    721   1.1  christos 
    722   1.1  christos 	if (data->offset < -(int)start)
    723   1.1  christos 		data->offset = -(int)start;
    724   1.1  christos 	if (data->offset > (int)(total - end))
    725   1.1  christos 		data->offset = (int)(total - end);
    726   1.1  christos 	start += data->offset;
    727   1.1  christos 	end += data->offset;
    728   1.1  christos 
    729   1.1  christos 	left = (start != 0);
    730   1.1  christos 	right = (end != total);
    731   1.1  christos 	if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
    732   1.1  christos 		left = right = 0;
    733   1.1  christos 	if (left && right) {
    734   1.1  christos 		each = (sx - 6) / visible;
    735   1.1  christos 		remaining = (sx - 6) - (visible * each);
    736   1.1  christos 	} else if (left || right) {
    737   1.1  christos 		each = (sx - 3) / visible;
    738   1.1  christos 		remaining = (sx - 3) - (visible * each);
    739   1.1  christos 	} else {
    740   1.1  christos 		each = sx / visible;
    741   1.1  christos 		remaining = sx - (visible * each);
    742   1.1  christos 	}
    743   1.1  christos 	if (each == 0)
    744   1.1  christos 		return;
    745   1.1  christos 
    746   1.1  christos 	if (left) {
    747   1.3  christos 		data->left = cx + 2;
    748   1.5  christos 		screen_write_cursormove(ctx, cx + 2, cy, 0);
    749   1.1  christos 		screen_write_vline(ctx, sy, 0, 0);
    750   1.5  christos 		screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
    751   1.1  christos 		screen_write_puts(ctx, &grid_default_cell, "<");
    752   1.3  christos 	} else
    753   1.3  christos 		data->left = -1;
    754   1.1  christos 	if (right) {
    755   1.3  christos 		data->right = cx + sx - 3;
    756   1.5  christos 		screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
    757   1.1  christos 		screen_write_vline(ctx, sy, 0, 0);
    758   1.5  christos 		screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
    759   1.1  christos 		screen_write_puts(ctx, &grid_default_cell, ">");
    760   1.3  christos 	} else
    761   1.3  christos 		data->right = -1;
    762   1.3  christos 
    763   1.3  christos 	data->start = start;
    764   1.3  christos 	data->end = end;
    765   1.3  christos 	data->each = each;
    766   1.1  christos 
    767   1.1  christos 	i = loop = 0;
    768   1.1  christos 	TAILQ_FOREACH(wp, &w->panes, entry) {
    769   1.1  christos 		if (loop == end)
    770   1.1  christos 			break;
    771   1.1  christos 		if (loop < start) {
    772   1.1  christos 			loop++;
    773   1.1  christos 			continue;
    774   1.1  christos 		}
    775   1.1  christos 
    776   1.1  christos 		if (wp == w->active)
    777   1.1  christos 			gc.fg = active_colour;
    778   1.1  christos 		else
    779   1.1  christos 			gc.fg = colour;
    780   1.1  christos 
    781   1.1  christos 		if (left)
    782   1.1  christos 			offset = 3 + (i * each);
    783   1.1  christos 		else
    784   1.1  christos 			offset = (i * each);
    785   1.1  christos 		if (loop == end - 1)
    786   1.1  christos 			width = each + remaining;
    787   1.1  christos 		else
    788   1.1  christos 			width = each - 1;
    789   1.1  christos 
    790   1.5  christos 		screen_write_cursormove(ctx, cx + offset, cy, 0);
    791   1.1  christos 		screen_write_preview(ctx, &wp->base, width, sy);
    792   1.1  christos 
    793   1.3  christos 		if (window_pane_index(wp, &pane_idx) != 0)
    794   1.3  christos 			pane_idx = loop;
    795   1.3  christos 		xasprintf(&label, " %u ", pane_idx);
    796   1.3  christos 		window_tree_draw_label(ctx, cx + offset, cy, each, sy, &gc,
    797   1.3  christos 		    label);
    798   1.1  christos 		free(label);
    799   1.1  christos 
    800   1.1  christos 		if (loop != end - 1) {
    801   1.5  christos 			screen_write_cursormove(ctx, cx + offset + width, cy, 0);
    802   1.1  christos 			screen_write_vline(ctx, sy, 0, 0);
    803   1.1  christos 		}
    804   1.1  christos 		loop++;
    805   1.1  christos 
    806   1.1  christos 		i++;
    807   1.1  christos 	}
    808   1.1  christos }
    809   1.1  christos 
    810   1.3  christos static void
    811   1.3  christos window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
    812   1.3  christos     u_int sx, u_int sy)
    813   1.1  christos {
    814   1.1  christos 	struct window_tree_itemdata	*item = itemdata;
    815   1.1  christos 	struct session			*sp;
    816   1.1  christos 	struct winlink			*wlp;
    817   1.1  christos 	struct window_pane		*wp;
    818   1.1  christos 
    819   1.1  christos 	window_tree_pull_item(item, &sp, &wlp, &wp);
    820   1.1  christos 	if (wp == NULL)
    821   1.3  christos 		return;
    822   1.1  christos 
    823   1.1  christos 	switch (item->type) {
    824   1.1  christos 	case WINDOW_TREE_NONE:
    825   1.3  christos 		break;
    826   1.1  christos 	case WINDOW_TREE_SESSION:
    827   1.3  christos 		window_tree_draw_session(modedata, sp, ctx, sx, sy);
    828   1.1  christos 		break;
    829   1.1  christos 	case WINDOW_TREE_WINDOW:
    830   1.3  christos 		window_tree_draw_window(modedata, sp, wlp->window, ctx, sx, sy);
    831   1.1  christos 		break;
    832   1.1  christos 	case WINDOW_TREE_PANE:
    833   1.3  christos 		screen_write_preview(ctx, &wp->base, sx, sy);
    834   1.1  christos 		break;
    835   1.1  christos 	}
    836   1.1  christos }
    837   1.1  christos 
    838   1.1  christos static int
    839  1.12       wiz window_tree_search(__unused void *modedata, void *itemdata, const char *ss,
    840  1.12       wiz     int icase)
    841   1.1  christos {
    842   1.1  christos 	struct window_tree_itemdata	*item = itemdata;
    843   1.1  christos 	struct session			*s;
    844   1.1  christos 	struct winlink			*wl;
    845   1.1  christos 	struct window_pane		*wp;
    846   1.6  christos 	char				*cmd;
    847   1.6  christos 	int				 retval;
    848   1.1  christos 
    849   1.1  christos 	window_tree_pull_item(item, &s, &wl, &wp);
    850   1.1  christos 
    851   1.1  christos 	switch (item->type) {
    852   1.1  christos 	case WINDOW_TREE_NONE:
    853   1.1  christos 		return (0);
    854   1.1  christos 	case WINDOW_TREE_SESSION:
    855   1.1  christos 		if (s == NULL)
    856   1.1  christos 			return (0);
    857  1.12       wiz 		if (icase)
    858  1.12       wiz 			return (strcasestr(s->name, ss) != NULL);
    859  1.12       wiz  		return (strstr(s->name, ss) != NULL);
    860   1.1  christos 	case WINDOW_TREE_WINDOW:
    861   1.1  christos 		if (s == NULL || wl == NULL)
    862   1.1  christos 			return (0);
    863  1.12       wiz 		if (icase)
    864  1.12       wiz 			return (strcasestr(wl->window->name, ss) != NULL);
    865   1.1  christos 		return (strstr(wl->window->name, ss) != NULL);
    866   1.1  christos 	case WINDOW_TREE_PANE:
    867   1.1  christos 		if (s == NULL || wl == NULL || wp == NULL)
    868   1.1  christos 			break;
    869   1.1  christos 		cmd = osdep_get_name(wp->fd, wp->tty);
    870  1.12       wiz 		if (cmd == NULL || *cmd == '\0') {
    871  1.12       wiz 			free(cmd);
    872   1.1  christos 			return (0);
    873  1.12       wiz 		}
    874  1.12       wiz 		if (icase)
    875  1.12       wiz 			retval = (strcasestr(cmd, ss) != NULL);
    876  1.12       wiz 		else
    877  1.12       wiz 			retval = (strstr(cmd, ss) != NULL);
    878   1.6  christos 		free(cmd);
    879   1.8  christos 		return (retval);
    880   1.1  christos 	}
    881   1.1  christos 	return (0);
    882   1.1  christos }
    883   1.1  christos 
    884   1.6  christos static void
    885   1.6  christos window_tree_menu(void *modedata, struct client *c, key_code key)
    886   1.6  christos {
    887   1.6  christos 	struct window_tree_modedata	*data = modedata;
    888   1.6  christos 	struct window_pane		*wp = data->wp;
    889   1.6  christos 	struct window_mode_entry	*wme;
    890   1.6  christos 
    891   1.6  christos 	wme = TAILQ_FIRST(&wp->modes);
    892   1.6  christos 	if (wme == NULL || wme->data != modedata)
    893   1.6  christos 		return;
    894   1.6  christos 	window_tree_key(wme, c, NULL, NULL, key, NULL);
    895   1.6  christos }
    896   1.6  christos 
    897   1.8  christos static key_code
    898   1.8  christos window_tree_get_key(void *modedata, void *itemdata, u_int line)
    899   1.8  christos {
    900   1.8  christos 	struct window_tree_modedata	*data = modedata;
    901   1.8  christos 	struct window_tree_itemdata	*item = itemdata;
    902   1.8  christos 	struct format_tree		*ft;
    903   1.8  christos 	struct session			*s;
    904   1.8  christos 	struct winlink			*wl;
    905   1.8  christos 	struct window_pane		*wp;
    906   1.8  christos 	char				*expanded;
    907   1.8  christos 	key_code			 key;
    908   1.8  christos 
    909   1.8  christos 	ft = format_create(NULL, NULL, FORMAT_NONE, 0);
    910   1.8  christos 	window_tree_pull_item(item, &s, &wl, &wp);
    911   1.8  christos 	if (item->type == WINDOW_TREE_SESSION)
    912   1.8  christos 		format_defaults(ft, NULL, s, NULL, NULL);
    913   1.8  christos 	else if (item->type == WINDOW_TREE_WINDOW)
    914   1.8  christos 		format_defaults(ft, NULL, s, wl, NULL);
    915   1.8  christos 	else
    916   1.8  christos 		format_defaults(ft, NULL, s, wl, wp);
    917   1.8  christos 	format_add(ft, "line", "%u", line);
    918   1.8  christos 
    919   1.8  christos 	expanded = format_expand(ft, data->key_format);
    920   1.8  christos 	key = key_string_lookup_string(expanded);
    921   1.8  christos 	free(expanded);
    922   1.8  christos 	format_free(ft);
    923  1.10       wiz 	return (key);
    924   1.8  christos }
    925   1.8  christos 
    926  1.12       wiz static int
    927  1.12       wiz window_tree_swap(void *cur_itemdata, void *other_itemdata)
    928  1.12       wiz {
    929  1.12       wiz 	struct window_tree_itemdata	*cur = cur_itemdata;
    930  1.12       wiz 	struct window_tree_itemdata	*other = other_itemdata;
    931  1.12       wiz 	struct session			*cur_session, *other_session;
    932  1.12       wiz 	struct winlink			*cur_winlink, *other_winlink;
    933  1.12       wiz 	struct window			*cur_window, *other_window;
    934  1.12       wiz 	struct window_pane		*cur_pane, *other_pane;
    935  1.12       wiz 
    936  1.12       wiz 	if (cur->type != other->type)
    937  1.12       wiz 		return (0);
    938  1.12       wiz 	if (cur->type != WINDOW_TREE_WINDOW)
    939  1.12       wiz 		return (0);
    940  1.12       wiz 
    941  1.12       wiz 	window_tree_pull_item(cur, &cur_session, &cur_winlink, &cur_pane);
    942  1.12       wiz 	window_tree_pull_item(other, &other_session, &other_winlink,
    943  1.12       wiz 	    &other_pane);
    944  1.12       wiz 
    945  1.12       wiz 	if (cur_session != other_session)
    946  1.12       wiz 		return (0);
    947  1.12       wiz 
    948  1.12       wiz 	if (window_tree_sort->field != WINDOW_TREE_BY_INDEX &&
    949  1.12       wiz 	    window_tree_cmp_window(&cur_winlink, &other_winlink) != 0) {
    950  1.12       wiz 		/*
    951  1.12       wiz 		 * Swapping indexes would not swap positions in the tree, so
    952  1.12       wiz 		 * prevent swapping to avoid confusing the user.
    953  1.12       wiz 		 */
    954  1.12       wiz 		return (0);
    955  1.12       wiz 	}
    956  1.12       wiz 
    957  1.12       wiz 	other_window = other_winlink->window;
    958  1.12       wiz 	TAILQ_REMOVE(&other_window->winlinks, other_winlink, wentry);
    959  1.12       wiz 	cur_window = cur_winlink->window;
    960  1.12       wiz 	TAILQ_REMOVE(&cur_window->winlinks, cur_winlink, wentry);
    961  1.12       wiz 
    962  1.12       wiz 	other_winlink->window = cur_window;
    963  1.12       wiz 	TAILQ_INSERT_TAIL(&cur_window->winlinks, other_winlink, wentry);
    964  1.12       wiz 	cur_winlink->window = other_window;
    965  1.12       wiz 	TAILQ_INSERT_TAIL(&other_window->winlinks, cur_winlink, wentry);
    966  1.12       wiz 
    967  1.12       wiz 	if (cur_session->curw == cur_winlink)
    968  1.12       wiz 		session_set_current(cur_session, other_winlink);
    969  1.12       wiz 	else if (cur_session->curw == other_winlink)
    970  1.12       wiz 		session_set_current(cur_session, cur_winlink);
    971  1.12       wiz 	session_group_synchronize_from(cur_session);
    972  1.12       wiz 	server_redraw_session_group(cur_session);
    973  1.12       wiz 	recalculate_sizes();
    974  1.12       wiz 
    975  1.12       wiz 	return (1);
    976  1.12       wiz }
    977  1.12       wiz 
    978   1.1  christos static struct screen *
    979   1.5  christos window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
    980   1.1  christos     struct args *args)
    981   1.1  christos {
    982   1.5  christos 	struct window_pane		*wp = wme->wp;
    983   1.1  christos 	struct window_tree_modedata	*data;
    984   1.1  christos 	struct screen			*s;
    985   1.1  christos 
    986   1.5  christos 	wme->data = data = xcalloc(1, sizeof *data);
    987   1.6  christos 	data->wp = wp;
    988   1.6  christos 	data->references = 1;
    989   1.1  christos 
    990   1.1  christos 	if (args_has(args, 's'))
    991   1.1  christos 		data->type = WINDOW_TREE_SESSION;
    992   1.1  christos 	else if (args_has(args, 'w'))
    993   1.1  christos 		data->type = WINDOW_TREE_WINDOW;
    994   1.1  christos 	else
    995   1.1  christos 		data->type = WINDOW_TREE_PANE;
    996   1.1  christos 	memcpy(&data->fs, fs, sizeof data->fs);
    997   1.1  christos 
    998   1.1  christos 	if (args == NULL || !args_has(args, 'F'))
    999   1.1  christos 		data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
   1000   1.1  christos 	else
   1001   1.1  christos 		data->format = xstrdup(args_get(args, 'F'));
   1002   1.8  christos 	if (args == NULL || !args_has(args, 'K'))
   1003   1.8  christos 		data->key_format = xstrdup(WINDOW_TREE_DEFAULT_KEY_FORMAT);
   1004   1.8  christos 	else
   1005   1.8  christos 		data->key_format = xstrdup(args_get(args, 'K'));
   1006  1.10       wiz 	if (args == NULL || args_count(args) == 0)
   1007   1.1  christos 		data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
   1008   1.1  christos 	else
   1009  1.10       wiz 		data->command = xstrdup(args_string(args, 0));
   1010   1.3  christos 	data->squash_groups = !args_has(args, 'G');
   1011  1.12       wiz 	if (args_has(args, 'y'))
   1012  1.12       wiz 		data->prompt_flags = PROMPT_ACCEPT;
   1013   1.1  christos 
   1014   1.1  christos 	data->data = mode_tree_start(wp, args, window_tree_build,
   1015   1.8  christos 	    window_tree_draw, window_tree_search, window_tree_menu, NULL,
   1016  1.12       wiz 	    window_tree_get_key, window_tree_swap, data, window_tree_menu_items,
   1017   1.8  christos 	    window_tree_sort_list, nitems(window_tree_sort_list), &s);
   1018   1.3  christos 	mode_tree_zoom(data->data, args);
   1019   1.1  christos 
   1020   1.1  christos 	mode_tree_build(data->data);
   1021   1.1  christos 	mode_tree_draw(data->data);
   1022   1.1  christos 
   1023   1.1  christos 	data->type = WINDOW_TREE_NONE;
   1024   1.1  christos 
   1025   1.1  christos 	return (s);
   1026   1.1  christos }
   1027   1.1  christos 
   1028   1.1  christos static void
   1029   1.1  christos window_tree_destroy(struct window_tree_modedata *data)
   1030   1.1  christos {
   1031   1.1  christos 	u_int	i;
   1032   1.1  christos 
   1033   1.1  christos 	if (--data->references != 0)
   1034   1.1  christos 		return;
   1035   1.1  christos 
   1036   1.1  christos 	for (i = 0; i < data->item_size; i++)
   1037   1.1  christos 		window_tree_free_item(data->item_list[i]);
   1038   1.1  christos 	free(data->item_list);
   1039   1.1  christos 
   1040   1.1  christos 	free(data->format);
   1041   1.8  christos 	free(data->key_format);
   1042   1.1  christos 	free(data->command);
   1043   1.1  christos 
   1044   1.1  christos 	free(data);
   1045   1.1  christos }
   1046   1.1  christos 
   1047   1.1  christos static void
   1048   1.5  christos window_tree_free(struct window_mode_entry *wme)
   1049   1.1  christos {
   1050   1.5  christos 	struct window_tree_modedata *data = wme->data;
   1051   1.1  christos 
   1052   1.1  christos 	if (data == NULL)
   1053   1.1  christos 		return;
   1054   1.1  christos 
   1055   1.1  christos 	data->dead = 1;
   1056   1.3  christos 	mode_tree_free(data->data);
   1057   1.1  christos 	window_tree_destroy(data);
   1058   1.1  christos }
   1059   1.1  christos 
   1060   1.1  christos static void
   1061   1.5  christos window_tree_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
   1062   1.1  christos {
   1063   1.5  christos 	struct window_tree_modedata	*data = wme->data;
   1064   1.1  christos 
   1065   1.1  christos 	mode_tree_resize(data->data, sx, sy);
   1066   1.1  christos }
   1067   1.1  christos 
   1068   1.8  christos static void
   1069   1.8  christos window_tree_update(struct window_mode_entry *wme)
   1070   1.8  christos {
   1071   1.8  christos 	struct window_tree_modedata	*data = wme->data;
   1072   1.8  christos 
   1073   1.8  christos 	mode_tree_build(data->data);
   1074   1.8  christos 	mode_tree_draw(data->data);
   1075   1.8  christos 	data->wp->flags |= PANE_REDRAW;
   1076   1.8  christos }
   1077   1.8  christos 
   1078   1.1  christos static char *
   1079   1.1  christos window_tree_get_target(struct window_tree_itemdata *item,
   1080   1.1  christos     struct cmd_find_state *fs)
   1081   1.1  christos {
   1082   1.1  christos 	struct session		*s;
   1083   1.1  christos 	struct winlink		*wl;
   1084   1.1  christos 	struct window_pane	*wp;
   1085   1.1  christos 	char			*target;
   1086   1.1  christos 
   1087   1.1  christos 	window_tree_pull_item(item, &s, &wl, &wp);
   1088   1.1  christos 
   1089   1.1  christos 	target = NULL;
   1090   1.1  christos 	switch (item->type) {
   1091   1.1  christos 	case WINDOW_TREE_NONE:
   1092   1.1  christos 		break;
   1093   1.1  christos 	case WINDOW_TREE_SESSION:
   1094   1.1  christos 		if (s == NULL)
   1095   1.1  christos 			break;
   1096   1.1  christos 		xasprintf(&target, "=%s:", s->name);
   1097   1.1  christos 		break;
   1098   1.1  christos 	case WINDOW_TREE_WINDOW:
   1099   1.1  christos 		if (s == NULL || wl == NULL)
   1100   1.1  christos 			break;
   1101   1.1  christos 		xasprintf(&target, "=%s:%u.", s->name, wl->idx);
   1102   1.1  christos 		break;
   1103   1.1  christos 	case WINDOW_TREE_PANE:
   1104   1.1  christos 		if (s == NULL || wl == NULL || wp == NULL)
   1105   1.1  christos 			break;
   1106   1.1  christos 		xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
   1107   1.1  christos 		break;
   1108   1.1  christos 	}
   1109   1.1  christos 	if (target == NULL)
   1110   1.1  christos 		cmd_find_clear_state(fs, 0);
   1111   1.1  christos 	else
   1112   1.1  christos 		cmd_find_from_winlink_pane(fs, wl, wp, 0);
   1113   1.1  christos 	return (target);
   1114   1.1  christos }
   1115   1.1  christos 
   1116   1.1  christos static void
   1117   1.7  christos window_tree_command_each(void *modedata, void *itemdata, struct client *c,
   1118   1.3  christos     __unused key_code key)
   1119   1.1  christos {
   1120   1.1  christos 	struct window_tree_modedata	*data = modedata;
   1121   1.1  christos 	struct window_tree_itemdata	*item = itemdata;
   1122   1.1  christos 	char				*name;
   1123   1.1  christos 	struct cmd_find_state		 fs;
   1124   1.1  christos 
   1125   1.1  christos 	name = window_tree_get_target(item, &fs);
   1126   1.1  christos 	if (name != NULL)
   1127   1.3  christos 		mode_tree_run_command(c, &fs, data->entered, name);
   1128   1.1  christos 	free(name);
   1129   1.1  christos }
   1130   1.1  christos 
   1131   1.1  christos static enum cmd_retval
   1132   1.1  christos window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
   1133   1.1  christos {
   1134   1.1  christos 	struct window_tree_modedata	*data = modedata;
   1135   1.1  christos 
   1136   1.1  christos 	if (!data->dead) {
   1137   1.1  christos 		mode_tree_build(data->data);
   1138   1.1  christos 		mode_tree_draw(data->data);
   1139   1.1  christos 		data->wp->flags |= PANE_REDRAW;
   1140   1.1  christos 	}
   1141   1.1  christos 	window_tree_destroy(data);
   1142   1.1  christos 	return (CMD_RETURN_NORMAL);
   1143   1.1  christos }
   1144   1.1  christos 
   1145   1.1  christos static int
   1146   1.1  christos window_tree_command_callback(struct client *c, void *modedata, const char *s,
   1147   1.1  christos     __unused int done)
   1148   1.1  christos {
   1149   1.1  christos 	struct window_tree_modedata	*data = modedata;
   1150   1.1  christos 
   1151   1.3  christos 	if (s == NULL || *s == '\0' || data->dead)
   1152   1.1  christos 		return (0);
   1153   1.1  christos 
   1154   1.1  christos 	data->entered = s;
   1155   1.3  christos 	mode_tree_each_tagged(data->data, window_tree_command_each, c,
   1156   1.3  christos 	    KEYC_NONE, 1);
   1157   1.1  christos 	data->entered = NULL;
   1158   1.1  christos 
   1159   1.1  christos 	data->references++;
   1160   1.1  christos 	cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
   1161   1.1  christos 
   1162   1.1  christos 	return (0);
   1163   1.1  christos }
   1164   1.1  christos 
   1165   1.1  christos static void
   1166   1.1  christos window_tree_command_free(void *modedata)
   1167   1.1  christos {
   1168   1.1  christos 	struct window_tree_modedata	*data = modedata;
   1169   1.1  christos 
   1170   1.1  christos 	window_tree_destroy(data);
   1171   1.1  christos }
   1172   1.1  christos 
   1173   1.1  christos static void
   1174   1.7  christos window_tree_kill_each(__unused void *modedata, void *itemdata,
   1175   1.3  christos     __unused struct client *c, __unused key_code key)
   1176   1.3  christos {
   1177   1.3  christos 	struct window_tree_itemdata	*item = itemdata;
   1178   1.3  christos 	struct session			*s;
   1179   1.3  christos 	struct winlink			*wl;
   1180   1.3  christos 	struct window_pane		*wp;
   1181   1.3  christos 
   1182   1.3  christos 	window_tree_pull_item(item, &s, &wl, &wp);
   1183   1.3  christos 
   1184   1.3  christos 	switch (item->type) {
   1185   1.3  christos 	case WINDOW_TREE_NONE:
   1186   1.3  christos 		break;
   1187   1.3  christos 	case WINDOW_TREE_SESSION:
   1188   1.3  christos 		if (s != NULL) {
   1189   1.3  christos 			server_destroy_session(s);
   1190   1.6  christos 			session_destroy(s, 1, __func__);
   1191   1.3  christos 		}
   1192   1.3  christos 		break;
   1193   1.3  christos 	case WINDOW_TREE_WINDOW:
   1194   1.3  christos 		if (wl != NULL)
   1195   1.8  christos 			server_kill_window(wl->window, 0);
   1196   1.3  christos 		break;
   1197   1.3  christos 	case WINDOW_TREE_PANE:
   1198   1.3  christos 		if (wp != NULL)
   1199   1.3  christos 			server_kill_pane(wp);
   1200   1.3  christos 		break;
   1201   1.3  christos 	}
   1202   1.3  christos }
   1203   1.3  christos 
   1204   1.3  christos static int
   1205   1.3  christos window_tree_kill_current_callback(struct client *c, void *modedata,
   1206   1.3  christos     const char *s, __unused int done)
   1207   1.3  christos {
   1208   1.3  christos 	struct window_tree_modedata	*data = modedata;
   1209   1.3  christos 	struct mode_tree_data		*mtd = data->data;
   1210   1.3  christos 
   1211   1.3  christos 	if (s == NULL || *s == '\0' || data->dead)
   1212   1.3  christos 		return (0);
   1213   1.3  christos 	if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
   1214   1.3  christos 		return (0);
   1215   1.3  christos 
   1216   1.3  christos 	window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
   1217   1.8  christos 	server_renumber_all();
   1218   1.3  christos 
   1219   1.3  christos 	data->references++;
   1220   1.3  christos 	cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
   1221   1.3  christos 
   1222   1.3  christos 	return (0);
   1223   1.3  christos }
   1224   1.3  christos 
   1225   1.3  christos static int
   1226   1.3  christos window_tree_kill_tagged_callback(struct client *c, void *modedata,
   1227   1.3  christos     const char *s, __unused int done)
   1228   1.3  christos {
   1229   1.3  christos 	struct window_tree_modedata	*data = modedata;
   1230   1.3  christos 	struct mode_tree_data		*mtd = data->data;
   1231   1.3  christos 
   1232   1.3  christos 	if (s == NULL || *s == '\0' || data->dead)
   1233   1.3  christos 		return (0);
   1234   1.3  christos 	if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
   1235   1.3  christos 		return (0);
   1236   1.3  christos 
   1237   1.3  christos 	mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
   1238   1.8  christos 	server_renumber_all();
   1239   1.3  christos 
   1240   1.3  christos 	data->references++;
   1241   1.3  christos 	cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
   1242   1.3  christos 
   1243   1.3  christos 	return (0);
   1244   1.3  christos }
   1245   1.3  christos 
   1246   1.3  christos static key_code
   1247   1.3  christos window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x,
   1248   1.3  christos     struct window_tree_itemdata *item)
   1249   1.3  christos {
   1250   1.3  christos 	struct session		*s;
   1251   1.3  christos 	struct winlink		*wl;
   1252   1.3  christos 	struct window_pane	*wp;
   1253   1.3  christos 	u_int			 loop;
   1254   1.3  christos 
   1255   1.3  christos 	if (key != KEYC_MOUSEDOWN1_PANE)
   1256   1.3  christos 		return (KEYC_NONE);
   1257   1.3  christos 
   1258   1.3  christos 	if (data->left != -1 && x <= (u_int)data->left)
   1259   1.3  christos 		return ('<');
   1260   1.3  christos 	if (data->right != -1 && x >= (u_int)data->right)
   1261   1.3  christos 		return ('>');
   1262   1.3  christos 
   1263   1.3  christos 	if (data->left != -1)
   1264   1.3  christos 		x -= data->left;
   1265   1.3  christos 	else if (x != 0)
   1266   1.3  christos 		x--;
   1267   1.3  christos 	if (x == 0 || data->end == 0)
   1268   1.3  christos 		x = 0;
   1269   1.3  christos 	else {
   1270   1.3  christos 		x = x / data->each;
   1271   1.3  christos 		if (data->start + x >= data->end)
   1272   1.3  christos 			x = data->end - 1;
   1273   1.3  christos 	}
   1274   1.3  christos 
   1275   1.3  christos 	window_tree_pull_item(item, &s, &wl, &wp);
   1276   1.3  christos 	if (item->type == WINDOW_TREE_SESSION) {
   1277   1.3  christos 		if (s == NULL)
   1278   1.3  christos 			return (KEYC_NONE);
   1279   1.3  christos 		mode_tree_expand_current(data->data);
   1280   1.3  christos 		loop = 0;
   1281   1.3  christos 		RB_FOREACH(wl, winlinks, &s->windows) {
   1282   1.3  christos 			if (loop == data->start + x)
   1283   1.3  christos 				break;
   1284   1.3  christos 			loop++;
   1285   1.3  christos 		}
   1286   1.3  christos 		if (wl != NULL)
   1287   1.4  christos 			mode_tree_set_current(data->data, (uintptr_t)wl);
   1288   1.3  christos 		return ('\r');
   1289   1.3  christos 	}
   1290   1.3  christos 	if (item->type == WINDOW_TREE_WINDOW) {
   1291   1.3  christos 		if (wl == NULL)
   1292   1.3  christos 			return (KEYC_NONE);
   1293   1.3  christos 		mode_tree_expand_current(data->data);
   1294   1.3  christos 		loop = 0;
   1295   1.3  christos 		TAILQ_FOREACH(wp, &wl->window->panes, entry) {
   1296   1.3  christos 			if (loop == data->start + x)
   1297   1.3  christos 				break;
   1298   1.3  christos 			loop++;
   1299   1.3  christos 		}
   1300   1.3  christos 		if (wp != NULL)
   1301   1.4  christos 			mode_tree_set_current(data->data, (uintptr_t)wp);
   1302   1.3  christos 		return ('\r');
   1303   1.3  christos 	}
   1304   1.3  christos 	return (KEYC_NONE);
   1305   1.3  christos }
   1306   1.3  christos 
   1307   1.3  christos static void
   1308   1.5  christos window_tree_key(struct window_mode_entry *wme, struct client *c,
   1309   1.5  christos     __unused struct session *s, __unused struct winlink *wl, key_code key,
   1310   1.5  christos     struct mouse_event *m)
   1311   1.1  christos {
   1312   1.5  christos 	struct window_pane		*wp = wme->wp;
   1313   1.5  christos 	struct window_tree_modedata	*data = wme->data;
   1314   1.3  christos 	struct window_tree_itemdata	*item, *new_item;
   1315   1.3  christos 	char				*name, *prompt = NULL;
   1316   1.8  christos 	struct cmd_find_state		 fs, *fsp = &data->fs;
   1317   1.1  christos 	int				 finished;
   1318   1.3  christos 	u_int				 tagged, x, y, idx;
   1319   1.3  christos 	struct session			*ns;
   1320   1.3  christos 	struct winlink			*nwl;
   1321   1.3  christos 	struct window_pane		*nwp;
   1322   1.1  christos 
   1323   1.1  christos 	item = mode_tree_get_current(data->data);
   1324   1.3  christos 	finished = mode_tree_key(data->data, c, &key, m, &x, &y);
   1325  1.11       wiz 
   1326  1.11       wiz again:
   1327   1.3  christos 	if (item != (new_item = mode_tree_get_current(data->data))) {
   1328   1.3  christos 		item = new_item;
   1329   1.1  christos 		data->offset = 0;
   1330   1.3  christos 	}
   1331  1.11       wiz 	if (KEYC_IS_MOUSE(key) && m != NULL) {
   1332   1.3  christos 		key = window_tree_mouse(data, key, x, item);
   1333  1.11       wiz 		goto again;
   1334  1.11       wiz 	}
   1335  1.11       wiz 
   1336   1.1  christos 	switch (key) {
   1337   1.1  christos 	case '<':
   1338   1.1  christos 		data->offset--;
   1339   1.1  christos 		break;
   1340   1.1  christos 	case '>':
   1341   1.1  christos 		data->offset++;
   1342   1.1  christos 		break;
   1343   1.8  christos 	case 'H':
   1344   1.9  christos 		mode_tree_expand(data->data, (uintptr_t)fsp->s);
   1345   1.9  christos 		mode_tree_expand(data->data, (uintptr_t)fsp->wl);
   1346   1.9  christos 		if (!mode_tree_set_current(data->data, (uintptr_t)wme->wp))
   1347   1.9  christos 			mode_tree_set_current(data->data, (uintptr_t)fsp->wl);
   1348   1.8  christos 		break;
   1349   1.8  christos 	case 'm':
   1350   1.8  christos 		window_tree_pull_item(item, &ns, &nwl, &nwp);
   1351   1.8  christos 		server_set_marked(ns, nwl, nwp);
   1352   1.8  christos 		mode_tree_build(data->data);
   1353   1.8  christos 		break;
   1354   1.8  christos 	case 'M':
   1355   1.8  christos 		server_clear_marked();
   1356   1.8  christos 		mode_tree_build(data->data);
   1357   1.8  christos 		break;
   1358   1.3  christos 	case 'x':
   1359   1.3  christos 		window_tree_pull_item(item, &ns, &nwl, &nwp);
   1360   1.3  christos 		switch (item->type) {
   1361   1.3  christos 		case WINDOW_TREE_NONE:
   1362   1.3  christos 			break;
   1363   1.3  christos 		case WINDOW_TREE_SESSION:
   1364   1.3  christos 			if (ns == NULL)
   1365   1.3  christos 				break;
   1366   1.3  christos 			xasprintf(&prompt, "Kill session %s? ", ns->name);
   1367   1.3  christos 			break;
   1368   1.3  christos 		case WINDOW_TREE_WINDOW:
   1369   1.3  christos 			if (nwl == NULL)
   1370   1.3  christos 				break;
   1371   1.3  christos 			xasprintf(&prompt, "Kill window %u? ", nwl->idx);
   1372   1.3  christos 			break;
   1373   1.3  christos 		case WINDOW_TREE_PANE:
   1374   1.3  christos 			if (nwp == NULL || window_pane_index(nwp, &idx) != 0)
   1375   1.3  christos 				break;
   1376   1.3  christos 			xasprintf(&prompt, "Kill pane %u? ", idx);
   1377   1.3  christos 			break;
   1378   1.3  christos 		}
   1379   1.3  christos 		if (prompt == NULL)
   1380   1.3  christos 			break;
   1381   1.3  christos 		data->references++;
   1382   1.8  christos 		status_prompt_set(c, NULL, prompt, "",
   1383   1.3  christos 		    window_tree_kill_current_callback, window_tree_command_free,
   1384  1.12       wiz 		    data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
   1385  1.12       wiz 		    PROMPT_TYPE_COMMAND);
   1386   1.3  christos 		free(prompt);
   1387   1.3  christos 		break;
   1388   1.3  christos 	case 'X':
   1389   1.3  christos 		tagged = mode_tree_count_tagged(data->data);
   1390   1.3  christos 		if (tagged == 0)
   1391   1.3  christos 			break;
   1392   1.3  christos 		xasprintf(&prompt, "Kill %u tagged? ", tagged);
   1393   1.3  christos 		data->references++;
   1394   1.8  christos 		status_prompt_set(c, NULL, prompt, "",
   1395   1.3  christos 		    window_tree_kill_tagged_callback, window_tree_command_free,
   1396  1.12       wiz 		    data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
   1397  1.12       wiz 		    PROMPT_TYPE_COMMAND);
   1398   1.3  christos 		free(prompt);
   1399   1.3  christos 		break;
   1400   1.1  christos 	case ':':
   1401   1.1  christos 		tagged = mode_tree_count_tagged(data->data);
   1402   1.1  christos 		if (tagged != 0)
   1403   1.1  christos 			xasprintf(&prompt, "(%u tagged) ", tagged);
   1404   1.1  christos 		else
   1405   1.1  christos 			xasprintf(&prompt, "(current) ");
   1406   1.1  christos 		data->references++;
   1407   1.8  christos 		status_prompt_set(c, NULL, prompt, "",
   1408   1.8  christos 		    window_tree_command_callback, window_tree_command_free,
   1409  1.10       wiz 		    data, PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
   1410   1.1  christos 		free(prompt);
   1411   1.1  christos 		break;
   1412   1.1  christos 	case '\r':
   1413   1.1  christos 		name = window_tree_get_target(item, &fs);
   1414   1.1  christos 		if (name != NULL)
   1415   1.3  christos 			mode_tree_run_command(c, NULL, data->command, name);
   1416   1.3  christos 		finished = 1;
   1417   1.1  christos 		free(name);
   1418   1.3  christos 		break;
   1419   1.1  christos 	}
   1420   1.1  christos 	if (finished)
   1421   1.1  christos 		window_pane_reset_mode(wp);
   1422   1.1  christos 	else {
   1423   1.1  christos 		mode_tree_draw(data->data);
   1424   1.1  christos 		wp->flags |= PANE_REDRAW;
   1425   1.1  christos 	}
   1426   1.1  christos }
   1427