1/* $OpenBSD$ */ 2 3/* 4 * Copyright (c) 2007 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#include <sys/ioctl.h> 21 22#include <ctype.h> 23#include <errno.h> 24#include <fcntl.h> 25#include <fnmatch.h> 26#include <regex.h> 27#include <signal.h> 28#include <stdint.h> 29#include <stdlib.h> 30#include <string.h> 31#include <time.h> 32#include <unistd.h> 33 34#include "tmux.h" 35 36/* 37 * Each window is attached to a number of panes, each of which is a pty. This 38 * file contains code to handle them. 39 * 40 * A pane has two buffers attached, these are filled and emptied by the main 41 * server poll loop. Output data is received from pty's in screen format, 42 * translated and returned as a series of escape sequences and strings via 43 * input_parse (in input.c). Input data is received as key codes and written 44 * directly via input_key. 45 * 46 * Each pane also has a "virtual" screen (screen.c) which contains the current 47 * state and is redisplayed when the window is reattached to a client. 48 * 49 * Windows are stored directly on a global array and wrapped in any number of 50 * winlink structs to be linked onto local session RB trees. A reference count 51 * is maintained and a window removed from the global list and destroyed when 52 * it reaches zero. 53 */ 54 55/* Global window list. */ 56struct windows windows; 57 58/* Global panes tree. */ 59struct window_pane_tree all_window_panes; 60static u_int next_window_pane_id; 61static u_int next_window_id; 62static u_int next_active_point; 63 64struct window_pane_input_data { 65 struct cmdq_item *item; 66 u_int wp; 67 struct client_file *file; 68}; 69 70static struct window_pane *window_pane_create(struct window *, u_int, u_int, 71 u_int); 72static void window_pane_destroy(struct window_pane *); 73 74RB_GENERATE(windows, window, entry, window_cmp); 75RB_GENERATE(winlinks, winlink, entry, winlink_cmp); 76RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp); 77 78int 79window_cmp(struct window *w1, struct window *w2) 80{ 81 return (w1->id - w2->id); 82} 83 84int 85winlink_cmp(struct winlink *wl1, struct winlink *wl2) 86{ 87 return (wl1->idx - wl2->idx); 88} 89 90int 91window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2) 92{ 93 return (wp1->id - wp2->id); 94} 95 96struct winlink * 97winlink_find_by_window(struct winlinks *wwl, struct window *w) 98{ 99 struct winlink *wl; 100 101 RB_FOREACH(wl, winlinks, wwl) { 102 if (wl->window == w) 103 return (wl); 104 } 105 106 return (NULL); 107} 108 109struct winlink * 110winlink_find_by_index(struct winlinks *wwl, int idx) 111{ 112 struct winlink wl; 113 114 if (idx < 0) 115 fatalx("bad index"); 116 117 wl.idx = idx; 118 return (RB_FIND(winlinks, wwl, &wl)); 119} 120 121struct winlink * 122winlink_find_by_window_id(struct winlinks *wwl, u_int id) 123{ 124 struct winlink *wl; 125 126 RB_FOREACH(wl, winlinks, wwl) { 127 if (wl->window->id == id) 128 return (wl); 129 } 130 return (NULL); 131} 132 133static int 134winlink_next_index(struct winlinks *wwl, int idx) 135{ 136 int i; 137 138 i = idx; 139 do { 140 if (winlink_find_by_index(wwl, i) == NULL) 141 return (i); 142 if (i == INT_MAX) 143 i = 0; 144 else 145 i++; 146 } while (i != idx); 147 return (-1); 148} 149 150u_int 151winlink_count(struct winlinks *wwl) 152{ 153 struct winlink *wl; 154 u_int n; 155 156 n = 0; 157 RB_FOREACH(wl, winlinks, wwl) 158 n++; 159 160 return (n); 161} 162 163struct winlink * 164winlink_add(struct winlinks *wwl, int idx) 165{ 166 struct winlink *wl; 167 168 if (idx < 0) { 169 if ((idx = winlink_next_index(wwl, -idx - 1)) == -1) 170 return (NULL); 171 } else if (winlink_find_by_index(wwl, idx) != NULL) 172 return (NULL); 173 174 wl = xcalloc(1, sizeof *wl); 175 wl->idx = idx; 176 RB_INSERT(winlinks, wwl, wl); 177 178 return (wl); 179} 180 181void 182winlink_set_window(struct winlink *wl, struct window *w) 183{ 184 if (wl->window != NULL) { 185 TAILQ_REMOVE(&wl->window->winlinks, wl, wentry); 186 window_remove_ref(wl->window, __func__); 187 } 188 TAILQ_INSERT_TAIL(&w->winlinks, wl, wentry); 189 wl->window = w; 190 window_add_ref(w, __func__); 191} 192 193void 194winlink_remove(struct winlinks *wwl, struct winlink *wl) 195{ 196 struct window *w = wl->window; 197 198 if (w != NULL) { 199 TAILQ_REMOVE(&w->winlinks, wl, wentry); 200 window_remove_ref(w, __func__); 201 } 202 203 RB_REMOVE(winlinks, wwl, wl); 204 free(wl); 205} 206 207struct winlink * 208winlink_next(struct winlink *wl) 209{ 210 return (RB_NEXT(winlinks, wwl, wl)); 211} 212 213struct winlink * 214winlink_previous(struct winlink *wl) 215{ 216 return (RB_PREV(winlinks, wwl, wl)); 217} 218 219struct winlink * 220winlink_next_by_number(struct winlink *wl, struct session *s, int n) 221{ 222 for (; n > 0; n--) { 223 if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL) 224 wl = RB_MIN(winlinks, &s->windows); 225 } 226 227 return (wl); 228} 229 230struct winlink * 231winlink_previous_by_number(struct winlink *wl, struct session *s, int n) 232{ 233 for (; n > 0; n--) { 234 if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL) 235 wl = RB_MAX(winlinks, &s->windows); 236 } 237 238 return (wl); 239} 240 241void 242winlink_stack_push(struct winlink_stack *stack, struct winlink *wl) 243{ 244 if (wl == NULL) 245 return; 246 247 winlink_stack_remove(stack, wl); 248 TAILQ_INSERT_HEAD(stack, wl, sentry); 249 wl->flags |= WINLINK_VISITED; 250} 251 252void 253winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl) 254{ 255 if (wl != NULL && (wl->flags & WINLINK_VISITED)) { 256 TAILQ_REMOVE(stack, wl, sentry); 257 wl->flags &= ~WINLINK_VISITED; 258 } 259} 260 261struct window * 262window_find_by_id_str(const char *s) 263{ 264 const char *errstr; 265 u_int id; 266 267 if (*s != '@') 268 return (NULL); 269 270 id = strtonum(s + 1, 0, UINT_MAX, &errstr); 271 if (errstr != NULL) 272 return (NULL); 273 return (window_find_by_id(id)); 274} 275 276struct window * 277window_find_by_id(u_int id) 278{ 279 struct window w; 280 281 w.id = id; 282 return (RB_FIND(windows, &windows, &w)); 283} 284 285void 286window_update_activity(struct window *w) 287{ 288 gettimeofday(&w->activity_time, NULL); 289 alerts_queue(w, WINDOW_ACTIVITY); 290} 291 292struct window * 293window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) 294{ 295 struct window *w; 296 297 if (xpixel == 0) 298 xpixel = DEFAULT_XPIXEL; 299 if (ypixel == 0) 300 ypixel = DEFAULT_YPIXEL; 301 302 w = xcalloc(1, sizeof *w); 303 w->name = xstrdup(""); 304 w->flags = 0; 305 306 TAILQ_INIT(&w->panes); 307 TAILQ_INIT(&w->last_panes); 308 w->active = NULL; 309 310 w->lastlayout = -1; 311 w->layout_root = NULL; 312 313 w->sx = sx; 314 w->sy = sy; 315 w->manual_sx = sx; 316 w->manual_sy = sy; 317 w->xpixel = xpixel; 318 w->ypixel = ypixel; 319 320 w->options = options_create(global_w_options); 321 322 w->references = 0; 323 TAILQ_INIT(&w->winlinks); 324 325 w->id = next_window_id++; 326 RB_INSERT(windows, &windows, w); 327 328 window_set_fill_character(w); 329 window_update_activity(w); 330 331 log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy, 332 w->xpixel, w->ypixel); 333 return (w); 334} 335 336static void 337window_destroy(struct window *w) 338{ 339 log_debug("window @%u destroyed (%d references)", w->id, w->references); 340 341 window_unzoom(w); 342 RB_REMOVE(windows, &windows, w); 343 344 if (w->layout_root != NULL) 345 layout_free_cell(w->layout_root); 346 if (w->saved_layout_root != NULL) 347 layout_free_cell(w->saved_layout_root); 348 free(w->old_layout); 349 350 window_destroy_panes(w); 351 352 if (event_initialized(&w->name_event)) 353 evtimer_del(&w->name_event); 354 355 if (event_initialized(&w->alerts_timer)) 356 evtimer_del(&w->alerts_timer); 357 if (event_initialized(&w->offset_timer)) 358 event_del(&w->offset_timer); 359 360 options_free(w->options); 361 free(w->fill_character); 362 363 free(w->name); 364 free(w); 365} 366 367int 368window_pane_destroy_ready(struct window_pane *wp) 369{ 370 int n; 371 372 if (wp->pipe_fd != -1) { 373 if (EVBUFFER_LENGTH(wp->pipe_event->output) != 0) 374 return (0); 375 if (ioctl(wp->fd, FIONREAD, &n) != -1 && n > 0) 376 return (0); 377 } 378 379 if (~wp->flags & PANE_EXITED) 380 return (0); 381 return (1); 382} 383 384void 385window_add_ref(struct window *w, const char *from) 386{ 387 w->references++; 388 log_debug("%s: @%u %s, now %d", __func__, w->id, from, w->references); 389} 390 391void 392window_remove_ref(struct window *w, const char *from) 393{ 394 w->references--; 395 log_debug("%s: @%u %s, now %d", __func__, w->id, from, w->references); 396 397 if (w->references == 0) 398 window_destroy(w); 399} 400 401void 402window_set_name(struct window *w, const char *new_name) 403{ 404 free(w->name); 405 utf8_stravis(&w->name, new_name, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); 406 notify_window("window-renamed", w); 407} 408 409void 410window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) 411{ 412 if (xpixel == 0) 413 xpixel = DEFAULT_XPIXEL; 414 if (ypixel == 0) 415 ypixel = DEFAULT_YPIXEL; 416 417 log_debug("%s: @%u resize %ux%u (%ux%u)", __func__, w->id, sx, sy, 418 xpixel == -1 ? w->xpixel : (u_int)xpixel, 419 ypixel == -1 ? w->ypixel : (u_int)ypixel); 420 w->sx = sx; 421 w->sy = sy; 422 if (xpixel != -1) 423 w->xpixel = xpixel; 424 if (ypixel != -1) 425 w->ypixel = ypixel; 426} 427 428void 429window_pane_send_resize(struct window_pane *wp, u_int sx, u_int sy) 430{ 431 struct window *w = wp->window; 432 struct winsize ws; 433 434 if (wp->fd == -1) 435 return; 436 437 log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, sx, sy); 438 439 memset(&ws, 0, sizeof ws); 440 ws.ws_col = sx; 441 ws.ws_row = sy; 442 ws.ws_xpixel = w->xpixel * ws.ws_col; 443 ws.ws_ypixel = w->ypixel * ws.ws_row; 444 if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) 445#ifdef __sun 446 /* 447 * Some versions of Solaris apparently can return an error when 448 * resizing; don't know why this happens, can't reproduce on 449 * other platforms and ignoring it doesn't seem to cause any 450 * issues. 451 */ 452 if (errno != EINVAL && errno != ENXIO) 453#endif 454 fatal("ioctl failed"); 455} 456 457int 458window_has_pane(struct window *w, struct window_pane *wp) 459{ 460 struct window_pane *wp1; 461 462 TAILQ_FOREACH(wp1, &w->panes, entry) { 463 if (wp1 == wp) 464 return (1); 465 } 466 return (0); 467} 468 469void 470window_update_focus(struct window *w) 471{ 472 if (w != NULL) { 473 log_debug("%s: @%u", __func__, w->id); 474 window_pane_update_focus(w->active); 475 } 476} 477 478void 479window_pane_update_focus(struct window_pane *wp) 480{ 481 struct client *c; 482 int focused = 0; 483 484 if (wp != NULL) { 485 if (wp != wp->window->active) 486 focused = 0; 487 else { 488 TAILQ_FOREACH(c, &clients, entry) { 489 if (c->session != NULL && 490 c->session->attached != 0 && 491 (c->flags & CLIENT_FOCUSED) && 492 c->session->curw->window == wp->window) { 493 focused = 1; 494 break; 495 } 496 } 497 } 498 if (!focused && (wp->flags & PANE_FOCUSED)) { 499 log_debug("%s: %%%u focus out", __func__, wp->id); 500 if (wp->base.mode & MODE_FOCUSON) 501 bufferevent_write(wp->event, "\033[O", 3); 502 notify_pane("pane-focus-out", wp); 503 wp->flags &= ~PANE_FOCUSED; 504 } else if (focused && (~wp->flags & PANE_FOCUSED)) { 505 log_debug("%s: %%%u focus in", __func__, wp->id); 506 if (wp->base.mode & MODE_FOCUSON) 507 bufferevent_write(wp->event, "\033[I", 3); 508 notify_pane("pane-focus-in", wp); 509 wp->flags |= PANE_FOCUSED; 510 } else 511 log_debug("%s: %%%u focus unchanged", __func__, wp->id); 512 } 513} 514 515int 516window_set_active_pane(struct window *w, struct window_pane *wp, int notify) 517{ 518 struct window_pane *lastwp; 519 520 log_debug("%s: pane %%%u", __func__, wp->id); 521 522 if (wp == w->active) 523 return (0); 524 lastwp = w->active; 525 526 window_pane_stack_remove(&w->last_panes, wp); 527 window_pane_stack_push(&w->last_panes, lastwp); 528 529 w->active = wp; 530 w->active->active_point = next_active_point++; 531 w->active->flags |= PANE_CHANGED; 532 533 if (options_get_number(global_options, "focus-events")) { 534 window_pane_update_focus(lastwp); 535 window_pane_update_focus(w->active); 536 } 537 538 tty_update_window_offset(w); 539 540 if (notify) 541 notify_window("window-pane-changed", w); 542 return (1); 543} 544 545static int 546window_pane_get_palette(struct window_pane *wp, int c) 547{ 548 if (wp == NULL) 549 return (-1); 550 return (colour_palette_get(&wp->palette, c)); 551} 552 553void 554window_redraw_active_switch(struct window *w, struct window_pane *wp) 555{ 556 struct grid_cell *gc1, *gc2; 557 int c1, c2; 558 559 if (wp == w->active) 560 return; 561 562 for (;;) { 563 /* 564 * If the active and inactive styles or palettes are different, 565 * need to redraw the panes. 566 */ 567 gc1 = &wp->cached_gc; 568 gc2 = &wp->cached_active_gc; 569 if (!grid_cells_look_equal(gc1, gc2)) 570 wp->flags |= PANE_REDRAW; 571 else { 572 c1 = window_pane_get_palette(wp, gc1->fg); 573 c2 = window_pane_get_palette(wp, gc2->fg); 574 if (c1 != c2) 575 wp->flags |= PANE_REDRAW; 576 else { 577 c1 = window_pane_get_palette(wp, gc1->bg); 578 c2 = window_pane_get_palette(wp, gc2->bg); 579 if (c1 != c2) 580 wp->flags |= PANE_REDRAW; 581 } 582 } 583 if (wp == w->active) 584 break; 585 wp = w->active; 586 } 587} 588 589struct window_pane * 590window_get_active_at(struct window *w, u_int x, u_int y) 591{ 592 struct window_pane *wp; 593 594 TAILQ_FOREACH(wp, &w->panes, entry) { 595 if (!window_pane_visible(wp)) 596 continue; 597 if (x < wp->xoff || x > wp->xoff + wp->sx) 598 continue; 599 if (y < wp->yoff || y > wp->yoff + wp->sy) 600 continue; 601 return (wp); 602 } 603 return (NULL); 604} 605 606struct window_pane * 607window_find_string(struct window *w, const char *s) 608{ 609 u_int x, y, top = 0, bottom = w->sy - 1; 610 int status; 611 612 x = w->sx / 2; 613 y = w->sy / 2; 614 615 status = options_get_number(w->options, "pane-border-status"); 616 if (status == PANE_STATUS_TOP) 617 top++; 618 else if (status == PANE_STATUS_BOTTOM) 619 bottom--; 620 621 if (strcasecmp(s, "top") == 0) 622 y = top; 623 else if (strcasecmp(s, "bottom") == 0) 624 y = bottom; 625 else if (strcasecmp(s, "left") == 0) 626 x = 0; 627 else if (strcasecmp(s, "right") == 0) 628 x = w->sx - 1; 629 else if (strcasecmp(s, "top-left") == 0) { 630 x = 0; 631 y = top; 632 } else if (strcasecmp(s, "top-right") == 0) { 633 x = w->sx - 1; 634 y = top; 635 } else if (strcasecmp(s, "bottom-left") == 0) { 636 x = 0; 637 y = bottom; 638 } else if (strcasecmp(s, "bottom-right") == 0) { 639 x = w->sx - 1; 640 y = bottom; 641 } else 642 return (NULL); 643 644 return (window_get_active_at(w, x, y)); 645} 646 647int 648window_zoom(struct window_pane *wp) 649{ 650 struct window *w = wp->window; 651 struct window_pane *wp1; 652 653 if (w->flags & WINDOW_ZOOMED) 654 return (-1); 655 656 if (window_count_panes(w) == 1) 657 return (-1); 658 659 if (w->active != wp) 660 window_set_active_pane(w, wp, 1); 661 662 TAILQ_FOREACH(wp1, &w->panes, entry) { 663 wp1->saved_layout_cell = wp1->layout_cell; 664 wp1->layout_cell = NULL; 665 } 666 667 w->saved_layout_root = w->layout_root; 668 layout_init(w, wp); 669 w->flags |= WINDOW_ZOOMED; 670 notify_window("window-layout-changed", w); 671 672 return (0); 673} 674 675int 676window_unzoom(struct window *w) 677{ 678 struct window_pane *wp; 679 680 if (!(w->flags & WINDOW_ZOOMED)) 681 return (-1); 682 683 w->flags &= ~WINDOW_ZOOMED; 684 layout_free(w); 685 w->layout_root = w->saved_layout_root; 686 w->saved_layout_root = NULL; 687 688 TAILQ_FOREACH(wp, &w->panes, entry) { 689 wp->layout_cell = wp->saved_layout_cell; 690 wp->saved_layout_cell = NULL; 691 } 692 layout_fix_panes(w, NULL); 693 notify_window("window-layout-changed", w); 694 695 return (0); 696} 697 698int 699window_push_zoom(struct window *w, int always, int flag) 700{ 701 log_debug("%s: @%u %d", __func__, w->id, 702 flag && (w->flags & WINDOW_ZOOMED)); 703 if (flag && (always || (w->flags & WINDOW_ZOOMED))) 704 w->flags |= WINDOW_WASZOOMED; 705 else 706 w->flags &= ~WINDOW_WASZOOMED; 707 return (window_unzoom(w) == 0); 708} 709 710int 711window_pop_zoom(struct window *w) 712{ 713 log_debug("%s: @%u %d", __func__, w->id, 714 !!(w->flags & WINDOW_WASZOOMED)); 715 if (w->flags & WINDOW_WASZOOMED) 716 return (window_zoom(w->active) == 0); 717 return (0); 718} 719 720struct window_pane * 721window_add_pane(struct window *w, struct window_pane *other, u_int hlimit, 722 int flags) 723{ 724 struct window_pane *wp; 725 726 if (other == NULL) 727 other = w->active; 728 729 wp = window_pane_create(w, w->sx, w->sy, hlimit); 730 if (TAILQ_EMPTY(&w->panes)) { 731 log_debug("%s: @%u at start", __func__, w->id); 732 TAILQ_INSERT_HEAD(&w->panes, wp, entry); 733 } else if (flags & SPAWN_BEFORE) { 734 log_debug("%s: @%u before %%%u", __func__, w->id, wp->id); 735 if (flags & SPAWN_FULLSIZE) 736 TAILQ_INSERT_HEAD(&w->panes, wp, entry); 737 else 738 TAILQ_INSERT_BEFORE(other, wp, entry); 739 } else { 740 log_debug("%s: @%u after %%%u", __func__, w->id, wp->id); 741 if (flags & SPAWN_FULLSIZE) 742 TAILQ_INSERT_TAIL(&w->panes, wp, entry); 743 else 744 TAILQ_INSERT_AFTER(&w->panes, other, wp, entry); 745 } 746 return (wp); 747} 748 749void 750window_lost_pane(struct window *w, struct window_pane *wp) 751{ 752 log_debug("%s: @%u pane %%%u", __func__, w->id, wp->id); 753 754 if (wp == marked_pane.wp) 755 server_clear_marked(); 756 757 window_pane_stack_remove(&w->last_panes, wp); 758 if (wp == w->active) { 759 w->active = TAILQ_FIRST(&w->last_panes); 760 if (w->active == NULL) { 761 w->active = TAILQ_PREV(wp, window_panes, entry); 762 if (w->active == NULL) 763 w->active = TAILQ_NEXT(wp, entry); 764 } 765 if (w->active != NULL) { 766 window_pane_stack_remove(&w->last_panes, w->active); 767 w->active->flags |= PANE_CHANGED; 768 notify_window("window-pane-changed", w); 769 window_update_focus(w); 770 } 771 } 772} 773 774void 775window_remove_pane(struct window *w, struct window_pane *wp) 776{ 777 window_lost_pane(w, wp); 778 779 TAILQ_REMOVE(&w->panes, wp, entry); 780 window_pane_destroy(wp); 781} 782 783struct window_pane * 784window_pane_at_index(struct window *w, u_int idx) 785{ 786 struct window_pane *wp; 787 u_int n; 788 789 n = options_get_number(w->options, "pane-base-index"); 790 TAILQ_FOREACH(wp, &w->panes, entry) { 791 if (n == idx) 792 return (wp); 793 n++; 794 } 795 return (NULL); 796} 797 798struct window_pane * 799window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n) 800{ 801 for (; n > 0; n--) { 802 if ((wp = TAILQ_NEXT(wp, entry)) == NULL) 803 wp = TAILQ_FIRST(&w->panes); 804 } 805 806 return (wp); 807} 808 809struct window_pane * 810window_pane_previous_by_number(struct window *w, struct window_pane *wp, 811 u_int n) 812{ 813 for (; n > 0; n--) { 814 if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL) 815 wp = TAILQ_LAST(&w->panes, window_panes); 816 } 817 818 return (wp); 819} 820 821int 822window_pane_index(struct window_pane *wp, u_int *i) 823{ 824 struct window_pane *wq; 825 struct window *w = wp->window; 826 827 *i = options_get_number(w->options, "pane-base-index"); 828 TAILQ_FOREACH(wq, &w->panes, entry) { 829 if (wp == wq) { 830 return (0); 831 } 832 (*i)++; 833 } 834 835 return (-1); 836} 837 838u_int 839window_count_panes(struct window *w) 840{ 841 struct window_pane *wp; 842 u_int n; 843 844 n = 0; 845 TAILQ_FOREACH(wp, &w->panes, entry) 846 n++; 847 return (n); 848} 849 850void 851window_destroy_panes(struct window *w) 852{ 853 struct window_pane *wp; 854 855 while (!TAILQ_EMPTY(&w->last_panes)) { 856 wp = TAILQ_FIRST(&w->last_panes); 857 window_pane_stack_remove(&w->last_panes, wp); 858 } 859 860 while (!TAILQ_EMPTY(&w->panes)) { 861 wp = TAILQ_FIRST(&w->panes); 862 TAILQ_REMOVE(&w->panes, wp, entry); 863 window_pane_destroy(wp); 864 } 865} 866 867const char * 868window_printable_flags(struct winlink *wl, int escape) 869{ 870 struct session *s = wl->session; 871 static char flags[32]; 872 int pos; 873 874 pos = 0; 875 if (wl->flags & WINLINK_ACTIVITY) { 876 flags[pos++] = '#'; 877 if (escape) 878 flags[pos++] = '#'; 879 } 880 if (wl->flags & WINLINK_BELL) 881 flags[pos++] = '!'; 882 if (wl->flags & WINLINK_SILENCE) 883 flags[pos++] = '~'; 884 if (wl == s->curw) 885 flags[pos++] = '*'; 886 if (wl == TAILQ_FIRST(&s->lastw)) 887 flags[pos++] = '-'; 888 if (server_check_marked() && wl == marked_pane.wl) 889 flags[pos++] = 'M'; 890 if (wl->window->flags & WINDOW_ZOOMED) 891 flags[pos++] = 'Z'; 892 flags[pos] = '\0'; 893 return (flags); 894} 895 896struct window_pane * 897window_pane_find_by_id_str(const char *s) 898{ 899 const char *errstr; 900 u_int id; 901 902 if (*s != '%') 903 return (NULL); 904 905 id = strtonum(s + 1, 0, UINT_MAX, &errstr); 906 if (errstr != NULL) 907 return (NULL); 908 return (window_pane_find_by_id(id)); 909} 910 911struct window_pane * 912window_pane_find_by_id(u_int id) 913{ 914 struct window_pane wp; 915 916 wp.id = id; 917 return (RB_FIND(window_pane_tree, &all_window_panes, &wp)); 918} 919 920static struct window_pane * 921window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) 922{ 923 struct window_pane *wp; 924 char host[HOST_NAME_MAX + 1]; 925 926 wp = xcalloc(1, sizeof *wp); 927 wp->window = w; 928 wp->options = options_create(w->options); 929 wp->flags = PANE_STYLECHANGED; 930 931 wp->id = next_window_pane_id++; 932 RB_INSERT(window_pane_tree, &all_window_panes, wp); 933 934 wp->fd = -1; 935 936 TAILQ_INIT(&wp->modes); 937 938 TAILQ_INIT (&wp->resize_queue); 939 940 wp->sx = sx; 941 wp->sy = sy; 942 943 wp->pipe_fd = -1; 944 945 colour_palette_init(&wp->palette); 946 colour_palette_from_option(&wp->palette, wp->options); 947 948 screen_init(&wp->base, sx, sy, hlimit); 949 wp->screen = &wp->base; 950 window_pane_default_cursor(wp); 951 952 screen_init(&wp->status_screen, 1, 1, 0); 953 954 if (gethostname(host, sizeof host) == 0) 955 screen_set_title(&wp->base, host); 956 957 return (wp); 958} 959 960static void 961window_pane_destroy(struct window_pane *wp) 962{ 963 struct window_pane_resize *r; 964 struct window_pane_resize *r1; 965 966 window_pane_reset_mode_all(wp); 967 free(wp->searchstr); 968 969 if (wp->fd != -1) { 970#ifdef HAVE_UTEMPTER 971 utempter_remove_record(wp->fd); 972#endif 973 bufferevent_free(wp->event); 974 close(wp->fd); 975 } 976 if (wp->ictx != NULL) 977 input_free(wp->ictx); 978 979 screen_free(&wp->status_screen); 980 981 screen_free(&wp->base); 982 983 if (wp->pipe_fd != -1) { 984 bufferevent_free(wp->pipe_event); 985 close(wp->pipe_fd); 986 } 987 988 if (event_initialized(&wp->resize_timer)) 989 event_del(&wp->resize_timer); 990 TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { 991 TAILQ_REMOVE(&wp->resize_queue, r, entry); 992 free(r); 993 } 994 995 RB_REMOVE(window_pane_tree, &all_window_panes, wp); 996 997 options_free(wp->options); 998 free(__UNCONST(wp->cwd)); 999 free(wp->shell); 1000 cmd_free_argv(wp->argc, wp->argv); 1001 colour_palette_free(&wp->palette); 1002 free(wp); 1003} 1004 1005static void 1006window_pane_read_callback(__unused struct bufferevent *bufev, void *data) 1007{ 1008 struct window_pane *wp = data; 1009 struct evbuffer *evb = wp->event->input; 1010 struct window_pane_offset *wpo = &wp->pipe_offset; 1011 size_t size = EVBUFFER_LENGTH(evb); 1012 char *new_data; 1013 size_t new_size; 1014 struct client *c; 1015 1016 if (wp->pipe_fd != -1) { 1017 new_data = window_pane_get_new_data(wp, wpo, &new_size); 1018 if (new_size > 0) { 1019 bufferevent_write(wp->pipe_event, new_data, new_size); 1020 window_pane_update_used_data(wp, wpo, new_size); 1021 } 1022 } 1023 1024 log_debug("%%%u has %zu bytes", wp->id, size); 1025 TAILQ_FOREACH(c, &clients, entry) { 1026 if (c->session != NULL && (c->flags & CLIENT_CONTROL)) 1027 control_write_output(c, wp); 1028 } 1029 input_parse_pane(wp); 1030 bufferevent_disable(wp->event, EV_READ); 1031} 1032 1033static void 1034window_pane_error_callback(__unused struct bufferevent *bufev, 1035 __unused short what, void *data) 1036{ 1037 struct window_pane *wp = data; 1038 1039 log_debug("%%%u error", wp->id); 1040 wp->flags |= PANE_EXITED; 1041 1042 if (window_pane_destroy_ready(wp)) 1043 server_destroy_pane(wp, 1); 1044} 1045 1046void 1047window_pane_set_event(struct window_pane *wp) 1048{ 1049 setblocking(wp->fd, 0); 1050 1051 wp->event = bufferevent_new(wp->fd, window_pane_read_callback, 1052 NULL, window_pane_error_callback, wp); 1053 if (wp->event == NULL) 1054 fatalx("out of memory"); 1055 wp->ictx = input_init(wp, wp->event, &wp->palette); 1056 1057 bufferevent_enable(wp->event, EV_READ|EV_WRITE); 1058} 1059 1060void 1061window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) 1062{ 1063 struct window_mode_entry *wme; 1064 struct window_pane_resize *r; 1065 1066 if (sx == wp->sx && sy == wp->sy) 1067 return; 1068 1069 r = xmalloc(sizeof *r); 1070 r->sx = sx; 1071 r->sy = sy; 1072 r->osx = wp->sx; 1073 r->osy = wp->sy; 1074 TAILQ_INSERT_TAIL (&wp->resize_queue, r, entry); 1075 1076 wp->sx = sx; 1077 wp->sy = sy; 1078 1079 log_debug("%s: %%%u resize %ux%u", __func__, wp->id, sx, sy); 1080 screen_resize(&wp->base, sx, sy, wp->base.saved_grid == NULL); 1081 1082 wme = TAILQ_FIRST(&wp->modes); 1083 if (wme != NULL && wme->mode->resize != NULL) 1084 wme->mode->resize(wme, sx, sy); 1085} 1086 1087int 1088window_pane_set_mode(struct window_pane *wp, struct window_pane *swp, 1089 const struct window_mode *mode, struct cmd_find_state *fs, 1090 struct args *args) 1091{ 1092 struct window_mode_entry *wme; 1093 1094 if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode) 1095 return (1); 1096 1097 TAILQ_FOREACH(wme, &wp->modes, entry) { 1098 if (wme->mode == mode) 1099 break; 1100 } 1101 if (wme != NULL) { 1102 TAILQ_REMOVE(&wp->modes, wme, entry); 1103 TAILQ_INSERT_HEAD(&wp->modes, wme, entry); 1104 } else { 1105 wme = xcalloc(1, sizeof *wme); 1106 wme->wp = wp; 1107 wme->swp = swp; 1108 wme->mode = mode; 1109 wme->prefix = 1; 1110 TAILQ_INSERT_HEAD(&wp->modes, wme, entry); 1111 wme->screen = wme->mode->init(wme, fs, args); 1112 } 1113 1114 wp->screen = wme->screen; 1115 wp->flags |= (PANE_REDRAW|PANE_CHANGED); 1116 1117 server_redraw_window_borders(wp->window); 1118 server_status_window(wp->window); 1119 notify_pane("pane-mode-changed", wp); 1120 1121 return (0); 1122} 1123 1124void 1125window_pane_reset_mode(struct window_pane *wp) 1126{ 1127 struct window_mode_entry *wme, *next; 1128 1129 if (TAILQ_EMPTY(&wp->modes)) 1130 return; 1131 1132 wme = TAILQ_FIRST(&wp->modes); 1133 TAILQ_REMOVE(&wp->modes, wme, entry); 1134 wme->mode->free(wme); 1135 free(wme); 1136 1137 next = TAILQ_FIRST(&wp->modes); 1138 if (next == NULL) { 1139 wp->flags &= ~PANE_UNSEENCHANGES; 1140 log_debug("%s: no next mode", __func__); 1141 wp->screen = &wp->base; 1142 } else { 1143 log_debug("%s: next mode is %s", __func__, next->mode->name); 1144 wp->screen = next->screen; 1145 if (next->mode->resize != NULL) 1146 next->mode->resize(next, wp->sx, wp->sy); 1147 } 1148 wp->flags |= (PANE_REDRAW|PANE_CHANGED); 1149 1150 server_redraw_window_borders(wp->window); 1151 server_status_window(wp->window); 1152 notify_pane("pane-mode-changed", wp); 1153} 1154 1155void 1156window_pane_reset_mode_all(struct window_pane *wp) 1157{ 1158 while (!TAILQ_EMPTY(&wp->modes)) 1159 window_pane_reset_mode(wp); 1160} 1161 1162static void 1163window_pane_copy_key(struct window_pane *wp, key_code key) 1164{ 1165 struct window_pane *loop; 1166 1167 TAILQ_FOREACH(loop, &wp->window->panes, entry) { 1168 if (loop != wp && 1169 TAILQ_EMPTY(&loop->modes) && 1170 loop->fd != -1 && 1171 (~loop->flags & PANE_INPUTOFF) && 1172 window_pane_visible(loop) && 1173 options_get_number(loop->options, "synchronize-panes")) 1174 input_key_pane(loop, key, NULL); 1175 } 1176} 1177 1178int 1179window_pane_key(struct window_pane *wp, struct client *c, struct session *s, 1180 struct winlink *wl, key_code key, struct mouse_event *m) 1181{ 1182 struct window_mode_entry *wme; 1183 1184 if (KEYC_IS_MOUSE(key) && m == NULL) 1185 return (-1); 1186 1187 wme = TAILQ_FIRST(&wp->modes); 1188 if (wme != NULL) { 1189 if (wme->mode->key != NULL && c != NULL) { 1190 key &= ~KEYC_MASK_FLAGS; 1191 wme->mode->key(wme, c, s, wl, key, m); 1192 } 1193 return (0); 1194 } 1195 1196 if (wp->fd == -1 || wp->flags & PANE_INPUTOFF) 1197 return (0); 1198 1199 if (input_key_pane(wp, key, m) != 0) 1200 return (-1); 1201 1202 if (KEYC_IS_MOUSE(key)) 1203 return (0); 1204 if (options_get_number(wp->options, "synchronize-panes")) 1205 window_pane_copy_key(wp, key); 1206 return (0); 1207} 1208 1209int 1210window_pane_visible(struct window_pane *wp) 1211{ 1212 if (~wp->window->flags & WINDOW_ZOOMED) 1213 return (1); 1214 return (wp == wp->window->active); 1215} 1216 1217int 1218window_pane_exited(struct window_pane *wp) 1219{ 1220 return (wp->fd == -1 || (wp->flags & PANE_EXITED)); 1221} 1222 1223u_int 1224window_pane_search(struct window_pane *wp, const char *term, int regex, 1225 int ignore) 1226{ 1227 struct screen *s = &wp->base; 1228 regex_t r; 1229 char *new = NULL, *line; 1230 u_int i; 1231 int flags = 0, found; 1232 size_t n; 1233 1234 if (!regex) { 1235 if (ignore) 1236 flags |= FNM_CASEFOLD; 1237 xasprintf(&new, "*%s*", term); 1238 } else { 1239 if (ignore) 1240 flags |= REG_ICASE; 1241 if (regcomp(&r, term, flags|REG_EXTENDED) != 0) 1242 return (0); 1243 } 1244 1245 for (i = 0; i < screen_size_y(s); i++) { 1246 line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s)); 1247 for (n = strlen(line); n > 0; n--) { 1248 if (!isspace((u_char)line[n - 1])) 1249 break; 1250 line[n - 1] = '\0'; 1251 } 1252 log_debug("%s: %s", __func__, line); 1253 if (!regex) 1254 found = (fnmatch(new, line, flags) == 0); 1255 else 1256 found = (regexec(&r, line, 0, NULL, 0) == 0); 1257 free(line); 1258 if (found) 1259 break; 1260 } 1261 if (!regex) 1262 free(new); 1263 else 1264 regfree(&r); 1265 1266 if (i == screen_size_y(s)) 1267 return (0); 1268 return (i + 1); 1269} 1270 1271/* Get MRU pane from a list. */ 1272static struct window_pane * 1273window_pane_choose_best(struct window_pane **list, u_int size) 1274{ 1275 struct window_pane *next, *best; 1276 u_int i; 1277 1278 if (size == 0) 1279 return (NULL); 1280 1281 best = list[0]; 1282 for (i = 1; i < size; i++) { 1283 next = list[i]; 1284 if (next->active_point > best->active_point) 1285 best = next; 1286 } 1287 return (best); 1288} 1289 1290/* 1291 * Find the pane directly above another. We build a list of those adjacent to 1292 * top edge and then choose the best. 1293 */ 1294struct window_pane * 1295window_pane_find_up(struct window_pane *wp) 1296{ 1297 struct window *w; 1298 struct window_pane *next, *best, **list; 1299 u_int edge, left, right, end, size; 1300 int status, found; 1301 1302 if (wp == NULL) 1303 return (NULL); 1304 w = wp->window; 1305 status = options_get_number(w->options, "pane-border-status"); 1306 1307 list = NULL; 1308 size = 0; 1309 1310 edge = wp->yoff; 1311 if (status == PANE_STATUS_TOP) { 1312 if (edge == 1) 1313 edge = w->sy + 1; 1314 } else if (status == PANE_STATUS_BOTTOM) { 1315 if (edge == 0) 1316 edge = w->sy; 1317 } else { 1318 if (edge == 0) 1319 edge = w->sy + 1; 1320 } 1321 1322 left = wp->xoff; 1323 right = wp->xoff + wp->sx; 1324 1325 TAILQ_FOREACH(next, &w->panes, entry) { 1326 if (next == wp) 1327 continue; 1328 if (next->yoff + next->sy + 1 != edge) 1329 continue; 1330 end = next->xoff + next->sx - 1; 1331 1332 found = 0; 1333 if (next->xoff < left && end > right) 1334 found = 1; 1335 else if (next->xoff >= left && next->xoff <= right) 1336 found = 1; 1337 else if (end >= left && end <= right) 1338 found = 1; 1339 if (!found) 1340 continue; 1341 list = xreallocarray(list, size + 1, sizeof *list); 1342 list[size++] = next; 1343 } 1344 1345 best = window_pane_choose_best(list, size); 1346 free(list); 1347 return (best); 1348} 1349 1350/* Find the pane directly below another. */ 1351struct window_pane * 1352window_pane_find_down(struct window_pane *wp) 1353{ 1354 struct window *w; 1355 struct window_pane *next, *best, **list; 1356 u_int edge, left, right, end, size; 1357 int status, found; 1358 1359 if (wp == NULL) 1360 return (NULL); 1361 w = wp->window; 1362 status = options_get_number(w->options, "pane-border-status"); 1363 1364 list = NULL; 1365 size = 0; 1366 1367 edge = wp->yoff + wp->sy + 1; 1368 if (status == PANE_STATUS_TOP) { 1369 if (edge >= w->sy) 1370 edge = 1; 1371 } else if (status == PANE_STATUS_BOTTOM) { 1372 if (edge >= w->sy - 1) 1373 edge = 0; 1374 } else { 1375 if (edge >= w->sy) 1376 edge = 0; 1377 } 1378 1379 left = wp->xoff; 1380 right = wp->xoff + wp->sx; 1381 1382 TAILQ_FOREACH(next, &w->panes, entry) { 1383 if (next == wp) 1384 continue; 1385 if (next->yoff != edge) 1386 continue; 1387 end = next->xoff + next->sx - 1; 1388 1389 found = 0; 1390 if (next->xoff < left && end > right) 1391 found = 1; 1392 else if (next->xoff >= left && next->xoff <= right) 1393 found = 1; 1394 else if (end >= left && end <= right) 1395 found = 1; 1396 if (!found) 1397 continue; 1398 list = xreallocarray(list, size + 1, sizeof *list); 1399 list[size++] = next; 1400 } 1401 1402 best = window_pane_choose_best(list, size); 1403 free(list); 1404 return (best); 1405} 1406 1407/* Find the pane directly to the left of another. */ 1408struct window_pane * 1409window_pane_find_left(struct window_pane *wp) 1410{ 1411 struct window *w; 1412 struct window_pane *next, *best, **list; 1413 u_int edge, top, bottom, end, size; 1414 int found; 1415 1416 if (wp == NULL) 1417 return (NULL); 1418 w = wp->window; 1419 1420 list = NULL; 1421 size = 0; 1422 1423 edge = wp->xoff; 1424 if (edge == 0) 1425 edge = w->sx + 1; 1426 1427 top = wp->yoff; 1428 bottom = wp->yoff + wp->sy; 1429 1430 TAILQ_FOREACH(next, &w->panes, entry) { 1431 if (next == wp) 1432 continue; 1433 if (next->xoff + next->sx + 1 != edge) 1434 continue; 1435 end = next->yoff + next->sy - 1; 1436 1437 found = 0; 1438 if (next->yoff < top && end > bottom) 1439 found = 1; 1440 else if (next->yoff >= top && next->yoff <= bottom) 1441 found = 1; 1442 else if (end >= top && end <= bottom) 1443 found = 1; 1444 if (!found) 1445 continue; 1446 list = xreallocarray(list, size + 1, sizeof *list); 1447 list[size++] = next; 1448 } 1449 1450 best = window_pane_choose_best(list, size); 1451 free(list); 1452 return (best); 1453} 1454 1455/* Find the pane directly to the right of another. */ 1456struct window_pane * 1457window_pane_find_right(struct window_pane *wp) 1458{ 1459 struct window *w; 1460 struct window_pane *next, *best, **list; 1461 u_int edge, top, bottom, end, size; 1462 int found; 1463 1464 if (wp == NULL) 1465 return (NULL); 1466 w = wp->window; 1467 1468 list = NULL; 1469 size = 0; 1470 1471 edge = wp->xoff + wp->sx + 1; 1472 if (edge >= w->sx) 1473 edge = 0; 1474 1475 top = wp->yoff; 1476 bottom = wp->yoff + wp->sy; 1477 1478 TAILQ_FOREACH(next, &w->panes, entry) { 1479 if (next == wp) 1480 continue; 1481 if (next->xoff != edge) 1482 continue; 1483 end = next->yoff + next->sy - 1; 1484 1485 found = 0; 1486 if (next->yoff < top && end > bottom) 1487 found = 1; 1488 else if (next->yoff >= top && next->yoff <= bottom) 1489 found = 1; 1490 else if (end >= top && end <= bottom) 1491 found = 1; 1492 if (!found) 1493 continue; 1494 list = xreallocarray(list, size + 1, sizeof *list); 1495 list[size++] = next; 1496 } 1497 1498 best = window_pane_choose_best(list, size); 1499 free(list); 1500 return (best); 1501} 1502 1503void 1504window_pane_stack_push(struct window_panes *stack, struct window_pane *wp) 1505{ 1506 if (wp != NULL) { 1507 window_pane_stack_remove(stack, wp); 1508 TAILQ_INSERT_HEAD(stack, wp, sentry); 1509 wp->flags |= PANE_VISITED; 1510 } 1511} 1512 1513void 1514window_pane_stack_remove(struct window_panes *stack, struct window_pane *wp) 1515{ 1516 if (wp != NULL && (wp->flags & PANE_VISITED)) { 1517 TAILQ_REMOVE(stack, wp, sentry); 1518 wp->flags &= ~PANE_VISITED; 1519 } 1520} 1521 1522/* Clear alert flags for a winlink */ 1523void 1524winlink_clear_flags(struct winlink *wl) 1525{ 1526 struct winlink *loop; 1527 1528 wl->window->flags &= ~WINDOW_ALERTFLAGS; 1529 TAILQ_FOREACH(loop, &wl->window->winlinks, wentry) { 1530 if ((loop->flags & WINLINK_ALERTFLAGS) != 0) { 1531 loop->flags &= ~WINLINK_ALERTFLAGS; 1532 server_status_session(loop->session); 1533 } 1534 } 1535} 1536 1537/* Shuffle window indexes up. */ 1538int 1539winlink_shuffle_up(struct session *s, struct winlink *wl, int before) 1540{ 1541 int idx, last; 1542 1543 if (wl == NULL) 1544 return (-1); 1545 if (before) 1546 idx = wl->idx; 1547 else 1548 idx = wl->idx + 1; 1549 1550 /* Find the next free index. */ 1551 for (last = idx; last < INT_MAX; last++) { 1552 if (winlink_find_by_index(&s->windows, last) == NULL) 1553 break; 1554 } 1555 if (last == INT_MAX) 1556 return (-1); 1557 1558 /* Move everything from last - 1 to idx up a bit. */ 1559 for (; last > idx; last--) { 1560 wl = winlink_find_by_index(&s->windows, last - 1); 1561 RB_REMOVE(winlinks, &s->windows, wl); 1562 wl->idx++; 1563 RB_INSERT(winlinks, &s->windows, wl); 1564 } 1565 1566 return (idx); 1567} 1568 1569static void 1570window_pane_input_callback(struct client *c, __unused const char *path, 1571 int error, int closed, struct evbuffer *buffer, void *data) 1572{ 1573 struct window_pane_input_data *cdata = data; 1574 struct window_pane *wp; 1575 u_char *buf = EVBUFFER_DATA(buffer); 1576 size_t len = EVBUFFER_LENGTH(buffer); 1577 1578 wp = window_pane_find_by_id(cdata->wp); 1579 if (cdata->file != NULL && (wp == NULL || c->flags & CLIENT_DEAD)) { 1580 if (wp == NULL) { 1581 c->retval = 1; 1582 c->flags |= CLIENT_EXIT; 1583 } 1584 file_cancel(cdata->file); 1585 } else if (cdata->file == NULL || closed || error != 0) { 1586 cmdq_continue(cdata->item); 1587 server_client_unref(c); 1588 free(cdata); 1589 } else 1590 input_parse_buffer(wp, buf, len); 1591 evbuffer_drain(buffer, len); 1592} 1593 1594int 1595window_pane_start_input(struct window_pane *wp, struct cmdq_item *item, 1596 char **cause) 1597{ 1598 struct client *c = cmdq_get_client(item); 1599 struct window_pane_input_data *cdata; 1600 1601 if (~wp->flags & PANE_EMPTY) { 1602 *cause = xstrdup("pane is not empty"); 1603 return (-1); 1604 } 1605 if (c->flags & (CLIENT_DEAD|CLIENT_EXITED)) 1606 return (1); 1607 if (c->session != NULL) 1608 return (1); 1609 1610 cdata = xmalloc(sizeof *cdata); 1611 cdata->item = item; 1612 cdata->wp = wp->id; 1613 cdata->file = file_read(c, "-", window_pane_input_callback, cdata); 1614 c->references++; 1615 1616 return (0); 1617} 1618 1619void * 1620window_pane_get_new_data(struct window_pane *wp, 1621 struct window_pane_offset *wpo, size_t *size) 1622{ 1623 size_t used = wpo->used - wp->base_offset; 1624 1625 *size = EVBUFFER_LENGTH(wp->event->input) - used; 1626 return (EVBUFFER_DATA(wp->event->input) + used); 1627} 1628 1629void 1630window_pane_update_used_data(struct window_pane *wp, 1631 struct window_pane_offset *wpo, size_t size) 1632{ 1633 size_t used = wpo->used - wp->base_offset; 1634 1635 if (size > EVBUFFER_LENGTH(wp->event->input) - used) 1636 size = EVBUFFER_LENGTH(wp->event->input) - used; 1637 wpo->used += size; 1638} 1639 1640void 1641window_set_fill_character(struct window *w) 1642{ 1643 const char *value; 1644 struct utf8_data *ud; 1645 1646 free(w->fill_character); 1647 w->fill_character = NULL; 1648 1649 value = options_get_string(w->options, "fill-character"); 1650 if (*value != '\0' && utf8_isvalid(value)) { 1651 ud = utf8_fromcstr(value); 1652 if (ud != NULL && ud[0].width == 1) 1653 w->fill_character = ud; 1654 } 1655} 1656 1657void 1658window_pane_default_cursor(struct window_pane *wp) 1659{ 1660 struct screen *s = wp->screen; 1661 int c; 1662 1663 c = options_get_number(wp->options, "cursor-colour"); 1664 s->default_ccolour = c; 1665 1666 c = options_get_number(wp->options, "cursor-style"); 1667 s->default_mode = 0; 1668 screen_set_cursor_style(c, &s->default_cstyle, &s->default_mode); 1669} 1670