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