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