Zombie windows, requested by Will Maier.

This commit is contained in:
Nicholas Marriott 2008-06-29 07:04:31 +00:00
parent 09a4f6a62d
commit d90d646ca8
17 changed files with 254 additions and 55 deletions

17
CHANGES
View File

@ -1,3 +1,18 @@
29 June 2008
* Zombie windows. These are not closed when the child process dies. May be
set for a window with the new "remain-on-exit" option; the default setting
of this flag for new windows may be set with the "remain-by-default" session
option.
A window may be restarted with the respawn-window command:
respawn-window [-k] [command]
If -k is given, any existing process running in the window is killed;
if command is omitted, the same command as when the window was first
created is used.
27 June 2008
* Handle nonexistent session or client to -t properly.
@ -577,4 +592,4 @@
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
$Id: CHANGES,v 1.145 2008-06-27 17:10:01 nicm Exp $
$Id: CHANGES,v 1.146 2008-06-29 07:04:28 nicm Exp $

View File

@ -1,4 +1,4 @@
# $Id: GNUmakefile,v 1.35 2008-06-25 20:43:13 nicm Exp $
# $Id: GNUmakefile,v 1.36 2008-06-29 07:04:29 nicm Exp $
.PHONY: clean
@ -29,6 +29,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
cmd-show-window-options.c cmd-command-prompt.c cmd-set-buffer.c \
cmd-show-buffer.c cmd-list-buffers.c cmd-delete-buffer.c \
cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \
cmd-respawn-window.c \
window-scroll.c window-more.c window-copy.c options.c paste.c \
tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.68 2008-06-25 20:43:13 nicm Exp $
# $Id: Makefile,v 1.69 2008-06-29 07:04:29 nicm Exp $
.SUFFIXES: .c .o .y .h
.PHONY: clean update-index.html upload-index.html
@ -33,6 +33,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
cmd-show-window-options.c cmd-command-prompt.c cmd-set-buffer.c \
cmd-show-buffer.c cmd-list-buffers.c cmd-delete-buffer.c \
cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \
cmd-respawn-window.c \
window-scroll.c window-more.c window-copy.c options.c paste.c \
tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c

4
TODO
View File

@ -49,12 +49,13 @@
-- For 0.4 --------------------------------------------------------------------
- document zombie windows
- document buffer stuff
- document next/prev word
- commands: save-buffer -b number filename
load-buffer -b number filename
copy-buffer -s src-session -t dst-session -a src-index -b dst-index
(from other session)
(from other session)
-- For 0.5 --------------------------------------------------------------------
@ -73,3 +74,4 @@
have a "edit-mode" option select which keymap
- zombie windows: don't disappear when the command dies. new command
respawn-window [command] to restart; ommitting commands uses previous
- many more info displays for various things

View File

@ -1,4 +1,4 @@
/* $Id: cmd-generic.c,v 1.11 2008-06-20 08:36:20 nicm Exp $ */
/* $Id: cmd-generic.c,v 1.12 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -73,6 +73,13 @@ cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
if (argc != 1)
goto usage;
data->arg = xstrdup(argv[0]);
} else if (self->entry->flags & CMD_ZEROONEARG) {
if (argc == 0)
data->arg = NULL;
else if (argc == 1)
data->arg = xstrdup(argv[0]);
else
goto usage;
} else {
if (argc != 0)
goto usage;
@ -192,6 +199,13 @@ cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
if (argc != 1)
goto usage;
data->arg = xstrdup(argv[0]);
} else if (self->entry->flags & CMD_ZEROONEARG) {
if (argc == 0)
data->arg = NULL;
else if (argc == 1)
data->arg = xstrdup(argv[0]);
else
goto usage;
} else {
if (argc != 0)
goto usage;
@ -325,6 +339,13 @@ cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
if (argc != 1)
goto usage;
data->arg = xstrdup(argv[0]);
} else if (self->entry->flags & CMD_ZEROONEARG) {
if (argc == 0)
data->arg = NULL;
else if (argc == 1)
data->arg = xstrdup(argv[0]);
else
goto usage;
} else {
if (argc != 0)
goto usage;

View File

@ -1,4 +1,4 @@
/* $Id: cmd-list-windows.c,v 1.20 2008-06-05 21:25:00 nicm Exp $ */
/* $Id: cmd-list-windows.c,v 1.21 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -50,6 +50,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
struct window *w;
u_int i;
unsigned long long size;
const char *name;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return;
@ -65,9 +66,13 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
size += w->base.hsize * (sizeof *w->base.grid_colr);
size += w->base.hsize * (sizeof *w->base.grid_size);
if (w->fd != -1)
name = ttyname(w->fd);
else
name = "";
ctx->print(ctx,
"%d: %s \"%s\" (%s) [%ux%u] [history %u/%u, %llu bytes]",
wl->idx, w->name, w->base.title, ttyname(w->fd),
wl->idx, w->name, w->base.title, name,
screen_size_x(&w->base), screen_size_y(&w->base),
w->base.hsize, w->base.hlimit, size);
}

74
cmd-respawn-window.c Normal file
View File

@ -0,0 +1,74 @@
/* $Id: cmd-respawn-window.c,v 1.1 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2008 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 "tmux.h"
/*
* Respawn a window (restart the command). Kill existing if -k given.
*/
void cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw",
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
CMD_ZEROONEARG|CMD_KFLAG,
cmd_target_init,
cmd_target_parse,
cmd_respawn_window_exec,
cmd_target_send,
cmd_target_recv,
cmd_target_free,
cmd_target_print
};
void
cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct session *s;
const char *env[] = { NULL, "TERM=screen", NULL };
char *cmd;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return;
if (wl->window->fd != -1 && !(data->flags & CMD_KFLAG)) {
ctx->error(ctx, "window still active: %s:%d", s->name, wl->idx);
return;
}
cmd = data->arg;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
if (window_spawn(wl->window, cmd, env) != 0) {
ctx->error(ctx, "respawn failed: %s:%d", s->name, wl->idx);
return;
}
screen_reset(&wl->window->base);
recalculate_sizes();
server_redraw_window(wl->window);
if (ctx->cmdclient != NULL)
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
}

