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