Annotation of src/usr.bin/tmux/window-tree.c, Revision 1.19
1.19 ! nicm 1: /* $OpenBSD: window-tree.c,v 1.18 2017/10/11 08:08:16 nicm Exp $ */
1.1 nicm 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 <stdlib.h>
22: #include <string.h>
23:
24: #include "tmux.h"
25:
26: static struct screen *window_tree_init(struct window_pane *,
27: struct cmd_find_state *, struct args *);
28: static void window_tree_free(struct window_pane *);
29: static void window_tree_resize(struct window_pane *, u_int, u_int);
30: static void window_tree_key(struct window_pane *,
31: struct client *, struct session *, key_code,
32: struct mouse_event *);
33:
34: #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -t '%%'"
35:
1.15 nicm 36: #define WINDOW_TREE_DEFAULT_FORMAT \
37: "#{?pane_format," \
38: "#{pane_current_command} \"#{pane_title}\"" \
39: "," \
40: "#{?window_format," \
41: "#{window_name}#{window_flags} " \
42: "(#{window_panes} panes)" \
43: "#{?#{==:#{window_panes},1}, \"#{pane_title}\",}" \
44: "," \
45: "#{session_windows} windows" \
46: "#{?session_grouped, (group ,}" \
47: "#{session_group}#{?session_grouped,),}" \
48: "#{?session_attached, (attached),}" \
49: "}" \
50: "}"
51:
1.1 nicm 52: const struct window_mode window_tree_mode = {
53: .name = "tree-mode",
54:
55: .init = window_tree_init,
56: .free = window_tree_free,
57: .resize = window_tree_resize,
58: .key = window_tree_key,
59: };
60:
61: enum window_tree_sort_type {
62: WINDOW_TREE_BY_INDEX,
63: WINDOW_TREE_BY_NAME,
64: WINDOW_TREE_BY_TIME,
65: };
66: static const char *window_tree_sort_list[] = {
67: "index",
68: "name",
69: "time"
70: };
71:
72: enum window_tree_type {
73: WINDOW_TREE_NONE,
74: WINDOW_TREE_SESSION,
75: WINDOW_TREE_WINDOW,
76: WINDOW_TREE_PANE,
77: };
78:
79: struct window_tree_itemdata {
80: enum window_tree_type type;
81: int session;
82: int winlink;
83: int pane;
84: };
85:
86: struct window_tree_modedata {
87: struct window_pane *wp;
88: int dead;
89: int references;
90:
91: struct mode_tree_data *data;
1.15 nicm 92: char *format;
1.1 nicm 93: char *command;
94:
95: struct window_tree_itemdata **item_list;
96: u_int item_size;
97:
98: struct client *client;
99: const char *entered;
100:
101: struct cmd_find_state fs;
102: enum window_tree_type type;
1.11 nicm 103:
104: int offset;
1.1 nicm 105: };
106:
107: static void
108: window_tree_pull_item(struct window_tree_itemdata *item, struct session **sp,
109: struct winlink **wlp, struct window_pane **wp)
110: {
111: *wp = NULL;
112: *wlp = NULL;
113: *sp = session_find_by_id(item->session);
114: if (*sp == NULL)
115: return;
116: if (item->type == WINDOW_TREE_SESSION) {
117: *wlp = (*sp)->curw;
118: *wp = (*wlp)->window->active;
119: return;
120: }
121:
122: *wlp = winlink_find_by_index(&(*sp)->windows, item->winlink);
123: if (*wlp == NULL) {
124: *sp = NULL;
125: return;
126: }
127: if (item->type == WINDOW_TREE_WINDOW) {
128: *wp = (*wlp)->window->active;
129: return;
130: }
131:
132: *wp = window_pane_find_by_id(item->pane);
133: if (!window_has_pane((*wlp)->window, *wp))
134: *wp = NULL;
135: if (*wp == NULL) {
136: *sp = NULL;
137: *wlp = NULL;
138: return;
139: }
140: }
141:
142: static struct window_tree_itemdata *
143: window_tree_add_item(struct window_tree_modedata *data)
144: {
145: struct window_tree_itemdata *item;
146:
147: data->item_list = xreallocarray(data->item_list, data->item_size + 1,
148: sizeof *data->item_list);
149: item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
150: return (item);
151: }
152:
153: static void
154: window_tree_free_item(struct window_tree_itemdata *item)
155: {
156: free(item);
157: }
158:
159: static int
160: window_tree_cmp_session_name(const void *a0, const void *b0)
161: {
162: const struct session *const *a = a0;
163: const struct session *const *b = b0;
164:
165: return (strcmp((*a)->name, (*b)->name));
166: }
167:
168: static int
169: window_tree_cmp_session_time(const void *a0, const void *b0)
170: {
171: const struct session *const *a = a0;
172: const struct session *const *b = b0;
173:
174: if (timercmp(&(*a)->activity_time, &(*b)->activity_time, >))
175: return (-1);
176: if (timercmp(&(*a)->activity_time, &(*b)->activity_time, <))
177: return (1);
178: return (strcmp((*a)->name, (*b)->name));
179: }
180:
181: static int
182: window_tree_cmp_window_name(const void *a0, const void *b0)
183: {
184: const struct winlink *const *a = a0;
185: const struct winlink *const *b = b0;
186:
187: return (strcmp((*a)->window->name, (*b)->window->name));
188: }
189:
190: static int
191: window_tree_cmp_window_time(const void *a0, const void *b0)
192: {
193: const struct winlink *const *a = a0;
194: const struct winlink *const *b = b0;
195:
196: if (timercmp(&(*a)->window->activity_time,
197: &(*b)->window->activity_time, >))
198: return (-1);
199: if (timercmp(&(*a)->window->activity_time,
200: &(*b)->window->activity_time, <))
201: return (1);
202: return (strcmp((*a)->window->name, (*b)->window->name));
203: }
204:
205: static int
206: window_tree_cmp_pane_time(const void *a0, const void *b0)
207: {
208: const struct window_pane *const *a = a0;
209: const struct window_pane *const *b = b0;
210:
211: if ((*a)->active_point < (*b)->active_point)
212: return (-1);
213: if ((*a)->active_point > (*b)->active_point)
214: return (1);
215: return (0);
216: }
217:
218: static void
219: window_tree_build_pane(struct session *s, struct winlink *wl,
220: struct window_pane *wp, void *modedata, struct mode_tree_item *parent)
221: {
222: struct window_tree_modedata *data = modedata;
223: struct window_tree_itemdata *item;
224: char *name, *text;
225: u_int idx;
226:
227: window_pane_index(wp, &idx);
228:
229: item = window_tree_add_item(data);
230: item->type = WINDOW_TREE_PANE;
231: item->session = s->id;
232: item->winlink = wl->idx;
233: item->pane = wp->id;
234:
1.15 nicm 235: text = format_single(NULL, data->format, NULL, s, wl, wp);
1.1 nicm 236: xasprintf(&name, "%u", idx);
237:
238: mode_tree_add(data->data, parent, item, (uint64_t)wp, name, text, -1);
239: free(text);
240: free(name);
241: }
242:
243: static int
1.16 nicm 244: window_tree_filter_pane(struct session *s, struct winlink *wl,
245: struct window_pane *wp, const char *filter)
246: {
247: char *cp;
248: int result;
249:
250: if (filter == NULL)
251: return (1);
252:
253: cp = format_single(NULL, filter, NULL, s, wl, wp);
254: result = format_true(cp);
255: free(cp);
256:
257: return (result);
258: }
259:
260: static int
1.1 nicm 261: window_tree_build_window(struct session *s, struct winlink *wl, void* modedata,
1.5 nicm 262: u_int sort_type, struct mode_tree_item *parent, const char *filter)
1.1 nicm 263: {
264: struct window_tree_modedata *data = modedata;
265: struct window_tree_itemdata *item;
266: struct mode_tree_item *mti;
1.16 nicm 267: char *name, *text;
1.1 nicm 268: struct window_pane *wp, **l;
269: u_int n, i;
270: int expanded;
271:
272: item = window_tree_add_item(data);
273: item->type = WINDOW_TREE_WINDOW;
274: item->session = s->id;
275: item->winlink = wl->idx;
276: item->pane = -1;
277:
1.15 nicm 278: text = format_single(NULL, data->format, NULL, s, wl, NULL);
1.1 nicm 279: xasprintf(&name, "%u", wl->idx);
280:
281: if (data->type == WINDOW_TREE_SESSION ||
282: data->type == WINDOW_TREE_WINDOW)
283: expanded = 0;
284: else
285: expanded = 1;
286: mti = mode_tree_add(data->data, parent, item, (uint64_t)wl, name, text,
287: expanded);
288: free(text);
289: free(name);
290:
1.16 nicm 291: wp = TAILQ_FIRST(&wl->window->panes);
292: if (TAILQ_NEXT(wp, entry) == NULL) {
293: if (!window_tree_filter_pane(s, wl, wp, filter))
294: goto empty;
1.13 nicm 295: return (1);
1.16 nicm 296: }
1.13 nicm 297:
1.1 nicm 298: l = NULL;
299: n = 0;
1.13 nicm 300:
1.1 nicm 301: TAILQ_FOREACH(wp, &wl->window->panes, entry) {
1.16 nicm 302: if (!window_tree_filter_pane(s, wl, wp, filter))
303: continue;
1.1 nicm 304: l = xreallocarray(l, n + 1, sizeof *l);
305: l[n++] = wp;
306: }
1.16 nicm 307: if (n == 0)
308: goto empty;
1.1 nicm 309:
310: switch (sort_type) {
311: case WINDOW_TREE_BY_INDEX:
312: break;
313: case WINDOW_TREE_BY_NAME:
314: /* Panes don't have names, so leave in number order. */
315: break;
316: case WINDOW_TREE_BY_TIME:
317: qsort(l, n, sizeof *l, window_tree_cmp_pane_time);
318: break;
319: }
320:
321: for (i = 0; i < n; i++)
322: window_tree_build_pane(s, wl, l[i], modedata, mti);
323: free(l);
324: return (1);
1.16 nicm 325:
326: empty:
327: window_tree_free_item(item);
328: data->item_size--;
329: mode_tree_remove(data->data, mti);
330: return (0);
1.1 nicm 331: }
332:
333: static void
334: window_tree_build_session(struct session *s, void* modedata,
1.5 nicm 335: u_int sort_type, const char *filter)
1.1 nicm 336: {
337: struct window_tree_modedata *data = modedata;
338: struct window_tree_itemdata *item;
339: struct mode_tree_item *mti;
340: char *text;
341: struct winlink *wl, **l;
342: u_int n, i, empty;
343: int expanded;
344:
345: item = window_tree_add_item(data);
346: item->type = WINDOW_TREE_SESSION;
347: item->session = s->id;
348: item->winlink = -1;
349: item->pane = -1;
350:
1.15 nicm 351: text = format_single(NULL, data->format, NULL, s, NULL, NULL);
1.1 nicm 352:
353: if (data->type == WINDOW_TREE_SESSION)
354: expanded = 0;
355: else
356: expanded = 1;
357: mti = mode_tree_add(data->data, NULL, item, (uint64_t)s, s->name, text,
358: expanded);
359: free(text);
360:
361: l = NULL;
362: n = 0;
363: RB_FOREACH(wl, winlinks, &s->windows) {
364: l = xreallocarray(l, n + 1, sizeof *l);
365: l[n++] = wl;
366: }
367: switch (sort_type) {
368: case WINDOW_TREE_BY_INDEX:
369: break;
370: case WINDOW_TREE_BY_NAME:
371: qsort(l, n, sizeof *l, window_tree_cmp_window_name);
372: break;
373: case WINDOW_TREE_BY_TIME:
374: qsort(l, n, sizeof *l, window_tree_cmp_window_time);
375: break;
376: }
377:
378: empty = 0;
379: for (i = 0; i < n; i++) {
380: if (!window_tree_build_window(s, l[i], modedata, sort_type, mti,
1.5 nicm 381: filter))
1.1 nicm 382: empty++;
383: }
384: if (empty == n) {
385: window_tree_free_item(item);
386: data->item_size--;
387: mode_tree_remove(data->data, mti);
388: }
389: free(l);
390: }
391:
392: static void
1.5 nicm 393: window_tree_build(void *modedata, u_int sort_type, uint64_t *tag,
394: const char *filter)
1.1 nicm 395: {
396: struct window_tree_modedata *data = modedata;
397: struct session *s, **l;
398: u_int n, i;
399:
400: for (i = 0; i < data->item_size; i++)
401: window_tree_free_item(data->item_list[i]);
402: free(data->item_list);
403: data->item_list = NULL;
404: data->item_size = 0;
405:
406: l = NULL;
407: n = 0;
408: RB_FOREACH(s, sessions, &sessions) {
409: l = xreallocarray(l, n + 1, sizeof *l);
410: l[n++] = s;
411: }
412: switch (sort_type) {
413: case WINDOW_TREE_BY_INDEX:
414: break;
415: case WINDOW_TREE_BY_NAME:
416: qsort(l, n, sizeof *l, window_tree_cmp_session_name);
417: break;
418: case WINDOW_TREE_BY_TIME:
419: qsort(l, n, sizeof *l, window_tree_cmp_session_time);
420: break;
421: }
422:
423: for (i = 0; i < n; i++)
1.5 nicm 424: window_tree_build_session(l[i], modedata, sort_type, filter);
1.1 nicm 425: free(l);
426:
427: switch (data->type) {
428: case WINDOW_TREE_NONE:
429: break;
430: case WINDOW_TREE_SESSION:
431: *tag = (uint64_t)data->fs.s;
432: break;
433: case WINDOW_TREE_WINDOW:
434: *tag = (uint64_t)data->fs.wl;
435: break;
436: case WINDOW_TREE_PANE:
1.18 nicm 437: if (window_count_panes(data->fs.wl->window) == 1)
438: *tag = (uint64_t)data->fs.wl;
439: else
440: *tag = (uint64_t)data->fs.wp;
1.1 nicm 441: break;
442: }
443: }
444:
1.19 ! nicm 445:
! 446: static void
! 447: window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
! 448: u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
! 449: {
! 450: size_t len;
! 451: u_int ox, oy;
! 452:
! 453: len = strlen(label);
! 454: if (sx == 0 || sy == 1 || len > sx)
! 455: return;
! 456: ox = (sx - len + 1) / 2;
! 457: oy = (sy + 1) / 2;
! 458:
! 459: if (ox > 1 && ox + len < sx - 1 && sy >= 3) {
! 460: screen_write_cursormove(ctx, px + ox - 1, py + oy - 1);
! 461: screen_write_box(ctx, len + 2, 3);
! 462: }
! 463: screen_write_cursormove(ctx, px + ox, py + oy);
! 464: screen_write_puts(ctx, gc, "%s", label);
! 465: }
! 466:
1.6 nicm 467: static void
1.11 nicm 468: window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
469: struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6 nicm 470: {
471: struct options *oo = s->options;
472: struct winlink *wl;
473: struct window *w;
1.9 nicm 474: u_int loop, total, visible, each, width, offset;
475: u_int current, start, end, remaining, i;
1.6 nicm 476: struct grid_cell gc;
1.9 nicm 477: int colour, active_colour, left, right;
1.6 nicm 478: char *label;
479:
1.9 nicm 480: total = winlink_count(&s->windows);
1.6 nicm 481:
482: memcpy(&gc, &grid_default_cell, sizeof gc);
483: colour = options_get_number(oo, "display-panes-colour");
484: active_colour = options_get_number(oo, "display-panes-active-colour");
485:
1.9 nicm 486: if (sx / total < 24) {
487: visible = sx / 24;
488: if (visible == 0)
489: visible = 1;
490: } else
491: visible = total;
492:
493: current = 0;
494: RB_FOREACH(wl, winlinks, &s->windows) {
495: if (wl == s->curw)
496: break;
497: current++;
498: }
1.6 nicm 499:
1.9 nicm 500: if (current < visible) {
501: start = 0;
502: end = visible;
503: } else if (current >= total - visible) {
504: start = total - visible;
505: end = total;
506: } else {
507: start = current - (visible / 2);
508: end = start + visible;
509: }
510:
1.11 nicm 511: if (data->offset < -(int)start)
512: data->offset = -(int)start;
513: if (data->offset > (int)(total - end))
514: data->offset = (int)(total - end);
515: start += data->offset;
516: end += data->offset;
517:
1.9 nicm 518: left = (start != 0);
519: right = (end != total);
520: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
521: left = right = 0;
522: if (left && right) {
523: each = (sx - 6) / visible;
524: remaining = (sx - 6) - (visible * each);
525: } else if (left || right) {
526: each = (sx - 3) / visible;
527: remaining = (sx - 3) - (visible * each);
528: } else {
529: each = sx / visible;
530: remaining = sx - (visible * each);
531: }
532: if (each == 0)
533: return;
534:
535: if (left) {
536: screen_write_cursormove(ctx, 2, 0);
537: screen_write_vline(ctx, sy, 0, 0);
538: screen_write_cursormove(ctx, 0, sy / 2);
539: screen_write_puts(ctx, &grid_default_cell, "<");
540: }
541: if (right) {
542: screen_write_cursormove(ctx, sx - 3, 0);
1.6 nicm 543: screen_write_vline(ctx, sy, 0, 0);
1.9 nicm 544: screen_write_cursormove(ctx, sx - 1, sy / 2);
545: screen_write_puts(ctx, &grid_default_cell, ">");
546: }
1.6 nicm 547:
1.9 nicm 548: i = loop = 0;
549: RB_FOREACH(wl, winlinks, &s->windows) {
550: if (loop == end)
551: break;
552: if (loop < start) {
553: loop++;
554: continue;
555: }
556: w = wl->window;
1.6 nicm 557:
558: if (wl == s->curw)
559: gc.fg = active_colour;
560: else
561: gc.fg = colour;
1.9 nicm 562:
563: if (left)
564: offset = 3 + (i * each);
565: else
566: offset = (i * each);
567: if (loop == end - 1)
1.12 nicm 568: width = each + remaining;
1.6 nicm 569: else
570: width = each - 1;
571:
1.9 nicm 572: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 573: screen_write_preview(ctx, &w->active->base, width, sy);
574:
575: xasprintf(&label, " %u:%s ", wl->idx, w->name);
576: if (strlen(label) > width)
577: xasprintf(&label, " %u ", wl->idx);
1.19 ! nicm 578: window_tree_draw_label(ctx, offset, 0, width, sy, &gc, label);
1.6 nicm 579: free(label);
580:
1.9 nicm 581: if (loop != end - 1) {
582: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 583: screen_write_vline(ctx, sy, 0, 0);
584: }
1.9 nicm 585: loop++;
586:
587: i++;
1.6 nicm 588: }
589: }
590:
591: static void
1.11 nicm 592: window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
593: struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6 nicm 594: {
595: struct options *oo = s->options;
596: struct window_pane *wp;
1.9 nicm 597: u_int loop, total, visible, each, width, offset;
598: u_int current, start, end, remaining, i;
1.6 nicm 599: struct grid_cell gc;
1.9 nicm 600: int colour, active_colour, left, right;
1.6 nicm 601: char *label;
602:
1.9 nicm 603: total = window_count_panes(w);
1.6 nicm 604:
605: memcpy(&gc, &grid_default_cell, sizeof gc);
606: colour = options_get_number(oo, "display-panes-colour");
607: active_colour = options_get_number(oo, "display-panes-active-colour");
608:
1.9 nicm 609: if (sx / total < 24) {
610: visible = sx / 24;
611: if (visible == 0)
612: visible = 1;
613: } else
614: visible = total;
615:
616: current = 0;
617: TAILQ_FOREACH(wp, &w->panes, entry) {
618: if (wp == w->active)
619: break;
620: current++;
621: }
622:
623: if (current < visible) {
624: start = 0;
625: end = visible;
626: } else if (current >= total - visible) {
627: start = total - visible;
628: end = total;
629: } else {
630: start = current - (visible / 2);
631: end = start + visible;
632: }
633:
1.11 nicm 634: if (data->offset < -(int)start)
635: data->offset = -(int)start;
636: if (data->offset > (int)(total - end))
637: data->offset = (int)(total - end);
638: start += data->offset;
639: end += data->offset;
640:
1.9 nicm 641: left = (start != 0);
642: right = (end != total);
643: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
644: left = right = 0;
645: if (left && right) {
646: each = (sx - 6) / visible;
647: remaining = (sx - 6) - (visible * each);
648: } else if (left || right) {
649: each = (sx - 3) / visible;
650: remaining = (sx - 3) - (visible * each);
651: } else {
652: each = sx / visible;
653: remaining = sx - (visible * each);
654: }
655: if (each == 0)
656: return;
1.6 nicm 657:
1.9 nicm 658: if (left) {
659: screen_write_cursormove(ctx, 2, 0);
1.6 nicm 660: screen_write_vline(ctx, sy, 0, 0);
1.9 nicm 661: screen_write_cursormove(ctx, 0, sy / 2);
662: screen_write_puts(ctx, &grid_default_cell, "<");
663: }
664: if (right) {
665: screen_write_cursormove(ctx, sx - 3, 0);
666: screen_write_vline(ctx, sy, 0, 0);
667: screen_write_cursormove(ctx, sx - 1, sy / 2);
668: screen_write_puts(ctx, &grid_default_cell, ">");
669: }
1.6 nicm 670:
1.9 nicm 671: i = loop = 0;
672: TAILQ_FOREACH(wp, &w->panes, entry) {
673: if (loop == end)
674: break;
675: if (loop < start) {
676: loop++;
677: continue;
678: }
1.6 nicm 679:
680: if (wp == w->active)
681: gc.fg = active_colour;
682: else
683: gc.fg = colour;
1.9 nicm 684:
685: if (left)
686: offset = 3 + (i * each);
687: else
688: offset = (i * each);
689: if (loop == end - 1)
1.12 nicm 690: width = each + remaining;
1.6 nicm 691: else
692: width = each - 1;
693:
1.9 nicm 694: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 695: screen_write_preview(ctx, &wp->base, width, sy);
696:
1.9 nicm 697: xasprintf(&label, " %u ", loop);
1.19 ! nicm 698: window_tree_draw_label(ctx, offset, 0, each, sy, &gc, label);
1.6 nicm 699: free(label);
700:
1.9 nicm 701: if (loop != end - 1) {
702: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 703: screen_write_vline(ctx, sy, 0, 0);
704: }
1.9 nicm 705: loop++;
706:
707: i++;
1.6 nicm 708: }
709: }
710:
1.1 nicm 711: static struct screen *
1.11 nicm 712: window_tree_draw(void *modedata, void *itemdata, u_int sx, u_int sy)
1.1 nicm 713: {
714: struct window_tree_itemdata *item = itemdata;
715: struct session *sp;
716: struct winlink *wlp;
717: struct window_pane *wp;
718: static struct screen s;
719: struct screen_write_ctx ctx;
720:
721: window_tree_pull_item(item, &sp, &wlp, &wp);
722: if (wp == NULL)
723: return (NULL);
724:
725: screen_init(&s, sx, sy, 0);
726: screen_write_start(&ctx, NULL, &s);
727:
1.6 nicm 728: switch (item->type) {
729: case WINDOW_TREE_NONE:
730: return (0);
731: case WINDOW_TREE_SESSION:
1.11 nicm 732: window_tree_draw_session(modedata, sp, &ctx, sx, sy);
1.6 nicm 733: break;
734: case WINDOW_TREE_WINDOW:
1.11 nicm 735: window_tree_draw_window(modedata, sp, wlp->window, &ctx, sx, sy);
1.6 nicm 736: break;
737: case WINDOW_TREE_PANE:
738: screen_write_preview(&ctx, &wp->base, sx, sy);
739: break;
740: }
1.1 nicm 741:
742: screen_write_stop(&ctx);
743: return (&s);
744: }
745:
1.3 nicm 746: static int
747: window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
748: {
749: struct window_tree_itemdata *item = itemdata;
750: struct session *s;
751: struct winlink *wl;
752: struct window_pane *wp;
753: const char *cmd;
754:
755: window_tree_pull_item(item, &s, &wl, &wp);
756:
757: switch (item->type) {
758: case WINDOW_TREE_NONE:
759: return (0);
760: case WINDOW_TREE_SESSION:
761: if (s == NULL)
762: return (0);
763: return (strstr(s->name, ss) != NULL);
764: case WINDOW_TREE_WINDOW:
765: if (s == NULL || wl == NULL)
766: return (0);
767: return (strstr(wl->window->name, ss) != NULL);
768: case WINDOW_TREE_PANE:
769: if (s == NULL || wl == NULL || wp == NULL)
770: break;
771: cmd = get_proc_name(wp->fd, wp->tty);
772: if (cmd == NULL || *cmd == '\0')
773: return (0);
774: return (strstr(cmd, ss) != NULL);
775: }
776: return (0);
777: }
778:
1.1 nicm 779: static struct screen *
780: window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
781: struct args *args)
782: {
783: struct window_tree_modedata *data;
784: struct screen *s;
785:
786: wp->modedata = data = xcalloc(1, sizeof *data);
787:
788: if (args_has(args, 's'))
789: data->type = WINDOW_TREE_SESSION;
790: else if (args_has(args, 'w'))
791: data->type = WINDOW_TREE_WINDOW;
792: else
793: data->type = WINDOW_TREE_PANE;
794: memcpy(&data->fs, fs, sizeof data->fs);
795:
796: data->wp = wp;
797: data->references = 1;
798:
1.15 nicm 799: if (args == NULL || !args_has(args, 'F'))
800: data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
801: else
802: data->format = xstrdup(args_get(args, 'F'));
1.1 nicm 803: if (args == NULL || args->argc == 0)
804: data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
805: else
806: data->command = xstrdup(args->argv[0]);
807:
1.4 nicm 808: data->data = mode_tree_start(wp, args, window_tree_build,
809: window_tree_draw, window_tree_search, data, window_tree_sort_list,
1.1 nicm 810: nitems(window_tree_sort_list), &s);
811:
812: mode_tree_build(data->data);
813: mode_tree_draw(data->data);
814:
815: data->type = WINDOW_TREE_NONE;
816:
817: return (s);
818: }
819:
820: static void
821: window_tree_destroy(struct window_tree_modedata *data)
822: {
823: u_int i;
824:
825: if (--data->references != 0)
826: return;
827:
828: mode_tree_free(data->data);
829:
830: for (i = 0; i < data->item_size; i++)
831: window_tree_free_item(data->item_list[i]);
832: free(data->item_list);
833:
1.15 nicm 834: free(data->format);
1.1 nicm 835: free(data->command);
1.15 nicm 836:
1.1 nicm 837: free(data);
838: }
839:
840: static void
841: window_tree_free(struct window_pane *wp)
842: {
843: struct window_tree_modedata *data = wp->modedata;
844:
845: if (data == NULL)
846: return;
847:
848: data->dead = 1;
849: window_tree_destroy(data);
850: }
851:
852: static void
853: window_tree_resize(struct window_pane *wp, u_int sx, u_int sy)
854: {
855: struct window_tree_modedata *data = wp->modedata;
856:
857: mode_tree_resize(data->data, sx, sy);
858: }
859:
860: static char *
861: window_tree_get_target(struct window_tree_itemdata *item,
862: struct cmd_find_state *fs)
863: {
864: struct session *s;
865: struct winlink *wl;
866: struct window_pane *wp;
867: char *target;
868:
869: window_tree_pull_item(item, &s, &wl, &wp);
870:
871: target = NULL;
872: switch (item->type) {
873: case WINDOW_TREE_NONE:
874: break;
875: case WINDOW_TREE_SESSION:
876: if (s == NULL)
877: break;
878: xasprintf(&target, "=%s:", s->name);
879: break;
880: case WINDOW_TREE_WINDOW:
881: if (s == NULL || wl == NULL)
882: break;
883: xasprintf(&target, "=%s:%u.", s->name, wl->idx);
884: break;
885: case WINDOW_TREE_PANE:
886: if (s == NULL || wl == NULL || wp == NULL)
887: break;
888: xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
889: break;
890: }
891: if (target == NULL)
892: cmd_find_clear_state(fs, 0);
893: else
1.17 nicm 894: cmd_find_from_winlink_pane(fs, wl, wp, 0);
1.1 nicm 895: return (target);
896: }
897:
898: static void
899: window_tree_command_each(void* modedata, void* itemdata, __unused key_code key)
900: {
901: struct window_tree_modedata *data = modedata;
902: struct window_tree_itemdata *item = itemdata;
903: char *name;
904: struct cmd_find_state fs;
905:
906: name = window_tree_get_target(item, &fs);
907: if (name != NULL)
908: mode_tree_run_command(data->client, &fs, data->entered, name);
909: free(name);
910: }
911:
912: static enum cmd_retval
913: window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
914: {
915: struct window_tree_modedata *data = modedata;
916:
917: if (!data->dead) {
918: mode_tree_build(data->data);
919: mode_tree_draw(data->data);
920: data->wp->flags |= PANE_REDRAW;
921: }
922: window_tree_destroy(data);
923: return (CMD_RETURN_NORMAL);
924: }
925:
926: static int
927: window_tree_command_callback(struct client *c, void *modedata, const char *s,
928: __unused int done)
929: {
930: struct window_tree_modedata *data = modedata;
931:
932: if (data->dead)
933: return (0);
934:
935: data->client = c;
936: data->entered = s;
937:
938: mode_tree_each_tagged(data->data, window_tree_command_each, KEYC_NONE,
939: 1);
940:
941: data->client = NULL;
942: data->entered = NULL;
943:
944: data->references++;
945: cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
946:
947: return (0);
948: }
949:
950: static void
951: window_tree_command_free(void *modedata)
952: {
953: struct window_tree_modedata *data = modedata;
954:
955: window_tree_destroy(data);
956: }
957:
958: static void
959: window_tree_key(struct window_pane *wp, struct client *c,
960: __unused struct session *s, key_code key, struct mouse_event *m)
961: {
962: struct window_tree_modedata *data = wp->modedata;
963: struct window_tree_itemdata *item;
964: char *command, *name, *prompt;
965: struct cmd_find_state fs;
966: int finished;
967: u_int tagged;
968:
1.11 nicm 969: item = mode_tree_get_current(data->data);
1.3 nicm 970: finished = mode_tree_key(data->data, c, &key, m);
1.11 nicm 971: if (item != mode_tree_get_current(data->data))
972: data->offset = 0;
1.1 nicm 973: switch (key) {
1.11 nicm 974: case '<':
975: data->offset--;
976: break;
977: case '>':
978: data->offset++;
979: break;
1.1 nicm 980: case ':':
981: tagged = mode_tree_count_tagged(data->data);
982: if (tagged != 0)
983: xasprintf(&prompt, "(%u tagged) ", tagged);
984: else
985: xasprintf(&prompt, "(current) ");
986: data->references++;
987: status_prompt_set(c, prompt, "", window_tree_command_callback,
988: window_tree_command_free, data, PROMPT_NOFORMAT);
989: free(prompt);
990: break;
991: case '\r':
992: item = mode_tree_get_current(data->data);
993: command = xstrdup(data->command);
994: name = window_tree_get_target(item, &fs);
995: window_pane_reset_mode(wp);
996: if (name != NULL)
1.2 nicm 997: mode_tree_run_command(c, NULL, command, name);
1.1 nicm 998: free(name);
999: free(command);
1000: return;
1001: }
1002: if (finished)
1003: window_pane_reset_mode(wp);
1004: else {
1005: mode_tree_draw(data->data);
1006: wp->flags |= PANE_REDRAW;
1007: }
1008: }