Annotation of src/usr.bin/tmux/window-tree.c, Revision 1.16
1.16 ! nicm 1: /* $OpenBSD: window-tree.c,v 1.15 2017/08/09 11:43:45 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:
437: *tag = (uint64_t)data->fs.wp;
438: break;
439: }
440: }
441:
1.6 nicm 442: static void
1.11 nicm 443: window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
444: struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6 nicm 445: {
446: struct options *oo = s->options;
447: struct winlink *wl;
448: struct window *w;
1.9 nicm 449: u_int loop, total, visible, each, width, offset;
450: u_int current, start, end, remaining, i;
1.6 nicm 451: struct grid_cell gc;
1.9 nicm 452: int colour, active_colour, left, right;
1.6 nicm 453: char *label;
454: size_t len;
455:
1.9 nicm 456: total = winlink_count(&s->windows);
1.6 nicm 457:
458: memcpy(&gc, &grid_default_cell, sizeof gc);
459: colour = options_get_number(oo, "display-panes-colour");
460: active_colour = options_get_number(oo, "display-panes-active-colour");
461:
1.9 nicm 462: if (sx / total < 24) {
463: visible = sx / 24;
464: if (visible == 0)
465: visible = 1;
466: } else
467: visible = total;
468:
469: current = 0;
470: RB_FOREACH(wl, winlinks, &s->windows) {
471: if (wl == s->curw)
472: break;
473: current++;
474: }
1.6 nicm 475:
1.9 nicm 476: if (current < visible) {
477: start = 0;
478: end = visible;
479: } else if (current >= total - visible) {
480: start = total - visible;
481: end = total;
482: } else {
483: start = current - (visible / 2);
484: end = start + visible;
485: }
486:
1.11 nicm 487: if (data->offset < -(int)start)
488: data->offset = -(int)start;
489: if (data->offset > (int)(total - end))
490: data->offset = (int)(total - end);
491: start += data->offset;
492: end += data->offset;
493:
1.9 nicm 494: left = (start != 0);
495: right = (end != total);
496: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
497: left = right = 0;
498: if (left && right) {
499: each = (sx - 6) / visible;
500: remaining = (sx - 6) - (visible * each);
501: } else if (left || right) {
502: each = (sx - 3) / visible;
503: remaining = (sx - 3) - (visible * each);
504: } else {
505: each = sx / visible;
506: remaining = sx - (visible * each);
507: }
508: if (each == 0)
509: return;
510:
511: if (left) {
512: screen_write_cursormove(ctx, 2, 0);
513: screen_write_vline(ctx, sy, 0, 0);
514: screen_write_cursormove(ctx, 0, sy / 2);
515: screen_write_puts(ctx, &grid_default_cell, "<");
516: }
517: if (right) {
518: screen_write_cursormove(ctx, sx - 3, 0);
1.6 nicm 519: screen_write_vline(ctx, sy, 0, 0);
1.9 nicm 520: screen_write_cursormove(ctx, sx - 1, sy / 2);
521: screen_write_puts(ctx, &grid_default_cell, ">");
522: }
1.6 nicm 523:
1.9 nicm 524: i = loop = 0;
525: RB_FOREACH(wl, winlinks, &s->windows) {
526: if (loop == end)
527: break;
528: if (loop < start) {
529: loop++;
530: continue;
531: }
532: w = wl->window;
1.6 nicm 533:
534: if (wl == s->curw)
535: gc.fg = active_colour;
536: else
537: gc.fg = colour;
1.9 nicm 538:
539: if (left)
540: offset = 3 + (i * each);
541: else
542: offset = (i * each);
543: if (loop == end - 1)
1.12 nicm 544: width = each + remaining;
1.6 nicm 545: else
546: width = each - 1;
547:
1.9 nicm 548: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 549: screen_write_preview(ctx, &w->active->base, width, sy);
550:
551: xasprintf(&label, " %u:%s ", wl->idx, w->name);
552: if (strlen(label) > width)
553: xasprintf(&label, " %u ", wl->idx);
554: len = strlen(label) / 2;
1.9 nicm 555: screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8 nicm 556: if (len < width)
1.7 nicm 557: screen_write_puts(ctx, &gc, "%s", label);
1.6 nicm 558: free(label);
559:
1.9 nicm 560: if (loop != end - 1) {
561: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 562: screen_write_vline(ctx, sy, 0, 0);
563: }
1.9 nicm 564: loop++;
565:
566: i++;
1.6 nicm 567: }
568: }
569:
570: static void
1.11 nicm 571: window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
572: struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6 nicm 573: {
574: struct options *oo = s->options;
575: struct window_pane *wp;
1.9 nicm 576: u_int loop, total, visible, each, width, offset;
577: u_int current, start, end, remaining, i;
1.6 nicm 578: struct grid_cell gc;
1.9 nicm 579: int colour, active_colour, left, right;
1.6 nicm 580: char *label;
581: size_t len;
582:
1.9 nicm 583: total = window_count_panes(w);
1.6 nicm 584:
585: memcpy(&gc, &grid_default_cell, sizeof gc);
586: colour = options_get_number(oo, "display-panes-colour");
587: active_colour = options_get_number(oo, "display-panes-active-colour");
588:
1.9 nicm 589: if (sx / total < 24) {
590: visible = sx / 24;
591: if (visible == 0)
592: visible = 1;
593: } else
594: visible = total;
595:
596: current = 0;
597: TAILQ_FOREACH(wp, &w->panes, entry) {
598: if (wp == w->active)
599: break;
600: current++;
601: }
602:
603: if (current < visible) {
604: start = 0;
605: end = visible;
606: } else if (current >= total - visible) {
607: start = total - visible;
608: end = total;
609: } else {
610: start = current - (visible / 2);
611: end = start + visible;
612: }
613:
1.11 nicm 614: if (data->offset < -(int)start)
615: data->offset = -(int)start;
616: if (data->offset > (int)(total - end))
617: data->offset = (int)(total - end);
618: start += data->offset;
619: end += data->offset;
620:
1.9 nicm 621: left = (start != 0);
622: right = (end != total);
623: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
624: left = right = 0;
625: if (left && right) {
626: each = (sx - 6) / visible;
627: remaining = (sx - 6) - (visible * each);
628: } else if (left || right) {
629: each = (sx - 3) / visible;
630: remaining = (sx - 3) - (visible * each);
631: } else {
632: each = sx / visible;
633: remaining = sx - (visible * each);
634: }
635: if (each == 0)
636: return;
1.6 nicm 637:
1.9 nicm 638: if (left) {
639: screen_write_cursormove(ctx, 2, 0);
1.6 nicm 640: screen_write_vline(ctx, sy, 0, 0);
1.9 nicm 641: screen_write_cursormove(ctx, 0, sy / 2);
642: screen_write_puts(ctx, &grid_default_cell, "<");
643: }
644: if (right) {
645: screen_write_cursormove(ctx, sx - 3, 0);
646: screen_write_vline(ctx, sy, 0, 0);
647: screen_write_cursormove(ctx, sx - 1, sy / 2);
648: screen_write_puts(ctx, &grid_default_cell, ">");
649: }
1.6 nicm 650:
1.9 nicm 651: i = loop = 0;
652: TAILQ_FOREACH(wp, &w->panes, entry) {
653: if (loop == end)
654: break;
655: if (loop < start) {
656: loop++;
657: continue;
658: }
1.6 nicm 659:
660: if (wp == w->active)
661: gc.fg = active_colour;
662: else
663: gc.fg = colour;
1.9 nicm 664:
665: if (left)
666: offset = 3 + (i * each);
667: else
668: offset = (i * each);
669: if (loop == end - 1)
1.12 nicm 670: width = each + remaining;
1.6 nicm 671: else
672: width = each - 1;
673:
1.9 nicm 674: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 675: screen_write_preview(ctx, &wp->base, width, sy);
676:
1.9 nicm 677: xasprintf(&label, " %u ", loop);
1.6 nicm 678: len = strlen(label) / 2;
1.9 nicm 679: screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8 nicm 680: if (len < width)
1.7 nicm 681: screen_write_puts(ctx, &gc, "%s", label);
1.6 nicm 682: free(label);
683:
1.9 nicm 684: if (loop != end - 1) {
685: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 686: screen_write_vline(ctx, sy, 0, 0);
687: }
1.9 nicm 688: loop++;
689:
690: i++;
1.6 nicm 691: }
692: }
693:
1.1 nicm 694: static struct screen *
1.11 nicm 695: window_tree_draw(void *modedata, void *itemdata, u_int sx, u_int sy)
1.1 nicm 696: {
697: struct window_tree_itemdata *item = itemdata;
698: struct session *sp;
699: struct winlink *wlp;
700: struct window_pane *wp;
701: static struct screen s;
702: struct screen_write_ctx ctx;
703:
704: window_tree_pull_item(item, &sp, &wlp, &wp);
705: if (wp == NULL)
706: return (NULL);
707:
708: screen_init(&s, sx, sy, 0);
709: screen_write_start(&ctx, NULL, &s);
710:
1.6 nicm 711: switch (item->type) {
712: case WINDOW_TREE_NONE:
713: return (0);
714: case WINDOW_TREE_SESSION:
1.11 nicm 715: window_tree_draw_session(modedata, sp, &ctx, sx, sy);
1.6 nicm 716: break;
717: case WINDOW_TREE_WINDOW:
1.11 nicm 718: window_tree_draw_window(modedata, sp, wlp->window, &ctx, sx, sy);
1.6 nicm 719: break;
720: case WINDOW_TREE_PANE:
721: screen_write_preview(&ctx, &wp->base, sx, sy);
722: break;
723: }
1.1 nicm 724:
725: screen_write_stop(&ctx);
726: return (&s);
727: }
728:
1.3 nicm 729: static int
730: window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
731: {
732: struct window_tree_itemdata *item = itemdata;
733: struct session *s;
734: struct winlink *wl;
735: struct window_pane *wp;
736: const char *cmd;
737:
738: window_tree_pull_item(item, &s, &wl, &wp);
739:
740: switch (item->type) {
741: case WINDOW_TREE_NONE:
742: return (0);
743: case WINDOW_TREE_SESSION:
744: if (s == NULL)
745: return (0);
746: return (strstr(s->name, ss) != NULL);
747: case WINDOW_TREE_WINDOW:
748: if (s == NULL || wl == NULL)
749: return (0);
750: return (strstr(wl->window->name, ss) != NULL);
751: case WINDOW_TREE_PANE:
752: if (s == NULL || wl == NULL || wp == NULL)
753: break;
754: cmd = get_proc_name(wp->fd, wp->tty);
755: if (cmd == NULL || *cmd == '\0')
756: return (0);
757: return (strstr(cmd, ss) != NULL);
758: }
759: return (0);
760: }
761:
1.1 nicm 762: static struct screen *
763: window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
764: struct args *args)
765: {
766: struct window_tree_modedata *data;
767: struct screen *s;
768:
769: wp->modedata = data = xcalloc(1, sizeof *data);
770:
771: if (args_has(args, 's'))
772: data->type = WINDOW_TREE_SESSION;
773: else if (args_has(args, 'w'))
774: data->type = WINDOW_TREE_WINDOW;
775: else
776: data->type = WINDOW_TREE_PANE;
777: memcpy(&data->fs, fs, sizeof data->fs);
778:
779: data->wp = wp;
780: data->references = 1;
781:
1.15 nicm 782: if (args == NULL || !args_has(args, 'F'))
783: data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
784: else
785: data->format = xstrdup(args_get(args, 'F'));
1.1 nicm 786: if (args == NULL || args->argc == 0)
787: data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
788: else
789: data->command = xstrdup(args->argv[0]);
790:
1.4 nicm 791: data->data = mode_tree_start(wp, args, window_tree_build,
792: window_tree_draw, window_tree_search, data, window_tree_sort_list,
1.1 nicm 793: nitems(window_tree_sort_list), &s);
794:
795: mode_tree_build(data->data);
796: mode_tree_draw(data->data);
797:
798: data->type = WINDOW_TREE_NONE;
799:
800: return (s);
801: }
802:
803: static void
804: window_tree_destroy(struct window_tree_modedata *data)
805: {
806: u_int i;
807:
808: if (--data->references != 0)
809: return;
810:
811: mode_tree_free(data->data);
812:
813: for (i = 0; i < data->item_size; i++)
814: window_tree_free_item(data->item_list[i]);
815: free(data->item_list);
816:
1.15 nicm 817: free(data->format);
1.1 nicm 818: free(data->command);
1.15 nicm 819:
1.1 nicm 820: free(data);
821: }
822:
823: static void
824: window_tree_free(struct window_pane *wp)
825: {
826: struct window_tree_modedata *data = wp->modedata;
827:
828: if (data == NULL)
829: return;
830:
831: data->dead = 1;
832: window_tree_destroy(data);
833: }
834:
835: static void
836: window_tree_resize(struct window_pane *wp, u_int sx, u_int sy)
837: {
838: struct window_tree_modedata *data = wp->modedata;
839:
840: mode_tree_resize(data->data, sx, sy);
841: }
842:
843: static char *
844: window_tree_get_target(struct window_tree_itemdata *item,
845: struct cmd_find_state *fs)
846: {
847: struct session *s;
848: struct winlink *wl;
849: struct window_pane *wp;
850: char *target;
851:
852: window_tree_pull_item(item, &s, &wl, &wp);
853:
854: target = NULL;
855: switch (item->type) {
856: case WINDOW_TREE_NONE:
857: break;
858: case WINDOW_TREE_SESSION:
859: if (s == NULL)
860: break;
861: xasprintf(&target, "=%s:", s->name);
862: break;
863: case WINDOW_TREE_WINDOW:
864: if (s == NULL || wl == NULL)
865: break;
866: xasprintf(&target, "=%s:%u.", s->name, wl->idx);
867: break;
868: case WINDOW_TREE_PANE:
869: if (s == NULL || wl == NULL || wp == NULL)
870: break;
871: xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
872: break;
873: }
874: if (target == NULL)
875: cmd_find_clear_state(fs, 0);
876: else
877: cmd_find_from_winlink_pane(fs, wl, wp);
878: return (target);
879: }
880:
881: static void
882: window_tree_command_each(void* modedata, void* itemdata, __unused key_code key)
883: {
884: struct window_tree_modedata *data = modedata;
885: struct window_tree_itemdata *item = itemdata;
886: char *name;
887: struct cmd_find_state fs;
888:
889: name = window_tree_get_target(item, &fs);
890: if (name != NULL)
891: mode_tree_run_command(data->client, &fs, data->entered, name);
892: free(name);
893: }
894:
895: static enum cmd_retval
896: window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
897: {
898: struct window_tree_modedata *data = modedata;
899:
900: if (!data->dead) {
901: mode_tree_build(data->data);
902: mode_tree_draw(data->data);
903: data->wp->flags |= PANE_REDRAW;
904: }
905: window_tree_destroy(data);
906: return (CMD_RETURN_NORMAL);
907: }
908:
909: static int
910: window_tree_command_callback(struct client *c, void *modedata, const char *s,
911: __unused int done)
912: {
913: struct window_tree_modedata *data = modedata;
914:
915: if (data->dead)
916: return (0);
917:
918: data->client = c;
919: data->entered = s;
920:
921: mode_tree_each_tagged(data->data, window_tree_command_each, KEYC_NONE,
922: 1);
923:
924: data->client = NULL;
925: data->entered = NULL;
926:
927: data->references++;
928: cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
929:
930: return (0);
931: }
932:
933: static void
934: window_tree_command_free(void *modedata)
935: {
936: struct window_tree_modedata *data = modedata;
937:
938: window_tree_destroy(data);
939: }
940:
941: static void
942: window_tree_key(struct window_pane *wp, struct client *c,
943: __unused struct session *s, key_code key, struct mouse_event *m)
944: {
945: struct window_tree_modedata *data = wp->modedata;
946: struct window_tree_itemdata *item;
947: char *command, *name, *prompt;
948: struct cmd_find_state fs;
949: int finished;
950: u_int tagged;
951:
1.11 nicm 952: item = mode_tree_get_current(data->data);
1.3 nicm 953: finished = mode_tree_key(data->data, c, &key, m);
1.11 nicm 954: if (item != mode_tree_get_current(data->data))
955: data->offset = 0;
1.1 nicm 956: switch (key) {
1.11 nicm 957: case '<':
958: data->offset--;
959: break;
960: case '>':
961: data->offset++;
962: break;
1.1 nicm 963: case ':':
964: tagged = mode_tree_count_tagged(data->data);
965: if (tagged != 0)
966: xasprintf(&prompt, "(%u tagged) ", tagged);
967: else
968: xasprintf(&prompt, "(current) ");
969: data->references++;
970: status_prompt_set(c, prompt, "", window_tree_command_callback,
971: window_tree_command_free, data, PROMPT_NOFORMAT);
972: free(prompt);
973: break;
974: case '\r':
975: item = mode_tree_get_current(data->data);
976: command = xstrdup(data->command);
977: name = window_tree_get_target(item, &fs);
978: window_pane_reset_mode(wp);
979: if (name != NULL)
1.2 nicm 980: mode_tree_run_command(c, NULL, command, name);
1.1 nicm 981: free(name);
982: free(command);
983: return;
984: }
985: if (finished)
986: window_pane_reset_mode(wp);
987: else {
988: mode_tree_draw(data->data);
989: wp->flags |= PANE_REDRAW;
990: }
991: }