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:
Nicholas Marriott 2007-10-26 12:29:07 +00:00
parent 9f06104c3a
commit 4ba3cf60be
18 changed files with 347 additions and 349 deletions

View File

@ -1,3 +1,10 @@
26 October 2007
* (nicm) Redo window data structures. The global array remains, but each per-
session list is now a RB tree of winlink structures. This disassociates the
window index from the array size (allowing arbitrary indexes) which still
allowing windows to have multiple indexes.
25 October 2007
* (nicm) has-session command: checks if session exists.
@ -163,5 +170,5 @@
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
$Id: CHANGES,v 1.51 2007-10-25 17:44:24 nicm Exp $
$Id: CHANGES,v 1.52 2007-10-26 12:29:07 nicm Exp $

3
TODO
View File

@ -1,4 +1,3 @@
- decide if TIOCPKT is necessary and either handle it or remove the code
- it would be nice if there wasn't so much copying buffers about, audit uses
- useful env vars like WINDOW
- sort out who controls the buffers in local.c a bit
@ -20,8 +19,6 @@
- profile/optimise, particularly (i suspect) input.c
- tidy up input.c a bit
- decide about customised status line
- rethink data structures. window->index is O(n), could have a w->idx member
or use queues/trees and avoid NULLs?
- client could pass term/tty fd up to server and then do nothing. what problems
would this cause? -- need access to all terminfo data at once... signals?
- cleanup/redesign IPC

View File

