/* $OpenBSD$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <util.h>
#include "tmux.h"
/*
* Each window is attached to a number of panes, each of which is a pty. This
* file contains code to handle them.
*
* A pane has two buffers attached, these are filled and emptied by the main
* server poll loop. Output data is received from pty's in screen format,
* translated and returned as a series of escape sequences and strings via
* input_parse (in input.c). Input data is received as key codes and written
* directly via input_key.
*
* Each pane also has a "virtual" screen (screen.c) which contains the current
* state and is redisplayed when the window is reattached to a client.
*
* Windows are stored directly on a global array and wrapped in any number of
* winlink structs to be linked onto local session RB trees. A reference count
* is maintained and a window removed from the global list and destroyed when
* it reaches zero.
*/
/* Global window list. */
struct windows windows;
/* Global panes tree. */
struct window_pane_tree all_window_panes;
u_int next_window_pane_id;
u_int next_window_id;
void window_pane_read_callback(struct bufferevent *, void *);
void window_pane_error_callback(struct bufferevent *, short, void *);
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
int
winlink_cmp(struct winlink *wl1, struct winlink *wl2)
{
return (wl1->idx - wl2->idx);
}
RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
int
window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2)
{
return (wp1->id - wp2->id);
}
struct winlink *
winlink_find_by_window(struct winlinks *wwl, struct window *w)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, wwl) {
if (wl->window == w)
return (wl);
}
return (NULL);
}
struct winlink *
winlink_find_by_index(struct winlinks *wwl, int idx)
{
struct winlink wl;
if (idx < 0)
fatalx("bad index");
wl.idx = idx;
return (RB_FIND(winlinks, wwl, &wl));
}
struct winlink *
winlink_find_by_window_id(struct winlinks *wwl, u_int id)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, wwl) {
if (wl->window->id == id)
return (wl);
}
return NULL;
}
int
winlink_next_index(struct winlinks *wwl, int idx)
{
int i;
i = idx;
do {
if (winlink_find_by_index(wwl, i) == NULL)
return (i);
if (i == INT_MAX)
i = 0;
else
i++;
} while (i != idx);
return (-1);
}
u_int
winlink_count(struct winlinks *wwl)
{
struct winlink *wl;
u_int n;
n = 0;
RB_FOREACH(wl, winlinks, wwl)
n++;
return (n);
}
struct winlink *
winlink_add(struct winlinks *wwl, int idx)
{
struct winlink *wl;
if (idx < 0) {
if ((idx = winlink_next_index(wwl, -idx - 1))