"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/window.c" (10 Jun 2021, 33300 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "window.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.2_vs_3.2a.

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