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