@ -1,4 +1,4 @@
/* $Id: cmd-kill-window.c,v 1.1 2007-10-19 11:10:35 nicm Exp $ */
/* $Id: cmd-kill-window.c,v 1.2 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -92,7 +92,7 @@ cmd_kill_window_exec(void *ptr, struct cmd_ctx *ctx)
struct cmd_kill_window_data *data = ptr, std = { -1 };
struct client *c = ctx->client;
struct session *s = ctx->session;
struct window *w;
struct winlink *wl;
u_int i;
int destroyed;
@ -100,13 +100,13 @@ cmd_kill_window_exec(void *ptr, struct cmd_ctx *ctx)
data = &std;
if (data->idx == -1)
w = s->window;
else if ((w = window_at(&s->windows, data->idx)) == NULL) {
wl = s->curw;
else if ((wl = winlink_find_by_index(&s->windows, data->idx)) == NULL) {
ctx->error(ctx, "no window %u", data->idx);
return;
}
destroyed = session_detach(s, w);
destroyed = session_detach(s, wl);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)

View File

@ -1,4 +1,4 @@
/* $Id: cmd-list-sessions.c,v 1.6 2007-10-23 09:36:07 nicm Exp $ */
/* $Id: cmd-list-sessions.c,v 1.7 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -45,8 +45,9 @@ cmd_list_sessions_exec(unused void *ptr, struct cmd_ctx *ctx)
{
struct client *c = ctx->client;
struct session *s = ctx->session;
struct winlink *wl;
char *tim;
u_int i, j, n;
u_int i, n;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
@ -54,10 +55,8 @@ cmd_list_sessions_exec(unused void *ptr, struct cmd_ctx *ctx)
continue;
n = 0;
for (j = 0; j < ARRAY_LENGTH(&s->windows); j++) {
if (ARRAY_ITEM(&s->windows, j) != NULL)
n++;
}
RB_FOREACH(wl, winlinks, &s->windows)
n++;
tim = ctime(&s->tim);
*strchr(tim, '\n') = '\0';

View File

@ -1,4 +1,4 @@
/* $Id: cmd-list-windows.c,v 1.3 2007-10-23 09:36:07 nicm Exp $ */
/* $Id: cmd-list-windows.c,v 1.4 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -44,17 +44,14 @@ cmd_list_windows_exec(unused void *ptr, struct cmd_ctx *ctx)
{
struct client *c = ctx->client;
struct session *s = ctx->session;
struct winlink *wl;
struct window *w;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&s->windows); i++) {
w = ARRAY_ITEM(&s->windows, i);
if (w == NULL)
continue;
ctx->print(ctx,
"%u: %s \"%s\" (%s) [%ux%u]", i, w->name, w->screen.title,
ttyname(w->fd), w->screen.sx, w->screen.sy);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx, "%u: %s \"%s\" (%s) [%ux%u]", wl->idx,
w->name, w->screen.title, ttyname(w->fd),
w->screen.sx, w->screen.sy);
}
if (!(ctx->flags & CMD_KEY))

View File

@ -1,4 +1,4 @@
/* $Id: cmd-new-session.c,v 1.13 2007-10-19 17:15:29 nicm Exp $ */
/* $Id: cmd-new-session.c,v 1.14 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -133,8 +133,8 @@ cmd_new_session_exec(void *ptr, struct cmd_ctx *ctx)
if (c->session == NULL)
fatalx("session_create failed");
if (data->winname != NULL) {
xfree(c->session->window->name);
c->session->window->name = xstrdup(data->winname);
xfree(c->session->curw->window->name);
c->session->curw->window->name = xstrdup(data->winname);
}
if (data->flag_detached)

View File

@ -1,4 +1,4 @@
/* $Id: cmd-new-window.c,v 1.9 2007-10-19 09:21:25 nicm Exp $ */
/* $Id: cmd-new-window.c,v 1.10 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -19,6 +19,7 @@
#include <sys/types.h>
#include <getopt.h>
#include <stdlib.h>
#include "tmux.h"
@ -35,11 +36,12 @@ void cmd_new_window_free(void *);
struct cmd_new_window_data {
char *name;
char *cmd;
int idx;
int flag_detached;
};
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww", "[-d] [-n name] [command]",
"new-window", "neww", "[-d] [-i index] [-n name] [command]",
0,
cmd_new_window_parse,
cmd_new_window_exec,
@ -52,15 +54,24 @@ int
cmd_new_window_parse(void **ptr, int argc, char **argv, char **cause)
{
struct cmd_new_window_data *data;
const char *errstr;
int opt;
*ptr = data = xmalloc(sizeof *data);
data->idx = -1;
data->flag_detached = 0;
data->name = NULL;
data->cmd = NULL;
while ((opt = getopt(argc, argv, "dn:")) != EOF) {
while ((opt = getopt(argc, argv, "di:n:")) != EOF) {
switch (opt) {
case 'i':
data->idx = strtonum(optarg, 0, UINT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "index %s", errstr);
goto error;
}
break;
case 'n':
data->name = xstrdup(optarg);
break;
@ -85,6 +96,7 @@ usage:
usage(cause, "%s %s",
cmd_new_window_entry.name, cmd_new_window_entry.usage);
error:
cmd_new_window_free(data);
return (-1);
}
@ -92,11 +104,12 @@ usage:
void
cmd_new_window_exec(void *ptr, struct cmd_ctx *ctx)
{
struct cmd_new_window_data *data = ptr, std = { NULL, NULL, 0 };
struct cmd_new_window_data *data = ptr;
struct cmd_new_window_data std = { NULL, NULL, -1, 0 };
struct client *c = ctx->client;
struct session *s = ctx->session;
struct winlink *wl;
char *cmd;
u_int i;
if (data == NULL)
data = &std;
@ -105,12 +118,14 @@ cmd_new_window_exec(void *ptr, struct cmd_ctx *ctx)
if (cmd == NULL)
cmd = default_command;
if (session_new(s, data->name, cmd, &i) != 0) {
if (data->idx < 0)
data->idx = -1;
if ((wl = session_new(s, data->name, cmd, data->idx)) == NULL) {
ctx->error(ctx, "command failed: %s", cmd);
return;
}
if (!data->flag_detached) {
session_select(s, i);
session_select(s, wl->idx);
server_redraw_session(s);
} else
server_status_session(s);

View File

@ -1,4 +1,4 @@
/* $Id: cmd-rename-window.c,v 1.7 2007-10-19 17:15:29 nicm Exp $ */
/* $Id: cmd-rename-window.c,v 1.8 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -96,19 +96,19 @@ cmd_rename_window_exec(void *ptr, struct cmd_ctx *ctx)
struct cmd_rename_window_data *data = ptr;
struct client *c = ctx->client;
struct session *s = ctx->session;
struct window *w;
struct winlink *wl;
if (data == NULL)
return;
if (data->idx == -1)
w = s->window;
else if ((w = window_at(&s->windows, data->idx)) == NULL) {
wl = s->curw;
else if ((wl = winlink_find_by_index(&s->windows, data->idx)) == NULL) {
ctx->error(ctx, "no window %u", data->idx);
return;
}
xfree(w->name);
w->name = xstrdup(data->newname);
xfree(wl->window->name);
wl->window->name = xstrdup(data->newname);
server_status_session(s);

View File

@ -1,4 +1,4 @@
/* $Id: cmd-select-window.c,v 1.4 2007-10-19 09:21:26 nicm Exp $ */
/* $Id: cmd-select-window.c,v 1.5 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -108,10 +108,16 @@ cmd_select_window_exec(void *ptr, struct cmd_ctx *ctx)
if (data == NULL)
return;
if (session_select(s, data->idx) == 0)
switch (session_select(s, data->idx)) {
case 0:
server_redraw_session(s);
else
break;
case 1:
break;
default:
ctx->error(ctx, "no window %u", data->idx);
break;
}
if (!(ctx->flags & CMD_KEY))
server_write_client(c, MSG_EXIT, NULL, 0);

View File

@ -1,4 +1,4 @@
/* $Id: cmd-send-prefix.c,v 1.2 2007-10-19 23:33:20 nicm Exp $ */
/* $Id: cmd-send-prefix.c,v 1.3 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -49,5 +49,5 @@ cmd_send_prefix_exec(unused void *ptr, struct cmd_ctx *ctx)
return;
}
window_key(c->session->window, prefix_key);
input_translate_key(c->session->curw->window->out, prefix_key);
}

View File

@ -1,4 +1,4 @@
/* $Id: key-bindings.c,v 1.11 2007-10-23 10:25:57 nicm Exp $ */
/* $Id: key-bindings.c,v 1.12 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -177,7 +177,7 @@ key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...)
if (!(c->flags & CLIENT_HOLD)) {
input_store_zero(c->out, CODE_CURSOROFF);
for (i = 0; i < c->session->window->screen.sy; i++) {
for (i = 0; i < c->session->curw->window->screen.sy; i++) {
input_store_two(c->out, CODE_CURSORMOVE, i + 1, 1);
input_store_zero(c->out, CODE_CLEARLINE);
}

View File

@ -1,4 +1,4 @@
/* $Id: server-fn.c,v 1.22 2007-10-23 10:48:23 nicm Exp $ */
/* $Id: server-fn.c,v 1.23 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -114,7 +114,7 @@ server_write_window_cur(
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL &&
c->session != NULL && c->session->window == w) {
c->session != NULL && c->session->curw->window == w) {
if (c->flags & CLIENT_HOLD) /* XXX OUTPUT only */
continue;
server_write_client(c, type, buf, len);
@ -165,7 +165,7 @@ server_status_client(struct client *c)
void
server_clear_client(struct client *c)
{
struct screen *s = &c->session->window->screen;
struct screen *s = &c->session->curw->window->screen;
struct hdr hdr;
size_t size;
u_int i;
@ -192,7 +192,7 @@ server_clear_client(struct client *c)
void
server_redraw_client(struct client *c)
{
struct screen *s = &c->session->window->screen;
struct screen *s = &c->session->curw->window->screen;
struct hdr hdr;
size_t size;
@ -248,7 +248,8 @@ server_clear_window_cur(struct window *w)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session != NULL && c->session->window == w)
if (c != NULL &&
c->session != NULL && c->session->curw->window == w)
server_clear_client(c);
}
}
@ -276,7 +277,8 @@ server_redraw_window_cur(struct window *w)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session != NULL && c->session->window == w)
if (c != NULL &&
c->session != NULL && c->session->curw->window == w)
server_redraw_client(c);
}
}
@ -304,7 +306,8 @@ server_status_window_cur(struct window *w)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session != NULL && c->session->window == w)
if (c != NULL &&
c->session != NULL && c->session->curw->window == w)
server_status_client(c);
}
}
@ -327,6 +330,7 @@ server_status_window_all(struct window *w)
void
server_write_message(struct client *c, const char *fmt, ...)
{
struct screen *s = &c->session->curw->window->screen;
struct hdr hdr;
va_list ap;
char *msg;
@ -364,8 +368,7 @@ server_write_message(struct client *c, const char *fmt, ...)
size = BUFFER_USED(c->out);
if (status_lines == 0) {
screen_draw(
&c->session->window->screen, c->out, c->sy - 1, c->sy - 1);
screen_draw(s, c->out, c->sy - 1, c->sy - 1);
} else
status_write(c);

View File

@ -1,4 +1,4 @@
/* $Id: server-msg.c,v 1.29 2007-10-23 10:48:23 nicm Exp $ */
/* $Id: server-msg.c,v 1.30 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -223,7 +223,7 @@ server_msg_fn_keys(struct hdr *hdr, struct client *c)
if (key == prefix_key)
c->flags |= CLIENT_PREFIX;
else
window_key(c->session->window, key);
input_translate_key(c->session->curw->window->out, key);
}
return (0);

View File

@ -1,4 +1,4 @@
/* $Id: server.c,v 1.34 2007-10-24 11:30:02 nicm Exp $ */
/* $Id: server.c,v 1.35 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -228,7 +228,7 @@ server_handle_windows(struct pollfd **pfd)
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
if ((w = ARRAY_ITEM(&windows, i)) != NULL) {
if (window_poll(w, *pfd) != 0)
if (buffer_poll(*pfd, w->in, w->out) != 0)
server_lost_window(w);
else
server_handle_window(w);
@ -259,14 +259,14 @@ server_fill_clients(struct pollfd **pfd)
/* Handle client pollfds. */
void
server_handle_clients(struct pollfd *(*pfd))
server_handle_clients(struct pollfd **pfd)
{
struct client *c;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if ((c = ARRAY_ITEM(&clients, i)) != NULL) {
if (buffer_poll((*pfd), c->in, c->out) != 0)
if (buffer_poll(*pfd, c->in, c->out) != 0)
server_lost_client(c);
else
server_msg_dispatch(c);
@ -345,7 +345,7 @@ server_handle_window(struct window *w)
u_int i;
b = buffer_create(BUFSIZ);
window_data(w, b);
input_parse(w, b);
if (BUFFER_USED(b) != 0) {
server_write_window_cur(
w, MSG_DATA, BUFFER_OUT(b), BUFFER_USED(b));
@ -368,7 +368,7 @@ server_handle_window(struct window *w)
case BELL_CURRENT:
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s != NULL && s->window == w)
if (s != NULL && s->curw->window == w)
server_write_session(s, MSG_DATA, "\007", 1);
}
break;
@ -384,6 +384,7 @@ server_lost_window(struct window *w)
{
struct client *c;
struct session *s;
struct winlink *wl;
u_int i, j;
int destroyed;
@ -397,16 +398,23 @@ server_lost_window(struct window *w)
continue;
/* Detach window and either redraw or kill clients. */
destroyed = session_detach(s, w);
for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j);
if (c == NULL || c->session != s)
restart:
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window != w)
continue;
if (destroyed) {
destroyed = session_detach(s, wl);
for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j);
if (c == NULL || c->session != s)
continue;
if (!destroyed) {
server_redraw_client(c);
continue;
}
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
} else
server_redraw_client(c);
}
goto restart;
}
}