View File

@ -1,4 +1,4 @@
/* $Id: cmd-set-option.c,v 1.36 2008-06-23 22:12:29 nicm Exp $ */
/* $Id: cmd-set-option.c,v 1.37 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -64,6 +64,7 @@ const struct set_option_entry set_option_table[NSETOPTION] = {
{ "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "history-limit", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "prefix", SET_OPTION_KEY, 0, 0, NULL },
{ "remain-by-default", SET_OPTION_FLAG, 0, 0, NULL },
{ "set-titles", SET_OPTION_FLAG, 0, 0, NULL },
{ "status", SET_OPTION_FLAG, 0, 0, NULL },
{ "status-bg", SET_OPTION_COLOUR, 0, 0, NULL },

View File

@ -1,4 +1,4 @@
/* $Id: cmd-set-window-option.c,v 1.10 2008-06-18 22:21:51 nicm Exp $ */
/* $Id: cmd-set-window-option.c,v 1.11 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -218,6 +218,20 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx)
s->name, wl->idx, number);
recalculate_sizes();
} else if (strcmp(data->option, "remain-on-exit") == 0) {
if (flag == -1) {
ctx->error(ctx, "bad value: %s", data->value);
return;
}
if (flag == -2)
wl->window->flags ^= WINDOW_ZOMBIFY;
else {
if (flag)
wl->window->flags |= WINDOW_ZOMBIFY;
else
wl->window->flags &= ~WINDOW_ZOMBIFY;
}
} else {
ctx->error(ctx, "unknown option: %s", data->option);
return;

View File

@ -1,4 +1,4 @@
/* $Id: cmd-show-window-options.c,v 1.1 2008-06-16 06:10:02 nicm Exp $ */
/* $Id: cmd-show-window-options.c,v 1.2 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -60,6 +60,8 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->print(ctx, "force-height %u", wl->window->limity);
if (wl->window->flags & WINDOW_MONITOR)
ctx->print(ctx, "monitor-activity");
if (wl->window->flags & WINDOW_ZOMBIFY)
ctx->print(ctx, "remain-on-exit");
if (ctx->cmdclient != NULL)
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);

3
cmd.c
View File

@ -1,4 +1,4 @@
/* $Id: cmd.c,v 1.59 2008-06-27 17:10:01 nicm Exp $ */
/* $Id: cmd.c,v 1.60 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -54,6 +54,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_refresh_client_entry,
&cmd_rename_session_entry,
&cmd_rename_window_entry,
&cmd_respawn_window_entry,
&cmd_scroll_mode_entry,
&cmd_select_prompt_entry,
&cmd_select_window_entry,

View File

@ -1,4 +1,4 @@
/* $Id: screen.c,v 1.62 2008-06-18 22:21:51 nicm Exp $ */
/* $Id: screen.c,v 1.63 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -156,6 +156,27 @@ screen_create(struct screen *s, u_int dx, u_int dy, u_int hlimit)
screen_clear_selection(s);
}
/* Reinitialise screen. */
void
screen_reset(struct screen *s)
{
s->cx = 0;
s->cy = 0;
s->rupper = 0;
s->rlower = s->dy - 1;
s->attr = SCREEN_DEFATTR;
s->colr = SCREEN_DEFCOLR;
s->mode = MODE_CURSOR|MODE_KCURSOR|MODE_KKEYPAD;
screen_display_fill_area(s, 0, 0,
screen_size_x(s), screen_size_y(s), ' ', 0, 0x88);
screen_clear_selection(s);
}
/* Resize screen. */
void
screen_resize(struct screen *s, u_int sx, u_int sy)

