mirror of
https://github.com/tmate-io/tmate.git
synced 2025-08-16 16:41:35 +02:00
Reorg window data structures. Add an intermediate data type (struct winlink) to hold index and make sessions hold a RB tree of them rather than a fixed array.
This commit is contained in:
265
window.c
265
window.c
@ -1,4 +1,4 @@
|
||||
/* $Id: window.c,v 1.23 2007-10-24 15:29:29 nicm Exp $ */
|
||||
/* $Id: window.c,v 1.24 2007-10-26 12:29:07 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -22,6 +22,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
@ -47,15 +48,109 @@
|
||||
* Each window also has a "virtual" screen (screen.c) which contains the
|
||||
* current state and is redisplayed when the window is reattached to a client.
|
||||
*
|
||||
* A global list of windows is maintained, and a window may also be a member
|
||||
* of any number of sessions. A reference count is maintained and a window
|
||||
* removed from the global list and destroyed when it reaches zero.
|
||||
* 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;
|
||||
struct windows windows;
|
||||
|
||||
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
|
||||
|
||||
int
|
||||
winlink_cmp(struct winlink *wl1, struct winlink *wl2)
|
||||
{
|
||||
return (wl1->idx - wl2->idx);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
int
|
||||
winlink_next_index(struct winlinks *wwl)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < INT_MAX; i++) {
|
||||
if (winlink_find_by_index(wwl, i) == NULL)
|
||||
return (i);
|
||||
}
|
||||
|
||||
fatalx("no free indexes");
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
winlink_add(struct winlinks *wwl, struct window *w, int idx)
|
||||
{
|
||||
struct winlink *wl;
|
||||
|
||||
if (idx == -1)
|
||||
idx = winlink_next_index(wwl);
|
||||
else if (winlink_find_by_index(wwl, idx) != NULL)
|
||||
return (NULL);
|
||||
|
||||
if (idx < 0)
|
||||
fatalx("bad index");
|
||||
|
||||
wl = xcalloc(1, sizeof *wl);
|
||||
wl->idx = idx;
|
||||
wl->window = w;
|
||||
RB_INSERT(winlinks, wwl, wl);
|
||||
|
||||
w->references++;
|
||||
|
||||
return (wl);
|
||||
}
|
||||
|
||||
void
|
||||
winlink_remove(struct winlinks *wwl, struct winlink *wl)
|
||||
{
|
||||
struct window *w = wl->window;
|
||||
|
||||
RB_REMOVE(winlinks, wwl, wl);
|
||||
xfree(wl);
|
||||
|
||||
if (w->references == 0)
|
||||
fatal("bad reference count");
|
||||
w->references--;
|
||||
if (w->references == 0)
|
||||
window_destroy(w);
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
winlink_next(unused struct winlinks *wwl, struct winlink *wl)
|
||||
{
|
||||
return (RB_NEXT(winlinks, wwl, wl));
|
||||
}
|
||||
|
||||
struct winlink *
|
||||
winlink_previous(struct winlinks *wwl, struct winlink *wl)
|
||||
{
|
||||
struct winlink *wk;
|
||||
int idx = wl->idx;
|
||||
|
||||
wk = NULL;
|
||||
wl = RB_MIN(winlinks, wwl);
|
||||
while (wl != NULL && wl->idx < idx) {
|
||||
wk = wl;
|
||||
wl = RB_NEXT(winlinks, wwl, wl);
|
||||
}
|
||||
if (wl == NULL)
|
||||
return (NULL);
|
||||
return (wk);
|
||||
}
|
||||
|
||||
/* Create a new window. */
|
||||
struct window *
|
||||
window_create(
|
||||
const char *name, const char *cmd, const char **environ, u_int sx, u_int sy)
|
||||
@ -92,10 +187,6 @@ window_create(
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fatal("fcntl failed");
|
||||
|
||||
mode = 1;
|
||||
if (ioctl(fd, TIOCPKT, &mode) == -1)
|
||||
fatal("ioctl failed");
|
||||
|
||||
w = xmalloc(sizeof *w);
|
||||
w->fd = fd;
|
||||
w->in = buffer_create(BUFSIZ);
|
||||
@ -126,60 +217,23 @@ window_create(
|
||||
} else
|
||||
w->name = xstrdup(name);
|
||||
|
||||
window_add(&windows, w);
|
||||
w->references = 1;
|
||||
ARRAY_ADD(&windows, w);
|
||||
w->references = 0;
|
||||
|
||||
return (w);
|
||||
}
|
||||
|
||||
/* Find window index in list. */
|
||||
int
|
||||
window_index(struct windows *ww, struct window *w, u_int *i)
|
||||
{
|
||||
for (*i = 0; *i < ARRAY_LENGTH(ww); (*i)++) {
|
||||
if (w == ARRAY_ITEM(ww, *i))
|
||||
return (0);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Add a window to a list. */
|
||||
void
|
||||
window_add(struct windows *ww, struct window *w)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (window_index(ww, NULL, &i) != 0)
|
||||
ARRAY_ADD(ww, w);
|
||||
else
|
||||
ARRAY_SET(ww, i, w);
|
||||
|
||||
w->references++;
|
||||
}
|
||||
|
||||
/* Remove a window from a list. */
|
||||
void
|
||||
window_remove(struct windows *ww, struct window *w)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (window_index(ww, w, &i) != 0)
|
||||
fatalx("window not found");
|
||||
ARRAY_SET(ww, i, NULL);
|
||||
while (!ARRAY_EMPTY(ww) && ARRAY_LAST(ww) == NULL)
|
||||
ARRAY_TRUNC(ww, 1);
|
||||
|
||||
w->references--;
|
||||
if (w->references == 0)
|
||||
window_destroy(w);
|
||||
if (w->references == 1)
|
||||
window_remove(&windows, w);
|
||||
}
|
||||
|
||||
/* Destroy a window. */
|
||||
void
|
||||
window_destroy(struct window *w)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
|
||||
if (ARRAY_ITEM(&windows, i) == w)
|
||||
break;
|
||||
}
|
||||
ARRAY_REMOVE(&windows, i);
|
||||
|
||||
close(w->fd);
|
||||
|
||||
input_free(w);
|
||||
@ -193,55 +247,6 @@ window_destroy(struct window *w)
|
||||
xfree(w);
|
||||
}
|
||||
|
||||
/* Locate next window in list. */
|
||||
struct window *
|
||||
window_next(struct windows *ww, struct window *w)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (window_index(ww, w, &i) != 0)
|
||||
fatalx("window not found");
|
||||
|
||||
if (i == ARRAY_LENGTH(ww) - 1)
|
||||
return (NULL);
|
||||
do {
|
||||
i++;
|
||||
w = window_at(ww, i);
|
||||
if (w != NULL)
|
||||
return (w);
|
||||
} while (i != ARRAY_LENGTH(ww) - 1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Locate previous window in list. */
|
||||
struct window *
|
||||
window_previous(struct windows *ww, struct window *w)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (window_index(ww, w, &i) != 0)
|
||||
fatalx("window not found");
|
||||
if (i == 0)
|
||||
return (NULL);
|
||||
do {
|
||||
i--;
|
||||
w = window_at(ww, i);
|
||||
if (w != NULL)
|
||||
return (w);
|
||||
} while (i != 0);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Locate window at specific position in list. */
|
||||
struct window *
|
||||
window_at(struct windows *ww, u_int i)
|
||||
{
|
||||
if (i >= ARRAY_LENGTH(ww))
|
||||
return (NULL);
|
||||
return (ARRAY_ITEM(ww, i));
|
||||
}
|
||||
|
||||
/* Resize a window. */
|
||||
int
|
||||
window_resize(struct window *w, u_int sx, u_int sy)
|
||||
{
|
||||
@ -261,51 +266,3 @@ window_resize(struct window *w, u_int sx, u_int sy)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Handle window poll results. This is special because of TIOCPKT. */
|
||||
int
|
||||
window_poll(struct window *w, struct pollfd *pfd)
|
||||
{
|
||||
struct termios tio;
|
||||
size_t size;
|
||||
u_char *ptr;
|
||||
|
||||
size = BUFFER_USED(w->in);
|
||||
if (buffer_poll(pfd, w->in, w->out) != 0)
|
||||
return (-1);
|
||||
|
||||
if (BUFFER_USED(w->in) == size)
|
||||
return (0);
|
||||
ptr = BUFFER_IN(w->in) - (BUFFER_USED(w->in) - size);
|
||||
|
||||
log_debug("window packet: %hhu", *ptr);
|
||||
switch (*ptr) {
|
||||
case TIOCPKT_DATA:
|
||||
case TIOCPKT_FLUSHREAD:
|
||||
case TIOCPKT_FLUSHWRITE:
|
||||
case TIOCPKT_STOP:
|
||||
case TIOCPKT_START:
|
||||
case TIOCPKT_DOSTOP:
|
||||
case TIOCPKT_NOSTOP:
|
||||
buffer_delete_range(w->in, size, 1);
|
||||
break;
|
||||
case TIOCPKT_IOCTL:
|
||||
buffer_delete_range(w->in, size, 1 + sizeof tio);
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Process window key. */
|
||||
void
|
||||
window_key(struct window *w, int key)
|
||||
{
|
||||
input_translate_key(w->out, key);
|
||||
}
|
||||
|
||||
/* Process output data from child process. */
|
||||
void
|
||||
window_data(struct window *w, struct buffer *b)
|
||||
{
|
||||
input_parse(w, b);
|
||||
}
|
||||
|
Reference in New Issue
Block a user