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