173
session.c
View File

@ -1,4 +1,4 @@
/* $Id: session.c,v 1.24 2007-10-24 11:05:59 nicm Exp $ */
/* $Id: session.c,v 1.25 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,33 +29,41 @@
struct sessions sessions;
void
session_cancelbell(struct session *s, struct window *w)
session_cancelbell(struct session *s, struct winlink *wl)
{
u_int i;
if (window_index(&s->bells, w, &i) == 0)
window_remove(&s->bells, w);
for (i = 0; i < ARRAY_LENGTH(&s->bells); i++) {
if (ARRAY_ITEM(&s->bells, i) == wl) {
ARRAY_REMOVE(&s->bells, i);
break;
}
}
}
void
session_addbell(struct session *s, struct window *w)
{
u_int i;
struct winlink *wl;
/* Never bell in the current window. */
if (w == s->window || !session_has(s, w))
return;
if (window_index(&s->bells, w, &i) != 0)
window_add(&s->bells, w);
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl == s->curw)
continue;
if (wl->window == w && !session_hasbell(s, wl))
ARRAY_ADD(&s->bells, wl);
}
}
int
session_hasbell(struct session *s, struct window *w)
session_hasbell(struct session *s, struct winlink *wl)
{
u_int i;
return (window_index(&s->bells, w, &i) == 0);
for (i = 0; i < ARRAY_LENGTH(&s->bells); i++) {
if (ARRAY_ITEM(&s->bells, i) == wl)
return (1);
}
return (0);
}
/* Find session by name. */
@ -83,8 +91,8 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy)
s = xmalloc(sizeof *s);
s->tim = time(NULL);
s->window = s->last = NULL;
ARRAY_INIT(&s->windows);
s->curw = s->lastw = NULL;
RB_INIT(&s->windows);
ARRAY_INIT(&s->bells);
s->sx = sx;
@ -103,7 +111,7 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy)
s->name = xstrdup(name);
else
xasprintf(&s->name, "%u", i);
if (session_new(s, NULL, cmd, &i) != 0) {
if (session_new(s, NULL, cmd, -1) == NULL) {
session_destroy(s);
return (NULL);
}
@ -116,7 +124,8 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy)
void
session_destroy(struct session *s)
{
u_int i;
struct winlink *wl;
u_int i;
if (session_index(s, &i) != 0)
fatalx("session not found");
@ -124,11 +133,11 @@ session_destroy(struct session *s)
while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL)
ARRAY_TRUNC(&sessions, 1);
for (i = 0; i < ARRAY_LENGTH(&s->windows); i++) {
if (ARRAY_ITEM(&s->windows, i) != NULL)
window_remove(&s->windows, ARRAY_ITEM(&s->windows, i));
while (!RB_EMPTY(&s->windows)) {
wl = RB_ROOT(&s->windows);
RB_REMOVE(winlinks, &s->windows, wl);
winlink_remove(&s->windows, wl);
}
ARRAY_FREE(&s->windows);
xfree(s->name);
xfree(s);
@ -146,44 +155,43 @@ session_index(struct session *s, u_int *i)
}
/* Create a new window on a session. */
int
session_new(struct session *s, const char *name, const char *cmd, u_int *i)
struct winlink *
session_new(struct session *s, const char *name, const char *cmd, int idx)
{
struct window *w;
const char *environ[] = { NULL, "TERM=screen", NULL };
char buf[256];
u_int i;
if (session_index(s, i) != 0)
if (session_index(s, &i) != 0)
fatalx("session not found");
xsnprintf(buf, sizeof buf, "TMUX=%ld,%u", (long) getpid(), *i);
xsnprintf(buf, sizeof buf, "TMUX=%ld,%u", (long) getpid(), i);
environ[0] = buf;
if ((w = window_create(name, cmd, environ, s->sx, s->sy)) == NULL)
return (-1);
session_attach(s, w);
window_index(&s->windows, w, i);
return (0);
return (NULL);
return (session_attach(s, w, idx));
}
/* Attach a window to a session. */
void
session_attach(struct session *s, struct window *w)
struct winlink *
session_attach(struct session *s, struct window *w, int idx)
{
window_add(&s->windows, w);
return (winlink_add(&s->windows, w, idx));
}
/* Detach a window from a session. */
int
session_detach(struct session *s, struct window *w)
session_detach(struct session *s, struct winlink *wl)
{
if (s->window == w && session_last(s) != 0 && session_previous(s) != 0)
if (s->curw == wl && session_last(s) != 0 && session_previous(s) != 0)
session_next(s);
if (s->last == w)
s->last = NULL;
if (s->lastw == wl)
s->lastw = NULL;
window_remove(&s->windows, w);
if (ARRAY_EMPTY(&s->windows)) {
session_cancelbell(s, wl);
winlink_remove(&s->windows, wl);
if (RB_EMPTY(&s->windows)) {
session_destroy(s);
return (1);
}
@ -194,34 +202,32 @@ session_detach(struct session *s, struct window *w)
int
session_has(struct session *s, struct window *w)
{
u_int i;
struct winlink *wl;
return (window_index(&s->windows, w, &i) == 0);
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window == w)
return (1);
}
return (0);
}
/* Move session to next window. */
int
session_next(struct session *s)
{
struct window *w;
u_int n;
struct winlink *wl;
if (s->window == NULL)
if (s->curw == NULL)
return (-1);
w = window_next(&s->windows, s->window);
if (w == NULL) {
n = 0;
while ((w = ARRAY_ITEM(&s->windows, n)) == NULL)
n++;
if (w == s->window)
return (1);
}
if (w == s->window)
return (0);
s->last = s->window;
s->window = w;
session_cancelbell(s, w);
wl = winlink_next(&s->windows, s->curw);
if (wl == NULL)
wl = RB_MIN(winlinks, &s->windows);
if (wl == s->curw)
return (1);
s->lastw = s->curw;
s->curw = wl;
session_cancelbell(s, wl);
return (0);
}
@ -229,22 +235,19 @@ session_next(struct session *s)
int
session_previous(struct session *s)
{
struct window *w;
struct winlink *wl;
if (s->window == NULL)
if (s->curw == NULL)
return (-1);
w = window_previous(&s->windows, s->window);
if (w == NULL) {
w = ARRAY_LAST(&s->windows);
if (w == s->window)
return (1);
}
if (w == s->window)
return (0);
s->last = s->window;
s->window = w;
session_cancelbell(s, w);
wl = winlink_previous(&s->windows, s->curw);
if (wl == NULL)
wl = RB_MAX(winlinks, &s->windows);
if (wl == s->curw)
return (1);
s->lastw = s->curw;
s->curw = wl;
session_cancelbell(s, wl);
return (0);
}
@ -252,16 +255,16 @@ session_previous(struct session *s)
int
session_select(struct session *s, u_int i)
{
struct window *w;
struct winlink *wl;
w = window_at(&s->windows, i);
if (w == NULL)
wl = winlink_find_by_index(&s->windows, i);
if (wl == NULL)
return (-1);
if (w == s->window)
return (0);
s->last = s->window;
s->window = w;
session_cancelbell(s, w);
if (wl == s->curw)
return (1);
s->lastw = s->curw;
s->curw = wl;
session_cancelbell(s, wl);
return (0);
}
@ -269,16 +272,16 @@ session_select(struct session *s, u_int i)
int
session_last(struct session *s)
{
struct window *w;
struct winlink *wl;
w = s->last;
if (w == NULL)
wl = s->lastw;
if (wl == NULL)
return (-1);
if (w == s->window)
if (wl == s->curw)
return (1);
s->last = s->window;
s->window = w;
session_cancelbell(s, w);
s->lastw = s->curw;
s->curw = wl;
session_cancelbell(s, wl);
return (0);
}

