diff --git a/CHANGES b/CHANGES index 9a1e7c8d..4ad3e010 100644 --- a/CHANGES +++ b/CHANGES @@ -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 $ diff --git a/GNUmakefile b/GNUmakefile index 9667c202..24f6f28c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -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 diff --git a/Makefile b/Makefile index 13c4bc3e..c8abee11 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/TODO b/TODO index 967b5cb9..e4e8c846 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/cmd-generic.c b/cmd-generic.c index 3ede0cf6..49bb14b2 100644 --- a/cmd-generic.c +++ b/cmd-generic.c @@ -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 @@ -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; diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 19a2fc5d..ec839e14 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -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 @@ -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); } diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c new file mode 100644 index 00000000..0b3cb0de --- /dev/null +++ b/cmd-respawn-window.c @@ -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 + * + * 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 + +#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); +} diff --git a/cmd-set-option.c b/cmd-set-option.c index d3a2c8a2..a980e8c9 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -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 @@ -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 }, diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index ec3f0582..d7742b91 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -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 @@ -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; diff --git a/cmd-show-window-options.c b/cmd-show-window-options.c index 1f4db81a..abd4078b 100644 --- a/cmd-show-window-options.c +++ b/cmd-show-window-options.c @@ -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 @@ -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); diff --git a/cmd.c b/cmd.c index 0fa4808c..afac3092 100644 --- a/cmd.c +++ b/cmd.c @@ -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 @@ -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, diff --git a/screen.c b/screen.c index 825803a7..ca253906 100644 --- a/screen.c +++ b/screen.c @@ -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 @@ -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) diff --git a/server.c b/server.c index 8e596299..ca14803c 100644 --- a/server.c +++ b/server.c @@ -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 @@ -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) diff --git a/session.c b/session.c index 67609172..5d3f79ea 100644 --- a/session.c +++ b/session.c @@ -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 @@ -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)); } diff --git a/tmux.c b/tmux.c index 392a1279..6525a755 100644 --- a/tmux.c +++ b/tmux.c @@ -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 @@ -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"); diff --git a/tmux.h b/tmux.h index 15d5cb8e..ee3cf7bf 100644 --- a/tmux.h +++ b/tmux.h @@ -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 @@ -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 *); diff --git a/window.c b/window.c index 2e5d7134..ac404d4e 100644 --- a/window.c +++ b/window.c @@ -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 @@ -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); }