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