View File

@ -1,4 +1,4 @@
/* $Id: status.c,v 1.6 2007-10-12 12:37:48 nicm Exp $ */
/* $Id: status.c,v 1.7 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,11 +27,10 @@ void status_print(struct buffer *, size_t *, const char *, ...);
void
status_write(struct client *c)
{
struct screen *s = &c->session->window->screen;
struct screen *s = &c->session->curw->window->screen;
struct buffer *b = c->out;
struct window *w;
struct winlink *wl;
size_t size;
u_int i;
char flag;
input_store_zero(b, CODE_CURSOROFF);
@ -39,19 +38,16 @@ status_write(struct client *c)
input_store_two(b, CODE_ATTRIBUTES, 0, status_colour);
size = c->sx;
for (i = 0; i < ARRAY_LENGTH(&c->session->windows); i++) {
w = ARRAY_ITEM(&c->session->windows, i);
if (w == NULL)
continue;
RB_FOREACH(wl, winlinks, &c->session->windows) {
flag = ' ';
if (w == c->session->last)
if (wl == c->session->lastw)
flag = '-';
if (w == c->session->window)
if (wl == c->session->curw)
flag = '*';
if (session_hasbell(c->session, w))
if (session_hasbell(c->session, wl))
flag = '!';
status_print(b, &size, "%u:%s%c ", i, w->name, flag);
status_print(
b, &size, "%u:%s%c ", wl->idx, wl->window->name, flag);
if (size == 0)
break;

60
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.70 2007-10-25 17:44:24 nicm Exp $ */
/* $Id: tmux.h,v 1.71 2007-10-26 12:29:07 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -19,6 +19,9 @@
#ifndef TMUX_H
#define TMUX_H
/* Shut up gcc warnings about empty if bodies. */
#define RB_AUGMENT(x) do {} while (0)
#include <sys/param.h>
#include <sys/tree.h>
#include <sys/queue.h>
@ -385,9 +388,6 @@ struct input_ctx {
ARRAY_DECL(, struct input_arg) args;
};
/* Input context macros. */
#define INPUT_FLAGS(ictx) ((ictx)->flags)
/* Window structure. */
struct window {
char *name;
@ -396,17 +396,26 @@ struct window {
struct buffer *in;
struct buffer *out;
u_int references;
struct input_ctx ictx;
int flags;
#define WINDOW_BELL 0x1
struct screen screen;
u_int references;
};
ARRAY_DECL(windows, struct window *);
/* Entry on local window list. */
struct winlink {
int idx;
struct window *window;
RB_ENTRY(winlink) entry;
};
RB_HEAD(winlinks, winlink);
/* Client session. */
struct session {
char *name;
@ -415,11 +424,11 @@ struct session {
u_int sx;
u_int sy;
struct window *window;
struct window *last;
struct windows windows;
struct winlink *curw;
struct winlink *lastw;
struct winlinks windows;
struct windows bells; /* windows with bells */
ARRAY_DECL(, struct winlink *) bells; /* windows with bells */
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
int flags;
@ -665,33 +674,34 @@ void local_output(struct buffer *, size_t);
/* window.c */
extern struct windows windows;
int window_cmp(struct window *, struct window *);
int winlink_cmp(struct winlink *, struct winlink *);
RB_PROTOTYPE(windows, window, entry, window_cmp);
RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp);
struct winlink *winlink_find_by_index(struct winlinks *, int);
struct winlink *winlink_find_by_window(struct winlinks *, struct window *);
int winlink_next_index(struct winlinks *);
struct winlink *winlink_add(struct winlinks *, struct window *, int);
void winlink_remove(struct winlinks *, struct winlink *);
struct winlink *winlink_next(struct winlinks *, struct winlink *);
struct winlink *winlink_previous(struct winlinks *, struct winlink *);
struct window *window_create(
const char *, const char *, const char **, u_int, u_int);
int window_index(struct windows *, struct window *, u_int *);
void window_add(struct windows *, struct window *);
void window_remove(struct windows *, struct window *);
void window_destroy(struct window *);
struct window *window_next(struct windows *, struct window *);
struct window *window_previous(struct windows *, struct window *);
struct window *window_at(struct windows *, u_int);
int window_resize(struct window *, u_int, u_int);
int window_poll(struct window *, struct pollfd *);
void window_key(struct window *, int);
void window_data(struct window *, struct buffer *);
/* session.c */
extern struct sessions sessions;
void session_cancelbell(struct session *, struct window *);
void session_cancelbell(struct session *, struct winlink *);
void session_addbell(struct session *, struct window *);
int session_hasbell(struct session *, struct window *);
int session_hasbell(struct session *, struct winlink *);
struct session *session_find(const char *);
struct session *session_create(const char *, const char *, u_int, u_int);
void session_destroy(struct session *);
int session_index(struct session *, u_int *);
int session_new(
struct session *, const char *, const char *, u_int *);
void session_attach(struct session *, struct window *);
int session_detach(struct session *, struct window *);
struct winlink *session_new(struct session *, const char *, const char *, int);
struct winlink *session_attach(struct session *, struct window *, int);
int session_detach(struct session *, struct winlink *);
int session_has(struct session *, struct window *);
int session_next(struct session *);
int session_previous(struct session *);

265
window.c
View File

@ -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);
}