Annotation of src/usr.bin/tmux/window-tree.c, Revision 1.9
1.9 ! nicm 1: /* $OpenBSD: window-tree.c,v 1.8 2017/06/30 22:37: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:
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;
1.9 ! nicm 418: u_int loop, total, visible, each, width, offset;
! 419: u_int current, start, end, remaining, i;
1.6 nicm 420: struct grid_cell gc;
1.9 ! nicm 421: int colour, active_colour, left, right;
1.6 nicm 422: char *label;
423: size_t len;
424:
1.9 ! nicm 425: if (sx == 0)
1.6 nicm 426: return;
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:
! 458: left = (start != 0);
! 459: right = (end != total);
! 460: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
! 461: left = right = 0;
! 462: if (left && right) {
! 463: each = (sx - 6) / visible;
! 464: remaining = (sx - 6) - (visible * each);
! 465: } else if (left || right) {
! 466: each = (sx - 3) / visible;
! 467: remaining = (sx - 3) - (visible * each);
! 468: } else {
! 469: each = sx / visible;
! 470: remaining = sx - (visible * each);
! 471: }
! 472: if (each == 0)
! 473: return;
! 474:
! 475: if (left) {
! 476: screen_write_cursormove(ctx, 2, 0);
! 477: screen_write_vline(ctx, sy, 0, 0);
! 478: screen_write_cursormove(ctx, 0, sy / 2);
! 479: screen_write_puts(ctx, &grid_default_cell, "<");
! 480: }
! 481: if (right) {
! 482: screen_write_cursormove(ctx, sx - 3, 0);
1.6 nicm 483: screen_write_vline(ctx, sy, 0, 0);
1.9 ! nicm 484: screen_write_cursormove(ctx, sx - 1, sy / 2);
! 485: screen_write_puts(ctx, &grid_default_cell, ">");
! 486: }
1.6 nicm 487:
1.9 ! nicm 488: i = loop = 0;
! 489: RB_FOREACH(wl, winlinks, &s->windows) {
! 490: if (loop == end)
! 491: break;
! 492: if (loop < start) {
! 493: loop++;
! 494: continue;
! 495: }
! 496: w = wl->window;
1.6 nicm 497:
498: if (wl == s->curw)
499: gc.fg = active_colour;
500: else
501: gc.fg = colour;
1.9 ! nicm 502:
! 503: if (left)
! 504: offset = 3 + (i * each);
! 505: else
! 506: offset = (i * each);
! 507: if (loop == end - 1)
! 508: width = each - 1 + remaining;
1.6 nicm 509: else
510: width = each - 1;
511:
1.9 ! nicm 512: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 513: screen_write_preview(ctx, &w->active->base, width, sy);
514:
515: xasprintf(&label, " %u:%s ", wl->idx, w->name);
516: if (strlen(label) > width)
517: xasprintf(&label, " %u ", wl->idx);
518: len = strlen(label) / 2;
1.9 ! nicm 519: screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8 nicm 520: if (len < width)
1.7 nicm 521: screen_write_puts(ctx, &gc, "%s", label);
1.6 nicm 522: free(label);
523:
1.9 ! nicm 524: if (loop != end - 1) {
! 525: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 526: screen_write_vline(ctx, sy, 0, 0);
527: }
1.9 ! nicm 528: loop++;
! 529:
! 530: i++;
1.6 nicm 531: }
532: }
533:
534: static void
535: window_tree_draw_window(struct session *s, struct window *w,
536: struct screen_write_ctx *ctx, u_int sx, u_int sy)
537: {
538: struct options *oo = s->options;
539: struct window_pane *wp;
1.9 ! nicm 540: u_int loop, total, visible, each, width, offset;
! 541: u_int current, start, end, remaining, i;
1.6 nicm 542: struct grid_cell gc;
1.9 ! nicm 543: int colour, active_colour, left, right;
1.6 nicm 544: char *label;
545: size_t len;
546:
1.9 ! nicm 547: if (sx == 0)
1.6 nicm 548: return;
1.9 ! nicm 549: total = window_count_panes(w);
1.6 nicm 550:
551: memcpy(&gc, &grid_default_cell, sizeof gc);
552: colour = options_get_number(oo, "display-panes-colour");
553: active_colour = options_get_number(oo, "display-panes-active-colour");
554:
1.9 ! nicm 555: if (sx / total < 24) {
! 556: visible = sx / 24;
! 557: if (visible == 0)
! 558: visible = 1;
! 559: } else
! 560: visible = total;
! 561:
! 562: current = 0;
! 563: TAILQ_FOREACH(wp, &w->panes, entry) {
! 564: if (wp == w->active)
! 565: break;
! 566: current++;
! 567: }
! 568:
! 569: if (current < visible) {
! 570: start = 0;
! 571: end = visible;
! 572: } else if (current >= total - visible) {
! 573: start = total - visible;
! 574: end = total;
! 575: } else {
! 576: start = current - (visible / 2);
! 577: end = start + visible;
! 578: }
! 579:
! 580: left = (start != 0);
! 581: right = (end != total);
! 582: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
! 583: left = right = 0;
! 584: if (left && right) {
! 585: each = (sx - 6) / visible;
! 586: remaining = (sx - 6) - (visible * each);
! 587: } else if (left || right) {
! 588: each = (sx - 3) / visible;
! 589: remaining = (sx - 3) - (visible * each);
! 590: } else {
! 591: each = sx / visible;
! 592: remaining = sx - (visible * each);
! 593: }
! 594: if (each == 0)
! 595: return;
1.6 nicm 596:
1.9 ! nicm 597: if (left) {
! 598: screen_write_cursormove(ctx, 2, 0);
1.6 nicm 599: screen_write_vline(ctx, sy, 0, 0);
1.9 ! nicm 600: screen_write_cursormove(ctx, 0, sy / 2);
! 601: screen_write_puts(ctx, &grid_default_cell, "<");
! 602: }
! 603: if (right) {
! 604: screen_write_cursormove(ctx, sx - 3, 0);
! 605: screen_write_vline(ctx, sy, 0, 0);
! 606: screen_write_cursormove(ctx, sx - 1, sy / 2);
! 607: screen_write_puts(ctx, &grid_default_cell, ">");
! 608: }
1.6 nicm 609:
1.9 ! nicm 610: i = loop = 0;
! 611: TAILQ_FOREACH(wp, &w->panes, entry) {
! 612: if (loop == end)
! 613: break;
! 614: if (loop < start) {
! 615: loop++;
! 616: continue;
! 617: }
1.6 nicm 618:
619: if (wp == w->active)
620: gc.fg = active_colour;
621: else
622: gc.fg = colour;
1.9 ! nicm 623:
! 624: if (left)
! 625: offset = 3 + (i * each);
! 626: else
! 627: offset = (i * each);
! 628: if (loop == end - 1)
! 629: width = each - 1 + remaining;
1.6 nicm 630: else
631: width = each - 1;
632:
1.9 ! nicm 633: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 634: screen_write_preview(ctx, &wp->base, width, sy);
635:
1.9 ! nicm 636: xasprintf(&label, " %u ", loop);
1.6 nicm 637: len = strlen(label) / 2;
1.9 ! nicm 638: screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8 nicm 639: if (len < width)
1.7 nicm 640: screen_write_puts(ctx, &gc, "%s", label);
1.6 nicm 641: free(label);
642:
1.9 ! nicm 643: if (loop != end - 1) {
! 644: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 645: screen_write_vline(ctx, sy, 0, 0);
646: }
1.9 ! nicm 647: loop++;
! 648:
! 649: i++;
1.6 nicm 650: }
651: }
652:
1.1 nicm 653: static struct screen *
654: window_tree_draw(__unused void *modedata, void *itemdata, u_int sx, u_int sy)
655: {
656: struct window_tree_itemdata *item = itemdata;
657: struct session *sp;
658: struct winlink *wlp;
659: struct window_pane *wp;
660: static struct screen s;
661: struct screen_write_ctx ctx;
662:
663: window_tree_pull_item(item, &sp, &wlp, &wp);
664: if (wp == NULL)
665: return (NULL);
666:
667: screen_init(&s, sx, sy, 0);
668: screen_write_start(&ctx, NULL, &s);
669:
1.6 nicm 670: switch (item->type) {
671: case WINDOW_TREE_NONE:
672: return (0);
673: case WINDOW_TREE_SESSION:
674: window_tree_draw_session(sp, &ctx, sx, sy);
675: break;
676: case WINDOW_TREE_WINDOW:
677: window_tree_draw_window(sp, wlp->window, &ctx, sx, sy);
678: break;
679: case WINDOW_TREE_PANE:
680: screen_write_preview(&ctx, &wp->base, sx, sy);
681: break;
682: }
1.1 nicm 683:
684: screen_write_stop(&ctx);
685: return (&s);
686: }
687:
1.3 nicm 688: static int
689: window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
690: {
691: struct window_tree_itemdata *item = itemdata;
692: struct session *s;
693: struct winlink *wl;
694: struct window_pane *wp;
695: const char *cmd;
696:
697: window_tree_pull_item(item, &s, &wl, &wp);
698:
699: switch (item->type) {
700: case WINDOW_TREE_NONE:
701: return (0);
702: case WINDOW_TREE_SESSION:
703: if (s == NULL)
704: return (0);
705: return (strstr(s->name, ss) != NULL);
706: case WINDOW_TREE_WINDOW:
707: if (s == NULL || wl == NULL)
708: return (0);
709: return (strstr(wl->window->name, ss) != NULL);
710: case WINDOW_TREE_PANE:
711: if (s == NULL || wl == NULL || wp == NULL)
712: break;
713: cmd = get_proc_name(wp->fd, wp->tty);
714: if (cmd == NULL || *cmd == '\0')
715: return (0);
716: return (strstr(cmd, ss) != NULL);
717: }
718: return (0);
719: }
720:
1.1 nicm 721: static struct screen *
722: window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
723: struct args *args)
724: {
725: struct window_tree_modedata *data;
726: struct screen *s;
727:
728: wp->modedata = data = xcalloc(1, sizeof *data);
729:
730: if (args_has(args, 's'))
731: data->type = WINDOW_TREE_SESSION;
732: else if (args_has(args, 'w'))
733: data->type = WINDOW_TREE_WINDOW;
734: else
735: data->type = WINDOW_TREE_PANE;
736: memcpy(&data->fs, fs, sizeof data->fs);
737:
738: data->wp = wp;
739: data->references = 1;
740:
741: if (args == NULL || args->argc == 0)
742: data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
743: else
744: data->command = xstrdup(args->argv[0]);
745:
1.4 nicm 746: data->data = mode_tree_start(wp, args, window_tree_build,
747: window_tree_draw, window_tree_search, data, window_tree_sort_list,
1.1 nicm 748: nitems(window_tree_sort_list), &s);
749:
750: mode_tree_build(data->data);
751: mode_tree_draw(data->data);
752:
753: data->type = WINDOW_TREE_NONE;
754:
755: return (s);
756: }
757:
758: static void
759: window_tree_destroy(struct window_tree_modedata *data)
760: {
761: u_int i;
762:
763: if (--data->references != 0)
764: return;
765:
766: mode_tree_free(data->data);
767:
768: for (i = 0; i < data->item_size; i++)
769: window_tree_free_item(data->item_list[i]);
770: free(data->item_list);
771:
772: free(data->command);
773: free(data);
774: }
775:
776: static void
777: window_tree_free(struct window_pane *wp)
778: {
779: struct window_tree_modedata *data = wp->modedata;
780:
781: if (data == NULL)
782: return;
783:
784: data->dead = 1;
785: window_tree_destroy(data);
786: }
787:
788: static void
789: window_tree_resize(struct window_pane *wp, u_int sx, u_int sy)
790: {
791: struct window_tree_modedata *data = wp->modedata;
792:
793: mode_tree_resize(data->data, sx, sy);
794: }
795:
796: static char *
797: window_tree_get_target(struct window_tree_itemdata *item,
798: struct cmd_find_state *fs)
799: {
800: struct session *s;
801: struct winlink *wl;
802: struct window_pane *wp;
803: char *target;
804:
805: window_tree_pull_item(item, &s, &wl, &wp);
806:
807: target = NULL;
808: switch (item->type) {
809: case WINDOW_TREE_NONE:
810: break;
811: case WINDOW_TREE_SESSION:
812: if (s == NULL)
813: break;
814: xasprintf(&target, "=%s:", s->name);
815: break;
816: case WINDOW_TREE_WINDOW:
817: if (s == NULL || wl == NULL)
818: break;
819: xasprintf(&target, "=%s:%u.", s->name, wl->idx);
820: break;
821: case WINDOW_TREE_PANE:
822: if (s == NULL || wl == NULL || wp == NULL)
823: break;
824: xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
825: break;
826: }
827: if (target == NULL)
828: cmd_find_clear_state(fs, 0);
829: else
830: cmd_find_from_winlink_pane(fs, wl, wp);
831: return (target);
832: }
833:
834: static void
835: window_tree_command_each(void* modedata, void* itemdata, __unused key_code key)
836: {
837: struct window_tree_modedata *data = modedata;
838: struct window_tree_itemdata *item = itemdata;
839: char *name;
840: struct cmd_find_state fs;
841:
842: name = window_tree_get_target(item, &fs);
843: if (name != NULL)
844: mode_tree_run_command(data->client, &fs, data->entered, name);
845: free(name);
846: }
847:
848: static enum cmd_retval
849: window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
850: {
851: struct window_tree_modedata *data = modedata;
852:
853: if (!data->dead) {
854: mode_tree_build(data->data);
855: mode_tree_draw(data->data);
856: data->wp->flags |= PANE_REDRAW;
857: }
858: window_tree_destroy(data);
859: return (CMD_RETURN_NORMAL);
860: }
861:
862: static int
863: window_tree_command_callback(struct client *c, void *modedata, const char *s,
864: __unused int done)
865: {
866: struct window_tree_modedata *data = modedata;
867:
868: if (data->dead)
869: return (0);
870:
871: data->client = c;
872: data->entered = s;
873:
874: mode_tree_each_tagged(data->data, window_tree_command_each, KEYC_NONE,
875: 1);
876:
877: data->client = NULL;
878: data->entered = NULL;
879:
880: data->references++;
881: cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
882:
883: return (0);
884: }
885:
886: static void
887: window_tree_command_free(void *modedata)
888: {
889: struct window_tree_modedata *data = modedata;
890:
891: window_tree_destroy(data);
892: }
893:
894: static void
895: window_tree_key(struct window_pane *wp, struct client *c,
896: __unused struct session *s, key_code key, struct mouse_event *m)
897: {
898: struct window_tree_modedata *data = wp->modedata;
899: struct window_tree_itemdata *item;
900: char *command, *name, *prompt;
901: struct cmd_find_state fs;
902: int finished;
903: u_int tagged;
904:
1.3 nicm 905: finished = mode_tree_key(data->data, c, &key, m);
1.1 nicm 906: switch (key) {
907: case ':':
908: tagged = mode_tree_count_tagged(data->data);
909: if (tagged != 0)
910: xasprintf(&prompt, "(%u tagged) ", tagged);
911: else
912: xasprintf(&prompt, "(current) ");
913: data->references++;
914: status_prompt_set(c, prompt, "", window_tree_command_callback,
915: window_tree_command_free, data, PROMPT_NOFORMAT);
916: free(prompt);
917: break;
918: case '\r':
919: item = mode_tree_get_current(data->data);
920: command = xstrdup(data->command);
921: name = window_tree_get_target(item, &fs);
922: window_pane_reset_mode(wp);
923: if (name != NULL)
1.2 nicm 924: mode_tree_run_command(c, NULL, command, name);
1.1 nicm 925: free(name);
926: free(command);
927: return;
928: }
929: if (finished)
930: window_pane_reset_mode(wp);
931: else {
932: mode_tree_draw(data->data);
933: wp->flags |= PANE_REDRAW;
934: }
935: }