Coverage Report

Created: 2025-08-29 06:28

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