View File

@ -1,4 +1,4 @@
/* $Id: server.c,v 1.76 2008-06-23 07:41:21 nicm Exp $ */
/* $Id: server.c,v 1.77 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -263,7 +263,7 @@ server_fill_windows(struct pollfd **pfd)
u_int i;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
if ((w = ARRAY_ITEM(&windows, i)) == NULL)
if ((w = ARRAY_ITEM(&windows, i)) == NULL || w->fd == -1)
(*pfd)->fd = -1;
else {
(*pfd)->fd = w->fd;
@ -284,7 +284,7 @@ server_handle_windows(struct pollfd **pfd)
u_int i;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
if ((w = ARRAY_ITEM(&windows, i)) != NULL) {
if ((w = ARRAY_ITEM(&windows, i)) != NULL && w->fd != -1) {
log_debug("testing window %d (%d)", (*pfd)->fd, w->fd);
if (buffer_poll(*pfd, w->in, w->out) != 0)
server_lost_window(w);
@ -629,6 +629,11 @@ server_lost_window(struct window *w)
log_debug("lost window %d", w->fd);
if (w->flags & WINDOW_ZOMBIFY) {
w->fd = -1;
return;
}
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)

View File

@ -1,4 +1,4 @@
/* $Id: session.c,v 1.39 2008-06-20 08:36:20 nicm Exp $ */
/* $Id: session.c,v 1.40 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -203,6 +203,10 @@ session_new(struct session *s, const char *name, const char *cmd, int idx)
hlimit = options_get_number(&s->options, "history-limit");
if ((w = window_create(name, cmd, env, s->sx, s->sy, hlimit)) == NULL)
return (NULL);
if (options_get_number(&s->options, "remain-by-default"))
w->flags |= WINDOW_ZOMBIFY;
return (session_attach(s, w, idx));
}

3
tmux.c
View File

@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.69 2008-06-23 22:12:29 nicm Exp $ */
/* $Id: tmux.c,v 1.70 2008-06-29 07:04:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -222,6 +222,7 @@ main(int argc, char **argv)
options_set_number(&global_options, "status-interval", 15);
options_set_number(&global_options, "set-titles", 1);
options_set_number(&global_options, "buffer-limit", 9);
options_set_number(&global_options, "remain-by-default", 0);
if (cfg_file == NULL) {
home = getenv("HOME");

12
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.170 2008-06-25 20:43:14 nicm Exp $ */
/* $Id: tmux.h,v 1.171 2008-06-29 07:04:31 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -549,6 +549,7 @@ struct window_mode {
/* Window structure. */
struct window {
char *name;
char *cmd;
int fd;
struct buffer *in;
@ -562,6 +563,7 @@ struct window {
#define WINDOW_ACTIVITY 0x4
#define WINDOW_MONITOR 0x8
#define WINDOW_AGGRESSIVE 0x10
#define WINDOW_ZOMBIFY 0x20
u_int limitx;
u_int limity;
@ -764,6 +766,7 @@ struct cmd_entry {
#define CMD_KFLAG 0x4
#define CMD_DFLAG 0x8
#define CMD_ONEARG 0x10
#define CMD_ZEROONEARG 0x20
int flags;
void (*init)(struct cmd *, int);
@ -821,7 +824,7 @@ struct set_option_entry {
const char **choices;
};
extern const struct set_option_entry set_option_table[];
#define NSETOPTION 13
#define NSETOPTION 14
#ifdef NO_STRTONUM
/* strtonum.c */
@ -967,6 +970,7 @@ extern const struct cmd_entry cmd_previous_window_entry;
extern const struct cmd_entry cmd_refresh_client_entry;
extern const struct cmd_entry cmd_rename_session_entry;
extern const struct cmd_entry cmd_rename_window_entry;
extern const struct cmd_entry cmd_respawn_window_entry;
extern const struct cmd_entry cmd_scroll_mode_entry;
extern const struct cmd_entry cmd_select_window_entry;
extern const struct cmd_entry cmd_send_keys_entry;
@ -1171,6 +1175,7 @@ void screen_redraw_columns(struct screen_redraw_ctx *, u_int, u_int);
const char *screen_colourstring(u_char);
u_char screen_stringcolour(const char *);
void screen_create(struct screen *, u_int, u_int, u_int);
void screen_reset(struct screen *);
void screen_destroy(struct screen *);
void screen_resize(struct screen *, u_int, u_int);
void screen_expand_line(struct screen *, u_int, u_int);
@ -1201,7 +1206,8 @@ 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, u_int);
const char *, const char **, u_int, u_int, u_int);
int window_spawn(struct window *, const char *, const char **);
void window_destroy(struct window *);
int window_resize(struct window *, u_int, u_int);
int window_set_mode(struct window *, const struct window_mode *);

View File

@ -1,4 +1,4 @@
/* $Id: window.c,v 1.45 2008-06-20 17:31:48 nicm Exp $ */
/* $Id: window.c,v 1.46 2008-06-29 07:04:31 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -166,50 +166,25 @@ winlink_previous(unused struct winlinks *wwl, struct winlink *wl)
struct window *
window_create(const char *name,
const char *cmd, const char **env, u_int sx, u_int sy, u_int hlimit)
const char *cmd, const char **envp, u_int sx, u_int sy, u_int hlimit)
{
struct window *w;
struct winsize ws;
int fd, mode;
char *ptr, *copy;
const char **entry;
memset(&ws, 0, sizeof ws);
ws.ws_col = sx;
ws.ws_row = sy;
switch (forkpty(&fd, NULL, NULL, &ws)) {
case -1:
return (NULL);
case 0:
for (entry = env; *entry != NULL; entry++) {
if (putenv(*entry) != 0)
fatal("putenv failed");
}
sigreset();
log_debug("started child: cmd=%s; pid=%d", cmd, (int) getpid());
log_close();
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
fatal("execl failed");
}
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
w = xmalloc(sizeof *w);
w->fd = fd;
w->cmd = NULL;
w->fd = -1;
w->in = buffer_create(BUFSIZ);
w->out = buffer_create(BUFSIZ);
w->mode = NULL;
w->flags = 0;
w->limitx = w->limity = UINT_MAX;
screen_create(&w->base, sx, sy, hlimit);
w->screen = &w->base;
input_init(w);
if (name == NULL) {
@ -238,9 +213,58 @@ window_create(const char *name,
ARRAY_ADD(&windows, w);
w->references = 0;
if (window_spawn(w, cmd, envp) != 0) {
window_destroy(w);
return (NULL);
}
return (w);
}
int
window_spawn(struct window *w, const char *cmd, const char **envp)
{
struct winsize ws;
int mode;
const char **envq;
if (w->fd != -1)
close(w->fd);
if (cmd != NULL) {
if (w->cmd != NULL)
xfree(w->cmd);
w->cmd = xstrdup(cmd);
}
memset(&ws, 0, sizeof ws);
ws.ws_col = screen_size_x(&w->base);
ws.ws_row = screen_size_y(&w->base);
switch (forkpty(&w->fd, NULL, NULL, &ws)) {
case -1:
return (1);
case 0:
for (envq = envp; *envq != NULL; envq++) {
if (putenv(*envq) != 0)
fatal("putenv failed");
}
sigreset();
log_debug("new child: cmd=%s; pid=%d", w->cmd, (int) getpid());
log_close();
execl(_PATH_BSHELL, "sh", "-c", w->cmd, (char *) NULL);
fatal("execl failed");
}
if ((mode = fcntl(w->fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(w->fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if (fcntl(w->fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
return (0);
}
void
window_destroy(struct window *w)
{
@ -252,7 +276,8 @@ window_destroy(struct window *w)
}
ARRAY_REMOVE(&windows, i);
close(w->fd);
if (w->fd != -1)
close(w->fd);
input_free(w);
@ -282,7 +307,7 @@ window_resize(struct window *w, u_int sx, u_int sy)
if (w->mode != NULL)
w->mode->resize(w, sx, sy);
if (ioctl(w->fd, TIOCSWINSZ, &ws) == -1)
if (w->fd != -1 && ioctl(w->fd, TIOCSWINSZ, &ws) == -1)
fatal("ioctl failed");
return (0);
}