diff -Nru tmux-1.0/array.h tmux-1.1/array.h --- tmux-1.0/array.h 2009-09-02 22:35:35.000000000 +0100 +++ tmux-1.1/array.h 2009-11-02 21:34:32.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: array.h,v 1.7 2008/09/29 16:58:02 nicm Exp $ */ +/* $Id: array.h,v 1.9 2009/11/02 21:34:32 tcunha Exp $ */ /* * Copyright (c) 2006 Nicholas Marriott @@ -85,7 +85,7 @@ ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \ } \ (a)->num--; \ - if ((a)->num == 0) \ + if ((a)->num == 0) \ ARRAY_FREE(a); \ } while (0) @@ -102,7 +102,7 @@ #define ARRAY_CONCAT(a, b) do { \ ARRAY_ENSURE(a, (b)->num); \ - memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)) \ + memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)); \ (a)->num += (b)->num; \ } while (0) diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/buffer-poll.c /tmp/wmlmc6MQoR/tmux-1.1/buffer-poll.c --- tmux-1.0/buffer-poll.c 2009-09-02 22:35:35.000000000 +0100 +++ tmux-1.1/buffer-poll.c 2009-10-23 18:49:47.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: buffer-poll.c,v 1.16 2009/08/19 09:28:10 nicm Exp $ */ +/* $Id: buffer-poll.c,v 1.18 2009/10/23 17:49:47 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -25,15 +25,15 @@ /* Fill buffers from socket based on poll results. */ int -buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) +buffer_poll(int fd, int events, struct buffer *in, struct buffer *out) { ssize_t n; - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) + if (events & (POLLERR|POLLNVAL)) return (-1); - if (pfd->revents & POLLIN) { + if (in != NULL && events & POLLIN) { buffer_ensure(in, BUFSIZ); - n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in)); + n = read(fd, BUFFER_IN(in), BUFFER_FREE(in)); if (n == 0) return (-1); if (n == -1) { @@ -41,9 +41,10 @@ return (-1); } else buffer_add(in, n); - } - if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { - n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out)); + } else if (events & POLLHUP) + return (-1); + if (out != NULL && BUFFER_USED(out) > 0 && events & POLLOUT) { + n = write(fd, BUFFER_OUT(out), BUFFER_USED(out)); if (n == -1) { if (errno != EINTR && errno != EAGAIN) return (-1); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cfg.c /tmp/wmlmc6MQoR/tmux-1.1/cfg.c --- tmux-1.0/cfg.c 2009-09-02 22:35:35.000000000 +0100 +++ tmux-1.1/cfg.c 2009-10-28 23:12:38.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cfg.c,v 1.22 2009/08/24 16:27:03 tcunha Exp $ */ +/* $Id: cfg.c,v 1.23 2009/10/28 23:12:38 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -53,9 +53,9 @@ int load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause) { - FILE *f; + FILE *f; u_int n; - char *buf, *line, *ptr; + char *buf, *line, *ptr; size_t len; struct cmd_list *cmdlist; struct cmd_ctx ctx; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/CHANGES /tmp/wmlmc6MQoR/tmux-1.1/CHANGES --- tmux-1.0/CHANGES 2009-09-20 19:42:41.000000000 +0100 +++ tmux-1.1/CHANGES 2009-11-05 12:35:47.000000000 +0000 @@ -1,3 +1,55 @@ +CHANGES FROM 1.0 TO 1.1, 05 November 2009 + +* New run-shell (alias run) command to run an external command without a + window, capture it's stdout, and send it to output mode. +* Ability to define multiple prefix keys. +* Internal locking mechanism removed. Instead, detach each client and run the + external command specified in the new session option lock-command (by default + lock -np), thus allowing the system password to be used. +* set-password command, and -U command line flag removed per the above change. +* Add support for -c command line flag to execute a shell command. +* New lock-client (alias lockc), and lock-session (alias locks) commands to + lock a particular client, or all clients attached to a session. +* Support C-n/C-p/C-v/M-v with emacs keys in choice mode. +* Use : for goto line rather than g in vi mode. +* Try to guess which client to use when no target client was specified. Finds + the current session, and if only one client is present, use it. Otherwise, + return the most recently used client. +* Make C-Down/C-Up in copy mode scroll the screen down/up one line without + moving the cursor. +* Scroll mode superseded by copy mode. +* New synchronize-panes window option to send all input to all other panes in + the same window. +* New lock-server session option to lock, when off (on by default), each + session when it has been idle for the lock-after-time setting. When on, the + entire server locks when all sessions have been idle for their individual + lock-after-time setting. +* Add support for grouped sessions which have independent name, options, + current window, but where the linked windows are synchronized (ie creating, + killing windows are mirrored between the sessions). A grouped session may be + created by passing -t to new-session. +* New mouse-select-pane session option to select the current pane with the + mouse. +* Queue, and run commands in the background for if-shell, status-left, + status-right, and #() by starting each once every status-interval. Adds the + capability to call some programs which would previously cause the server to + hang (eg sleep/tmux). It also avoids running commands excessively (ie if used + multiple times, it will be run only once). +* When a window is zombified and automatic-rename is on, append [dead] to the + name. +* Split list-panes (alias lsp) off from list-windows. +* New pipe-pane (alias pipep) to redirect a pane output to an external command. +* Support for automatic-renames for Solaris. +* Permit attributes to be turned off in #[] by prefixing with no (eg nobright). +* Add H/M/L in vi mode, and M-R/M-r in emacs to move the cursor to the top, + middle, and bottom of the screen. +* -a option added to kill-pane to kill all except current pane. +* The -d command line flag is now gone (can be replaced by terminal-overrides). + Just use op/AX to detect default colours. +* input/tty/utf8 improvements. +* xterm-keys rewrite. +* Additional code reduction, and bug fixes. + CHANGES FROM 0.9 TO 1.0, 20 Sept 2009 * Option to alter the format of the window title set by tmux. @@ -1358,7 +1410,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.299 2009/07/01 22:15:16 nicm Exp $ +$Id: CHANGES,v 1.301 2009/11/05 12:35:47 tcunha Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/client.c /tmp/wmlmc6MQoR/tmux-1.1/client.c --- tmux-1.0/client.c 2009-09-04 15:47:31.000000000 +0100 +++ tmux-1.1/client.c 2009-11-02 21:41:16.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: client.c,v 1.70 2009/09/03 21:06:30 tcunha Exp $ */ +/* $Id: client.c,v 1.84 2009/11/02 21:41:16 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -33,21 +33,23 @@ #include "tmux.h" -void client_send_environ(struct client_ctx *); -void client_handle_winch(struct client_ctx *); +struct imsgbuf client_ibuf; +const char *client_exitmsg; -int -client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) +void client_send_identify(int); +void client_send_environ(void); +void client_write_server(enum msgtype, void *, size_t); +int client_dispatch(void); +void client_suspend(void); + +struct imsgbuf * +client_init(char *path, int cmdflags, int flags) { - struct sockaddr_un sa; - struct stat sb; - struct msg_identify_data data; - struct winsize ws; - size_t size; - int fd, fd2, mode; - char *name, *term; + struct sockaddr_un sa; + size_t size; + int fd, mode; #ifdef HAVE_SETPROCTITLE - char rpathbuf[MAXPATHLEN]; + char rpathbuf[MAXPATHLEN]; #endif #ifdef HAVE_SETPROCTITLE @@ -56,19 +58,6 @@ setproctitle("client (%s)", rpathbuf); #endif - if (lstat(path, &sb) != 0) { - if (cmdflags & CMD_STARTSERVER && errno == ENOENT) { - if ((fd = server_start(path)) == -1) - goto start_failed; - goto server_started; - } - goto not_found; - } - if (!S_ISSOCK(sb.st_mode)) { - errno = ENOTSOCK; - goto not_found; - } - memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); @@ -78,12 +67,17 @@ } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - fatal("socket"); + fatal("socket failed"); if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { - if (errno == ECONNREFUSED) { - if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER)) + if (!(cmdflags & CMD_STARTSERVER)) + goto not_found; + switch (errno) { + case ECONNREFUSED: + if (unlink(path) != 0) goto not_found; + /* FALLTHROUGH */ + case ENOENT: if ((fd = server_start(path)) == -1) goto start_failed; goto server_started; @@ -96,64 +90,73 @@ fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); - imsg_init(&cctx->ibuf, fd); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + imsg_init(&client_ibuf, fd); if (cmdflags & CMD_SENDENVIRON) - client_send_environ(cctx); - if (isatty(STDIN_FILENO)) { - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) - fatal("ioctl(TIOCGWINSZ)"); - data.flags = flags; - data.sx = ws.ws_col; - data.sy = ws.ws_row; - - if (getcwd(data.cwd, sizeof data.cwd) == NULL) - *data.cwd = '\0'; - - *data.term = '\0'; - if ((term = getenv("TERM")) != NULL) { - if (strlcpy(data.term, - term, sizeof data.term) >= sizeof data.term) - *data.term = '\0'; - } - - *data.tty = '\0'; - if ((name = ttyname(STDIN_FILENO)) == NULL) - fatal("ttyname failed"); - if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty) - fatalx("ttyname failed"); - - fd2 = dup(STDIN_FILENO); - imsg_compose(&cctx->ibuf, MSG_IDENTIFY, - PROTOCOL_VERSION, -1, fd2, &data, sizeof data); - } + client_send_environ(); + if (isatty(STDIN_FILENO)) + client_send_identify(flags); - return (0); + return (&client_ibuf); start_failed: log_warnx("server failed to start"); - return (1); + return (NULL); not_found: log_warn("server not found"); - return (1); + return (NULL); } void -client_send_environ(struct client_ctx *cctx) +client_send_identify(int flags) +{ + struct msg_identify_data data; + struct winsize ws; + char *term; + int fd; + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) + fatal("ioctl(TIOCGWINSZ)"); + data.flags = flags; + + if (getcwd(data.cwd, sizeof data.cwd) == NULL) + *data.cwd = '\0'; + + term = getenv("TERM"); + if (term == NULL || + strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) + *data.term = '\0'; + + if ((fd = dup(STDIN_FILENO)) == -1) + fatal("dup failed"); + imsg_compose(&client_ibuf, + MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); +} + +void +client_send_environ(void) { - char **var; struct msg_environ_data data; + char **var; for (var = environ; *var != NULL; var++) { if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) continue; - client_write_server(cctx, MSG_ENVIRON, &data, sizeof data); + client_write_server(MSG_ENVIRON, &data, sizeof data); } } -int -client_main(struct client_ctx *cctx) +void +client_write_server(enum msgtype type, void *buf, size_t len) +{ + imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); +} + +__dead void +client_main(void) { struct pollfd pfd; int n, nfds; @@ -168,27 +171,34 @@ * MSG_READY switched to here. Process anything outstanding now so poll * doesn't hang waiting for messages that have already arrived. */ - if (client_msg_dispatch(cctx) != 0) + if (client_dispatch() != 0) goto out; for (;;) { - if (sigterm) - client_write_server(cctx, MSG_EXITING, NULL, 0); + if (sigterm) { + client_exitmsg = "terminated"; + client_write_server(MSG_EXITING, NULL, 0); + } if (sigchld) { - waitpid(WAIT_ANY, NULL, WNOHANG); sigchld = 0; + waitpid(WAIT_ANY, NULL, WNOHANG); + continue; + } + if (sigwinch) { + sigwinch = 0; + client_write_server(MSG_RESIZE, NULL, 0); + continue; } - if (sigwinch) - client_handle_winch(cctx); if (sigcont) { - siginit(); - client_write_server(cctx, MSG_WAKEUP, NULL, 0); sigcont = 0; + siginit(); + client_write_server(MSG_WAKEUP, NULL, 0); + continue; } - pfd.fd = cctx->ibuf.fd; + pfd.fd = client_ibuf.fd; pfd.events = POLLIN; - if (cctx->ibuf.w.queued > 0) + if (client_ibuf.w.queued > 0) pfd.events |= POLLOUT; if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { @@ -203,75 +213,41 @@ fatalx("socket error"); if (pfd.revents & POLLIN) { - if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { - cctx->exittype = CCTX_DIED; + if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) { + client_exitmsg = "lost server"; break; } - if (client_msg_dispatch(cctx) != 0) + if (client_dispatch() != 0) break; } if (pfd.revents & POLLOUT) { - if (msgbuf_write(&cctx->ibuf.w) < 0) { - cctx->exittype = CCTX_DIED; + if (msgbuf_write(&client_ibuf.w) < 0) { + client_exitmsg = "lost server"; break; } } } out: - if (sigterm) { - printf("[terminated]\n"); - return (1); - } - switch (cctx->exittype) { - case CCTX_DIED: - printf("[lost server]\n"); - return (0); - case CCTX_SHUTDOWN: - printf("[server exited]\n"); - return (0); - case CCTX_EXIT: - if (cctx->errstr != NULL) { - printf("[error: %s]\n", cctx->errstr); - return (1); - } - printf("[exited]\n"); - return (0); - case CCTX_DETACH: - printf("[detached]\n"); - return (0); - default: - printf("[unknown error]\n"); - return (1); + /* Print the exit message, if any, and exit. */ + if (client_exitmsg != NULL) { + if (!login_shell) + printf("[%s]\n", client_exitmsg); + exit(1); } -} - -void -client_handle_winch(struct client_ctx *cctx) -{ - struct msg_resize_data data; - struct winsize ws; - - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) - fatal("ioctl failed"); - - data.sx = ws.ws_col; - data.sy = ws.ws_row; - client_write_server(cctx, MSG_RESIZE, &data, sizeof data); - - sigwinch = 0; + exit(0); } int -client_msg_dispatch(struct client_ctx *cctx) +client_dispatch(void) { struct imsg imsg; - struct msg_print_data printdata; + struct msg_lock_data lockdata; ssize_t n, datalen; for (;;) { - if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); @@ -282,25 +258,15 @@ if (datalen != 0) fatalx("bad MSG_DETACH size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_DETACH; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "detached"; break; - case MSG_ERROR: - if (datalen != sizeof printdata) - fatalx("bad MSG_ERROR size"); - memcpy(&printdata, imsg.data, sizeof printdata); - - printdata.msg[(sizeof printdata.msg) - 1] = '\0'; - /* Error string used after exit message from server. */ - cctx->errstr = xstrdup(printdata.msg); - imsg_free(&imsg); - return (-1); case MSG_EXIT: if (datalen != 0) fatalx("bad MSG_EXIT size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_EXIT; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "exited"; break; case MSG_EXITED: if (datalen != 0) @@ -312,8 +278,8 @@ if (datalen != 0) fatalx("bad MSG_SHUTDOWN size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_SHUTDOWN; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "server exited"; break; case MSG_SUSPEND: if (datalen != 0) @@ -321,6 +287,15 @@ client_suspend(); break; + case MSG_LOCK: + if (datalen != sizeof lockdata) + fatalx("bad MSG_LOCK size"); + memcpy(&lockdata, imsg.data, sizeof lockdata); + + lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; + system(lockdata.cmd); + client_write_server(MSG_UNLOCK, NULL, 0); + break; default: fatalx("unexpected message"); } @@ -328,3 +303,23 @@ imsg_free(&imsg); } } + +void +client_suspend(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + act.sa_handler = SIG_DFL; + if (sigaction(SIGTSTP, &act, NULL) != 0) + fatal("sigaction failed"); + + act.sa_handler = sighandler; + if (sigaction(SIGCONT, &act, NULL) != 0) + fatal("sigaction failed"); + + kill(getpid(), SIGTSTP); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/client-fn.c /tmp/wmlmc6MQoR/tmux-1.1/client-fn.c --- tmux-1.0/client-fn.c 2009-09-02 22:35:35.000000000 +0100 +++ tmux-1.1/client-fn.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,90 +0,0 @@ -/* $Id: client-fn.c,v 1.10 2009/08/14 21:04:04 tcunha Exp $ */ - -/* - * Copyright (c) 2007 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 -#include -#include - -#include "tmux.h" - -void -client_fill_session(struct msg_command_data *data) -{ - char *env, *ptr1, *ptr2, buf[256]; - size_t len; - const char *errstr; - long long ll; - - data->pid = -1; - if ((env = getenv("TMUX")) == NULL) - return; - - if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) - return; - for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) - ; - if (*ptr1 != ',') - return; - ptr1++; - ptr2++; - - len = ptr2 - ptr1 - 1; - if (len > (sizeof buf) - 1) - return; - memcpy(buf, ptr1, len); - buf[len] = '\0'; - - ll = strtonum(buf, 0, LONG_MAX, &errstr); - if (errstr != NULL) - return; - data->pid = ll; - - ll = strtonum(ptr2, 0, UINT_MAX, &errstr); - if (errstr != NULL) - return; - data->idx = ll; -} - -void -client_write_server( - struct client_ctx *cctx, enum msgtype type, void *buf, size_t len) -{ - imsg_compose(&cctx->ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); -} - -void -client_suspend(void) -{ - struct sigaction act; - - memset(&act, 0, sizeof act); - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - act.sa_handler = SIG_DFL; - if (sigaction(SIGTSTP, &act, NULL) != 0) - fatal("sigaction failed"); - - act.sa_handler = sighandler; - if (sigaction(SIGCONT, &act, NULL) != 0) - fatal("sigaction failed"); - - kill(getpid(), SIGTSTP); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-break-pane.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-break-pane.c --- tmux-1.0/cmd-break-pane.c 2009-09-15 19:54:56.000000000 +0100 +++ tmux-1.1/cmd-break-pane.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-break-pane.c,v 1.8 2009/08/16 19:16:27 tcunha Exp $ */ +/* $Id: cmd-break-pane.c,v 1.9 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -78,6 +78,7 @@ session_select(s, wl->idx); server_redraw_session(s); + server_status_session_group(s); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd.c /tmp/wmlmc6MQoR/tmux-1.1/cmd.c --- tmux-1.0/cmd.c 2009-09-02 20:52:13.000000000 +0100 +++ tmux-1.1/cmd.c 2009-11-04 22:46:25.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.115 2009/08/31 22:30:15 tcunha Exp $ */ +/* $Id: cmd.c,v 1.130 2009/11/04 22:46:25 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -57,16 +57,20 @@ &cmd_list_clients_entry, &cmd_list_commands_entry, &cmd_list_keys_entry, + &cmd_list_panes_entry, &cmd_list_sessions_entry, &cmd_list_windows_entry, &cmd_load_buffer_entry, + &cmd_lock_client_entry, &cmd_lock_server_entry, + &cmd_lock_session_entry, &cmd_move_window_entry, &cmd_new_session_entry, &cmd_new_window_entry, &cmd_next_layout_entry, &cmd_next_window_entry, &cmd_paste_buffer_entry, + &cmd_pipe_pane_entry, &cmd_previous_layout_entry, &cmd_previous_window_entry, &cmd_refresh_client_entry, @@ -75,8 +79,8 @@ &cmd_resize_pane_entry, &cmd_respawn_window_entry, &cmd_rotate_window_entry, + &cmd_run_shell_entry, &cmd_save_buffer_entry, - &cmd_scroll_mode_entry, &cmd_select_layout_entry, &cmd_select_pane_entry, &cmd_select_prompt_entry, @@ -87,7 +91,6 @@ &cmd_set_buffer_entry, &cmd_set_environment_entry, &cmd_set_option_entry, - &cmd_set_password_entry, &cmd_set_window_option_entry, &cmd_show_buffer_entry, &cmd_show_environment_entry, @@ -106,7 +109,8 @@ NULL }; -struct session *cmd_newest_session(struct sessions *); +struct session *cmd_choose_session(struct sessions *); +struct client *cmd_choose_client(struct clients *); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); @@ -174,7 +178,7 @@ cmd_parse(int argc, char **argv, char **cause) { const struct cmd_entry **entryp, *entry; - struct cmd *cmd; + struct cmd *cmd; char s[BUFSIZ]; int opt, ambiguous = 0; @@ -258,10 +262,6 @@ int cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) { - if (server_locked) { - ctx->error(ctx, "server is locked"); - return (-1); - } return (cmd->entry->exec(cmd, ctx)); } @@ -284,9 +284,10 @@ /* * Figure out the current session. Use: 1) the current session, if the command - * context has one; 2) the session containing the pty of the calling client, if - * any 3) the session specified in the TMUX variable from the environment (as - * passed from the client); 3) the newest session. + * context has one; 2) the most recently used session containing the pty of the + * calling client, if any; 3) the session specified in the TMUX variable from + * the environment (as passed from the client); 4) the most recently used + * session from all sessions. */ struct session * cmd_current_session(struct cmd_ctx *ctx) @@ -328,7 +329,7 @@ ARRAY_ADD(&ss, s); } - s = cmd_newest_session(&ss); + s = cmd_choose_session(&ss); ARRAY_FREE(&ss); if (s != NULL) return (s); @@ -345,29 +346,92 @@ return (s); } - return (cmd_newest_session(&sessions)); + return (cmd_choose_session(&sessions)); } -/* Find the newest session. */ +/* Find the most recently used session from a list. */ struct session * -cmd_newest_session(struct sessions *ss) +cmd_choose_session(struct sessions *ss) { - struct session *s, *snewest; + struct session *s, *sbest; struct timeval *tv = NULL; u_int i; - snewest = NULL; + sbest = NULL; for (i = 0; i < ARRAY_LENGTH(ss); i++) { if ((s = ARRAY_ITEM(ss, i)) == NULL) continue; - if (tv == NULL || timercmp(&s->tv, tv, >)) { - snewest = s; - tv = &s->tv; + if (tv == NULL || timercmp(&s->activity_time, tv, >)) { + sbest = s; + tv = &s->activity_time; + } + } + + return (sbest); +} + +/* + * Find the current client. First try the current client if set, then pick the + * most recently used of the clients attached to the current session if any, + * then of all clients. + */ +struct client * +cmd_current_client(struct cmd_ctx *ctx) +{ + struct session *s; + struct client *c; + struct clients cc; + u_int i; + + if (ctx->curclient != NULL) + return (ctx->curclient); + + /* + * No current client set. Find the current session and return the + * newest of its clients. + */ + s = cmd_current_session(ctx); + if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { + ARRAY_INIT(&cc); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if ((c = ARRAY_ITEM(&clients, i)) == NULL) + continue; + if (s == c->session) + ARRAY_ADD(&cc, c); + } + + c = cmd_choose_client(&cc); + ARRAY_FREE(&cc); + if (c != NULL) + return (c); + } + + return (cmd_choose_client(&clients)); +} + +/* Choose the most recently used client from a list. */ +struct client * +cmd_choose_client(struct clients *cc) +{ + struct client *c, *cbest; + struct timeval *tv = NULL; + u_int i; + + cbest = NULL; + for (i = 0; i < ARRAY_LENGTH(cc); i++) { + if ((c = ARRAY_ITEM(cc, i)) == NULL) + continue; + if (c->session == NULL) + continue; + + if (tv == NULL || timercmp(&c->activity_time, tv, >)) { + cbest = c; + tv = &c->activity_time; } } - return (snewest); + return (cbest); } /* Find the target client or report an error and return NULL. */ @@ -380,7 +444,7 @@ /* A NULL argument means the current client. */ if (arg == NULL) - return (ctx->curclient); + return (cmd_current_client(ctx)); tmparg = xstrdup(arg); /* Trim a single trailing colon if any. */ @@ -411,7 +475,8 @@ u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) == NULL) + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) continue; path = c->tty.path; @@ -439,19 +504,25 @@ *ambiguous = 0; /* - * Look for matches. Session names must be unique so an exact match - * can't be ambigious and can just be returned. + * Look for matches. First look for exact matches - session names must + * be unique so an exact match can't be ambigious and can just be + * returned. */ - sfound = NULL; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; - - /* Check for an exact match and return it if found. */ if (strcmp(name, s->name) == 0) return (s); - - /* Then check for pattern matches. */ + } + + /* + * Otherwise look for partial matches, returning early if it is found to + * be ambiguous. + */ + sfound = NULL; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) + continue; if (strncmp(name, s->name, strlen(name)) == 0 || fnmatch(name, s->name, 0) == 0) { if (sfound != NULL) { @@ -461,7 +532,6 @@ sfound = s; } } - return (sfound); } @@ -793,7 +863,7 @@ /* Get the current session. */ if ((s = cmd_current_session(ctx)) == NULL) { - ctx->error(ctx, "can't establish current session"); + ctx->error(ctx, "can't establish current session"); return (NULL); } if (sp != NULL) diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-choose-session.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-choose-session.c --- tmux-1.0/cmd-choose-session.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/cmd-choose-session.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-choose-session.c,v 1.13 2009/09/07 23:59:19 tcunha Exp $ */ +/* $Id: cmd-choose-session.c,v 1.14 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -54,7 +54,9 @@ struct cmd_choose_session_data *cdata; struct winlink *wl; struct session *s; + struct session_group *sg; u_int i, idx, cur; + char tmp[64]; if (ctx->curclient == NULL) { ctx->error(ctx, "must be run interactively"); @@ -76,10 +78,18 @@ cur = idx; idx++; + sg = session_group_find(s); + if (sg == NULL) + *tmp = '\0'; + else { + idx = session_group_index(sg); + xsnprintf(tmp, sizeof tmp, " (group %u)", idx); + } + window_choose_add(wl->window->active, i, - "%s: %u windows [%ux%u]%s", s->name, + "%s: %u windows [%ux%u]%s%s", s->name, winlink_count(&s->windows), s->sx, s->sy, - s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); } cdata = xmalloc(sizeof *cdata); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-choose-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-choose-window.c --- tmux-1.0/cmd-choose-window.c 2009-09-15 19:54:56.000000000 +0100 +++ tmux-1.1/cmd-choose-window.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-choose-window.c,v 1.17 2009/09/07 23:59:19 tcunha Exp $ */ +/* $Id: cmd-choose-window.c,v 1.18 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -89,7 +89,7 @@ flag = '+'; else if (wm == s->curw) flag = '*'; - else if (wm == SLIST_FIRST(&s->lastw)) + else if (wm == TAILQ_FIRST(&s->lastw)) flag = '-'; title = w->active->screen->title; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-command-prompt.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-command-prompt.c --- tmux-1.0/cmd-command-prompt.c 2009-08-26 10:09:09.000000000 +0100 +++ tmux-1.1/cmd-command-prompt.c 2009-09-22 15:06:40.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-command-prompt.c,v 1.25 2009/08/25 13:53:39 tcunha Exp $ */ +/* $Id: cmd-command-prompt.c,v 1.26 2009/09/22 14:06:40 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -90,7 +90,7 @@ struct cmd_command_prompt_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "p:t:")) != -1) { diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-copy-buffer.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-copy-buffer.c --- tmux-1.0/cmd-copy-buffer.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/cmd-copy-buffer.c 2009-09-22 15:06:40.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-copy-buffer.c,v 1.4 2009/09/07 23:48:54 tcunha Exp $ */ +/* $Id: cmd-copy-buffer.c,v 1.5 2009/09/22 14:06:40 tcunha Exp $ */ /* * Copyright (c) 2009 Tiago Cunha @@ -70,7 +70,7 @@ const char *errstr; int n, opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) { diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-copy-mode.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-copy-mode.c --- tmux-1.0/cmd-copy-mode.c 2009-08-21 11:56:23.000000000 +0100 +++ tmux-1.1/cmd-copy-mode.c 2009-10-06 15:14:06.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-copy-mode.c,v 1.23 2009/08/20 11:37:46 tcunha Exp $ */ +/* $Id: cmd-copy-mode.c,v 1.24 2009/10/06 14:14:06 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -24,19 +24,35 @@ * Enter copy mode. */ +void cmd_copy_mode_init(struct cmd *, int); int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, "[-u] " CMD_TARGET_PANE_USAGE, 0, CMD_CHFLAG('u'), - cmd_target_init, + cmd_copy_mode_init, cmd_target_parse, cmd_copy_mode_exec, cmd_target_free, NULL }; +void +cmd_copy_mode_init(struct cmd *self, int key) +{ + struct cmd_target_data *data; + + cmd_target_init(self, key); + data = self->data; + + switch (key) { + case KEYC_PPAGE: + data->chflags |= CMD_CHFLAG('u'); + break; + } +} + int cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) { diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-display-message.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-display-message.c --- tmux-1.0/cmd-display-message.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-display-message.c 2009-10-12 00:55:26.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-display-message.c,v 1.2 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-display-message.c,v 1.3 2009/10/11 23:55:26 tcunha Exp $ */ /* * Copyright (c) 2009 Tiago Cunha @@ -55,7 +55,7 @@ else template = data->arg; - msg = status_replace(c->session, template, time(NULL)); + msg = status_replace(c, template, time(NULL)); status_message_set(c, "%s", msg); xfree(msg); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-if-shell.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-if-shell.c --- tmux-1.0/cmd-if-shell.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-if-shell.c 2009-11-02 21:38:26.000000000 +0000 @@ -1,7 +1,8 @@ -/* $Id: cmd-if-shell.c,v 1.4 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-if-shell.c,v 1.7 2009/11/02 21:38:26 tcunha Exp $ */ /* * Copyright (c) 2009 Tiago Cunha + * Copyright (c) 2009 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 @@ -17,9 +18,8 @@ */ #include +#include -#include -#include #include #include "tmux.h" @@ -28,124 +28,90 @@ * Executes a tmux command if a shell command returns true. */ -int cmd_if_shell_parse(struct cmd *, int, char **, char **); int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); -void cmd_if_shell_free(struct cmd *); -void cmd_if_shell_init(struct cmd *, int); -size_t cmd_if_shell_print(struct cmd *, char *, size_t); -struct cmd_if_shell_data { - char *cmd; - char *sh_cmd; -}; +void cmd_if_shell_callback(struct job *); +void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", "shell-command command", - 0, 0, - cmd_if_shell_init, - cmd_if_shell_parse, + CMD_ARG2, 0, + cmd_target_init, + cmd_target_parse, cmd_if_shell_exec, - cmd_if_shell_free, - cmd_if_shell_print + cmd_target_free, + cmd_target_print }; -void -cmd_if_shell_init(struct cmd *self, unused int arg) -{ - struct cmd_if_shell_data *data; - - self->data = data = xmalloc(sizeof *data); - data->cmd = NULL; - data->sh_cmd = NULL; -} +struct cmd_if_shell_data { + char *cmd; + struct cmd_ctx ctx; +}; int -cmd_if_shell_parse(struct cmd *self, int argc, char **argv, char **cause) +cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_if_shell_data *data; - int opt; + struct cmd_target_data *data = self->data; + struct cmd_if_shell_data *cdata; + struct job *job; + + cdata = xmalloc(sizeof *cdata); + cdata->cmd = xstrdup(data->arg2); + memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); + + if (ctx->cmdclient != NULL) + ctx->cmdclient->references++; + if (ctx->curclient != NULL) + ctx->curclient->references++; + + job = job_add(NULL, 0, NULL, + data->arg, cmd_if_shell_callback, cmd_if_shell_free, cdata); + job_run(job); - self->entry->init(self, 0); - data = self->data; - - while ((opt = getopt(argc, argv, "")) != -1) { - switch (opt) { - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 2) - goto usage; - - data->sh_cmd = xstrdup(argv[0]); - data->cmd = xstrdup(argv[1]); - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); + return (1); /* don't let client exit */ } -int -cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) +void +cmd_if_shell_callback(struct job *job) { - struct cmd_if_shell_data *data = self->data; + struct cmd_if_shell_data *cdata = job->data; + struct cmd_ctx *ctx = &cdata->ctx; struct cmd_list *cmdlist; char *cause; - int ret; - if ((ret = system(data->sh_cmd)) < 0) { - ctx->error(ctx, "system error: %s", strerror(errno)); - return (-1); - } else if (ret != 0) - return (0); + if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) + return; - if (cmd_string_parse(data->cmd, &cmdlist, &cause) != 0) { + if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { if (cause != NULL) { ctx->error(ctx, "%s", cause); xfree(cause); } - return (-1); + return; } if (cmd_list_exec(cmdlist, ctx) < 0) { cmd_list_free(cmdlist); - return (-1); + return; } cmd_list_free(cmdlist); - return (0); } void -cmd_if_shell_free(struct cmd *self) +cmd_if_shell_free(void *data) { - struct cmd_if_shell_data *data = self->data; - - if (data->cmd != NULL) - xfree(data->cmd); - if (data->sh_cmd != NULL) - xfree(data->sh_cmd); - xfree(data); -} + struct cmd_if_shell_data *cdata = data; + struct cmd_ctx *ctx = &cdata->ctx; -size_t -cmd_if_shell_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_if_shell_data *data = self->data; - size_t off = 0; + if (ctx->cmdclient != NULL) { + ctx->cmdclient->references--; + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + } + if (ctx->curclient != NULL) + ctx->curclient->references--; - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->sh_cmd != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->sh_cmd); - if (off < len && data->cmd != NULL) - off += cmd_prarg(buf + off, len - off, " ", data->cmd); - return (off); + xfree(cdata->cmd); + xfree(cdata); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-kill-pane.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-kill-pane.c --- tmux-1.0/cmd-kill-pane.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-kill-pane.c 2009-10-25 10:41:03.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd-kill-pane.c,v 1.12 2009/07/30 20:45:20 tcunha Exp $ */ +/* $Id: cmd-kill-pane.c,v 1.14 2009/10/25 10:41:03 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -30,8 +30,8 @@ const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", - CMD_TARGET_PANE_USAGE, - 0, 0, + "[-a] " CMD_TARGET_PANE_USAGE, + 0, CMD_CHFLAG('a'), cmd_target_init, cmd_target_parse, cmd_kill_pane_exec, @@ -44,7 +44,7 @@ { struct cmd_target_data *data = self->data; struct winlink *wl; - struct window_pane *wp; + struct window_pane *loopwp, *nextwp, *wp; if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) return (-1); @@ -52,11 +52,25 @@ if (window_count_panes(wl->window) == 1) { /* Only one pane, kill the window. */ server_kill_window(wl->window); + recalculate_sizes(); return (0); } - layout_close_pane(wp); - window_remove_pane(wl->window, wp); + if (data->chflags & CMD_CHFLAG('a')) { + loopwp = TAILQ_FIRST(&wl->window->panes); + while (loopwp != NULL) { + nextwp = TAILQ_NEXT(loopwp, entry); + if (loopwp != wp) { + layout_close_pane(loopwp); + window_remove_pane(wl->window, loopwp); + } + loopwp = nextwp; + } + } else { + layout_close_pane(wp); + window_remove_pane(wl->window, wp); + } server_redraw_window(wl->window); + return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-kill-session.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-kill-session.c --- tmux-1.0/cmd-kill-session.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-kill-session.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-kill-session.c,v 1.14 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-kill-session.c,v 1.15 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -53,7 +53,7 @@ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c->session == s) { + if (c != NULL && c->session == s) { c->session = NULL; server_write_client(c, MSG_EXIT, NULL, 0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-kill-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-kill-window.c --- tmux-1.0/cmd-kill-window.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-kill-window.c 2009-09-20 23:15:32.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-kill-window.c,v 1.19 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-kill-window.c,v 1.20 2009/09/20 22:15:32 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -47,6 +47,7 @@ return (-1); server_kill_window(wl->window); + recalculate_sizes(); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-link-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-link-window.c --- tmux-1.0/cmd-link-window.c 2009-09-15 19:54:56.000000000 +0100 +++ tmux-1.1/cmd-link-window.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-link-window.c,v 1.32 2009/08/16 19:16:27 tcunha Exp $ */ +/* $Id: cmd-link-window.c,v 1.35 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -43,55 +43,23 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_srcdst_data *data = self->data; - struct session *dst; - struct winlink *wl_src, *wl_dst; + struct session *src, *dst; + struct winlink *wl; char *cause; - int idx; + int idx, kflag, dflag; - if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL) + if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) return (-1); if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - wl_dst = NULL; - if (idx != -1) - wl_dst = winlink_find_by_index(&dst->windows, idx); - if (wl_dst != NULL) { - if (wl_dst->window == wl_src->window) - return (0); - - if (data->chflags & CMD_CHFLAG('k')) { - /* - * Can't use session_detach as it will destroy session - * if this makes it empty. - */ - session_alert_cancel(dst, wl_dst); - winlink_stack_remove(&dst->lastw, wl_dst); - winlink_remove(&dst->windows, wl_dst); - - /* Force select/redraw if current. */ - if (wl_dst == dst->curw) { - data->chflags &= ~CMD_CHFLAG('d'); - dst->curw = NULL; - } - } - } - - if (idx == -1) - idx = -1 - options_get_number(&dst->options, "base-index"); - wl_dst = session_attach(dst, wl_src->window, idx, &cause); - if (wl_dst == NULL) { - ctx->error(ctx, "create session failed: %s", cause); + kflag = data->chflags & CMD_CHFLAG('k'); + dflag = data->chflags & CMD_CHFLAG('d'); + if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { + ctx->error(ctx, "can't link window: %s", cause); xfree(cause); return (-1); } - - if (data->chflags & CMD_CHFLAG('d')) - server_status_session(dst); - else { - session_select(dst, wl_dst->idx); - server_redraw_session(dst); - } recalculate_sizes(); return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-list-panes.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-list-panes.c --- tmux-1.0/cmd-list-panes.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/cmd-list-panes.c 2009-10-15 21:10:28.000000000 +0100 @@ -0,0 +1,74 @@ +/* $Id: cmd-list-panes.c,v 1.2 2009/10/15 20:10:28 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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 + +#include "tmux.h" + +/* + * List panes on given window.. + */ + +int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_list_panes_entry = { + "list-panes", "lsp", + CMD_TARGET_WINDOW_USAGE, + 0, 0, + cmd_target_init, + cmd_target_parse, + cmd_list_panes_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct winlink *wl; + struct window_pane *wp; + struct grid *gd; + struct grid_line *gl; + u_int i, n; + unsigned long long size; + + if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) + return (-1); + + n = 0; + TAILQ_FOREACH(wp, &wl->window->panes, entry) { + gd = wp->base.grid; + + size = 0; + for (i = 0; i < gd->hsize; i++) { + gl = &gd->linedata[i]; + size += gl->cellsize * sizeof *gl->celldata; + size += gl->utf8size * sizeof *gl->utf8data; + } + size += gd->hsize * sizeof *gd->linedata; + + ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]", + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); + n++; + } + + return (0); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-list-sessions.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-list-sessions.c --- tmux-1.0/cmd-list-sessions.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-list-sessions.c 2009-11-04 22:42:31.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd-list-sessions.c,v 1.21 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-list-sessions.c,v 1.23 2009/11/04 22:42:31 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -42,23 +42,32 @@ int cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) { - struct session *s; - char *tim; - u_int i; - time_t t; + struct session *s; + struct session_group *sg; + char *tim, tmp[64]; + u_int i, idx; + time_t t; for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); if (s == NULL) continue; - t = s->tv.tv_sec; + sg = session_group_find(s); + if (sg == NULL) + *tmp = '\0'; + else { + idx = session_group_index(sg); + xsnprintf(tmp, sizeof tmp, " (group %u)", idx); + } + + t = s->creation_time.tv_sec; tim = ctime(&t); *strchr(tim, '\n') = '\0'; - ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s", + ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s", s->name, winlink_count(&s->windows), tim, s->sx, s->sy, - s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); } return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-list-windows.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-list-windows.c --- tmux-1.0/cmd-list-windows.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-list-windows.c 2009-10-12 01:08:12.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-list-windows.c,v 1.40 2009/08/09 17:28:23 tcunha Exp $ */ +/* $Id: cmd-list-windows.c,v 1.41 2009/10/12 00:08:12 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -45,42 +45,13 @@ struct cmd_target_data *data = self->data; struct session *s; struct winlink *wl; - struct window *w; - struct window_pane *wp; - struct grid *gd; - struct grid_line *gl; - u_int i; - unsigned long long size; - const char *name; if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); RB_FOREACH(wl, winlinks, &s->windows) { - w = wl->window; - ctx->print(ctx, - "%3d: %s [%ux%u]", wl->idx, w->name, w->sx, w->sy); - - TAILQ_FOREACH(wp, &w->panes, entry) { - gd = wp->base.grid; - - size = 0; - for (i = 0; i < gd->hsize; i++) { - gl = &gd->linedata[i]; - size += gl->cellsize * sizeof *gl->celldata; - size += gl->utf8size * sizeof *gl->utf8data; - } - size += gd->hsize * sizeof *gd->linedata; - - name = NULL; - if (wp->fd != -1) - name = ttyname(wp->fd); - if (name == NULL) - name = "unknown"; - ctx->print(ctx, - " %s [%ux%u] [history %u/%u, %llu bytes]", - name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size); - } + ctx->print(ctx, "%d: %s [%ux%u]", + wl->idx, wl->window->name, wl->window->sx, wl->window->sy); } return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-load-buffer.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-load-buffer.c --- tmux-1.0/cmd-load-buffer.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/cmd-load-buffer.c 2009-10-28 23:10:05.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd-load-buffer.c,v 1.10 2009/09/07 23:48:54 tcunha Exp $ */ +/* $Id: cmd-load-buffer.c,v 1.11 2009/10/28 23:10:05 tcunha Exp $ */ /* * Copyright (c) 2009 Tiago Cunha @@ -56,13 +56,14 @@ if ((s = cmd_find_session(ctx, data->target)) == NULL) return (-1); - if (stat(data->arg, &sb) < 0) { + if ((f = fopen(data->arg, "rb")) == NULL) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); return (-1); } - if ((f = fopen(data->arg, "rb")) == NULL) { + if (fstat(fileno(f), &sb) < 0) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); + fclose(f); return (-1); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-lock-client.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-lock-client.c --- tmux-1.0/cmd-lock-client.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/cmd-lock-client.c 2009-09-25 18:51:39.000000000 +0100 @@ -0,0 +1,53 @@ +/* $Id: cmd-lock-client.c,v 1.1 2009/09/25 17:51:39 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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" + +/* + * Lock a single client. + */ + +int cmd_lock_client_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_lock_client_entry = { + "lock-client", "lockc", + CMD_TARGET_CLIENT_USAGE, + 0, 0, + cmd_target_init, + cmd_target_parse, + cmd_lock_client_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_lock_client_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct client *c; + + if ((c = cmd_find_client(ctx, data->target)) == NULL) + return (-1); + + server_lock_client(c); + recalculate_sizes(); + + return (0); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-lock-server.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-lock-server.c --- tmux-1.0/cmd-lock-server.c 2009-08-11 15:38:44.000000000 +0100 +++ tmux-1.1/cmd-lock-server.c 2009-09-25 18:47:42.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-lock-server.c,v 1.6 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-lock-server.c,v 1.7 2009/09/25 17:47:42 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -45,6 +45,7 @@ cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { server_lock(); + recalculate_sizes(); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-lock-session.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-lock-session.c --- tmux-1.0/cmd-lock-session.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/cmd-lock-session.c 2009-09-25 18:51:39.000000000 +0100 @@ -0,0 +1,53 @@ +/* $Id: cmd-lock-session.c,v 1.1 2009/09/25 17:51:39 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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" + +/* + * Lock all clients attached to a session. + */ + +int cmd_lock_session_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_lock_session_entry = { + "lock-session", "locks", + CMD_TARGET_SESSION_USAGE, + 0, 0, + cmd_target_init, + cmd_target_parse, + cmd_lock_session_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_lock_session_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct session *s; + + if ((s = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + + server_lock_session(s); + recalculate_sizes(); + + return (0); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-move-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-move-window.c --- tmux-1.0/cmd-move-window.c 2009-09-15 19:54:56.000000000 +0100 +++ tmux-1.1/cmd-move-window.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-move-window.c,v 1.9 2009/08/16 19:16:27 tcunha Exp $ */ +/* $Id: cmd-move-window.c,v 1.12 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -44,68 +44,23 @@ { struct cmd_srcdst_data *data = self->data; struct session *src, *dst; - struct winlink *wl_src, *wl_dst; - struct client *c; - u_int i; - int destroyed, idx; + struct winlink *wl; char *cause; + int idx, kflag, dflag; - if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL) + if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) return (-1); if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) return (-1); - wl_dst = NULL; - if (idx != -1) - wl_dst = winlink_find_by_index(&dst->windows, idx); - if (wl_dst != NULL) { - if (wl_dst->window == wl_src->window) - return (0); - - if (data->chflags & CMD_CHFLAG('k')) { - /* - * Can't use session_detach as it will destroy session - * if this makes it empty. - */ - session_alert_cancel(dst, wl_dst); - winlink_stack_remove(&dst->lastw, wl_dst); - winlink_remove(&dst->windows, wl_dst); - - /* Force select/redraw if current. */ - if (wl_dst == dst->curw) { - data->chflags &= ~CMD_CHFLAG('d'); - dst->curw = NULL; - } - } - } - - if (idx == -1) - idx = -1 - options_get_number(&dst->options, "base-index"); - wl_dst = session_attach(dst, wl_src->window, idx, &cause); - if (wl_dst == NULL) { - ctx->error(ctx, "attach window failed: %s", cause); + kflag = data->chflags & CMD_CHFLAG('k'); + dflag = data->chflags & CMD_CHFLAG('d'); + if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { + ctx->error(ctx, "can't move window: %s", cause); xfree(cause); return (-1); } - - destroyed = session_detach(src, wl_src); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != src) - continue; - if (destroyed) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } else - server_redraw_client(c); - } - - if (data->chflags & CMD_CHFLAG('d')) - server_status_session(dst); - else { - session_select(dst, wl_dst->idx); - server_redraw_session(dst); - } + server_unlink_window(src, wl); recalculate_sizes(); return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-new-session.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-new-session.c --- tmux-1.0/cmd-new-session.c 2009-09-16 13:36:27.000000000 +0100 +++ tmux-1.1/cmd-new-session.c 2009-10-12 01:49:06.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-new-session.c,v 1.66 2009/09/16 12:36:27 nicm Exp $ */ +/* $Id: cmd-new-session.c,v 1.69 2009/10/12 00:49:06 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -20,7 +20,6 @@ #include #include -#include #include "tmux.h" @@ -35,6 +34,7 @@ size_t cmd_new_session_print(struct cmd *, char *, size_t); struct cmd_new_session_data { + char *target; char *newname; char *winname; char *cmd; @@ -43,7 +43,7 @@ const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "[-d] [-n window-name] [-s session-name] [command]", + "[-d] [-n window-name] [-s session-name] [-t target-session] [command]", CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0, cmd_new_session_init, cmd_new_session_parse, @@ -59,6 +59,7 @@ self->data = data = xmalloc(sizeof *data); data->flag_detached = 0; + data->target = NULL; data->newname = NULL; data->winname = NULL; data->cmd = NULL; @@ -70,10 +71,10 @@ struct cmd_new_session_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; - while ((opt = getopt(argc, argv, "ds:n:")) != -1) { + while ((opt = getopt(argc, argv, "ds:t:n:")) != -1) { switch (opt) { case 'd': data->flag_detached = 1; @@ -82,6 +83,10 @@ if (data->newname == NULL) data->newname = xstrdup(optarg); break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; case 'n': if (data->winname == NULL) data->winname = xstrdup(optarg); @@ -95,6 +100,9 @@ if (argc != 0 && argc != 1) goto usage; + if (data->target != NULL && (argc == 1 || data->winname != NULL)) + goto usage; + if (argc == 1) data->cmd = xstrdup(argv[0]); @@ -111,7 +119,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) { struct cmd_new_session_data *data = self->data; - struct session *s; + struct session *s, *groupwith; struct window *w; struct environ env; struct termios tio, *tiop; @@ -125,6 +133,11 @@ return (-1); } + groupwith = NULL; + if (data->target != NULL && + (groupwith = cmd_find_session(ctx, data->target)) == NULL) + return (-1); + /* * There are three cases: * @@ -205,7 +218,9 @@ sy = 1; /* Figure out the command for the new window. */ - if (data->cmd != NULL) + if (data->target != NULL) + cmd = NULL; + else if (data->cmd != NULL) cmd = data->cmd; else cmd = options_get_string(&global_s_options, "default-command"); @@ -228,7 +243,7 @@ environ_free(&env); /* Set the initial window name if one given. */ - if (data->winname != NULL) { + if (cmd != NULL && data->winname != NULL) { w = s->curw->window; xfree(w->name); @@ -238,6 +253,16 @@ } /* + * If a target session is given, this is to be part of a session group, + * so add it to the group and synchronize. + */ + if (groupwith != NULL) { + session_group_add(groupwith, s); + session_group_synchronize_to(s); + session_select(s, RB_ROOT(&s->windows)->idx); + } + + /* * Set the client to the new session. If a command client exists, it is * taking this session and needs to get MSG_READY and stay around. */ diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-new-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-new-window.c --- tmux-1.0/cmd-new-window.c 2009-09-15 19:54:57.000000000 +0100 +++ tmux-1.1/cmd-new-window.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-new-window.c,v 1.37 2009/08/16 19:16:27 tcunha Exp $ */ +/* $Id: cmd-new-window.c,v 1.39 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -70,7 +70,7 @@ struct cmd_new_window_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "dkt:n:")) != -1) { @@ -164,9 +164,9 @@ } if (!data->flag_detached) { session_select(s, wl->idx); - server_redraw_session(s); - } else - server_status_session(s); + server_redraw_session_group(s); + } else + server_status_session_group(s); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-pipe-pane.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-pipe-pane.c --- tmux-1.0/cmd-pipe-pane.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/cmd-pipe-pane.c 2009-10-23 18:26:40.000000000 +0100 @@ -0,0 +1,125 @@ +/* $Id: cmd-pipe-pane.c,v 1.3 2009/10/23 17:26:40 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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 +#include +#include +#include + +#include "tmux.h" + +/* + * Open pipe to redirect pane output. If already open, close first. + */ + +int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *); + +const struct cmd_entry cmd_pipe_pane_entry = { + "pipe-pane", "pipep", + CMD_TARGET_PANE_USAGE "[-o] [command]", + CMD_ARG01, CMD_CHFLAG('o'), + cmd_target_init, + cmd_target_parse, + cmd_pipe_pane_exec, + cmd_target_free, + cmd_target_print +}; + +int +cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct window_pane *wp; + int old_fd, pipe_fd[2], null_fd, mode; + + if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) + return (-1); + + /* Destroy the old pipe. */ + old_fd = wp->pipe_fd; + if (wp->pipe_fd != -1) { + buffer_destroy(wp->pipe_buf); + close(wp->pipe_fd); + wp->pipe_fd = -1; + } + + /* If no pipe command, that is enough. */ + if (data->arg == NULL || *data->arg == '\0') + return (0); + + /* + * With -o, only open the new pipe if there was no previous one. This + * allows a pipe to be toggled with a single key, for example: + * + * bind ^p pipep -o 'cat >>~/output' + */ + if (data->chflags & CMD_CHFLAG('o') && old_fd != -1) + return (0); + + /* Open the new pipe. */ + if (pipe(pipe_fd) != 0) { + ctx->error(ctx, "pipe error: %s", strerror(errno)); + return (-1); + } + + /* Fork the child. */ + switch (fork()) { + case -1: + ctx->error(ctx, "fork error: %s", strerror(errno)); + return (-1); + case 0: + /* Child process. */ + close(pipe_fd[0]); + sigreset(); + + if (dup2(pipe_fd[1], STDIN_FILENO) == -1) + _exit(1); + if (pipe_fd[1] != STDIN_FILENO) + close(pipe_fd[1]); + + null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); + if (dup2(null_fd, STDOUT_FILENO) == -1) + _exit(1); + if (dup2(null_fd, STDERR_FILENO) == -1) + _exit(1); + if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) + close(null_fd); + + execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL); + _exit(1); + default: + /* Parent process. */ + close(pipe_fd[1]); + + wp->pipe_fd = pipe_fd[0]; + wp->pipe_buf = buffer_create(BUFSIZ); + wp->pipe_off = BUFFER_USED(wp->in); + + if ((mode = fcntl(wp->pipe_fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + return (0); + } + + return (0); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-rename-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-rename-window.c --- tmux-1.0/cmd-rename-window.c 2009-09-15 19:54:57.000000000 +0100 +++ tmux-1.1/cmd-rename-window.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-rename-window.c,v 1.29 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-rename-window.c,v 1.30 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -53,7 +53,7 @@ wl->window->name = xstrdup(data->arg); options_set_number(&wl->window->options, "automatic-rename", 0); - server_status_session(s); + server_status_window(wl->window); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-run-shell.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-run-shell.c --- tmux-1.0/cmd-run-shell.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/cmd-run-shell.c 2009-11-02 21:38:26.000000000 +0000 @@ -0,0 +1,137 @@ +/* $Id: cmd-run-shell.c,v 1.4 2009/11/02 21:38:26 tcunha Exp $ */ + +/* + * Copyright (c) 2009 Tiago Cunha + * Copyright (c) 2009 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 + +#include + +#include "tmux.h" + +/* + * Runs a command without a window. + */ + +int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); + +void cmd_run_shell_callback(struct job *); +void cmd_run_shell_free(void *); + +const struct cmd_entry cmd_run_shell_entry = { + "run-shell", "run", + "command", + CMD_ARG1, 0, + cmd_target_init, + cmd_target_parse, + cmd_run_shell_exec, + cmd_target_free, + cmd_target_print +}; + +struct cmd_run_shell_data { + char *cmd; + struct cmd_ctx ctx; +}; + +int +cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_target_data *data = self->data; + struct cmd_run_shell_data *cdata; + struct job *job; + + cdata = xmalloc(sizeof *cdata); + cdata->cmd = xstrdup(data->arg); + memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); + + if (ctx->cmdclient != NULL) + ctx->cmdclient->references++; + if (ctx->curclient != NULL) + ctx->curclient->references++; + + job = job_add(NULL, 0, NULL, + data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata); + job_run(job); + + return (1); /* don't let client exit */ +} + +void +cmd_run_shell_callback(struct job *job) +{ + struct cmd_run_shell_data *cdata = job->data; + struct cmd_ctx *ctx = &cdata->ctx; + char *cmd, *msg, *line, *buf; + size_t off, len, llen; + int retcode; + + buf = BUFFER_OUT(job->out); + len = BUFFER_USED(job->out); + + cmd = cdata->cmd; + + if (len != 0) { + line = buf; + for (off = 0; off < len; off++) { + if (buf[off] == '\n') { + llen = buf + off - line; + if (llen > INT_MAX) + break; + ctx->print(ctx, "%.*s", (int) llen, line); + line = buf + off + 1; + } + } + llen = buf + len - line; + if (llen > 0 && llen < INT_MAX) + ctx->print(ctx, "%.*s", (int) llen, line); + } + + msg = NULL; + if (WIFEXITED(job->status)) { + if ((retcode = WEXITSTATUS(job->status)) != 0) + xasprintf(&msg, "'%s' returned %d", cmd, retcode); + } else if (WIFSIGNALED(job->status)) { + retcode = WTERMSIG(job->status); + xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); + } + if (msg != NULL) { + if (len != 0) + ctx->print(ctx, "%s", msg); + else + ctx->info(ctx, "%s", msg); + xfree(msg); + } +} + +void +cmd_run_shell_free(void *data) +{ + struct cmd_run_shell_data *cdata = data; + struct cmd_ctx *ctx = &cdata->ctx; + + if (ctx->cmdclient != NULL) { + ctx->cmdclient->references--; + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + } + if (ctx->curclient != NULL) + ctx->curclient->references--; + + xfree(cdata->cmd); + xfree(cdata); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-save-buffer.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-save-buffer.c --- tmux-1.0/cmd-save-buffer.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/cmd-save-buffer.c 2009-10-28 23:08:52.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd-save-buffer.c,v 1.8 2009/09/07 23:48:54 tcunha Exp $ */ +/* $Id: cmd-save-buffer.c,v 1.9 2009/10/28 23:08:52 tcunha Exp $ */ /* * Copyright (c) 2009 Tiago Cunha @@ -70,6 +70,7 @@ f = fopen(data->arg, "ab"); else f = fopen(data->arg, "wb"); + umask(mask); if (f == NULL) { ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); return (-1); @@ -82,7 +83,6 @@ } fclose(f); - umask(mask); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-scroll-mode.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-scroll-mode.c --- tmux-1.0/cmd-scroll-mode.c 2009-08-21 11:56:23.000000000 +0100 +++ tmux-1.1/cmd-scroll-mode.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,70 +0,0 @@ -/* $Id: cmd-scroll-mode.c,v 1.23 2009/08/20 11:37:46 tcunha Exp $ */ - -/* - * Copyright (c) 2007 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" - -/* - * Enter scroll mode. - */ - -void cmd_scroll_mode_init(struct cmd *, int); -int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *); - -const struct cmd_entry cmd_scroll_mode_entry = { - "scroll-mode", NULL, - "[-u] " CMD_TARGET_PANE_USAGE, - 0, CMD_CHFLAG('u'), - cmd_scroll_mode_init, - cmd_target_parse, - cmd_scroll_mode_exec, - cmd_target_free, - cmd_target_print -}; - -void -cmd_scroll_mode_init(struct cmd *self, int key) -{ - struct cmd_target_data *data; - - cmd_target_init(self, key); - data = self->data; - - switch (key) { - case KEYC_PPAGE: - data->chflags |= CMD_CHFLAG('u'); - break; - } -} - -int -cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_target_data *data = self->data; - struct window_pane *wp; - - if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL) - return (-1); - - window_pane_set_mode(wp, &window_scroll_mode); - if (wp->mode == &window_scroll_mode && data->chflags & CMD_CHFLAG('u')) - window_scroll_pageup(wp); - - return (0); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-send-keys.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-send-keys.c --- tmux-1.0/cmd-send-keys.c 2009-08-21 11:56:23.000000000 +0100 +++ tmux-1.1/cmd-send-keys.c 2009-09-22 15:03:11.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-send-keys.c,v 1.21 2009/08/20 11:37:46 tcunha Exp $ */ +/* $Id: cmd-send-keys.c,v 1.22 2009/09/22 14:03:11 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -33,7 +33,6 @@ struct cmd_send_keys_data { char *target; - int idx; u_int nkeys; int *keys; }; @@ -58,7 +57,6 @@ self->data = data = xmalloc(sizeof *data); data->target = NULL; - data->idx = -1; data->nkeys = 0; data->keys = NULL; @@ -143,8 +141,6 @@ return (off); if (off < len && data->target != NULL) off += cmd_prarg(buf + off, len - off, " -t ", data->target); - if (off < len && data->idx != -1) - off += xsnprintf(buf + off, len - off, " -i %d", data->idx); for (i = 0; i < data->nkeys; i++) { if (off >= len) diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-send-prefix.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-send-prefix.c --- tmux-1.0/cmd-send-prefix.c 2009-08-21 11:56:23.000000000 +0100 +++ tmux-1.1/cmd-send-prefix.c 2009-09-22 15:22:20.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-send-prefix.c,v 1.26 2009/08/20 11:37:46 tcunha Exp $ */ +/* $Id: cmd-send-prefix.c,v 1.27 2009/09/22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -43,13 +43,13 @@ struct cmd_target_data *data = self->data; struct session *s; struct window_pane *wp; - int key; + struct keylist *keylist; if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); - key = options_get_number(&s->options, "prefix"); - window_pane_key(wp, ctx->curclient, key); + keylist = options_get_data(&s->options, "prefix"); + window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist)); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-server-info.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-server-info.c --- tmux-1.0/cmd-server-info.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/cmd-server-info.c 2009-11-04 22:42:31.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd-server-info.c,v 1.28 2009/09/07 23:59:19 tcunha Exp $ */ +/* $Id: cmd-server-info.c,v 1.33 2009/11/04 22:42:31 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -55,6 +55,7 @@ struct tty_code *code; struct tty_term_code_entry *ent; struct utsname un; + struct job *job; struct grid *gd; struct grid_line *gl; u_int i, j, k; @@ -68,11 +69,10 @@ *strchr(tim, '\n') = '\0'; ctx->print(ctx, "tmux " BUILD ", pid %ld, started %s", (long) getpid(), tim); - ctx->print(ctx, "socket path %s, debug level %d%s%s", - socket_path, debug_level, be_quiet ? ", quiet" : "", - login_shell ? ", login shell" : ""); - if (uname(&un) == 0) { - ctx->print(ctx, "system is %s %s %s %s", + ctx->print(ctx, "socket path %s, debug level %d%s", + socket_path, debug_level, be_quiet ? ", quiet" : ""); + if (uname(&un) == 0) { + ctx->print(ctx, "system is %s %s %s %s", un.sysname, un.release, un.version, un.machine); } if (cfg_file != NULL) @@ -105,7 +105,7 @@ if (s == NULL) continue; - t = s->tv.tv_sec; + t = s->creation_time.tv_sec; tim = ctime(&t); *strchr(tim, '\n') = '\0'; @@ -179,5 +179,11 @@ } ctx->print(ctx, "%s", ""); + ctx->print(ctx, "Jobs:"); + SLIST_FOREACH(job, &all_jobs, lentry) { + ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d, flags=0x%x]", + job->cmd, job->fd, job->pid, job->status, job->flags); + } + return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-set-option.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-set-option.c --- tmux-1.0/cmd-set-option.c 2009-09-20 19:11:24.000000000 +0100 +++ tmux-1.1/cmd-set-option.c 2009-11-02 21:38:26.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd-set-option.c,v 1.79 2009/09/19 18:53:01 tcunha Exp $ */ +/* $Id: cmd-set-option.c,v 1.85 2009/11/02 21:38:26 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -62,10 +62,13 @@ { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "lock-after-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, + { "lock-command", SET_OPTION_STRING, 0, 0, NULL }, + { "lock-server", SET_OPTION_FLAG, 0, 0, NULL }, { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "prefix", SET_OPTION_KEY, 0, 0, NULL }, + { "mouse-select-pane", SET_OPTION_FLAG, 0, 0, NULL }, + { "prefix", SET_OPTION_KEYS, 0, 0, NULL }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, @@ -105,7 +108,10 @@ struct client *c; struct options *oo; const struct set_option_entry *entry, *opt; + struct jobs *jobs; + struct job *job, *nextjob; u_int i; + int try_again; if (data->chflags & CMD_CHFLAG('g')) oo = &global_s_options; @@ -162,8 +168,8 @@ case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); break; - case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->arg2); + case SET_OPTION_KEYS: + set_option_keys(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: set_option_colour(ctx, oo, entry, data->arg2); @@ -181,10 +187,36 @@ } recalculate_sizes(); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session != NULL) + + /* + * Special-case: kill all persistent jobs if status-left, status-right + * or set-titles-string have changed. Persistent jobs are only used by + * the status line at the moment so this works XXX. + */ + if (strcmp(entry->name, "status-left") == 0 || + strcmp(entry->name, "status-right") == 0 || + strcmp(entry->name, "set-titles-string") == 0) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + jobs = &c->status_jobs; + do { + try_again = 0; + job = RB_ROOT(jobs); + while (job != NULL) { + nextjob = RB_NEXT(jobs, jobs, job); + if (job->flags & JOB_PERSIST) { + job_remove(jobs, job); + try_again = 1; + break; + } + job = nextjob; + } + } while (try_again); server_redraw_client(c); + } } return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-set-password.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-set-password.c --- tmux-1.0/cmd-set-password.c 2009-08-11 15:38:45.000000000 +0100 +++ tmux-1.1/cmd-set-password.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,145 +0,0 @@ -/* $Id: cmd-set-password.c,v 1.8 2009/07/28 22:12:16 tcunha Exp $ */ - -/* - * Copyright (c) 2009 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 -#include - -#include "tmux.h" - -/* - * Set server password. - */ - -int cmd_set_password_parse(struct cmd *, int, char **, char **); -int cmd_set_password_exec(struct cmd *, struct cmd_ctx *); -void cmd_set_password_free(struct cmd *); -void cmd_set_password_init(struct cmd *, int); -size_t cmd_set_password_print(struct cmd *, char *, size_t); - -struct cmd_set_password_data { - char *password; - int flag_encrypted; -}; - -const struct cmd_entry cmd_set_password_entry = { - "set-password", "pass", - "[-c] password", - 0, 0, - cmd_set_password_init, - cmd_set_password_parse, - cmd_set_password_exec, - cmd_set_password_free, - cmd_set_password_print -}; - -void -cmd_set_password_init(struct cmd *self, unused int arg) -{ - struct cmd_set_password_data *data; - - self->data = data = xmalloc(sizeof *data); - data->password = NULL; - data->flag_encrypted = 0; -} - -int -cmd_set_password_parse(struct cmd *self, int argc, char **argv, char **cause) -{ - struct cmd_set_password_data *data; - int opt; - char *out; - - self->entry->init(self, 0); - data = self->data; - - while ((opt = getopt(argc, argv, "c")) != -1) { - switch (opt) { - case 'c': - data->flag_encrypted = 1; - break; - default: - goto usage; - } - } - argc -= optind; - argv += optind; - if (argc != 1) - goto usage; - - if (!data->flag_encrypted) { - if ((out = crypt(argv[0], "$1")) != NULL) - data->password = xstrdup(out); - } else - data->password = xstrdup(argv[0]); - - return (0); - -usage: - xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); - - self->entry->free(self); - return (-1); -} - -int -cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx) -{ - struct cmd_set_password_data *data = self->data; - - if (data->password == NULL) { - ctx->error(ctx, "failed to encrypt password"); - return (-1); - } - - if (server_password != NULL) - xfree(server_password); - if (*data->password == '\0') - server_password = NULL; - else - server_password = xstrdup(data->password); - - return (0); -} - -void -cmd_set_password_free(struct cmd *self) -{ - struct cmd_set_password_data *data = self->data; - - if (data->password != NULL) - xfree(data->password); - xfree(data); -} - -size_t -cmd_set_password_print(struct cmd *self, char *buf, size_t len) -{ - struct cmd_set_password_data *data = self->data; - size_t off = 0; - - off += xsnprintf(buf, len, "%s", self->entry->name); - if (data == NULL) - return (off); - if (off < len && data->flag_encrypted) - off += xsnprintf(buf + off, len - off, " -c"); - if (off < len && data->password != NULL) - off += xsnprintf(buf + off, len - off, " password"); - return (off); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-set-window-option.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-set-window-option.c --- tmux-1.0/cmd-set-window-option.c 2009-08-11 15:42:59.000000000 +0100 +++ tmux-1.1/cmd-set-window-option.c 2009-10-09 14:07:04.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-set-window-option.c,v 1.38 2009/08/11 14:42:59 nicm Exp $ */ +/* $Id: cmd-set-window-option.c,v 1.40 2009/10/09 13:07:04 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -64,6 +64,7 @@ { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, + { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, @@ -140,8 +141,8 @@ case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); break; - case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->arg2); + case SET_OPTION_KEYS: + set_option_keys(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: set_option_colour(ctx, oo, entry, data->arg2); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-show-options.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-show-options.c --- tmux-1.0/cmd-show-options.c 2009-08-11 15:38:45.000000000 +0100 +++ tmux-1.1/cmd-show-options.c 2009-09-22 14:56:02.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-show-options.c,v 1.16 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-show-options.c,v 1.17 2009/09/22 13:56:02 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -46,9 +46,9 @@ struct cmd_target_data *data = self->data; struct session *s; struct options *oo; + struct options_entry *o; const struct set_option_entry *entry; - char *vs; - long long vn; + const char *optval; if (data->chflags & CMD_CHFLAG('g')) oo = &global_s_options; @@ -59,46 +59,10 @@ } for (entry = set_option_table; entry->name != NULL; entry++) { - if (options_find1(oo, entry->name) == NULL) + if ((o = options_find1(oo, entry->name)) == NULL) continue; - - switch (entry->type) { - case SET_OPTION_STRING: - vs = options_get_string(oo, entry->name); - ctx->print(ctx, "%s \"%s\"", entry->name, vs); - break; - case SET_OPTION_NUMBER: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %lld", entry->name, vn); - break; - case SET_OPTION_KEY: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, key_string_lookup_key(vn)); - break; - case SET_OPTION_COLOUR: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, colour_tostring(vn)); - break; - case SET_OPTION_ATTRIBUTES: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, attributes_tostring(vn)); - break; - case SET_OPTION_FLAG: - vn = options_get_number(oo, entry->name); - if (vn) - ctx->print(ctx, "%s on", entry->name); - else - ctx->print(ctx, "%s off", entry->name); - break; - case SET_OPTION_CHOICE: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, entry->choices[vn]); - break; - } + optval = set_option_print(entry, o); + ctx->print(ctx, "%s %s", entry->name, optval); } return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-show-window-options.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-show-window-options.c --- tmux-1.0/cmd-show-window-options.c 2009-08-11 15:38:45.000000000 +0100 +++ tmux-1.1/cmd-show-window-options.c 2009-09-22 14:56:02.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-show-window-options.c,v 1.12 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-show-window-options.c,v 1.13 2009/09/22 13:56:02 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -46,9 +46,9 @@ struct cmd_target_data *data = self->data; struct winlink *wl; struct options *oo; + struct options_entry *o; const struct set_option_entry *entry; - char *vs; - long long vn; + const char *optval; if (data->chflags & CMD_CHFLAG('g')) oo = &global_w_options; @@ -59,46 +59,10 @@ } for (entry = set_window_option_table; entry->name != NULL; entry++) { - if (options_find1(oo, entry->name) == NULL) + if ((o = options_find1(oo, entry->name)) == NULL) continue; - - switch (entry->type) { - case SET_OPTION_STRING: - vs = options_get_string(oo, entry->name); - ctx->print(ctx, "%s \"%s\"", entry->name, vs); - break; - case SET_OPTION_NUMBER: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %lld", entry->name, vn); - break; - case SET_OPTION_KEY: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, key_string_lookup_key(vn)); - break; - case SET_OPTION_COLOUR: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, colour_tostring(vn)); - break; - case SET_OPTION_ATTRIBUTES: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, attributes_tostring(vn)); - break; - case SET_OPTION_FLAG: - vn = options_get_number(oo, entry->name); - if (vn) - ctx->print(ctx, "%s on", entry->name); - else - ctx->print(ctx, "%s off", entry->name); - break; - case SET_OPTION_CHOICE: - vn = options_get_number(oo, entry->name); - ctx->print(ctx, "%s %s", - entry->name, entry->choices[vn]); - break; - } + optval = set_option_print(entry, o); + ctx->print(ctx, "%s %s", entry->name, optval); } return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-source-file.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-source-file.c --- tmux-1.0/cmd-source-file.c 2009-08-26 10:09:09.000000000 +0100 +++ tmux-1.1/cmd-source-file.c 2009-09-22 15:06:40.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-source-file.c,v 1.8 2009/08/24 16:27:03 tcunha Exp $ */ +/* $Id: cmd-source-file.c,v 1.9 2009/09/22 14:06:40 tcunha Exp $ */ /* * Copyright (c) 2008 Tiago Cunha @@ -60,7 +60,7 @@ struct cmd_source_file_data *data; int opt; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "")) != -1) { diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-split-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-split-window.c --- tmux-1.0/cmd-split-window.c 2009-09-16 13:36:27.000000000 +0100 +++ tmux-1.1/cmd-split-window.c 2009-09-22 15:06:40.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-split-window.c,v 1.27 2009/09/16 12:36:27 nicm Exp $ */ +/* $Id: cmd-split-window.c,v 1.28 2009/09/22 14:06:40 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -83,7 +83,7 @@ int opt; const char *errstr; - self->entry->init(self, 0); + self->entry->init(self, KEYC_NONE); data = self->data; while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) { diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-string.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-string.c --- tmux-1.0/cmd-string.c 2009-08-11 15:38:45.000000000 +0100 +++ tmux-1.1/cmd-string.c 2009-10-28 23:12:38.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: cmd-string.c,v 1.23 2009/08/09 17:48:55 tcunha Exp $ */ +/* $Id: cmd-string.c,v 1.24 2009/10/28 23:12:38 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -204,33 +204,33 @@ char *buf, *t; size_t len; - buf = NULL; + buf = NULL; len = 0; - while ((ch = cmd_string_getc(s, p)) != endch) { - switch (ch) { + while ((ch = cmd_string_getc(s, p)) != endch) { + switch (ch) { case EOF: goto error; - case '\\': + case '\\': if (!esc) break; - switch (ch = cmd_string_getc(s, p)) { + switch (ch = cmd_string_getc(s, p)) { case EOF: goto error; case 'e': ch = '\033'; break; - case 'r': - ch = '\r'; - break; - case 'n': - ch = '\n'; - break; - case 't': - ch = '\t'; - break; - } - break; + case 'r': + ch = '\r'; + break; + case 'n': + ch = '\n'; + break; + case 't': + ch = '\t'; + break; + } + break; case '$': if (!esc) break; @@ -241,13 +241,13 @@ len += strlen(t); xfree(t); continue; - } + } if (len >= SIZE_MAX - 2) goto error; buf = xrealloc(buf, 1, len + 1); - buf[len++] = ch; - } + buf[len++] = ch; + } buf = xrealloc(buf, 1, len + 1); buf[len] = '\0'; @@ -272,7 +272,7 @@ ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \ ((ch) >= '0' && (ch) <= '9')) - buf = NULL; + buf = NULL; len = 0; fch = EOF; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-swap-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-swap-window.c --- tmux-1.0/cmd-swap-window.c 2009-09-15 19:54:57.000000000 +0100 +++ tmux-1.1/cmd-swap-window.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-swap-window.c,v 1.17 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-swap-window.c,v 1.18 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -44,6 +44,7 @@ { struct cmd_srcdst_data *data = self->data; struct session *src, *dst; + struct session_group *sg_src, *sg_dst; struct winlink *wl_src, *wl_dst; struct window *w; @@ -52,6 +53,14 @@ if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL) return (-1); + sg_src = session_group_find(src); + sg_dst = session_group_find(dst); + if (src != dst && + sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) { + ctx->error(ctx, "can't move window, sessions are grouped"); + return (-1); + } + if (wl_dst->window == wl_src->window) return (0); @@ -64,9 +73,12 @@ if (src != dst) session_select(src, wl_src->idx); } - server_redraw_session(src); - if (src != dst) - server_redraw_session(dst); + session_group_synchronize_from(src); + server_redraw_session_group(src); + if (src != dst) { + session_group_synchronize_from(dst); + server_redraw_session_group(dst); + } recalculate_sizes(); return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/cmd-unlink-window.c /tmp/wmlmc6MQoR/tmux-1.1/cmd-unlink-window.c --- tmux-1.0/cmd-unlink-window.c 2009-08-11 15:38:46.000000000 +0100 +++ tmux-1.1/cmd-unlink-window.c 2009-10-12 00:38:16.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: cmd-unlink-window.c,v 1.16 2009/07/28 22:12:16 tcunha Exp $ */ +/* $Id: cmd-unlink-window.c,v 1.19 2009/10/11 23:38:16 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -42,30 +42,29 @@ { struct cmd_target_data *data = self->data; struct winlink *wl; - struct session *s; - struct client *c; - u_int i; - int destroyed; + struct window *w; + struct session *s, *s2; + struct session_group *sg; + u_int references; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return (-1); + w = wl->window; - if (!(data->chflags & CMD_CHFLAG('k')) && wl->window->references == 1) { + sg = session_group_find(s); + if (sg != NULL) { + references = 0; + TAILQ_FOREACH(s2, &sg->sessions, gentry) + references++; + } else + references = 1; + + if (!(data->chflags & CMD_CHFLAG('k')) && w->references == references) { ctx->error(ctx, "window is only linked to one session"); return (-1); } - - destroyed = session_detach(s, wl); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (destroyed) { - c->session = NULL; - server_write_client(c, MSG_EXIT, NULL, 0); - } else - server_redraw_client(c); - } + + server_unlink_window(s, wl); recalculate_sizes(); return (0); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/compat/forkpty-aix.c.~1.3.~ /tmp/wmlmc6MQoR/tmux-1.1/compat/forkpty-aix.c.~1.3.~ --- tmux-1.0/compat/forkpty-aix.c.~1.3.~ 2009-08-19 17:06:45.000000000 +0100 +++ tmux-1.1/compat/forkpty-aix.c.~1.3.~ 1970-01-01 01:00:00.000000000 +0100 @@ -1,95 +0,0 @@ -/* $Id: forkpty-aix.c,v 1.3 2009/08/19 16:06:45 nicm Exp $ */ - -/* - * Copyright (c) 2009 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 - -#include -#include -#include -#include - -#include "tmux.h" - -pid_t -forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws) -{ - int slave, fd; - char *path; - pid_t pid; - - if ((*master = open("/dev/ptc", O_RDWR|O_NOCTTY)) == -1) - return (-1); - - if ((path = ttyname(*master)) == NULL) - goto out; - if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1) - goto out; - - switch (pid = fork()) { - case -1: - goto out; - case 0: - close(*master); - - fd = open(_PATH_TTY, O_RDWR|O_NOCTTY); - if (fd >= 0) { - ioctl(fd, TIOCNOTTY, NULL); - close(fd); - } - - if (setsid() < 0) - fatal("setsid"); - - fd = open(_PATH_TTY, O_RDWR|O_NOCTTY); - if (fd >= 0) - fatalx("open succeeded (failed to disconnect)"); - - fd = open(path, O_RDWR); - if (fd < 0) - fatal("open failed"); - close(fd); - - fd = open("/dev/tty", O_WRONLY); - if (fd < 0) - fatal("open failed"); - close(fd); - - if (tcsetattr(slave, TCSAFLUSH, tio) == -1) - fatal("tcsetattr failed"); - if (ioctl(slave, TIOCSWINSZ, ws) == -1) - fatal("ioctl failed"); - - dup2(slave, 0); - dup2(slave, 1); - dup2(slave, 2); - if (slave > 2) - close(slave); - return (0); - } - - close(slave); - return (pid); - -out: - if (*master != -1) - close(*master); - if (slave != -1) - close(slave); - return (-1); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/compat/forkpty-sunos.c /tmp/wmlmc6MQoR/tmux-1.1/compat/forkpty-sunos.c --- tmux-1.0/compat/forkpty-sunos.c 2009-09-20 19:31:16.000000000 +0100 +++ tmux-1.1/compat/forkpty-sunos.c 2009-10-15 21:08:09.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: forkpty-sunos.c,v 1.8 2009/09/20 18:31:16 nicm Exp $ */ +/* $Id: forkpty-sunos.c,v 1.9 2009/10/15 07:11:25 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -27,7 +27,7 @@ #include "tmux.h" pid_t -forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws) +forkpty(int *master, char *name, struct termios *tio, struct winsize *ws) { int slave; char *path; @@ -42,6 +42,8 @@ if ((path = ptsname(*master)) == NULL) goto out; + if (name != NULL) + strlcpy(name, path, TTY_NAME_MAX); if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1) goto out; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/compat/forkpty-sunos.c.~1.7.~ /tmp/wmlmc6MQoR/tmux-1.1/compat/forkpty-sunos.c.~1.7.~ --- tmux-1.0/compat/forkpty-sunos.c.~1.7.~ 2009-08-20 18:22:08.000000000 +0100 +++ tmux-1.1/compat/forkpty-sunos.c.~1.7.~ 1970-01-01 01:00:00.000000000 +0100 @@ -1,87 +0,0 @@ -/* $Id: forkpty-sunos.c,v 1.7 2009/08/19 16:06:45 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 - -#include -#include -#include -#include - -#include "tmux.h" - -pid_t -forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws) -{ - int slave; - char *path; - pid_t pid; - - if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1) - return (-1); - if (grantpt(*master) != 0) - goto out; - if (unlockpt(*master) != 0) - goto out; - - if ((path = ptsname(*master)) == NULL) - goto out; - if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1) - goto out; - - switch (pid = fork()) { - case -1: - goto out; - case 0: - close(*master); - - setsid(); -#ifdef TIOCSCTTY - if (ioctl(slave, TIOCSCTTY, NULL) == -1) - fatal("ioctl failed"); -#endif - - if (ioctl(slave, I_PUSH, "ptem") == -1) - fatal("ioctl failed"); - if (ioctl(slave, I_PUSH, "ldterm") == -1) - fatal("ioctl failed"); - - if (tcsetattr(slave, TCSAFLUSH, tio) == -1) - fatal("tcsetattr failed"); - if (ioctl(slave, TIOCSWINSZ, ws) == -1) - fatal("ioctl failed"); - - dup2(slave, 0); - dup2(slave, 1); - dup2(slave, 2); - if (slave > 2) - close(slave); - return (0); - } - - close(slave); - return (pid); - -out: - if (*master != -1) - close(*master); - if (slave != -1) - close(slave); - return (-1); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/compat.h /tmp/wmlmc6MQoR/tmux-1.1/compat.h --- tmux-1.0/compat.h 2009-09-04 15:47:31.000000000 +0100 +++ tmux-1.1/compat.h 2009-10-06 16:32:21.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: compat.h,v 1.17 2009/09/03 20:54:39 tcunha Exp $ */ +/* $Id: compat.h,v 1.19 2009/10/06 15:32:21 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -91,10 +91,6 @@ #include "compat/imsg.h" #endif -#ifdef HAVE_LOGIN_CAP -#include -#endif - #ifdef HAVE_BROKEN_CMSG_FIRSTHDR /* Broken on OS X. */ #undef CMSG_FIRSTHDR @@ -142,18 +138,10 @@ } while (0) #endif -#ifndef PASS_MAX -#define PASS_MAX 128 -#endif - #ifndef TTY_NAME_MAX #define TTY_NAME_MAX 32 #endif -#ifndef _PW_BUF_LEN -#define _PW_BUF_LEN 1024 -#endif - #ifndef HAVE_BZERO #define bzero(buf, len) memset((buf), 0, (len)); #endif diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/configure /tmp/wmlmc6MQoR/tmux-1.1/configure --- tmux-1.0/configure 2009-09-20 18:51:54.000000000 +0100 +++ tmux-1.1/configure 2009-10-25 22:09:56.000000000 +0000 @@ -1,5 +1,20 @@ #!/bin/sh -# $Id: configure,v 1.38 2009/09/20 17:51:54 nicm Exp $ +# $Id: configure,v 1.43 2009/10/25 21:45:26 nicm Exp $ +# +# Copyright (c) 2009 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. +# TMUX_PLATFORM=${TMUX_PLATFORM:-`uname -s`} @@ -22,7 +37,6 @@ #undef HAVE_GETOPT #undef HAVE_IMSG #undef HAVE_LIBUTIL_H -#undef HAVE_LOGIN_CAP #undef HAVE_PATHS_H #undef HAVE_POLL #undef HAVE_PROGNAME @@ -51,7 +65,6 @@ #define HAVE_FGETLN #define HAVE_FORKPTY #define HAVE_GETOPT -#define HAVE_LOGIN_CAP #define HAVE_PATHS_H #define HAVE_POLL #define HAVE_PROGNAME @@ -139,15 +152,9 @@ #define HAVE_STRLCPY EOF cat <>$CONFIG_MK -CPPFLAGS+= -I/usr/local/include/ncurses \ - -I/opt/csw/include -I/opt/csw/include/ncurses \ - -I/opt/sfw/include -I/opt/sfw/include/ncurses CFLAGS+= -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS -LDFLAGS+= -L/usr/gnu/lib \ - -L/opt/csw/lib \ - -L/opt/sfw/lib LIBS+= -lcurses -lsocket -lnsl -SRCS+= osdep-unknown.c \ +SRCS+= osdep-sunos.c \ compat/asprintf.c \ compat/daemon.c \ compat/fgetln.c \ @@ -202,7 +209,6 @@ #define HAVE_FORKPTY #define HAVE_GETOPT #define HAVE_LIBUTIL_H -#define HAVE_LOGIN_CAP #define HAVE_PATHS_H #define HAVE_POLL #define HAVE_PROGNAME @@ -212,7 +218,6 @@ #define HAVE_STRLCPY #define HAVE_STRTONUM #define HAVE_STRSEP -#define HAVE_TREE_H #define HAVE_U_INT EOF cat <>$CONFIG_MK @@ -233,7 +238,6 @@ #define HAVE_FGETLN #define HAVE_FORKPTY #define HAVE_GETOPT -#define HAVE_LOGIN_CAP #define HAVE_PATHS_H #define HAVE_POLL #define HAVE_PROGNAME diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/changelog /tmp/wmlmc6MQoR/tmux-1.1/debian/changelog --- tmux-1.0/debian/changelog 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/changelog 2009-12-01 00:36:36.000000000 +0000 @@ -1,6 +1,15 @@ +tmux (1.1-1) unstable; urgency=low + + [ Karl Ferdinand Ebert ] + * New upstream release fixes "tmux does not support screen-256color like + it claims". Thanks very much Tim Allen for pointing this out. + (Closes: #550701). + + -- Karl Ferdinand Ebert Fri, 06 Nov 2009 17:03:29 +0100 + tmux (1.0-1) unstable; urgency=low - * New upstream release (Closes: #548818) + * New upstream release + fixes "add a setenv command like in Screen" (Closes: #531151) + and "Omit tmux-generated line-wrapping newlines from paste buffer" (Closes: #531497) diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/control /tmp/wmlmc6MQoR/tmux-1.1/debian/control --- tmux-1.0/debian/control 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/control 2009-12-01 00:36:36.000000000 +0000 @@ -2,7 +2,7 @@ Section: admin Priority: optional Maintainer: Karl Ferdinand Ebert -Build-Depends: debhelper (>= 7),quilt,libncurses5-dev +Build-Depends: debhelper (>= 7), libncurses5-dev, quilt Standards-Version: 3.8.3 Homepage: http://sf.net/projects/tmux diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/copyright /tmp/wmlmc6MQoR/tmux-1.1/debian/copyright --- tmux-1.0/debian/copyright 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/copyright 2009-12-01 00:36:36.000000000 +0000 @@ -142,3 +142,6 @@ Copyright (C) 2001-2003 Adam Lazur Copyright (C) 2007 Jan Christoph Nordholz +File: debian/patches/08_fix_colours.diff + Copyright (c) 2009 Nicholas Marriott + diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/02_fix_wring_location.diff /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/02_fix_wring_location.diff --- tmux-1.0/debian/patches/02_fix_wring_location.diff 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/02_fix_wring_location.diff 2009-12-01 00:36:36.000000000 +0000 @@ -1,16 +1,16 @@ # correct directory /usr/local --- a/GNUmakefile +++ b/GNUmakefile -@@ -8,7 +8,7 @@ +@@ -23,7 +23,7 @@ - CC?= gcc + CC?= cc CFLAGS+= -DBUILD="\"$(VERSION)\"" -LDFLAGS+= -L/usr/local/lib +LDFLAGS+= -L/usr/lib LIBS+= - ifdef FDEBUG -@@ -30,7 +30,7 @@ + # Sun CC +@@ -51,7 +51,7 @@ endif endif @@ -19,7 +19,7 @@ INSTALLDIR= install -d INSTALLBIN= install -g bin -o root -m 555 INSTALLMAN= install -g bin -o root -m 444 -@@ -59,7 +59,7 @@ +@@ -80,7 +80,7 @@ install: all $(INSTALLDIR) $(DESTDIR)$(PREFIX)/bin $(INSTALLBIN) tmux $(DESTDIR)$(PREFIX)/bin/tmux @@ -31,7 +31,7 @@ -include .depend --- a/Makefile +++ b/Makefile -@@ -9,7 +9,7 @@ +@@ -24,7 +24,7 @@ CC?= cc CFLAGS+= -DBUILD="\"$(VERSION)\"" @@ -40,7 +40,7 @@ LIBS+= .ifdef FDEBUG -@@ -32,7 +32,7 @@ +@@ -47,7 +47,7 @@ .endif .endif @@ -49,7 +49,7 @@ INSTALLDIR= install -d INSTALLBIN= install -g bin -o root -m 555 INSTALLMAN= install -g bin -o root -m 444 -@@ -64,5 +64,5 @@ +@@ -79,5 +79,5 @@ install: all ${INSTALLDIR} ${DESTDIR}${PREFIX}/bin ${INSTALLBIN} tmux ${DESTDIR}${PREFIX}/bin/ diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/02_fix_wring_location.diff.old /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/02_fix_wring_location.diff.old --- tmux-1.0/debian/patches/02_fix_wring_location.diff.old 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/02_fix_wring_location.diff.old 1970-01-01 01:00:00.000000000 +0100 @@ -1,57 +0,0 @@ -#! /bin/sh /usr/share/dpatch/dpatch-run -## 02_fix_wrong_location.dpatch by > -## -## All lines beginning with `## DP:' are a description of the patch. -## DP: correct directory /usr/local - -@DPATCH@ -diff -urNad tmux-0.9~/GNUmakefile tmux-0.9/GNUmakefile ---- tmux-0.9~/GNUmakefile 2009-07-02 00:10:06.000000000 +0200 -+++ tmux-0.9/GNUmakefile 2009-07-07 16:26:34.000000000 +0200 -@@ -8,7 +8,7 @@ - - CC?= gcc - CFLAGS+= -DBUILD="\"$(VERSION)\"" --LDFLAGS+= -L/usr/local/lib -+LDFLAGS+= -L/usr/lib - LIBS+= -lncurses - - # This sort of sucks but gets rid of the stupid warning and should work on -@@ -27,7 +27,7 @@ - CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align - endif - --PREFIX?= /usr/local -+PREFIX?= /usr/ - INSTALLDIR= install -d - INSTALLBIN= install -g bin -o root -m 555 - INSTALLMAN= install -g bin -o root -m 444 -@@ -53,5 +53,5 @@ - install: all - $(INSTALLDIR) $(DESTDIR)$(PREFIX)/bin - $(INSTALLBIN) tmux $(DESTDIR)$(PREFIX)/bin/tmux -- $(INSTALLDIR) $(DESTDIR)$(PREFIX)/man/man1 -- $(INSTALLMAN) tmux.1 $(DESTDIR)$(PREFIX)/man/man1/tmux.1 -+ $(INSTALLDIR) $(DESTDIR)$(PREFIX)/share/man/man1 -+ $(INSTALLMAN) tmux.1 $(DESTDIR)$(PREFIX)/share/man/man1/tmux.1 -diff -urNad tmux-0.9~/Makefile tmux-0.9/Makefile ---- tmux-0.9~/Makefile 2009-07-04 01:42:13.000000000 +0200 -+++ tmux-0.9/Makefile 2009-07-07 16:24:04.000000000 +0200 -@@ -29,7 +29,8 @@ - CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align - .endif - --PREFIX?= /usr/local -+#PREFIX?= /usr/local -+PREFIX?= /usr - INSTALLDIR= install -d - INSTALLBIN= install -g bin -o root -m 555 - INSTALLMAN= install -g bin -o root -m 444 -@@ -58,5 +59,5 @@ - install: all - ${INSTALLDIR} ${DESTDIR}${PREFIX}/bin - ${INSTALLBIN} tmux ${DESTDIR}${PREFIX}/bin/ -- ${INSTALLDIR} ${DESTDIR}${PREFIX}/man/man1 -- ${INSTALLMAN} tmux.1 ${DESTDIR}${PREFIX}/man/man1/ -+ ${INSTALLDIR} ${DESTDIR}${PREFIX}/share/man/man1 -+ ${INSTALLMAN} tmux.1 ${DESTDIR}${PREFIX}/share/man/man1/ diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/03_proper_socket_handling.diff /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/03_proper_socket_handling.diff --- tmux-1.0/debian/patches/03_proper_socket_handling.diff 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/03_proper_socket_handling.diff 2009-12-01 00:36:36.000000000 +0000 @@ -1,7 +1,7 @@ # setting /usr/bin/tmux with sgid and proper location of socket --- a/GNUmakefile +++ b/GNUmakefile -@@ -32,7 +32,7 @@ +@@ -53,7 +53,7 @@ PREFIX?= /usr/ INSTALLDIR= install -d @@ -12,7 +12,7 @@ SRCS= $(shell echo *.c|sed 's|osdep-[a-z0-9]*.c||g') --- a/Makefile +++ b/Makefile -@@ -34,7 +34,7 @@ +@@ -49,7 +49,7 @@ PREFIX?= /usr INSTALLDIR= install -d @@ -34,7 +34,7 @@ #define _PATH_DEV "/dev/" --- a/tmux.c +++ b/tmux.c -@@ -239,7 +239,7 @@ +@@ -264,7 +264,7 @@ u_int uid; uid = getuid(); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/04_dropping_unnecessary_privileges.diff /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/04_dropping_unnecessary_privileges.diff --- tmux-1.0/debian/patches/04_dropping_unnecessary_privileges.diff 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/04_dropping_unnecessary_privileges.diff 2009-12-01 00:36:36.000000000 +0000 @@ -1,7 +1,7 @@ # using setresgid() for safely dropping utmp group membership. --- a/tmux.c +++ b/tmux.c -@@ -236,9 +236,11 @@ +@@ -261,9 +261,11 @@ { char base[MAXPATHLEN], *path; struct stat sb; @@ -14,7 +14,7 @@ xsnprintf(base, MAXPATHLEN, "%s/%s/%s-%d", _PATH_VARRUN, __progname, __progname, uid); if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) -@@ -254,6 +256,9 @@ +@@ -279,6 +281,9 @@ errno = EACCES; return (NULL); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/05_build_kfreebsd_hurd.diff /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/05_build_kfreebsd_hurd.diff --- tmux-1.0/debian/patches/05_build_kfreebsd_hurd.diff 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/05_build_kfreebsd_hurd.diff 2009-12-01 00:36:36.000000000 +0000 @@ -1,7 +1,7 @@ # Enable kFreeBSD and Hurd specific configure script --- a/configure +++ b/configure -@@ -75,7 +75,7 @@ +@@ -88,7 +88,7 @@ EOF ;; # ------------------------------------------------------------------------------ @@ -12,7 +12,7 @@ #define HAVE_BZERO --- a/tmux.h +++ b/tmux.h -@@ -325,6 +325,10 @@ +@@ -399,6 +399,10 @@ char argv[COMMAND_LENGTH]; }; @@ -21,10 +21,10 @@ +#endif + struct msg_identify_data { - char tty[TTY_NAME_MAX]; + char cwd[MAXPATHLEN]; -@@ -916,6 +920,10 @@ - u_int orlower; +@@ -1057,6 +1061,10 @@ + u_char y; }; +#ifndef IOV_MAX diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/06_hardening_write_return.diff /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/06_hardening_write_return.diff --- tmux-1.0/debian/patches/06_hardening_write_return.diff 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/06_hardening_write_return.diff 2009-12-01 00:36:36.000000000 +0000 @@ -1,7 +1,7 @@ # Harden write and chdir because of ignored return value --- a/tty.c +++ b/tty.c -@@ -336,7 +336,8 @@ +@@ -283,7 +283,8 @@ void tty_raw(struct tty *tty, const char *s) { @@ -11,7 +11,7 @@ } void -@@ -369,7 +370,8 @@ +@@ -316,7 +317,8 @@ buffer_write(tty->out, s, strlen(s)); if (tty->log_fd != -1) @@ -21,7 +21,7 @@ } void -@@ -394,7 +396,8 @@ +@@ -342,7 +344,8 @@ } if (tty->log_fd != -1) @@ -31,7 +31,7 @@ } void -@@ -407,7 +410,8 @@ +@@ -355,7 +358,8 @@ break; buffer_write8(tty->out, gu->data[i]); if (tty->log_fd != -1) @@ -40,10 +40,10 @@ + fatal("write failed"); } - width = utf8_width(gu->data); + tty->cx += gu->width; --- a/window.c +++ b/window.c -@@ -490,7 +490,9 @@ +@@ -516,7 +516,9 @@ return (-1); case 0: if (chdir(wp->cwd) != 0) diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/07_fix_hyphen.diff /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/07_fix_hyphen.diff --- tmux-1.0/debian/patches/07_fix_hyphen.diff 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/07_fix_hyphen.diff 2009-12-01 00:36:36.000000000 +0000 @@ -1,7 +1,7 @@ # fixes lintian's complains about missing hyphens. --- a/tmux.1 +++ b/tmux.1 -@@ -330,13 +330,13 @@ +@@ -334,13 +334,13 @@ .Pp Examples include: .Bd -literal -offset indent @@ -16,10 +16,10 @@ -new-window ; split-window -d +new-window ; split-window \-d - - bind-key D detach-client \e\; lock-server .Ed -@@ -643,7 +643,7 @@ + .Sh CLIENTS AND SESSIONS + The following commands are available: +@@ -670,7 +670,7 @@ and the result executed as a command. If .Ar template @@ -28,7 +28,7 @@ This command works only from inside .Nm . .It Xo -@@ -660,7 +660,7 @@ +@@ -687,7 +687,7 @@ and the result executed as a command. If .Ar template @@ -37,7 +37,7 @@ This command works only from inside .Nm . .It Xo -@@ -677,7 +677,7 @@ +@@ -704,7 +704,7 @@ and the result executed as a command. If .Ar template @@ -46,7 +46,16 @@ This command works only from inside .Nm . .It Ic display-panes Op Fl t Ar target-client -@@ -1359,7 +1359,7 @@ +@@ -870,7 +870,7 @@ + option only opens a new pipe if no previous pipe exists, allowing a pipe to + be toggled with a single key, for example: + .Bd -literal -offset indent +-bind-key C-p pipe-pane -o 'cat >>~/output' ++bind-key C-p pipe-pane \-o 'cat >>~/output' + .Ed + .It Xo Ic previous-window + .Op Fl a +@@ -1493,7 +1493,7 @@ Examples are: .Bd -literal -offset indent #(sysctl vm.loadavg) @@ -54,8 +63,8 @@ +#[fg=yellow,bold]#(apm \-l)%%#[default] [#S] .Ed .Pp - Where appropriate, these may be prefixed with a number to specify the maximum -@@ -1539,7 +1539,7 @@ + Where appropriate, special character sequences may be prefixed with a number to +@@ -1673,7 +1673,7 @@ .Ic rename-window . It may be switched off globally with: .Bd -literal -offset indent @@ -64,7 +73,7 @@ .Ed .Pp .It Ic clock-mode-colour Ar colour -@@ -2052,29 +2052,29 @@ +@@ -2189,29 +2189,29 @@ .Pp Changing the default prefix key: .Bd -literal -offset indent diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/patches/.dpkg-source-applied /tmp/wmlmc6MQoR/tmux-1.1/debian/patches/.dpkg-source-applied --- tmux-1.0/debian/patches/.dpkg-source-applied 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/patches/.dpkg-source-applied 2009-12-01 00:36:36.000000000 +0000 @@ -3,3 +3,4 @@ 04_dropping_unnecessary_privileges.diff 05_build_kfreebsd_hurd.diff 06_hardening_write_return.diff +07_fix_hyphen.diff diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/debian/rules /tmp/wmlmc6MQoR/tmux-1.1/debian/rules --- tmux-1.0/debian/rules 2009-12-01 00:36:36.000000000 +0000 +++ tmux-1.1/debian/rules 2009-12-01 00:36:36.000000000 +0000 @@ -2,10 +2,10 @@ export DEB_BUILD_HARDENING=1 -include /usr/share/quilt/quilt.make - configure: configure-stamp +include /usr/share/quilt/quilt.make + configure-stamp: patch dh_testdir ./configure @@ -18,7 +18,7 @@ $(MAKE) touch $@ -clean: unpatch +clean: unpatch dh_testdir dh_testroot rm -f build-stamp configure-stamp diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/examples/h-boetes.conf /tmp/wmlmc6MQoR/tmux-1.1/examples/h-boetes.conf --- tmux-1.0/examples/h-boetes.conf 2009-08-16 22:53:33.000000000 +0100 +++ tmux-1.1/examples/h-boetes.conf 2009-10-25 22:09:57.000000000 +0000 @@ -1,3 +1,7 @@ +# $Id: h-boetes.conf,v 1.2 2009/10/25 21:45:26 nicm Exp $ +# +# From Han Boetes. + set -g default-command zsh set -g status-right "#(uptime|awk '{print $11}') #(date)" diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/examples/n-marriott.conf /tmp/wmlmc6MQoR/tmux-1.1/examples/n-marriott.conf --- tmux-1.0/examples/n-marriott.conf 2009-07-14 18:44:09.000000000 +0100 +++ tmux-1.1/examples/n-marriott.conf 2009-10-25 22:09:57.000000000 +0000 @@ -1,52 +1,66 @@ +# $Id: n-marriott.conf,v 1.10 2009/10/25 21:45:26 nicm Exp $ +# +# By Nicholas Marriott. Public domain. + # Default global options. set -g status-bg green -set -g status-right-length 60 -set -g default-command "exec /bin/ksh -l" +set -g status-right "%H:%M" # %d-%b-%y set -g bell-action none set -g lock-after-time 1800 # Default global window options. -#setw -g remain-on-exit on +setw -g remain-on-exit on +setw -g window-status-current-attr "underscore" # Prefix key. set -g prefix C-a unbind C-b bind C-a send-prefix -# Unlock password. -pass -c '$2a$06$7LpuTSfDjcz.KD3a9mdEuuJmC.zEq6RBqHWMjdv9/qqzrfWedUBHe' - # Keys to switch session. -bind q switchc -t0 -bind w switchc -t1 -bind e switchc -t2 +bind Q switchc -t0 +bind W switchc -t1 +bind E switchc -t2 # Other key bindings. -bind i choose-window +bind F1 selectw -t:10 +bind F2 selectw -t:11 +bind F3 selectw -t:12 +bind F4 selectw -t:13 +bind F5 selectw -t:14 +bind F6 selectw -t:15 +bind F7 selectw -t:16 +bind F8 selectw -t:17 +bind F9 selectw -t:18 +bind F10 selectw -t:19 +bind F11 selectw -t:20 +bind F12 selectw -t:21 bind m setw monitor-activity bind y setw force-width 81 bind u setw force-width 0 -bind D detach \; lock -bind N neww \; splitw -d - -bind '~' split-window "exec top -s 0.5" -bind "#" split-window "exec ncmpc -f ~/.ncmpc.conf" -bind / command-prompt "split-window 'exec man %%'" +bind -n F1 run-shell 'mpc toggle >/dev/null 2>&1' +bind -n F2 run-shell 'mpc' +bind -n F3 run-shell 'mpc prev >/dev/null 2>&1' +bind -n F4 run-shell 'mpc next >/dev/null 2>&1' +bind -n F5 run-shell 'mpc volume -5 >/dev/null 2>&1' +bind -n F6 run-shell 'mpc volume +5 >/dev/null 2>&1' # First session. -new -d -s0 -nirssi 'exec ssh -t natalya screen -DRS irssi irssi' +new -d -s0 -nirssi 'exec ssh -t natalya exec sh ~/bin/tmux-start' setw -t0:0 monitor-activity on setw -t0:0 aggressive-resize on set -t0 status-bg green neww -d -ntodo 'exec emacs ~/TODO' setw -t0:1 aggressive-resize on -neww -d -nncmpc 'exec ncmpc -f ~/.ncmpc.conf' +neww -d -ntodo2 'exec emacs ~/TODO2' setw -t0:2 aggressive-resize on -neww -d -nmutt 'exec mutt' +neww -d -nncmpc 'exec ncmpc -f ~/.ncmpc.conf' setw -t0:3 aggressive-resize on +neww -d -nmutt 'exec mutt' +setw -t0:4 aggressive-resize on neww -d neww -d neww -d @@ -63,6 +77,7 @@ linkw -dk -t1 -s0:1 linkw -dk -t2 -s0:2 linkw -dk -t3 -s0:3 +linkw -dk -t4 -s0:4 neww -d neww -d neww -d @@ -77,6 +92,7 @@ linkw -dk -t1 -s0:1 linkw -dk -t2 -s0:2 linkw -dk -t3 -s0:3 +linkw -dk -t4 -s0:4 neww -d neww -d neww -d diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/examples/n-marriott.sh /tmp/wmlmc6MQoR/tmux-1.1/examples/n-marriott.sh --- tmux-1.0/examples/n-marriott.sh 2009-04-20 20:23:36.000000000 +0100 +++ tmux-1.1/examples/n-marriott.sh 1970-01-01 01:00:00.000000000 +0100 @@ -1,11 +0,0 @@ -#!/bin/sh -x - -[ ! -z "$TMUX" ] && exit - -# I alias this script to "session" in .profile and use it to reconnect to -# the main session (0) on my main tmux server. - -TMUX="tmux -dLmain" - -$TMUX has -t0 2>/dev/null || $TMUX -qf ~/.tmux.conf.main start -exec $TMUX attach -d -t0 diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/examples/screen-keys.conf /tmp/wmlmc6MQoR/tmux-1.1/examples/screen-keys.conf --- tmux-1.0/examples/screen-keys.conf 2009-08-07 13:09:50.000000000 +0100 +++ tmux-1.1/examples/screen-keys.conf 2009-10-25 22:09:57.000000000 +0000 @@ -1,4 +1,6 @@ -# $Id: screen-keys.conf,v 1.3 2009/08/07 12:09:50 nicm Exp $ +# $Id: screen-keys.conf,v 1.5 2009/10/25 21:58:05 nicm Exp $ +# +# By Nicholas Marriott. Public domain. # # This configuration file binds many of the common GNU screen key bindings to # appropriate tmux key bindings. Note that for some key bindings there is no @@ -73,13 +75,13 @@ # quit \ unbind \ -bind \ kill-server +bind \ confirm-before "kill-server" # kill K k unbind K -bind K kill-window +bind K confirm-before "kill-window" unbind k -bind k kill-window +bind k confirm-before "kill-window" # redisplay ^L l unbind ^L diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/examples/tmux.vim /tmp/wmlmc6MQoR/tmux-1.1/examples/tmux.vim --- tmux-1.0/examples/tmux.vim 2009-09-20 19:11:24.000000000 +0100 +++ tmux-1.1/examples/tmux.vim 2009-10-25 22:16:55.000000000 +0000 @@ -1,7 +1,8 @@ " Vim syntax file " Language: tmux(1) configuration file " Maintainer: Tiago Cunha -" Last Change: $Date: 2009/09/19 18:53:56 $ +" Last Change: $Date: 2009/10/25 22:16:55 $ +" License: This file is placed in the public domain. if version < 600 syntax clear @@ -23,14 +24,14 @@ syn keyword tmuxCmds list-clients linkw link-window unlinkw unlink-window syn keyword tmuxCmds next[-window] send[-keys] swapw swap-window syn keyword tmuxCmds rename[-session] kill-session switchc switch-client -syn keyword tmuxCmds has[-session] scroll-mode copy-mode pasteb paste-buffer +syn keyword tmuxCmds has[-session] copy-mode pasteb paste-buffer syn keyword tmuxCmds new[-session] start[-server] kill-server setw syn keyword tmuxCmds set-window-option show[-options] showw show-window-options syn keyword tmuxCmds command-prompt setb set-buffer showb show-buffer lsb syn keyword tmuxCmds list-buffers deleteb delete-buffer lscm list-commands syn keyword tmuxCmds movew move-window select-prompt respawnw respawn-window syn keyword tmuxCmds source[-file] info server-info clock-mode lock[-server] -syn keyword tmuxCmds pass set-password saveb save-buffer downp down-pane killp +syn keyword tmuxCmds saveb save-buffer downp down-pane killp syn keyword tmuxCmds kill-pane resizep resize-pane selectp select-pane swapp syn keyword tmuxCmds swap-pane splitw split-window upp up-pane choose-session syn keyword tmuxCmds choose-window loadb load-buffer copyb copy-buffer suspendc @@ -38,7 +39,9 @@ syn keyword tmuxCmds next-layout rotatew rotate-window confirm[-before] syn keyword tmuxCmds clearhist clear-history selectl select-layout if[-shell] syn keyword tmuxCmds display[-message] set-environment show-environment -syn keyword tmuxCmds choose-client displayp display-panes +syn keyword tmuxCmds choose-client displayp display-panes run[-shell] lockc +syn keyword tmuxCmds lock-client locks lock-session lsp list-panes pipep +syn keyword tmuxCmds pipe-pane syn keyword tmuxOptsSet prefix status status-fg status-bg bell-action syn keyword tmuxOptsSet default-command history-limit status-left status-right @@ -52,7 +55,8 @@ syn keyword tmuxOptsSet status-left-fg status-right-attr status-right-bg syn keyword tmuxOptsSet status-right-fg update-environment base-index syn keyword tmuxOptsSet display-panes-colour display-panes-time default-shell -syn keyword tmuxOptsSet set-titles-string +syn keyword tmuxOptsSet set-titles-string lock-command lock-server +syn keyword tmuxOptsSet mouse-select-pane syn keyword tmuxOptsSetw monitor-activity aggressive-resize force-width syn keyword tmuxOptsSetw force-height remain-on-exit uft8 mode-fg mode-bg @@ -61,7 +65,7 @@ syn keyword tmuxOptsSetw window-status-bg window-status-fg automatic-rename syn keyword tmuxOptsSetw main-pane-width main-pane-height monitor-content syn keyword tmuxOptsSetw window-status-current-attr window-status-current-bg -syn keyword tmuxOptsSetw window-status-current-fg mode-mouse +syn keyword tmuxOptsSetw window-status-current-fg mode-mouse synchronize-panes syn keyword tmuxTodo FIXME NOTE TODO XXX contained diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/examples/t-williams.conf /tmp/wmlmc6MQoR/tmux-1.1/examples/t-williams.conf --- tmux-1.0/examples/t-williams.conf 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/examples/t-williams.conf 2009-11-02 18:59:28.000000000 +0000 @@ -0,0 +1,104 @@ +# $Id: t-williams.conf,v 1.1 2009/11/02 18:59:28 nicm Exp $ +# +# ~/.tmux.conf - tmux terminal multiplexer config +# Thayer Williams (http://cinderwick.ca) +# "Feel free to do whatever you like with it." + +# I typically start tmux from ~/.xinitrc with the following: +# +# urxvt -e bash -c "tmux attach -d -t mysession" & +# +# and recall it any time thereafter with xbindkeys (Mod4+s): +# +# "urxvt -e bash -c 'tmux attach -d -t mysession'" +# m:0x50 + c:39 + + +# set prefix key to ctrl+a until I have time to adapt +unbind C-b +set -g prefix C-a + +# send the prefix to client inside window (ala nested sessions) +bind-key a send-prefix + +# toggle last window like screen +bind-key C-a last-window + +# confirm before killing a window or the server +bind-key k confirm kill-window +bind-key K confirm kill-server + +# toggle statusbar +bind-key b set-option status + +# ctrl+left/right cycles thru windows +bind-key -n C-right next +bind-key -n C-left prev + +# open a man page in new window +bind / command-prompt "split-window 'exec man %%'" + +# quick view of processes +bind '~' split-window "exec htop" + +# scrollback buffer n lines +set -g history-limit 5000 + +# listen for activity on all windows +set -g bell-action any + +# on-screen time for display-panes in ms +set -g display-panes-time 2000 + +# start window indexing at one instead of zero +set -g base-index 1 + +# enable wm window titles +set -g set-titles on + +# wm window title string (uses statusbar variables) +set -g set-titles-string "tmux.#I.#W" + +# session initialization +new -s mysession mutt +neww -t 2 +neww -d -t 3 +neww -d -t 5 mocp +neww -d -t 6 rtorrent +selectw -t 1 + +# statusbar -------------------------------------------------------------- + +set -g display-time 2000 + +# default statusbar colors +set -g status-fg white +set -g status-bg default +set -g status-attr default + +# default window title colors +set-window-option -g window-status-fg cyan +set-window-option -g window-status-bg default +set-window-option -g window-status-attr dim + +# active window title colors +set-window-option -g window-status-current-fg white +set-window-option -g window-status-current-bg default +set-window-option -g window-status-current-attr bright + +# command/message line colors +set -g message-fg white +set -g message-bg black +set -g message-attr bright + +# center align the window list +set -g status-justify centre + +# show some useful stats but only when tmux is started +# outside of Xorg, otherwise dwm statusbar shows these already +set -g status-right "" +set -g status-left "" +if '[ -z "$DISPLAY" ]' 'set -g status-left "[#[fg=green] #H #[default]]"' +if '[ -z "$DISPLAY" ]' 'set -g status-right "[ #[fg=magenta]#(cat /proc/loadavg | cut -d \" \" -f 1,2,3)#[default] ][ #[fg=cyan,bright]%a %Y-%m-%d %H:%M #[default]]"' +if '[ -z "$DISPLAY" ]' 'set -g status-right-length 50' + diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/GNUmakefile /tmp/wmlmc6MQoR/tmux-1.1/GNUmakefile --- tmux-1.0/GNUmakefile 2009-09-20 19:12:05.000000000 +0100 +++ tmux-1.1/GNUmakefile 2009-11-05 12:30:55.000000000 +0000 @@ -1,16 +1,37 @@ -# $Id: GNUmakefile,v 1.113 2009/08/26 08:58:39 nicm Exp $ +# $Id: GNUmakefile,v 1.120 2009/11/05 12:30:55 tcunha Exp $ +# +# Copyright (c) 2009 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. +# .PHONY: clean -VERSION= 1.0 +VERSION= 1.1 #FDEBUG= 1 -CC?= gcc +CC?= cc CFLAGS+= -DBUILD="\"$(VERSION)\"" LDFLAGS+= -L/usr/local/lib LIBS+= +# Sun CC +ifneq ($(shell ($(CC) -V 2>&1|awk '/Sun C/' || true)), ) + CFLAGS+=-erroff=E_EMPTY_DECLARATION + FDEBUG= +endif + ifdef FDEBUG CFLAGS+= -g -ggdb -DDEBUG CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 @@ -48,7 +69,7 @@ $(CC) $(CPPFLAGS) $(CFLAGS) -MM $(SRCS) > .depend clean: - rm -f tmux *.o *~ *.core *.log compat/*.o + rm -f tmux *.o *~ *.core *.log compat/*.o compat/*~ clean-depend: rm -f .depend diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/grid.c /tmp/wmlmc6MQoR/tmux-1.1/grid.c --- tmux-1.0/grid.c 2009-09-16 13:28:52.000000000 +0100 +++ tmux-1.1/grid.c 2009-10-15 02:55:12.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: grid.c,v 1.33 2009/09/15 23:54:57 tcunha Exp $ */ +/* $Id: grid.c,v 1.34 2009/10/15 01:55:12 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -161,29 +161,77 @@ return (0); } -/* Scroll a line into the history. */ +/* + * Collect lines from the history if at the limit. Free the top (oldest) 10% + * and shift up. + */ void -grid_scroll_line(struct grid *gd) +grid_collect_history(struct grid *gd) { u_int yy; GRID_DEBUG(gd, ""); - if (gd->hsize >= gd->hlimit) { - /* If the limit is hit, free the bottom 10% and shift up. */ - yy = gd->hlimit / 10; - if (yy < 1) - yy = 1; + if (gd->hsize < gd->hlimit) + return; - grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); - gd->hsize -= yy; - } + yy = gd->hlimit / 10; + if (yy < 1) + yy = 1; - yy = gd->hsize + gd->sy; + grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); + gd->hsize -= yy; +} + +/* + * Scroll the entire visible screen, moving one line into the history. Just + * allocate a new line at the bottom and move the history size indicator. + */ +void +grid_scroll_history(struct grid *gd) +{ + u_int yy; + + GRID_DEBUG(gd, ""); + yy = gd->hsize + gd->sy; gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); + + gd->hsize++; +} + +/* Scroll a region up, moving the top line into the history. */ +void +grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower) +{ + struct grid_line *gl_history, *gl_upper, *gl_lower; + u_int yy; + + GRID_DEBUG(gd, "upper=%u, lower=%u", upper, lower); + + /* Create a space for a new line. */ + yy = gd->hsize + gd->sy; + gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); + + /* Move the entire screen down to free a space for this line. */ + gl_history = &gd->linedata[gd->hsize]; + memmove(gl_history + 1, gl_history, gd->sy * sizeof *gl_history); + + /* Adjust the region and find its start and end. */ + upper++; + gl_upper = &gd->linedata[upper]; + lower++; + gl_lower = &gd->linedata[lower]; + + /* Move the line into the history. */ + memcpy(gl_history, gl_upper, sizeof *gl_history); + + /* Then move the region up and clear the bottom line. */ + memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper); + memset(gl_lower, 0, sizeof *gl_lower); + /* Move the history offset down over the line. */ gd->hsize++; } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/grid-view.c /tmp/wmlmc6MQoR/tmux-1.1/grid-view.c --- tmux-1.0/grid-view.c 2009-07-14 07:40:33.000000000 +0100 +++ tmux-1.1/grid-view.c 2009-10-15 02:55:12.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: grid-view.c,v 1.18 2009/07/14 06:40:33 nicm Exp $ */ +/* $Id: grid-view.c,v 1.19 2009/10/15 01:55:12 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -92,15 +92,20 @@ { GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); - if (gd->flags & GRID_HISTORY && rupper == 0 && rlower == gd->sy - 1) { - grid_scroll_line(gd); - return; + if (gd->flags & GRID_HISTORY) { + grid_collect_history(gd); + if (rupper == 0 && rlower == gd->sy - 1) + grid_scroll_history(gd); + else { + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + grid_scroll_history_region(gd, rupper, rlower); + } + } else { + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + grid_move_lines(gd, rupper, rupper + 1, rlower - rupper); } - - rupper = grid_view_y(gd, rupper); - rlower = grid_view_y(gd, rlower); - - grid_move_lines(gd, rupper, rupper + 1, rlower - rupper); } /* Scroll region down. */ diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/input.c /tmp/wmlmc6MQoR/tmux-1.1/input.c --- tmux-1.0/input.c 2009-08-23 12:50:31.000000000 +0100 +++ tmux-1.1/input.c 2009-10-28 23:12:38.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: input.c,v 1.95 2009/08/21 21:07:20 tcunha Exp $ */ +/* $Id: input.c,v 1.101 2009/10/28 23:12:38 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -128,7 +128,7 @@ void input_new_argument(struct input_ctx *ictx) { - struct input_arg *arg; + struct input_arg *arg; ARRAY_EXPAND(&ictx->args, 1); @@ -139,7 +139,7 @@ int input_add_argument(struct input_ctx *ictx, u_char ch) { - struct input_arg *arg; + struct input_arg *arg; if (ARRAY_LENGTH(&ictx->args) == 0) return (0); @@ -572,15 +572,14 @@ void input_state_utf8(u_char ch, struct input_ctx *ictx) { - log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch); + log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch); - ictx->utf8_buf[ictx->utf8_off++] = ch; - if (--ictx->utf8_len != 0) - return; + if (utf8_append(&ictx->utf8data, ch)) + return; /* more to come */ input_state(ictx, input_state_first); ictx->cell.flags |= GRID_FLAG_UTF8; - screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); + screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); ictx->cell.flags &= ~GRID_FLAG_UTF8; } @@ -590,40 +589,17 @@ struct window_pane *wp = ictx->wp; if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { - /* - * UTF-8 sequence. - * - * 11000010-11011111 C2-DF start of 2-byte sequence - * 11100000-11101111 E0-EF start of 3-byte sequence - * 11110000-11110100 F0-F4 start of 4-byte sequence - */ - memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf); - ictx->utf8_buf[0] = ch; - ictx->utf8_off = 1; - - if (ch >= 0xc2 && ch <= 0xdf) { - log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch); + if (utf8_open(&ictx->utf8data, ch)) { + log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", + ictx->utf8data.size, ictx->off, ch, ch); input_state(ictx, input_state_utf8); - ictx->utf8_len = 1; - return; - } - if (ch >= 0xe0 && ch <= 0xef) { - log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch); - input_state(ictx, input_state_utf8); - ictx->utf8_len = 2; - return; - } - if (ch >= 0xf0 && ch <= 0xf4) { - log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch); - input_state(ictx, input_state_utf8); - ictx->utf8_len = 3; return; } } log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); ictx->cell.data = ch; - screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); + screen_write_cell(&ictx->ctx, &ictx->cell, NULL); } void @@ -646,7 +622,7 @@ ictx->wp->window->flags |= WINDOW_BELL; break; case '\010': /* BS */ - screen_write_cursorleft(&ictx->ctx, 1); + screen_write_backspace(&ictx->ctx); break; case '\011': /* TAB */ /* Don't tab beyond the end of the line. */ @@ -816,7 +792,7 @@ { struct input_sequence_entry *entry, find; struct screen *s = ictx->ctx.s; - u_int i; + u_int i; struct input_arg *iarg; log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, " @@ -1185,6 +1161,10 @@ screen_write_kcursormode(&ictx->ctx, 1); log_debug("kcursor on"); break; + case 3: /* DECCOLM */ + screen_write_cursormove(&ictx->ctx, 0, 0); + screen_write_clearscreen(&ictx->ctx); + break; case 25: /* TCEM */ screen_write_cursormode(&ictx->ctx, 1); log_debug("cursor on"); @@ -1257,6 +1237,10 @@ screen_write_kcursormode(&ictx->ctx, 0); log_debug("kcursor off"); break; + case 3: /* DECCOLM */ + screen_write_cursormove(&ictx->ctx, 0, 0); + screen_write_clearscreen(&ictx->ctx); + break; case 25: /* TCEM */ screen_write_cursormode(&ictx->ctx, 0); log_debug("cursor off"); @@ -1486,6 +1470,28 @@ gc->flags &= ~GRID_FLAG_BG256; gc->bg = 8; break; + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + gc->flags |= GRID_FLAG_FG256; + gc->fg = m - 82; + break; + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + gc->flags |= GRID_FLAG_BG256; + gc->bg = m - 92; + break; } } } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/input-keys.c /tmp/wmlmc6MQoR/tmux-1.1/input-keys.c --- tmux-1.0/input-keys.c 2009-07-30 21:14:57.000000000 +0100 +++ tmux-1.1/input-keys.c 2009-10-28 23:05:01.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: input-keys.c,v 1.29 2009/07/28 22:37:02 tcunha Exp $ */ +/* $Id: input-keys.c,v 1.39 2009/10/28 23:05:01 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -24,6 +24,13 @@ #include "tmux.h" +/* + * This file is rather misleadingly named, it contains the code which takes a + * key code and translates it into something suitable to be sent to the + * application running in a pane (similar to input.c does in the other + * direction with output). + */ + struct input_key_ent { int key; const char *data; @@ -31,111 +38,138 @@ int flags; #define INPUTKEY_KEYPAD 0x1 /* keypad key */ #define INPUTKEY_CURSOR 0x2 /* cursor key */ -#define INPUTKEY_CTRL 0x4 /* may be modified with ctrl */ -#define INPUTKEY_XTERM 0x4 /* may have xterm argument appended */ }; struct input_key_ent input_keys[] = { /* Backspace key. */ - { KEYC_BSPACE, "\177", 0 }, + { KEYC_BSPACE, "\177", 0 }, /* Function keys. */ - { KEYC_F1, "\033OP", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F2, "\033OQ", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F3, "\033OR", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F4, "\033OS", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F5, "\033[15~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F6, "\033[17~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F7, "\033[18~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F8, "\033[19~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F9, "\033[20~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F10, "\033[21~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F11, "\033[23~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F12, "\033[24~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F13, "\033[25~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F14, "\033[26~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F15, "\033[28~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F16, "\033[29~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F17, "\033[31~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F18, "\033[32~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F19, "\033[33~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_F20, "\033[34~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_IC, "\033[2~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_DC, "\033[3~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_HOME, "\033[1~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_END, "\033[4~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL|INPUTKEY_XTERM }, - { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL }, - - /* Arrow keys. Cursor versions must come first. */ - { KEYC_UP | KEYC_CTRL, "\033Oa", 0 }, - { KEYC_DOWN | KEYC_CTRL, "\033Ob", 0 }, - { KEYC_RIGHT | KEYC_CTRL, "\033Oc", 0 }, - { KEYC_LEFT | KEYC_CTRL, "\033Od", 0 }, - - { KEYC_UP | KEYC_SHIFT, "\033[a", 0 }, - { KEYC_DOWN | KEYC_SHIFT, "\033[b", 0 }, - { KEYC_RIGHT | KEYC_SHIFT, "\033[c", 0 }, - { KEYC_LEFT | KEYC_SHIFT, "\033[d", 0 }, + { KEYC_F1, "\033OP", 0 }, + { KEYC_F2, "\033OQ", 0 }, + { KEYC_F3, "\033OR", 0 }, + { KEYC_F4, "\033OS", 0 }, + { KEYC_F5, "\033[15~", 0 }, + { KEYC_F5|KEYC_CTRL, "\033[15^", 0 }, + { KEYC_F6, "\033[17~", 0 }, + { KEYC_F6|KEYC_CTRL, "\033[17^", 0 }, + { KEYC_F7, "\033[18~", 0 }, + { KEYC_F7|KEYC_CTRL, "\033[18^", 0 }, + { KEYC_F8, "\033[19~", 0 }, + { KEYC_F8|KEYC_CTRL, "\033[19^", 0 }, + { KEYC_F9, "\033[20~", 0 }, + { KEYC_F9|KEYC_CTRL, "\033[20^", 0 }, + { KEYC_F10, "\033[21~", 0 }, + { KEYC_F10|KEYC_CTRL, "\033[21^", 0 }, + { KEYC_F11, "\033[23~", 0 }, + { KEYC_F1|KEYC_CTRL, "\033[23^", 0 }, + { KEYC_F12, "\033[24~", 0 }, + { KEYC_F12|KEYC_CTRL, "\033[24^", 0 }, + { KEYC_F13, "\033[25~", 0 }, + { KEYC_F13|KEYC_CTRL, "\033[25^", 0 }, + { KEYC_F14, "\033[26~", 0 }, + { KEYC_F14|KEYC_CTRL, "\033[26^", 0 }, + { KEYC_F15, "\033[28~", 0 }, + { KEYC_F15|KEYC_CTRL, "\033[28^", 0 }, + { KEYC_F16, "\033[29~", 0 }, + { KEYC_F16|KEYC_CTRL, "\033[29^", 0 }, + { KEYC_F17, "\033[31~", 0 }, + { KEYC_F17|KEYC_CTRL, "\033[31^", 0 }, + { KEYC_F18, "\033[32~", 0 }, + { KEYC_F18|KEYC_CTRL, "\033[32^", 0 }, + { KEYC_F19, "\033[33~", 0 }, + { KEYC_F19|KEYC_CTRL, "\033[33^", 0 }, + { KEYC_F20, "\033[34~", 0 }, + { KEYC_F20|KEYC_CTRL, "\033[34^", 0 }, + { KEYC_IC, "\033[2~", 0 }, + { KEYC_IC|KEYC_CTRL, "\033[2^", 0 }, + { KEYC_DC, "\033[3~", 0 }, + { KEYC_DC|KEYC_CTRL, "\033[3^", 0 }, + { KEYC_HOME, "\033[1~", 0 }, + { KEYC_HOME|KEYC_CTRL, "\033[1^", 0 }, + { KEYC_END, "\033[4~", 0 }, + { KEYC_END|KEYC_CTRL, "\033[4^", 0 }, + { KEYC_NPAGE, "\033[6~", 0 }, + { KEYC_NPAGE|KEYC_CTRL, "\033[6^", 0 }, + { KEYC_PPAGE, "\033[5~", 0 }, + { KEYC_PPAGE|KEYC_CTRL, "\033[5^", 0 }, + { KEYC_BTAB, "\033[Z", 0 }, + + /* + * Arrow keys. Cursor versions must come first. The codes are toggled + * between CSI and SS3 versions when ctrl is pressed. + */ + { KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR }, + { KEYC_DOWN|KEYC_CTRL, "\033[B", INPUTKEY_CURSOR }, + { KEYC_RIGHT|KEYC_CTRL, "\033[C", INPUTKEY_CURSOR }, + { KEYC_LEFT|KEYC_CTRL, "\033[D", INPUTKEY_CURSOR }, - { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, - { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, - { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, - { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, - - { KEYC_UP, "\033[A", 0 }, - { KEYC_DOWN, "\033[B", 0 }, - { KEYC_RIGHT, "\033[C", 0 }, - { KEYC_LEFT, "\033[D", 0 }, + { KEYC_UP, "\033OA", INPUTKEY_CURSOR }, + { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, + { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, + { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, + + { KEYC_UP|KEYC_CTRL, "\033OA", 0 }, + { KEYC_DOWN|KEYC_CTRL, "\033OB", 0 }, + { KEYC_RIGHT|KEYC_CTRL, "\033OC", 0 }, + { KEYC_LEFT|KEYC_CTRL, "\033OD", 0 }, + + { KEYC_UP, "\033[A", 0 }, + { KEYC_DOWN, "\033[B", 0 }, + { KEYC_RIGHT, "\033[C", 0 }, + { KEYC_LEFT, "\033[D", 0 }, /* Keypad keys. Keypad versions must come first. */ - { KEYC_KP0_1, "/", INPUTKEY_KEYPAD }, - { KEYC_KP0_2, "*", INPUTKEY_KEYPAD }, - { KEYC_KP0_3, "-", INPUTKEY_KEYPAD }, - { KEYC_KP1_0, "7", INPUTKEY_KEYPAD }, - { KEYC_KP1_1, "8", INPUTKEY_KEYPAD }, - { KEYC_KP1_2, "9", INPUTKEY_KEYPAD }, - { KEYC_KP1_3, "+", INPUTKEY_KEYPAD }, - { KEYC_KP2_0, "4", INPUTKEY_KEYPAD }, - { KEYC_KP2_1, "5", INPUTKEY_KEYPAD }, - { KEYC_KP2_2, "6", INPUTKEY_KEYPAD }, - { KEYC_KP3_0, "1", INPUTKEY_KEYPAD }, - { KEYC_KP3_1, "2", INPUTKEY_KEYPAD }, - { KEYC_KP3_2, "3", INPUTKEY_KEYPAD }, - { KEYC_KP3_3, "\n", INPUTKEY_KEYPAD }, /* this can be CRLF too? */ - { KEYC_KP4_0, "0", INPUTKEY_KEYPAD }, - { KEYC_KP4_2, ".", INPUTKEY_KEYPAD }, - { KEYC_KP0_1, "\033Oo", 0 }, - { KEYC_KP0_2, "\033Oj", 0 }, - { KEYC_KP0_3, "\033Om", 0 }, - { KEYC_KP1_0, "\033Ow", 0 }, - { KEYC_KP1_1, "\033Ox", 0 }, - { KEYC_KP1_2, "\033Oy", 0 }, - { KEYC_KP1_3, "\033Ok", 0 }, - { KEYC_KP2_0, "\033Ot", 0 }, - { KEYC_KP2_1, "\033Ou", 0 }, - { KEYC_KP2_2, "\033Ov", 0 }, - { KEYC_KP3_0, "\033Oq", 0 }, - { KEYC_KP3_1, "\033Or", 0 }, - { KEYC_KP3_2, "\033Os", 0 }, - { KEYC_KP3_3, "\033OM", 0 }, - { KEYC_KP4_0, "\033Op", 0 }, - { KEYC_KP4_2, "\033On", 0 }, + { KEYC_KP_SLASH, "/", INPUTKEY_KEYPAD }, + { KEYC_KP_STAR, "*", INPUTKEY_KEYPAD }, + { KEYC_KP_MINUS, "-", INPUTKEY_KEYPAD }, + { KEYC_KP_SEVEN, "7", INPUTKEY_KEYPAD }, + { KEYC_KP_EIGHT, "8", INPUTKEY_KEYPAD }, + { KEYC_KP_NINE, "9", INPUTKEY_KEYPAD }, + { KEYC_KP_PLUS, "+", INPUTKEY_KEYPAD }, + { KEYC_KP_FOUR, "4", INPUTKEY_KEYPAD }, + { KEYC_KP_FIVE, "5", INPUTKEY_KEYPAD }, + { KEYC_KP_SIX, "6", INPUTKEY_KEYPAD }, + { KEYC_KP_ONE, "1", INPUTKEY_KEYPAD }, + { KEYC_KP_TWO, "2", INPUTKEY_KEYPAD }, + { KEYC_KP_THREE, "3", INPUTKEY_KEYPAD }, + { KEYC_KP_ENTER, "\n", INPUTKEY_KEYPAD }, + { KEYC_KP_ZERO, "0", INPUTKEY_KEYPAD }, + { KEYC_KP_PERIOD, ".", INPUTKEY_KEYPAD }, + + { KEYC_KP_SLASH, "\033Oo", 0 }, + { KEYC_KP_STAR, "\033Oj", 0 }, + { KEYC_KP_MINUS, "\033Om", 0 }, + { KEYC_KP_SEVEN, "\033Ow", 0 }, + { KEYC_KP_EIGHT, "\033Ox", 0 }, + { KEYC_KP_NINE, "\033Oy", 0 }, + { KEYC_KP_PLUS, "\033Ok", 0 }, + { KEYC_KP_FOUR, "\033Ot", 0 }, + { KEYC_KP_FIVE, "\033Ou", 0 }, + { KEYC_KP_SIX, "\033Ov", 0 }, + { KEYC_KP_ONE, "\033Oq", 0 }, + { KEYC_KP_TWO, "\033Or", 0 }, + { KEYC_KP_THREE, "\033Os", 0 }, + { KEYC_KP_ENTER, "\033OM", 0 }, + { KEYC_KP_ZERO, "\033Op", 0 }, + { KEYC_KP_PERIOD, "\033On", 0 }, }; -/* Translate a key code from client into an output key sequence. */ +/* Translate a key code into an output key sequence. */ void input_key(struct window_pane *wp, int key) { struct input_key_ent *ike; u_int i; - char ch; size_t dlen; - int xterm_keys; + char *out; log_debug2("writing key 0x%x", key); + /* + * If this is a normal 7-bit key, just send it, with a leading escape + * if necessary. + */ if (key != KEYC_NONE && (key & ~KEYC_ESCAPE) < 0x100) { if (key & KEYC_ESCAPE) buffer_write8(wp->out, '\033'); @@ -143,6 +177,19 @@ return; } + /* + * Then try to look this up as an xterm key, if the flag to output them + * is set. + */ + if (options_get_number(&wp->window->options, "xterm-keys")) { + if ((out = xterm_keys_lookup(key)) != NULL) { + buffer_write(wp->out, out, strlen(out)); + xfree(out); + return; + } + } + + /* Otherwise look the key up in the table. */ for (i = 0; i < nitems(input_keys); i++) { ike = &input_keys[i]; @@ -155,12 +202,6 @@ if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key) break; - if ((key & KEYC_SHIFT) && (ike->key | KEYC_SHIFT) == key) - break; - if ((key & KEYC_CTRL) && (ike->key | KEYC_CTRL) == key) { - if (ike->flags & INPUTKEY_CTRL) - break; - } if (ike->key == key) break; } @@ -169,62 +210,22 @@ return; } dlen = strlen(ike->data); - log_debug2("found key 0x%x: \"%s\"", key, ike->data); - /* - * If in xterm keys mode, work out and append the modifier as an - * argument. - */ - xterm_keys = options_get_number(&wp->window->options, "xterm-keys"); - if (xterm_keys && ike->flags & INPUTKEY_XTERM) { - ch = '\0'; - if (key & (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) - ch = '8'; - else if (key & (KEYC_ESCAPE|KEYC_CTRL)) - ch = '7'; - else if (key & (KEYC_SHIFT|KEYC_CTRL)) - ch = '6'; - else if (key & KEYC_CTRL) - ch = '5'; - else if (key & (KEYC_SHIFT|KEYC_ESCAPE)) - ch = '4'; - else if (key & KEYC_ESCAPE) - ch = '3'; - else if (key & KEYC_SHIFT) - ch = '2'; - if (ch != '\0') { - buffer_write(wp->out, ike->data, dlen - 1); - buffer_write8(wp->out, ';'); - buffer_write8(wp->out, ch); - buffer_write8(wp->out, ike->data[dlen - 1]); - } else - buffer_write(wp->out, ike->data, dlen); - return; - } - - /* - * Not in xterm mode. Prefix a \033 for escape, and set bit 5 of the - * last byte for ctrl. - */ + /* Prefix a \033 for escape. */ if (key & KEYC_ESCAPE) buffer_write8(wp->out, '\033'); - if (key & KEYC_CTRL && ike->flags & INPUTKEY_CTRL) { - buffer_write(wp->out, ike->data, dlen - 1); - buffer_write8(wp->out, ike->data[dlen - 1] ^ 0x20); - return; - } buffer_write(wp->out, ike->data, dlen); } -/* Handle input mouse. */ +/* Translate mouse and output. */ void -input_mouse(struct window_pane *wp, u_char b, u_char x, u_char y) +input_mouse(struct window_pane *wp, struct mouse_event *m) { if (wp->screen->mode & MODE_MOUSE) { buffer_write(wp->out, "\033[M", 3); - buffer_write8(wp->out, b + 32); - buffer_write8(wp->out, x + 33); - buffer_write8(wp->out, y + 33); + buffer_write8(wp->out, m->b + 32); + buffer_write8(wp->out, m->x + 33); + buffer_write8(wp->out, m->y + 33); } } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/job.c /tmp/wmlmc6MQoR/tmux-1.1/job.c --- tmux-1.0/job.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/job.c 2009-11-02 21:38:26.000000000 +0000 @@ -0,0 +1,196 @@ +/* $Id: job.c,v 1.9 2009/11/02 21:38:26 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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 +#include +#include + +#include "tmux.h" + +/* + * Job scheduling. Run queued commands in the background and record their + * output. + */ + +/* All jobs list. */ +struct joblist all_jobs = SLIST_HEAD_INITIALIZER(&all_jobs); + +RB_GENERATE(jobs, job, entry, job_cmp); + +int +job_cmp(struct job *job1, struct job *job2) +{ + return (strcmp(job1->cmd, job2->cmd)); +} + +/* Initialise job tree. */ +void +job_tree_init(struct jobs *jobs) +{ + RB_INIT(jobs); +} + +/* Destroy a job tree. */ +void +job_tree_free(struct jobs *jobs) +{ + struct job *job; + + while (!RB_EMPTY(jobs)) { + job = RB_ROOT(jobs); + RB_REMOVE(jobs, jobs, job); + job_free(job); + } +} + +/* Find a job and return it. */ +struct job * +job_get(struct jobs *jobs, const char *cmd) +{ + struct job job; + + job.cmd = (char *) cmd; + return (RB_FIND(jobs, jobs, &job)); +} + +/* Add a job. */ +struct job * +job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd, + void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) +{ + struct job *job; + + job = xmalloc(sizeof *job); + job->cmd = xstrdup(cmd); + job->pid = -1; + job->status = 0; + + job->client = c; + + job->fd = -1; + job->out = buffer_create(BUFSIZ); + + job->callbackfn = callbackfn; + job->freefn = freefn; + job->data = data; + + job->flags = flags|JOB_DONE; + + if (jobs != NULL) + RB_INSERT(jobs, jobs, job); + SLIST_INSERT_HEAD(&all_jobs, job, lentry); + + return (job); +} + +/* Remove job from tree and free. */ +void +job_remove(struct jobs *jobs, struct job *job) +{ + if (jobs != NULL) + RB_REMOVE(jobs, jobs, job); + job_free(job); +} + +/* Kill and free an individual job. */ +void +job_free(struct job *job) +{ + job_kill(job); + + SLIST_REMOVE(&all_jobs, job, job, lentry); + xfree(job->cmd); + + if (job->freefn != NULL && job->data != NULL) + job->freefn(job->data); + + if (job->fd != -1) + close(job->fd); + if (job->out != NULL) + buffer_destroy(job->out); + + xfree(job); +} + +/* Start a job running, if it isn't already. */ +int +job_run(struct job *job) +{ + int nullfd, out[2], mode; + + if (!(job->flags & JOB_DONE)) + return (0); + job->flags &= ~JOB_DONE; + + if (pipe(out) != 0) + return (-1); + + switch (job->pid = fork()) { + case -1: + return (-1); + case 0: /* child */ + sigreset(); + /* XXX environ? */ + + if (dup2(out[1], STDOUT_FILENO) == -1) + fatal("dup2 failed"); + if (out[1] != STDOUT_FILENO) + close(out[1]); + close(out[0]); + + nullfd = open(_PATH_DEVNULL, O_RDWR, 0); + if (nullfd < 0) + fatal("open failed"); + if (dup2(nullfd, STDIN_FILENO) == -1) + fatal("dup2 failed"); + if (dup2(nullfd, STDERR_FILENO) == -1) + fatal("dup2 failed"); + if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) + close(nullfd); + + execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL); + fatal("execl failed"); + default: /* parent */ + close(out[1]); + + job->fd = out[0]; + if ((mode = fcntl(job->fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + + if (BUFFER_USED(job->out) != 0) + buffer_remove(job->out, BUFFER_USED(job->out)); + + return (0); + } +} + +/* Kill a job. */ +void +job_kill(struct job *job) +{ + if (job->pid == -1) + return; + kill(job->pid, SIGTERM); + job->pid = -1; +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/key-bindings.c /tmp/wmlmc6MQoR/tmux-1.1/key-bindings.c --- tmux-1.0/key-bindings.c 2009-09-02 20:52:13.000000000 +0100 +++ tmux-1.1/key-bindings.c 2009-10-06 15:14:07.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: key-bindings.c,v 1.82 2009/08/31 22:30:15 tcunha Exp $ */ +/* $Id: key-bindings.c,v 1.83 2009/10/06 14:14:07 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -122,7 +122,6 @@ { '8', 0, &cmd_select_window_entry }, { '9', 0, &cmd_select_window_entry }, { ':', 0, &cmd_command_prompt_entry }, - { '=', 0, &cmd_scroll_mode_entry }, { '?', 0, &cmd_list_keys_entry }, { '[', 0, &cmd_copy_mode_entry }, { '\'', 0, &cmd_select_prompt_entry }, @@ -150,7 +149,7 @@ { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, - { KEYC_PPAGE, 0, &cmd_scroll_mode_entry }, + { KEYC_PPAGE, 0, &cmd_copy_mode_entry }, { 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry }, { 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry }, { KEYC_UP, 0, &cmd_up_pane_entry }, diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/key-string.c /tmp/wmlmc6MQoR/tmux-1.1/key-string.c --- tmux-1.0/key-string.c 2009-07-30 21:14:57.000000000 +0100 +++ tmux-1.1/key-string.c 2009-10-28 22:53:03.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: key-string.c,v 1.22 2009/07/28 23:13:00 tcunha Exp $ */ +/* $Id: key-string.c,v 1.25 2009/10/28 22:53:03 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -57,6 +57,7 @@ { "PPage", KEYC_PPAGE }, { "Tab", '\011' }, { "BTab", KEYC_BTAB }, + { "Space", ' ' }, { "BSpace", KEYC_BSPACE }, { "Enter", '\r' }, { "Escape", '\033' }, @@ -68,22 +69,22 @@ { "Right", KEYC_RIGHT }, /* Numeric keypad. */ - { "KP/", KEYC_KP0_1 }, - { "KP*", KEYC_KP0_2 }, - { "KP-", KEYC_KP0_3 }, - { "KP7", KEYC_KP1_0 }, - { "KP8", KEYC_KP1_1 }, - { "KP9", KEYC_KP1_2 }, - { "KP+", KEYC_KP1_3 }, - { "KP4", KEYC_KP2_0 }, - { "KP5", KEYC_KP2_1 }, - { "KP6", KEYC_KP2_2 }, - { "KP1", KEYC_KP3_0 }, - { "KP2", KEYC_KP3_1 }, - { "KP3", KEYC_KP3_2 }, - { "KPEnter", KEYC_KP3_3 }, - { "KP0", KEYC_KP4_0 }, - { "KP.", KEYC_KP4_2 }, + { "KP/", KEYC_KP_SLASH }, + { "KP*", KEYC_KP_STAR }, + { "KP-", KEYC_KP_MINUS }, + { "KP7", KEYC_KP_SEVEN }, + { "KP8", KEYC_KP_EIGHT }, + { "KP9", KEYC_KP_NINE }, + { "KP+", KEYC_KP_PLUS }, + { "KP4", KEYC_KP_FOUR }, + { "KP5", KEYC_KP_FIVE }, + { "KP6", KEYC_KP_SIX }, + { "KP1", KEYC_KP_ONE }, + { "KP2", KEYC_KP_TWO }, + { "KP3", KEYC_KP_THREE }, + { "KPEnter", KEYC_KP_ENTER }, + { "KP0", KEYC_KP_ZERO }, + { "KP.", KEYC_KP_PERIOD }, }; int @@ -120,6 +121,8 @@ if (ptr[1] == '\0') { if (ptr[0] == 32) return (0); + if (ptr[0] == 63) + return (KEYC_BSPACE); if (ptr[0] >= 64 && ptr[0] <= 95) return (ptr[0] - 64); if (ptr[0] >= 97 && ptr[0] <= 122) diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/Makefile /tmp/wmlmc6MQoR/tmux-1.1/Makefile --- tmux-1.0/Makefile 2009-09-20 19:12:06.000000000 +0100 +++ tmux-1.1/Makefile 2009-11-05 12:30:55.000000000 +0000 @@ -1,9 +1,24 @@ -# $Id: Makefile,v 1.148 2009/08/26 08:58:39 nicm Exp $ +# $Id: Makefile,v 1.153 2009/11/05 12:30:55 tcunha Exp $ +# +# Copyright (c) 2009 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. +# .SUFFIXES: .c .o .PHONY: clean -VERSION= 1.0 +VERSION= 1.1 #FDEBUG= 1 @@ -53,7 +68,7 @@ mkdep ${CPPFLAGS} ${CFLAGS} ${SRCS:M*.c} clean: - rm -f tmux *.o *~ *.core *.log compat/*.o + rm -f tmux *.o *~ *.core *.log compat/*.o compat/*~ clean-depend: rm -f .depend diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/mode-key.c /tmp/wmlmc6MQoR/tmux-1.1/mode-key.c --- tmux-1.0/mode-key.c 2009-09-03 11:56:13.000000000 +0100 +++ tmux-1.1/mode-key.c 2009-10-15 02:52:47.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: mode-key.c,v 1.28 2009/09/02 22:45:17 tcunha Exp $ */ +/* $Id: mode-key.c,v 1.34 2009/10/15 01:52:47 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -77,6 +77,7 @@ /* Copy keys command strings. */ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" }, + { MODEKEYCOPY_BOTTOMLINE, "bottom-line" }, { MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, @@ -84,16 +85,20 @@ { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, { MODEKEYCOPY_GOTOLINE, "goto-line" }, { MODEKEYCOPY_LEFT, "cursor-left" }, + { MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTWORD, "next-word" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_RIGHT, "cursor-right" }, + { MODEKEYCOPY_SCROLLDOWN, "scroll-down" }, + { MODEKEYCOPY_SCROLLUP, "scroll-up" }, { MODEKEYCOPY_SEARCHAGAIN, "search-again" }, { MODEKEYCOPY_SEARCHDOWN, "search-forward" }, { MODEKEYCOPY_SEARCHUP, "search-backward" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, + { MODEKEYCOPY_TOPLINE, "top-line" }, { MODEKEYCOPY_UP, "cursor-up" }, { 0, NULL } @@ -155,9 +160,15 @@ const struct mode_key_entry mode_key_vi_copy[] = { { ' ', 0, MODEKEYCOPY_STARTSELECTION }, { '$', 0, MODEKEYCOPY_ENDOFLINE }, - { '/', 0, MODEKEYCOPY_SEARCHUP }, + { '/', 0, MODEKEYCOPY_SEARCHDOWN }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, - { '?', 0, MODEKEYCOPY_SEARCHDOWN }, + { ':', 0, MODEKEYCOPY_GOTOLINE }, + { '?', 0, MODEKEYCOPY_SEARCHUP }, + { 'H', 0, MODEKEYCOPY_TOPLINE }, + { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, + { 'K', 0, MODEKEYCOPY_SCROLLUP }, + { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, + { 'M', 0, MODEKEYCOPY_MIDDLELINE }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, @@ -168,7 +179,6 @@ { '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, - { 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'h', 0, MODEKEYCOPY_LEFT }, { 'j', 0, MODEKEYCOPY_DOWN }, { 'k', 0, MODEKEYCOPY_UP }, @@ -177,13 +187,15 @@ { 'q', 0, MODEKEYCOPY_CANCEL }, { 'w', 0, MODEKEYCOPY_NEXTWORD }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, + { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, + { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, - + { 0, -1, 0 } }; struct mode_key_tree mode_key_tree_vi_copy; @@ -191,7 +203,7 @@ /* emacs editing keys. */ const struct mode_key_entry mode_key_emacs_edit[] = { { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, - { '\002' /* C-p */, 0, MODEKEYEDIT_CURSORLEFT }, + { '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT }, { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, @@ -221,9 +233,13 @@ /* emacs choice selection keys. */ const struct mode_key_entry mode_key_emacs_choice[] = { { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, + { '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN }, + { '\020' /* C-p */, 0, MODEKEYCHOICE_UP }, + { '\026' /* C-v */, 0, MODEKEYCHOICE_PAGEDOWN }, { '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL }, { '\r', 0, MODEKEYCHOICE_CHOOSE }, { 'q', 0, MODEKEYCHOICE_CANCEL }, + { 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP }, { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, @@ -256,14 +272,18 @@ { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'q', 0, MODEKEYCOPY_CANCEL }, + { 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE }, + { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, + { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, + { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/names.c /tmp/wmlmc6MQoR/tmux-1.1/names.c --- tmux-1.0/names.c 2009-09-02 20:52:13.000000000 +0100 +++ tmux-1.1/names.c 2009-10-12 01:03:04.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: names.c,v 1.15 2009/09/02 01:02:44 tcunha Exp $ */ +/* $Id: names.c,v 1.17 2009/10/12 00:03:04 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -36,7 +36,7 @@ struct timeval tv, tv2; if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); @@ -73,6 +73,12 @@ xfree(name); } + if (w->active->fd == -1) { + xasprintf(&name, "%s[dead]", wname); + xfree(wname); + wname = name; + } + if (strcmp(wname, w->name) == 0) xfree(wname); else { diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/NOTES /tmp/wmlmc6MQoR/tmux-1.1/NOTES --- tmux-1.0/NOTES 2009-07-06 19:53:24.000000000 +0100 +++ tmux-1.1/NOTES 2009-11-05 12:35:47.000000000 +0000 @@ -4,15 +4,17 @@ to be accessed and controlled from a single terminal. tmux is intended to be a simple, modern, BSD-licensed alternative to programs such as GNU screen. -This 0.9 release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still -run on Solaris and AIX (although they hasn't been tested in a while). It is +This release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still +run on Solaris and AIX (although they haven't been tested in a while). It is usable, although there remain a number of missing features and some remaining bugs are expected. -If upgrading from 0.5, PLEASE NOTE the following configuration file changes: it -is now required to pass the -g flag to set-option or set-window-option to set -global options; remain-by-default and utf8-default are now gone, use global -window options (set-window-option -g) instead. +If upgrading from 1.0, PLEASE NOTE: +- The internal locking mechanism has gone, so the set-password command and -U + command line option have been removed. +- The -d command line flag was dropped. It will now automatically detect the + default colours by using op/AX. Nevertheless, if needed, the + terminal-overrides session option can replace it. tmux consists of a server part and multiple clients. The server is created when required and runs continuously unless killed by the user. Clients access the @@ -37,17 +39,14 @@ - Support for VT100 line drawing characters. - A large command set. - Vertical window splitting and layout. -- Automatic server locking on inactivity. +- Automatic server locking on inactivity by running an external command. - A configuration file. - UTF-8 support. A more extensive, but rough, todo list is included in the TODO file. tmux also depends on several features of the client terminal (TERM), if these -are missing it may refuse to run, or not behave correctly. Known working are -TERM=screen (tmux in screen), xterm, xterm-color and rxvt. Note that TERM=xterm -does not support colour on OpenBSD. screen ignores this, tmux does not: use -xterm-color or rxvt for colour. +are missing it may refuse to run, or not behave correctly. tmux supports UTF-8. To use it, the utf8 option must be set on each window; this may be turned on for all windows by setting it as a global option, see @@ -81,6 +80,12 @@ nicm@users.sf.net +This file and the CHANGES, FAQ and TODO files are licensed under the ISC +license. Files under examples/ remain copyright their authors unless otherwise +stated in the file but permission has been received to distribute them with +tmux. All other files have a license and copyright notice at their +start. Please contact me with any queries. + -- Nicholas Marriott -$Id: NOTES,v 1.49 2009/07/06 18:53:24 nicm Exp $ +$Id: NOTES,v 1.51 2009/11/05 12:35:47 tcunha Exp $ diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/options.c /tmp/wmlmc6MQoR/tmux-1.1/options.c --- tmux-1.0/options.c 2009-08-18 22:41:49.000000000 +0100 +++ tmux-1.1/options.c 2009-09-22 15:22:20.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: options.c,v 1.6 2009/07/22 17:46:53 tcunha Exp $ */ +/* $Id: options.c,v 1.9 2009/09/22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -53,7 +53,9 @@ SPLAY_REMOVE(options_tree, &oo->tree, o); xfree(o->name); if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); xfree(o); } } @@ -94,11 +96,13 @@ SPLAY_REMOVE(options_tree, &oo->tree, o); xfree(o->name); if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); xfree(o); } -void printflike3 +struct options_entry *printflike3 options_set_string(struct options *oo, const char *name, const char *fmt, ...) { struct options_entry *o; @@ -109,12 +113,15 @@ o->name = xstrdup(name); SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); va_start(ap, fmt); o->type = OPTIONS_STRING; - xvasprintf(&o->value.string, fmt, ap); + xvasprintf(&o->str, fmt, ap); va_end(ap); + return (o); } char * @@ -126,10 +133,10 @@ fatalx("missing option"); if (o->type != OPTIONS_STRING) fatalx("option not a string"); - return (o->value.string); + return (o->str); } -void +struct options_entry * options_set_number(struct options *oo, const char *name, long long value) { struct options_entry *o; @@ -139,11 +146,13 @@ o->name = xstrdup(name); SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) - xfree(o->value.string); + xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); o->type = OPTIONS_NUMBER; - o->value.number = value; - + o->num = value; + return (o); } long long @@ -155,5 +164,38 @@ fatalx("missing option"); if (o->type != OPTIONS_NUMBER) fatalx("option not a number"); - return (o->value.number); + return (o->num); +} + +struct options_entry * +options_set_data( + struct options *oo, const char *name, void *value, void (*freefn)(void *)) +{ + struct options_entry *o; + + if ((o = options_find1(oo, name)) == NULL) { + o = xmalloc(sizeof *o); + o->name = xstrdup(name); + SPLAY_INSERT(options_tree, &oo->tree, o); + } else if (o->type == OPTIONS_STRING) + xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); + + o->type = OPTIONS_DATA; + o->data = value; + o->freefn = freefn; + return (o); +} + +void * +options_get_data(struct options *oo, const char *name) +{ + struct options_entry *o; + + if ((o = options_find(oo, name)) == NULL) + fatalx("missing option"); + if (o->type != OPTIONS_DATA) + fatalx("option not data"); + return (o->data); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/options-cmd.c /tmp/wmlmc6MQoR/tmux-1.1/options-cmd.c --- tmux-1.0/options-cmd.c 2009-08-09 19:15:54.000000000 +0100 +++ tmux-1.1/options-cmd.c 2009-09-22 15:22:20.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: options-cmd.c,v 1.5 2009/08/09 16:48:34 tcunha Exp $ */ +/* $Id: options-cmd.c,v 1.8 2009/09/22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -23,11 +23,59 @@ #include "tmux.h" +const char * +set_option_print(const struct set_option_entry *entry, struct options_entry *o) +{ + static char out[BUFSIZ]; + const char *s; + struct keylist *keylist; + u_int i; + + *out = '\0'; + switch (entry->type) { + case SET_OPTION_STRING: + xsnprintf(out, sizeof out, "\"%s\"", o->str); + break; + case SET_OPTION_NUMBER: + xsnprintf(out, sizeof out, "%lld", o->num); + break; + case SET_OPTION_KEYS: + keylist = o->data; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + strlcat(out, key_string_lookup_key( + ARRAY_ITEM(keylist, i)), sizeof out); + if (i != ARRAY_LENGTH(keylist) - 1) + strlcat(out, ",", sizeof out); + } + break; + case SET_OPTION_COLOUR: + s = colour_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case SET_OPTION_ATTRIBUTES: + s = attributes_tostring(o->num); + xsnprintf(out, sizeof out, "%s", s); + break; + case SET_OPTION_FLAG: + if (o->num) + strlcpy(out, "on", sizeof out); + else + strlcpy(out, "off", sizeof out); + break; + case SET_OPTION_CHOICE: + s = entry->choices[o->num]; + xsnprintf(out, sizeof out, "%s", s); + break; + } + return (out); +} + void set_option_string(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value, int append) { - char *oldvalue, *newvalue; + struct options_entry *o; + char *oldvalue, *newvalue; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -40,8 +88,9 @@ } else newvalue = value; - options_set_string(oo, entry->name, "%s", newvalue); - ctx->info(ctx, "set option: %s -> %s", entry->name, newvalue); + o = options_set_string(oo, entry->name, "%s", newvalue); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); if (newvalue != value) xfree(newvalue); @@ -51,8 +100,9 @@ set_option_number(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - long long number; - const char *errstr; + struct options_entry *o; + long long number; + const char *errstr; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -64,35 +114,52 @@ ctx->error(ctx, "value is %s: %s", errstr, value); return; } - options_set_number(oo, entry->name, number); - ctx->info(ctx, "set option: %s -> %lld", entry->name, number); + + o = options_set_number(oo, entry->name, number); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void -set_option_key(struct cmd_ctx *ctx, struct options *oo, +set_option_keys(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int key; + struct options_entry *o; + struct keylist *keylist; + char *copyvalue, *ptr, *str; + int key; if (value == NULL) { ctx->error(ctx, "empty value"); return; } - if ((key = key_string_lookup_string(value)) == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", value); - return; + keylist = xmalloc(sizeof *keylist); + ARRAY_INIT(keylist); + + ptr = copyvalue = xstrdup(value); + while ((str = strsep(&ptr, ",")) != NULL) { + if ((key = key_string_lookup_string(str)) == KEYC_NONE) { + xfree(keylist); + ctx->error(ctx, "unknown key: %s", str); + xfree(copyvalue); + return; + } + ARRAY_ADD(keylist, key); } - options_set_number(oo, entry->name, key); - ctx->info(ctx, - "set option: %s -> %s", entry->name, key_string_lookup_key(key)); + xfree(copyvalue); + + o = options_set_data(oo, entry->name, keylist, xfree); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_colour(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int colour; + struct options_entry *o; + int colour; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -104,16 +171,17 @@ return; } - options_set_number(oo, entry->name, colour); - ctx->info(ctx, - "set option: %s -> %s", entry->name, colour_tostring(colour)); + o = options_set_number(oo, entry->name, colour); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_attributes(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int attr; + struct options_entry *o; + int attr; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -125,16 +193,17 @@ return; } - options_set_number(oo, entry->name, attr); - ctx->info(ctx, - "set option: %s -> %s", entry->name, attributes_tostring(attr)); + o = options_set_number(oo, entry->name, attr); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_flag(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - int flag; + struct options_entry *o; + int flag; if (value == NULL || *value == '\0') flag = !options_get_number(oo, entry->name); @@ -153,17 +222,18 @@ } } - options_set_number(oo, entry->name, flag); - ctx->info(ctx, - "set option: %s -> %s", entry->name, flag ? "on" : "off"); + o = options_set_number(oo, entry->name, flag); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } void set_option_choice(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { - const char **choicep; - int n, choice = -1; + struct options_entry *o; + const char **choicep; + int n, choice = -1; if (value == NULL) { ctx->error(ctx, "empty value"); @@ -187,7 +257,7 @@ return; } - options_set_number(oo, entry->name, choice); - ctx->info(ctx, - "set option: %s -> %s", entry->name, entry->choices[choice]); + o = options_set_number(oo, entry->name, choice); + ctx->info( + ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/osdep-netbsd.c /tmp/wmlmc6MQoR/tmux-1.1/osdep-netbsd.c --- tmux-1.0/osdep-netbsd.c 2009-08-09 19:15:54.000000000 +0100 +++ tmux-1.1/osdep-netbsd.c 2009-09-25 18:42:48.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: osdep-netbsd.c,v 1.8 2009/08/09 18:00:45 tcunha Exp $ */ +/* $Id: osdep-netbsd.c,v 1.9 2009/09/24 12:30:22 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -77,7 +77,7 @@ return (NULL); buf = NULL; - len = sizeof(p); + len = sizeof(bestp); mib[0] = CTL_KERN; mib[1] = KERN_PROC2; mib[2] = KERN_PROC_PGRP; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/osdep-sunos.c /tmp/wmlmc6MQoR/tmux-1.1/osdep-sunos.c --- tmux-1.0/osdep-sunos.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/osdep-sunos.c 2009-10-15 21:08:09.000000000 +0100 @@ -0,0 +1,65 @@ +/* $Id: osdep-sunos.c,v 1.2 2009/10/15 07:11:25 nicm Exp $ */ + +/* + * Copyright (c) 2009 Todd Carson + * + * 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 + +#include +#include +#include +#include +#include + +#include "tmux.h" + +char * +osdep_get_name(int fd, char *tty) +{ + struct psinfo p; + struct stat st; + char *path; + ssize_t bytes; + int f; + pid_t pgrp; + + if ((f = open(tty, O_RDONLY)) < 0) + return (NULL); + + if ((fstat(f, &st) != 0) || + (ioctl(f, TIOCGPGRP, &pgrp) != 0)) { + close(f); + return (NULL); + } + close(f); + + xasprintf(&path, "/proc/%hu/psinfo", pgrp); + f = open(path, O_RDONLY); + xfree(path); + if (f < 0) + return (NULL); + + bytes = read(f, &p, sizeof(p)); + close(f); + if (bytes != sizeof(p)) + return (NULL); + + if (p.pr_ttydev != st.st_rdev) + return (NULL); + + return (xstrdup(p.pr_fname)); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/paste.c /tmp/wmlmc6MQoR/tmux-1.1/paste.c --- tmux-1.0/paste.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/paste.c 2009-11-04 22:39:20.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: paste.c,v 1.9 2009/09/07 23:48:54 tcunha Exp $ */ +/* $Id: paste.c,v 1.11 2009/11/04 22:39:20 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -116,8 +116,6 @@ pb->data = data; pb->size = size; - if (gettimeofday(&pb->tv, NULL) != 0) - fatal("gettimeofday"); } int @@ -133,8 +131,6 @@ pb->data = data; pb->size = size; - if (gettimeofday(&pb->tv, NULL) != 0) - fatal("gettimeofday"); return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/resize.c /tmp/wmlmc6MQoR/tmux-1.1/resize.c --- tmux-1.0/resize.c 2009-07-20 18:17:28.000000000 +0100 +++ tmux-1.1/resize.c 2009-09-25 18:47:42.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: resize.c,v 1.23 2009/07/20 15:42:05 tcunha Exp $ */ +/* $Id: resize.c,v 1.24 2009/09/25 17:47:42 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -60,7 +60,7 @@ ssx = ssy = UINT_MAX; for (j = 0; j < ARRAY_LENGTH(&clients); j++) { c = ARRAY_ITEM(&clients, j); - if (c == NULL) + if (c == NULL || c->flags & CLIENT_SUSPENDED) continue; if (c->session == s) { if (c->tty.sx < ssx) diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/screen-redraw.c /tmp/wmlmc6MQoR/tmux-1.1/screen-redraw.c --- tmux-1.0/screen-redraw.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/screen-redraw.c 2009-10-28 23:17:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: screen-redraw.c,v 1.47 2009/09/11 14:13:52 tcunha Exp $ */ +/* $Id: screen-redraw.c,v 1.49 2009/10/28 23:17:28 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -195,7 +195,7 @@ for (i = 0; i < tty->sx; i++) { type = screen_redraw_check_cell(c, i, j); if (type != CELL_INSIDE) { - tty_cursor(tty, i, j, 0, 0); + tty_cursor(tty, i, j); tty_putc(tty, border[type]); } } @@ -239,7 +239,7 @@ struct tty *tty = &c->tty; struct session *s = c->session; struct grid_cell gc; - u_int idx, px, py, i, j; + u_int idx, px, py, i, j, xoff, yoff; int colour; char buf[16], *ptr; size_t len; @@ -251,11 +251,13 @@ return; colour = options_get_number(&s->options, "display-panes-colour"); - px = wp->sx / 2; - py = wp->sy / 2; + px = wp->sx / 2; py = wp->sy / 2; + xoff = wp->xoff; yoff = wp->yoff; + if (wp->sx < len * 6 || wp->sy < 5) { - tty_cursor(tty, px - len / 2, py, wp->xoff, wp->yoff); + tty_cursor(tty, xoff + px - len / 2, yoff + py); memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = '_'; /* not space */ colour_set_fg(&gc, colour); tty_attributes(tty, &gc); tty_puts(tty, buf); @@ -266,6 +268,7 @@ py -= 2; memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = '_'; /* not space */ colour_set_bg(&gc, colour); tty_attributes(tty, &gc); for (ptr = buf; *ptr != '\0'; ptr++) { @@ -275,7 +278,7 @@ for (j = 0; j < 5; j++) { for (i = px; i < px + 5; i++) { - tty_cursor(tty, i, py + j, wp->xoff, wp->yoff); + tty_cursor(tty, xoff + i, yoff + py + j); if (clock_table[idx][j][i - px]) tty_putc(tty, ' '); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/screen-write.c /tmp/wmlmc6MQoR/tmux-1.1/screen-write.c --- tmux-1.0/screen-write.c 2009-09-16 13:28:52.000000000 +0100 +++ tmux-1.1/screen-write.c 2009-10-23 18:16:24.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.73 2009/09/15 23:54:57 tcunha Exp $ */ +/* $Id: screen-write.c,v 1.83 2009/10/23 17:16:24 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,8 +22,10 @@ #include "tmux.h" -void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *); +void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); void screen_write_overwrite(struct screen_write_ctx *); +int screen_write_combine( + struct screen_write_ctx *, const struct utf8_data *); /* Initialise writing with a window. */ void @@ -91,10 +93,11 @@ size_t printflike2 screen_write_strlen(int utf8flag, const char *fmt, ...) { - va_list ap; - char *msg; - u_char *ptr, utf8buf[4]; - size_t left, size = 0; + va_list ap; + char *msg; + struct utf8_data utf8data; + u_char *ptr; + size_t left, size = 0; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); @@ -102,24 +105,17 @@ ptr = msg; while (*ptr != '\0') { - if (utf8flag && *ptr > 0x7f) { - memset(utf8buf, 0xff, sizeof utf8buf); + if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { + ptr++; left = strlen(ptr); - if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { - memcpy(utf8buf, ptr, 2); - ptr += 2; - } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { - memcpy(utf8buf, ptr, 3); - ptr += 3; - } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { - memcpy(utf8buf, ptr, 4); - ptr += 4; - } else { - *utf8buf = *ptr; + if (left < utf8data.size - 1) + break; + while (utf8_append(&utf8data, *ptr)) ptr++; - } - size += utf8_width(utf8buf); + ptr++; + + size += utf8data.width; } else { size++; ptr++; @@ -158,47 +154,38 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap) { - char *msg; - u_char *ptr, utf8buf[4]; - size_t left, size = 0; - int width; + char *msg; + struct utf8_data utf8data; + u_char *ptr; + size_t left, size = 0; xvasprintf(&msg, fmt, ap); ptr = msg; while (*ptr != '\0') { - if (utf8flag && *ptr > 0x7f) { - memset(utf8buf, 0xff, sizeof utf8buf); + if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { + ptr++; left = strlen(ptr); - if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { - memcpy(utf8buf, ptr, 2); - ptr += 2; - } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { - memcpy(utf8buf, ptr, 3); - ptr += 3; - } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { - memcpy(utf8buf, ptr, 4); - ptr += 4; - } else { - *utf8buf = *ptr; + if (left < utf8data.size - 1) + break; + while (utf8_append(&utf8data, *ptr)) ptr++; - } + ptr++; - width = utf8_width(utf8buf); - if (maxlen > 0 && size + width > (size_t) maxlen) { + if (maxlen > 0 && + size + utf8data.width > (size_t) maxlen) { while (size < (size_t) maxlen) { screen_write_putc(ctx, gc, ' '); size++; } break; } - size += width; - + size += utf8data.width; + gc->flags |= GRID_FLAG_UTF8; - screen_write_cell(ctx, gc, utf8buf); + screen_write_cell(ctx, gc, &utf8data); gc->flags &= ~GRID_FLAG_UTF8; - } else { if (maxlen > 0 && size + 1 > (size_t) maxlen) break; @@ -218,11 +205,11 @@ ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...) { struct grid_cell lgc; + struct utf8_data utf8data; va_list ap; char *msg; - u_char *ptr, *last, utf8buf[4]; + u_char *ptr, *last; size_t left, size = 0; - int width; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); @@ -246,38 +233,29 @@ continue; } - if (utf8flag && *ptr > 0x7f) { - memset(utf8buf, 0xff, sizeof utf8buf); + if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { + ptr++; left = strlen(ptr); - if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { - memcpy(utf8buf, ptr, 2); - ptr += 2; - } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { - memcpy(utf8buf, ptr, 3); - ptr += 3; - } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { - memcpy(utf8buf, ptr, 4); - ptr += 4; - } else { - *utf8buf = *ptr; + if (left < utf8data.size - 1) + break; + while (utf8_append(&utf8data, *ptr)) ptr++; - } + ptr++; - width = utf8_width(utf8buf); - if (maxlen > 0 && size + width > (size_t) maxlen) { + if (maxlen > 0 && + size + utf8data.width > (size_t) maxlen) { while (size < (size_t) maxlen) { screen_write_putc(ctx, gc, ' '); size++; } break; } - size += width; + size += utf8data.width; lgc.flags |= GRID_FLAG_UTF8; - screen_write_cell(ctx, &lgc, utf8buf); + screen_write_cell(ctx, &lgc, &utf8data); lgc.flags &= ~GRID_FLAG_UTF8; - } else { if (maxlen > 0 && size + 1 > (size_t) maxlen) break; @@ -347,6 +325,10 @@ bg = defgc->bg; } else return; + } else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { + if ((val = attributes_fromstring(tmp + 2)) == -1) + return; + attr &= ~val; } else { if ((val = attributes_fromstring(tmp)) == -1) return; @@ -370,8 +352,9 @@ struct grid *gd = src->grid; struct grid_line *gl; const struct grid_cell *gc; - u_char *udata; - u_int xx, yy, cx, cy, ax, bx; + const struct grid_utf8 *gu; + struct utf8_data utf8data; + u_int xx, yy, cx, cy, ax, bx, i; cx = s->cx; cy = s->cy; @@ -392,21 +375,30 @@ bx = gl->cellsize; else bx = px + nx; + for (xx = ax; xx < bx; xx++) { - udata = NULL; if (xx >= gl->cellsize) gc = &grid_default_cell; - else { + else gc = &gl->celldata[xx]; - if (gc->flags & GRID_FLAG_UTF8) - udata = gl->utf8data[xx].data; + if (gc->flags & GRID_FLAG_UTF8) { + gu = &gl->utf8data[xx]; + memcpy(utf8data.data, + gu->data, sizeof utf8data.data); + utf8data.width = gu->width; + utf8data.size = 0; + for (i = 0; i < UTF8_SIZE; i++) { + if (gu->data[i] == 0xff) + break; + utf8data.size++; + } } - screen_write_cell(ctx, gc, udata); + screen_write_cell(ctx, gc, &utf8data); } if (px + nx == gd->sx && px + nx > gl->cellsize) screen_write_clearendofline(ctx); } else - screen_write_clearline(ctx); + screen_write_clearline(ctx); cy++; screen_write_cursormove(ctx, cx, cy); } @@ -414,9 +406,14 @@ /* Set up context for TTY command. */ void -screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) +screen_write_initctx( + struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, int save_last) { - struct screen *s = ctx->s; + struct screen *s = ctx->s; + struct grid *gd = s->grid; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int xx; ttyctx->wp = ctx->wp; @@ -425,6 +422,23 @@ ttyctx->orlower = s->rlower; ttyctx->orupper = s->rupper; + + if (!save_last) + return; + + /* Save the last cell on the screen. */ + gc = NULL; + for (xx = 1; xx < screen_size_x(s); xx++) { + gc = grid_view_peek_cell(gd, screen_size_x(s) - xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + } + ttyctx->last_width = xx; + memcpy(&ttyctx->last_cell, gc, sizeof ttyctx->last_cell); + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_view_peek_utf8(gd, screen_size_x(s) - xx, s->cy); + memcpy(&ttyctx->last_utf8, gu, sizeof ttyctx->last_utf8); + } } /* Cursor up by ny. */ @@ -509,6 +523,25 @@ s->cx -= nx; } +/* Backspace; cursor left unless at start of wrapped line when can move up. */ +void +screen_write_backspace(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + struct grid_line *gl; + + if (s->cx == 0) { + if (s->cy == 0) + return; + gl = &s->grid->linedata[s->grid->hsize + s->cy - 1]; + if (gl->flags & GRID_LINE_WRAPPED) { + s->cy--; + s->cx = screen_size_x(s) - 1; + } + } else + s->cx--; +} + /* VT100 alignment test. */ void screen_write_alignmenttest(struct screen_write_ctx *ctx) @@ -518,7 +551,7 @@ struct grid_cell gc; u_int xx, yy; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); memcpy(&gc, &grid_default_cell, sizeof gc); gc.data = 'E'; @@ -532,6 +565,7 @@ s->cy = 0; s->rupper = 0; + s->rlower = screen_size_y(s) - 1; tty_write(tty_cmd_alignmenttest, &ttyctx); @@ -552,7 +586,7 @@ if (nx == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cx <= screen_size_x(s) - 1) grid_view_insert_cells(s->grid, s->cx, s->cy, nx); @@ -576,7 +610,7 @@ if (nx == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cx <= screen_size_x(s) - 1) grid_view_delete_cells(s->grid, s->cx, s->cy, nx); @@ -601,7 +635,7 @@ if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_insert_lines(s->grid, s->cy, ny); @@ -615,7 +649,7 @@ if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_insert_lines(s->grid, s->cy, ny); @@ -642,7 +676,7 @@ if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_delete_lines(s->grid, s->cy, ny); @@ -656,7 +690,7 @@ if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_delete_lines(s->grid, s->cy, ny); @@ -674,7 +708,7 @@ struct screen *s = ctx->s; struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); @@ -689,7 +723,7 @@ struct tty_ctx ttyctx; u_int sx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); @@ -707,7 +741,7 @@ struct tty_ctx ttyctx; u_int sx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); @@ -753,7 +787,7 @@ struct screen *s = ctx->s; struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); if (s->cy == s->rupper) grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); @@ -809,15 +843,15 @@ s->mode &= ~MODE_MOUSE; } -/* Line feed (down with scroll). */ +/* Line feed. */ void screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) { struct screen *s = ctx->s; struct grid_line *gl; - struct tty_ctx ttyctx; + struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); gl = &s->grid->linedata[s->grid->hsize + s->cy]; if (wrapped) @@ -830,6 +864,7 @@ else if (s->cy < screen_size_y(s) - 1) s->cy++; + ttyctx.num = wrapped; tty_write(tty_cmd_linefeed, &ttyctx); } @@ -874,7 +909,7 @@ struct tty_ctx ttyctx; u_int sx, sy; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); sy = screen_size_y(s); @@ -894,7 +929,7 @@ struct tty_ctx ttyctx; u_int sx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); sx = screen_size_x(s); @@ -915,7 +950,7 @@ struct screen *s = ctx->s; struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx); + screen_write_initctx(ctx, &ttyctx, 0); grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); @@ -924,15 +959,15 @@ /* Write cell data. */ void -screen_write_cell( - struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata) +screen_write_cell(struct screen_write_ctx *ctx, + const struct grid_cell *gc, const struct utf8_data *utf8data) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; - struct grid_utf8 gu, *tmp_gu; - u_int width, xx, i; - struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp; + struct grid_utf8 gu; + u_int width, xx; + struct grid_cell tmp_gc, *tmp_gcp; int insert = 0; /* Ignore padding. */ @@ -940,48 +975,33 @@ return; /* Find character width. */ - if (gc->flags & GRID_FLAG_UTF8) { - width = utf8_width(udata); - - gu.width = width; - memcpy(&gu.data, udata, sizeof gu.data); - } else + if (gc->flags & GRID_FLAG_UTF8) + width = utf8data->width; + else width = 1; - /* If the width is zero, combine onto the previous character. */ - if (width == 0) { - if (s->cx == 0) - return; - tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy); - if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) { - tmp_gcp->flags |= GRID_FLAG_UTF8; - memset(&gu.data, 0xff, sizeof gu.data); - *gu.data = tmp_gcp->data; - gu.width = 1; - grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu); - } - tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); + /* + * If this is a wide character and there is no room on the screen, for + * the entire character, don't print it. + */ + if (width > 1 && (width > screen_size_x(s) || + (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width))) + return; - for (i = 0; i < UTF8_SIZE; i++) { - if (tmp_gu->data[i] == 0xff) - break; + /* + * If the width is zero, combine onto the previous character, if + * there is space. + */ + if (width == 0) { + if (screen_write_combine(ctx, utf8data) == 0) { + screen_write_initctx(ctx, &ttyctx, 0); + tty_write(tty_cmd_utf8character, &ttyctx); } - memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); - - /* Assume the previous character has just been input. */ - screen_write_initctx(ctx, &ttyctx); - ttyctx.ptr = udata; - tty_write(tty_cmd_utf8character, &ttyctx); return; } - /* If the character is wider than the screen, don't print it. */ - if (width > screen_size_x(s)) { - memcpy(&tmp_gc, gc, sizeof tmp_gc); - tmp_gc.data = '_'; - width = 1; - gc = &tmp_gc; - } + /* Initialise the redraw context, saving the last cell. */ + screen_write_initctx(ctx, &ttyctx, 1); /* If in insert mode, make space for the cells. */ if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) { @@ -992,8 +1012,8 @@ /* Check this will fit on the current line and wrap if not. */ if (s->cx > screen_size_x(s) - width) { - screen_write_carriagereturn(ctx); screen_write_linefeed(ctx, 1); + s->cx = 0; /* carriage return */ } /* Sanity checks. */ @@ -1015,11 +1035,17 @@ /* Set the cell. */ grid_view_set_cell(gd, s->cx, s->cy, gc); - if (gc->flags & GRID_FLAG_UTF8) + if (gc->flags & GRID_FLAG_UTF8) { + /* Construct UTF-8 and write it. */ + gu.width = utf8data->width; + memset(gu.data, 0xff, sizeof gu.data); + if (utf8data->size > sizeof gu.data) + fatalx("UTF-8 data overflow"); + memcpy(gu.data, utf8data->data, utf8data->size); grid_view_set_utf8(gd, s->cx, s->cy, &gu); + } /* Move the cursor. */ - screen_write_initctx(ctx, &ttyctx); s->cx += width; /* Draw to the screen if necessary. */ @@ -1029,11 +1055,13 @@ } ttyctx.utf8 = &gu; if (screen_check_selection(s, s->cx - width, s->cy)) { - memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2); - tmp_gc2.data = gc->data; - tmp_gc2.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); - tmp_gc2.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); - ttyctx.cell = &tmp_gc2; + memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); + tmp_gc.data = gc->data; + tmp_gc.flags = gc->flags & + ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + tmp_gc.flags |= s->sel.cell.flags & + (GRID_FLAG_FG256|GRID_FLAG_BG256); + ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); } else { ttyctx.cell = gc; @@ -1041,6 +1069,55 @@ } } +/* Combine a UTF-8 zero-width character onto the previous. */ +int +screen_write_combine( + struct screen_write_ctx *ctx, const struct utf8_data *utf8data) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + struct grid_cell *gc; + struct grid_utf8 *gu, tmp_gu; + u_int i, old_size; + + /* Can't combine if at 0. */ + if (s->cx == 0) + return (-1); + + /* Retrieve the previous cell and convert to UTF-8 if not already. */ + gc = grid_view_get_cell(gd, s->cx - 1, s->cy); + if (!(gc->flags & GRID_FLAG_UTF8)) { + memset(&tmp_gu.data, 0xff, sizeof tmp_gu.data); + *tmp_gu.data = gc->data; + tmp_gu.width = 1; + + grid_view_set_utf8(gd, s->cx - 1, s->cy, &tmp_gu); + gc->flags |= GRID_FLAG_UTF8; + } + + /* Get the previous cell's UTF-8 data and its size. */ + gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); + for (old_size = 0; old_size < UTF8_SIZE; old_size++) { + if (gu->data[old_size] == 0xff) + break; + } + + /* If there isn't space, scrap this character. */ + if (old_size + utf8data->size > UTF8_SIZE) { + for (i = 0; i < gu->width && i != UTF8_SIZE; i++) + gu->data[i] = '_'; + if (i != UTF8_SIZE) + gu->data[i] = 0xff; + return (0); + } + + /* Otherwise save the character. */ + memcpy(gu->data + old_size, utf8data->data, utf8data->size); + if (old_size + utf8data->size != UTF8_SIZE) + gu->data[old_size + utf8data->size] = 0xff; + return (0); +} + /* * UTF-8 wide characters are a bit of an annoyance. They take up more than one * cell on the screen, so following cells must not be drawn by marking them as diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/server.c /tmp/wmlmc6MQoR/tmux-1.1/server.c --- tmux-1.0/server.c 2009-09-20 19:11:24.000000000 +0100 +++ tmux-1.1/server.c 2009-11-04 22:42:31.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.189 2009/09/19 18:53:01 tcunha Exp $ */ +/* $Id: server.c,v 1.216 2009/11/04 22:42:31 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -44,40 +44,141 @@ struct clients clients; struct clients dead_clients; -void server_create_client(int); +/* Mapping of a pollfd to an fd independent of its position in the array. */ +struct poll_item { + int fd; + int events; + + void (*fn)(int, int, void *); + void *data; + + RB_ENTRY(poll_item) entry; +}; +RB_HEAD(poll_items, poll_item) poll_items; + +int server_poll_cmp(struct poll_item *, struct poll_item *); +struct poll_item*server_poll_lookup(int); +struct pollfd *server_poll_flatten(int *); +void server_poll_dispatch(struct pollfd *, int); +void server_poll_reset(void); +RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp); +RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp); + int server_create_socket(void); +void server_callback(int, int, void *); int server_main(int); void server_shutdown(void); +int server_should_shutdown(void); void server_child_signal(void); -void server_fill_windows(struct pollfd **); -void server_handle_windows(struct pollfd **); -void server_fill_clients(struct pollfd **); -void server_handle_clients(struct pollfd **); -void server_accept_client(int); -void server_handle_client(struct client *); -void server_handle_window(struct window *, struct window_pane *); -int server_check_window_bell(struct session *, struct window *); -int server_check_window_activity(struct session *, - struct window *); -int server_check_window_content(struct session *, struct window *, - struct window_pane *); void server_clean_dead(void); -void server_lost_client(struct client *); -void server_check_window(struct window *); -void server_check_redraw(struct client *); -void server_set_title(struct client *); -void server_redraw_locked(struct client *); -void server_check_timers(struct client *); void server_second_timers(void); +void server_lock_server(void); +void server_lock_sessions(void); int server_update_socket(void); -/* Create a new client. */ +int +server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2) +{ + return (pitem1->fd - pitem2->fd); +} + void -server_create_client(int fd) +server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data) { - struct client *c; - int mode; - u_int i; + struct poll_item *pitem; + + pitem = xmalloc(sizeof *pitem); + pitem->fd = fd; + pitem->events = events; + + pitem->fn = fn; + pitem->data = data; + + RB_INSERT(poll_items, &poll_items, pitem); +} + +struct poll_item * +server_poll_lookup(int fd) +{ + struct poll_item pitem; + + pitem.fd = fd; + return (RB_FIND(poll_items, &poll_items, &pitem)); +} + +struct pollfd * +server_poll_flatten(int *nfds) +{ + struct poll_item *pitem; + struct pollfd *pfds; + + pfds = NULL; + *nfds = 0; + RB_FOREACH(pitem, poll_items, &poll_items) { + pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds); + pfds[*nfds].fd = pitem->fd; + pfds[*nfds].events = pitem->events; + (*nfds)++; + } + return (pfds); +} + +void +server_poll_dispatch(struct pollfd *pfds, int nfds) +{ + struct poll_item *pitem; + struct pollfd *pfd; + + while (nfds > 0) { + pfd = &pfds[--nfds]; + if (pfd->revents != 0) { + pitem = server_poll_lookup(pfd->fd); + pitem->fn(pitem->fd, pfd->revents, pitem->data); + } + } + xfree(pfds); +} + +void +server_poll_reset(void) +{ + struct poll_item *pitem; + + while (!RB_EMPTY(&poll_items)) { + pitem = RB_ROOT(&poll_items); + RB_REMOVE(poll_items, &poll_items, pitem); + xfree(pitem); + } +} + +/* Create server socket. */ +int +server_create_socket(void) +{ + struct sockaddr_un sa; + size_t size; + mode_t mask; + int fd, mode; + + memset(&sa, 0, sizeof sa); + sa.sun_family = AF_UNIX; + size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); + if (size >= sizeof sa.sun_path) { + errno = ENAMETOOLONG; + fatal("socket failed"); + } + unlink(sa.sun_path); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + fatal("socket failed"); + + mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); + if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) + fatal("bind failed"); + umask(mask); + + if (listen(fd, 16) == -1) + fatal("listen failed"); if ((mode = fcntl(fd, F_GETFL)) == -1) fatal("fcntl failed"); @@ -86,34 +187,33 @@ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); - c = xcalloc(1, sizeof *c); - c->references = 0; - imsg_init(&c->ibuf, fd); - - ARRAY_INIT(&c->prompt_hdata); - - c->tty.fd = -1; - c->title = NULL; - - c->session = NULL; - c->tty.sx = 80; - c->tty.sy = 24; - screen_init(&c->status, c->tty.sx, 1, 0); + return (fd); +} - c->message_string = NULL; +/* Callback for server socket. */ +void +server_callback(int fd, int events, unused void *data) +{ + struct sockaddr_storage sa; + socklen_t slen = sizeof sa; + int newfd; - c->prompt_string = NULL; - c->prompt_buffer = NULL; - c->prompt_index = 0; + if (events & (POLLERR|POLLNVAL|POLLHUP)) + fatalx("lost server socket"); + if (!(events & POLLIN)) + return; - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) == NULL) { - ARRAY_SET(&clients, i, c); + newfd = accept(fd, (struct sockaddr *) &sa, &slen); + if (newfd == -1) { + if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) return; - } + fatal("accept failed"); } - ARRAY_ADD(&clients, c); - log_debug("new client %d", fd); + if (sigterm) { + close(newfd); + return; + } + server_client_create(newfd); } /* Fork new server. */ @@ -157,14 +257,11 @@ ARRAY_INIT(&dead_clients); ARRAY_INIT(&sessions); ARRAY_INIT(&dead_sessions); + TAILQ_INIT(&session_groups); mode_key_init_trees(); key_bindings_init(); utf8_build(); - server_locked = 0; - server_password = NULL; - server_activity = time(NULL); - start_time = time(NULL); socket_path = path; @@ -176,16 +273,15 @@ #endif srv_fd = server_create_socket(); - server_create_client(pair[1]); + server_client_create(pair[1]); - if (access(SYSTEM_CFG, R_OK) != 0) { - if (errno != ENOENT) { - xasprintf( - &cause, "%s: %s", strerror(errno), SYSTEM_CFG); + if (access(SYSTEM_CFG, R_OK) == 0) { + if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) goto error; - } - } else if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0) + } else if (errno != ENOENT) { + xasprintf(&cause, "%s: %s", strerror(errno), SYSTEM_CFG); goto error; + } if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0) goto error; @@ -204,53 +300,13 @@ exit(server_main(srv_fd)); } -/* Create server socket. */ -int -server_create_socket(void) -{ - struct sockaddr_un sa; - size_t size; - mode_t mask; - int fd, mode; - - memset(&sa, 0, sizeof sa); - sa.sun_family = AF_UNIX; - size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); - if (size >= sizeof sa.sun_path) { - errno = ENAMETOOLONG; - fatal("socket failed"); - } - unlink(sa.sun_path); - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - fatal("socket failed"); - - mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); - if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) - fatal("bind failed"); - umask(mask); - - if (listen(fd, 16) == -1) - fatal("listen 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"); - - return (fd); -} - /* Main server loop. */ int server_main(int srv_fd) { - struct window *w; - struct pollfd *pfds, *pfd; + struct pollfd *pfds; int nfds, xtimeout; - u_int i, n; + u_int i; time_t now, last; siginit(); @@ -264,61 +320,47 @@ if (sigterm) server_shutdown(); + /* Stop if no sessions or clients left. */ + if (server_should_shutdown()) + break; + /* Handle child exit. */ if (sigchld) { - server_child_signal(); sigchld = 0; + server_child_signal(); + continue; } /* Recreate socket on SIGUSR1. */ if (sigusr1) { + sigusr1 = 0; close(srv_fd); srv_fd = server_create_socket(); - sigusr1 = 0; + continue; } - /* Initialise pollfd array. */ - nfds = 1; - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w != NULL) - nfds += window_count_panes(w); - } - nfds += ARRAY_LENGTH(&clients) * 2; - pfds = xrealloc(pfds, nfds, sizeof *pfds); - memset(pfds, 0, nfds * sizeof *pfds); - pfd = pfds; - - /* Fill server socket. */ - pfd->fd = srv_fd; - pfd->events = POLLIN; - pfd++; + /* Initialise pollfd array and add server socket. */ + server_poll_reset(); + server_poll_add(srv_fd, POLLIN, server_callback, NULL); /* Fill window and client sockets. */ - server_fill_windows(&pfd); - server_fill_clients(&pfd); - + server_job_prepare(); + server_window_prepare(); + server_client_prepare(); + /* Update socket permissions. */ xtimeout = INFTIM; if (server_update_socket() != 0) xtimeout = POLL_TIMEOUT; /* Do the poll. */ + pfds = server_poll_flatten(&nfds); if (poll(pfds, nfds, xtimeout) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } - pfd = pfds; - - /* Handle server socket. */ - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) - fatalx("lost server socket"); - if (pfd->revents & POLLIN) { - server_accept_client(srv_fd); - continue; - } - pfd++; + server_poll_dispatch(pfds, nfds); /* Call second-based timers. */ now = time(NULL); @@ -327,41 +369,18 @@ server_second_timers(); } - /* Set window names. */ - set_window_names(); - - /* - * Handle window and client sockets. Clients can create - * windows, so windows must come first to avoid messing up by - * increasing the array size. - */ - server_handle_windows(&pfd); - server_handle_clients(&pfd); + /* Run once-per-loop events. */ + server_job_loop(); + server_window_loop(); + server_client_loop(); /* Collect any unset key bindings. */ key_bindings_clean(); /* Collect dead clients and sessions. */ server_clean_dead(); - - /* - * If we have no sessions and clients left, let's get out - * of here... - */ - n = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) != NULL) - n++; - } - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) != NULL) - n++; - } - if (n == 0) - break; } - if (pfds != NULL) - xfree(pfds); + server_poll_reset(); for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if (ARRAY_ITEM(&sessions, i) != NULL) @@ -371,7 +390,7 @@ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) != NULL) - server_lost_client(ARRAY_ITEM(&clients, i)); + server_client_lost(ARRAY_ITEM(&clients, i)); } ARRAY_FREE(&clients); @@ -385,8 +404,6 @@ options_free(&global_s_options); options_free(&global_w_options); - if (server_password != NULL) - xfree(server_password); return (0); } @@ -399,6 +416,16 @@ struct client *c; u_int i, j; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL) { + if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) + server_client_lost(c); + else + server_write_client(c, MSG_SHUTDOWN, NULL, 0); + } + } + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = ARRAY_ITEM(&sessions, i); for (j = 0; j < ARRAY_LENGTH(&clients); j++) { @@ -411,16 +438,23 @@ if (s != NULL) session_destroy(s); } +} +/* Check if the server should be shutting down (no more clients or windows). */ +int +server_should_shutdown(void) +{ + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if (ARRAY_ITEM(&sessions, i) != NULL) + return (0); + } for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL) { - if (c->flags & CLIENT_BAD) - server_lost_client(c); - else - server_write_client(c, MSG_SHUTDOWN, NULL, 0); - } + if (ARRAY_ITEM(&clients, i) != NULL) + return (0); } + return (1); } /* Handle SIGCHLD. */ @@ -429,6 +463,7 @@ { struct window *w; struct window_pane *wp; + struct job *job; int status; pid_t pid; u_int i; @@ -438,12 +473,19 @@ case -1: if (errno == ECHILD) return; - fatal("waitpid"); + fatal("waitpid failed"); case 0: return; } - if (!WIFSTOPPED(status)) + if (!WIFSTOPPED(status)) { + SLIST_FOREACH(job, &all_jobs, lentry) { + if (pid == job->pid) { + job->pid = -1; + job->status = status; + } + } continue; + } if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) continue; @@ -461,527 +503,6 @@ } } -/* Fill window pollfds. */ -void -server_fill_windows(struct pollfd **pfd) -{ - struct window *w; - struct window_pane *wp; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - (*pfd)->fd = wp->fd; - if (wp->fd != -1) { - (*pfd)->events = POLLIN; - if (BUFFER_USED(wp->out) > 0) - (*pfd)->events |= POLLOUT; - } - (*pfd)++; - } - } -} - -/* Handle window pollfds. */ -void -server_handle_windows(struct pollfd **pfd) -{ - struct window *w; - struct window_pane *wp; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd != -1) { - if (buffer_poll(*pfd, wp->in, wp->out) != 0) { - close(wp->fd); - wp->fd = -1; - } else - server_handle_window(w, wp); - } - (*pfd)++; - } - - server_check_window(w); - } -} - -/* Check for general redraw on client. */ -void -server_check_redraw(struct client *c) -{ - struct session *s; - struct window_pane *wp; - int flags, redraw; - - if (c == NULL || c->session == NULL) - return; - s = c->session; - - flags = c->tty.flags & TTY_FREEZE; - c->tty.flags &= ~TTY_FREEZE; - - if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { - if (options_get_number(&s->options, "set-titles")) - server_set_title(c); - - if (c->message_string != NULL) - redraw = status_message_redraw(c); - else if (c->prompt_string != NULL) - redraw = status_prompt_redraw(c); - else - redraw = status_redraw(c); - if (!redraw) - c->flags &= ~CLIENT_STATUS; - } - - if (c->flags & CLIENT_REDRAW) { - if (server_locked) - server_redraw_locked(c); - else - screen_redraw_screen(c, 0); - c->flags &= ~CLIENT_STATUS; - } else { - TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { - if (wp->flags & PANE_REDRAW) - screen_redraw_pane(c, wp); - } - } - - if (c->flags & CLIENT_STATUS) - screen_redraw_screen(c, 1); - - c->tty.flags |= flags; - - c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); -} - -/* Set client title. */ -void -server_set_title(struct client *c) -{ - struct session *s = c->session; - const char *template; - char *title; - - template = options_get_string(&s->options, "set-titles-string"); - - title = status_replace(c->session, template, time(NULL)); - if (c->title == NULL || strcmp(title, c->title) != 0) { - if (c->title != NULL) - xfree(c->title); - c->title = xstrdup(title); - tty_set_title(&c->tty, c->title); - } - xfree(title); -} - -/* Redraw client when locked. */ -void -server_redraw_locked(struct client *c) -{ - struct screen_write_ctx ctx; - struct screen screen; - struct grid_cell gc; - u_int colour, xx, yy, i; - int style; - - xx = c->tty.sx; - yy = c->tty.sy - 1; - if (xx == 0 || yy == 0) - return; - colour = options_get_number(&global_w_options, "clock-mode-colour"); - style = options_get_number(&global_w_options, "clock-mode-style"); - - memcpy(&gc, &grid_default_cell, sizeof gc); - colour_set_fg(&gc, colour); - gc.attr |= GRID_ATTR_BRIGHT; - - screen_init(&screen, xx, yy, 0); - - screen_write_start(&ctx, NULL, &screen); - clock_draw(&ctx, colour, style); - - if (password_failures != 0) { - screen_write_cursormove(&ctx, 0, 0); - screen_write_puts( - &ctx, &gc, "%u failed attempts", password_failures); - if (time(NULL) < password_backoff) - screen_write_puts(&ctx, &gc, "; sleeping"); - } - - screen_write_stop(&ctx); - - for (i = 0; i < screen_size_y(&screen); i++) - tty_draw_line(&c->tty, &screen, i, 0, 0); - screen_redraw_screen(c, 1); - - screen_free(&screen); -} - -/* Check for timers on client. */ -void -server_check_timers(struct client *c) -{ - struct session *s; - struct timeval tv; - u_int interval; - - if (c == NULL || c->session == NULL) - return; - s = c->session; - - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); - - if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) - server_clear_identify(c); - - if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) - status_message_clear(c); - - if (c->message_string != NULL || c->prompt_string != NULL) { - /* - * Don't need timed redraw for messages/prompts so bail now. - * The status timer isn't reset when they are redrawn anyway. - */ - return; - } - if (!options_get_number(&s->options, "status")) - return; - - /* Check timer; resolution is only a second so don't be too clever. */ - interval = options_get_number(&s->options, "status-interval"); - if (interval == 0) - return; - if (tv.tv_sec < c->status_timer.tv_sec || - ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) - c->flags |= CLIENT_STATUS; -} - -/* Fill client pollfds. */ -void -server_fill_clients(struct pollfd **pfd) -{ - struct client *c; - struct window *w; - struct window_pane *wp; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - - server_check_timers(c); - server_check_redraw(c); - - if (c == NULL) - (*pfd)->fd = -1; - else { - (*pfd)->fd = c->ibuf.fd; - if (!(c->flags & CLIENT_BAD)) - (*pfd)->events |= POLLIN; - if (c->ibuf.w.queued > 0) - (*pfd)->events |= POLLOUT; - } - (*pfd)++; - - if (c == NULL || c->flags & CLIENT_SUSPENDED || - c->tty.fd == -1 || c->session == NULL) - (*pfd)->fd = -1; - else { - (*pfd)->fd = c->tty.fd; - (*pfd)->events = POLLIN; - if (BUFFER_USED(c->tty.out) > 0) - (*pfd)->events |= POLLOUT; - } - (*pfd)++; - } - - /* - * Clear any window redraw flags (will have been redrawn as part of - * client). - */ - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - w->flags &= ~WINDOW_REDRAW; - TAILQ_FOREACH(wp, &w->panes, entry) - wp->flags &= ~PANE_REDRAW; - } -} - -/* Handle client pollfds. */ -void -server_handle_clients(struct pollfd **pfd) -{ - struct client *c; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - - if (c != NULL) { - if ((*pfd)->revents & (POLLERR|POLLNVAL|POLLHUP)) { - server_lost_client(c); - (*pfd) += 2; - continue; - } - - if ((*pfd)->revents & POLLOUT) { - if (msgbuf_write(&c->ibuf.w) < 0) { - server_lost_client(c); - (*pfd) += 2; - continue; - } - } - - if (c->flags & CLIENT_BAD) { - if (c->ibuf.w.queued == 0) - server_lost_client(c); - (*pfd) += 2; - continue; - } else if ((*pfd)->revents & POLLIN) { - if (server_msg_dispatch(c) != 0) { - server_lost_client(c); - (*pfd) += 2; - continue; - } - } - } - (*pfd)++; - - if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && - c->tty.fd != -1 && c->session != NULL) { - if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0) - server_lost_client(c); - else - server_handle_client(c); - } - (*pfd)++; - } -} - -/* accept(2) and create new client. */ -void -server_accept_client(int srv_fd) -{ - struct sockaddr_storage sa; - socklen_t slen = sizeof sa; - int fd; - - fd = accept(srv_fd, (struct sockaddr *) &sa, &slen); - if (fd == -1) { - if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) - return; - fatal("accept failed"); - } - if (sigterm) { - close(fd); - return; - } - server_create_client(fd); -} - -/* Input data from client. */ -void -server_handle_client(struct client *c) -{ - struct window *w; - struct window_pane *wp; - struct screen *s; - struct timeval tv; - struct key_binding *bd; - int key, prefix, status, xtimeout; - int mode; - u_char mouse[3]; - - xtimeout = options_get_number(&c->session->options, "repeat-time"); - if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); - if (timercmp(&tv, &c->repeat_timer, >)) - c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); - } - - /* Process keys. */ - prefix = options_get_number(&c->session->options, "prefix"); - while (tty_keys_next(&c->tty, &key, mouse) == 0) { - server_activity = time(NULL); - - if (c->session == NULL) - return; - w = c->session->curw->window; - wp = w->active; /* could die */ - - /* Special case: number keys jump to pane in identify mode. */ - if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { - wp = window_pane_at_index(w, key - '0'); - if (wp != NULL && window_pane_visible(wp)) - window_set_active_pane(w, wp); - server_clear_identify(c); - continue; - } - - status_message_clear(c); - server_clear_identify(c); - if (c->prompt_string != NULL) { - status_prompt_key(c, key); - continue; - } - if (server_locked) - continue; - - /* Check for mouse keys. */ - if (key == KEYC_MOUSE) { - window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]); - continue; - } - - /* No previous prefix key. */ - if (!(c->flags & CLIENT_PREFIX)) { - if (key == prefix) - c->flags |= CLIENT_PREFIX; - else { - /* Try as a non-prefix key binding. */ - if ((bd = key_bindings_lookup(key)) == NULL) - window_pane_key(wp, c, key); - else - key_bindings_dispatch(bd, c); - } - continue; - } - - /* Prefix key already pressed. Reset prefix and lookup key. */ - c->flags &= ~CLIENT_PREFIX; - if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { - /* If repeating, treat this as a key, else ignore. */ - if (c->flags & CLIENT_REPEAT) { - c->flags &= ~CLIENT_REPEAT; - if (key == prefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - } - continue; - } - - /* If already repeating, but this key can't repeat, skip it. */ - if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { - c->flags &= ~CLIENT_REPEAT; - if (key == prefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - continue; - } - - /* If this key can repeat, reset the repeat flags and timer. */ - if (xtimeout != 0 && bd->can_repeat) { - c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - - tv.tv_sec = xtimeout / 1000; - tv.tv_usec = (xtimeout % 1000) * 1000L; - if (gettimeofday(&c->repeat_timer, NULL) != 0) - fatal("gettimeofday"); - timeradd(&c->repeat_timer, &tv, &c->repeat_timer); - } - - /* Dispatch the command. */ - key_bindings_dispatch(bd, c); - } - if (c->session == NULL) - return; - wp = c->session->curw->window->active; /* could die - do each loop */ - s = wp->screen; - - /* - * Update cursor position and mode settings. The scroll region and - * attributes are cleared across poll(2) as this is the most likely - * time a user may interrupt tmux, for example with ~^Z in ssh(1). This - * is a compromise between excessive resets and likelihood of an - * interrupt. - * - * tty_region/tty_reset/tty_update_mode already take care of not - * resetting things that are already in their default state. - */ - status = options_get_number(&c->session->options, "status"); - tty_region(&c->tty, 0, c->tty.sy - 1, 0); - if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) - tty_cursor(&c->tty, 0, 0, 0, 0); - else - tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); - - mode = s->mode; - if (server_locked) - mode &= ~TTY_NOCURSOR; - tty_update_mode(&c->tty, mode); - tty_reset(&c->tty); -} - -/* Lost a client. */ -void -server_lost_client(struct client *c) -{ - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) == c) - ARRAY_SET(&clients, i, NULL); - } - log_debug("lost client %d", c->ibuf.fd); - - /* - * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called - * and tty_free might close an unrelated fd. - */ - if (c->flags & CLIENT_TERMINAL) - tty_free(&c->tty); - - screen_free(&c->status); - - if (c->title != NULL) - xfree(c->title); - - if (c->message_string != NULL) - xfree(c->message_string); - - if (c->prompt_string != NULL) - xfree(c->prompt_string); - if (c->prompt_buffer != NULL) - xfree(c->prompt_buffer); - for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) - xfree(ARRAY_ITEM(&c->prompt_hdata, i)); - ARRAY_FREE(&c->prompt_hdata); - - if (c->cwd != NULL) - xfree(c->cwd); - - close(c->ibuf.fd); - imsg_clear(&c->ibuf); - - for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { - if (ARRAY_ITEM(&dead_clients, i) == NULL) { - ARRAY_SET(&dead_clients, i, c); - break; - } - } - if (i == ARRAY_LENGTH(&dead_clients)) - ARRAY_ADD(&dead_clients, c); - c->flags |= CLIENT_DEAD; - - recalculate_sizes(); -} - /* Free dead, unreferenced clients and sessions. */ void server_clean_dead(void) @@ -1007,272 +528,84 @@ } } -/* Handle window data. */ +/* Call any once-per-second timers. */ void -server_handle_window(struct window *w, struct window_pane *wp) +server_second_timers(void) { - struct session *s; - u_int i; - int update; - - window_pane_parse(wp); + struct window *w; + struct window_pane *wp; + u_int i; - if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0) - return; + if (options_get_number(&global_s_options, "lock-server")) + server_lock_server(); + else + server_lock_sessions(); - update = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL || !session_has(s, w)) + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) continue; - update += server_check_window_bell(s, w); - update += server_check_window_activity(s, w); - update += server_check_window_content(s, w, wp); - } - if (update) - server_status_window(w); - - w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); -} - -int -server_check_window_bell(struct session *s, struct window *w) -{ - struct client *c; - u_int i; - int action, visual; - - if (!(w->flags & WINDOW_BELL)) - return (0); - if (session_alert_has_window(s, w, WINDOW_BELL)) - return (0); - session_alert_add(s, w, WINDOW_BELL); - - action = options_get_number(&s->options, "bell-action"); - switch (action) { - case BELL_ANY: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); - continue; - } - if (c->session->curw->window == w) { - status_message_set(c, "Bell in current window"); - continue; - } - status_message_set(c, "Bell in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - break; - case BELL_CURRENT: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (c->session->curw->window != w) - continue; - if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); - continue; - } - status_message_set(c, "Bell in current window"); - } - break; - } - return (1); -} - -int -server_check_window_activity(struct session *s, struct window *w) -{ - struct client *c; - u_int i; - - if (!(w->flags & WINDOW_ACTIVITY)) - return (0); - - if (!options_get_number(&w->options, "monitor-activity")) - return (0); - - if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) - return (0); - if (s->curw->window == w) - return (0); - - session_alert_add(s, w, WINDOW_ACTIVITY); - if (s->flags & SESSION_UNATTACHED) - return (0); - if (options_get_number(&s->options, "visual-activity")) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - status_message_set(c, "Activity in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - } - - return (1); -} - -int -server_check_window_content( - struct session *s, struct window *w, struct window_pane *wp) -{ - struct client *c; - u_int i; - char *found, *ptr; - - if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ - return (0); - - ptr = options_get_string(&w->options, "monitor-content"); - if (ptr == NULL || *ptr == '\0') - return (0); - - if (session_alert_has_window(s, w, WINDOW_CONTENT)) - return (0); - if (s->curw->window == w) - return (0); - - if ((found = window_pane_search(wp, ptr, NULL)) == NULL) - return (0); - xfree(found); - - session_alert_add(s, w, WINDOW_CONTENT); - if (s->flags & SESSION_UNATTACHED) - return (0); - if (options_get_number(&s->options, "visual-content")) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - status_message_set(c, "Content in window %u", - winlink_find_by_window(&s->windows, w)->idx); + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->mode != NULL && wp->mode->timer != NULL) + wp->mode->timer(wp); } } - - return (1); } -/* Check if window still exists. */ +/* Lock the server if ALL sessions have hit the time limit. */ void -server_check_window(struct window *w) +server_lock_server(void) { - struct window_pane *wp, *wq; - struct options *oo = &w->options; - struct session *s; - struct winlink *wl; - u_int i; - int destroyed; - - destroyed = 1; - - wp = TAILQ_FIRST(&w->panes); - while (wp != NULL) { - wq = TAILQ_NEXT(wp, entry); - /* - * If the pane has died and the remain-on-exit flag is not set, - * remove the pane; otherwise, if the flag is set, don't allow - * the window to be destroyed (or it'll close when the last - * pane dies). - */ - if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) { - layout_close_pane(wp); - window_remove_pane(w, wp); - server_redraw_window(w); - } else - destroyed = 0; - wp = wq; - } - - if (!destroyed) - return; + struct session *s; + u_int i; + int timeout; + time_t t; + t = time(NULL); for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; - if (!session_has(s, w)) + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; - restart: - /* Detach window and either redraw or kill clients. */ - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->window != w) - continue; - if (session_detach(s, wl)) { - server_destroy_session(s); - break; - } - server_redraw_session(s); - goto restart; + if (s->flags & SESSION_UNATTACHED) { + if (gettimeofday(&s->activity_time, NULL) != 0) + fatal("gettimeofday failed"); + continue; } + + timeout = options_get_number(&s->options, "lock-after-time"); + if (timeout <= 0 || t <= s->activity_time.tv_sec + timeout) + return; /* not timed out */ } + server_lock(); recalculate_sizes(); } -/* Call any once-per-second timers. */ +/* Lock any sessions which have timed out. */ void -server_second_timers(void) +server_lock_sessions(void) { - struct window *w; - struct client *c; - struct window_pane *wp; - u_int i; - int xtimeout; - struct tm now, then; - static time_t last_t = 0; - time_t t; + struct session *s; + u_int i; + int timeout; + time_t t; t = time(NULL); - - xtimeout = options_get_number(&global_s_options, "lock-after-time"); - if (xtimeout > 0 && t > server_activity + xtimeout) - server_lock(); - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if ((s = ARRAY_ITEM(&sessions, i)) == NULL) continue; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->mode != NULL && wp->mode->timer != NULL) - wp->mode->timer(wp); - } - } - - if (password_backoff != 0 && t >= password_backoff) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) != NULL) - server_redraw_client(c); + if (s->flags & SESSION_UNATTACHED) { + if (gettimeofday(&s->activity_time, NULL) != 0) + fatal("gettimeofday failed"); + continue; } - password_backoff = 0; - } - - /* Check for a minute having passed. */ - gmtime_r(&t, &now); - gmtime_r(&last_t, &then); - if (now.tm_min == then.tm_min) - return; - last_t = t; - /* If locked, redraw all clients. */ - if (server_locked) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if ((c = ARRAY_ITEM(&clients, i)) != NULL) - server_redraw_client(c); + timeout = options_get_number(&s->options, "lock-after-time"); + if (timeout > 0 && t > s->activity_time.tv_sec + timeout) { + server_lock_session(s); + recalculate_sizes(); } } } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/server-client.c /tmp/wmlmc6MQoR/tmux-1.1/server-client.c --- tmux-1.0/server-client.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/server-client.c 2009-11-04 22:46:25.000000000 +0000 @@ -0,0 +1,768 @@ +/* $Id: server-client.c,v 1.12 2009/11/04 22:46:25 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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 +#include +#include +#include + +#include "tmux.h" + +void server_client_handle_data(struct client *); +void server_client_check_redraw(struct client *); +void server_client_set_title(struct client *); +void server_client_check_timers(struct client *); + +int server_client_msg_dispatch(struct client *); +void server_client_msg_command(struct client *, struct msg_command_data *); +void server_client_msg_identify( + struct client *, struct msg_identify_data *, int); +void server_client_msg_shell(struct client *); + +void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); +void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...); +void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...); + + +/* Create a new client. */ +void +server_client_create(int fd) +{ + struct client *c; + int mode; + u_int i; + + 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"); + + c = xcalloc(1, sizeof *c); + c->references = 0; + imsg_init(&c->ibuf, fd); + + if (gettimeofday(&c->creation_time, NULL) != 0) + fatal("gettimeofday failed"); + memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); + + ARRAY_INIT(&c->prompt_hdata); + + c->tty.fd = -1; + c->title = NULL; + + c->session = NULL; + c->tty.sx = 80; + c->tty.sy = 24; + + screen_init(&c->status, c->tty.sx, 1, 0); + job_tree_init(&c->status_jobs); + + c->message_string = NULL; + + c->prompt_string = NULL; + c->prompt_buffer = NULL; + c->prompt_index = 0; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) == NULL) { + ARRAY_SET(&clients, i, c); + return; + } + } + ARRAY_ADD(&clients, c); + log_debug("new client %d", fd); +} + +/* Lost a client. */ +void +server_client_lost(struct client *c) +{ + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) == c) + ARRAY_SET(&clients, i, NULL); + } + log_debug("lost client %d", c->ibuf.fd); + + /* + * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called + * and tty_free might close an unrelated fd. + */ + if (c->flags & CLIENT_TERMINAL) + tty_free(&c->tty); + + screen_free(&c->status); + job_tree_free(&c->status_jobs); + + if (c->title != NULL) + xfree(c->title); + + if (c->message_string != NULL) + xfree(c->message_string); + + if (c->prompt_string != NULL) + xfree(c->prompt_string); + if (c->prompt_buffer != NULL) + xfree(c->prompt_buffer); + for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) + xfree(ARRAY_ITEM(&c->prompt_hdata, i)); + ARRAY_FREE(&c->prompt_hdata); + + if (c->cwd != NULL) + xfree(c->cwd); + + close(c->ibuf.fd); + imsg_clear(&c->ibuf); + + for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { + if (ARRAY_ITEM(&dead_clients, i) == NULL) { + ARRAY_SET(&dead_clients, i, c); + break; + } + } + if (i == ARRAY_LENGTH(&dead_clients)) + ARRAY_ADD(&dead_clients, c); + c->flags |= CLIENT_DEAD; + + recalculate_sizes(); +} + +/* Register clients for poll. */ +void +server_client_prepare(void) +{ + struct client *c; + u_int i; + int events; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if ((c = ARRAY_ITEM(&clients, i)) == NULL) + continue; + + events = 0; + if (!(c->flags & CLIENT_BAD)) + events |= POLLIN; + if (c->ibuf.w.queued > 0) + events |= POLLOUT; + server_poll_add(c->ibuf.fd, events, server_client_callback, c); + + if (c->tty.fd == -1) + continue; + if (c->flags & CLIENT_SUSPENDED || c->session == NULL) + continue; + events = POLLIN; + if (BUFFER_USED(c->tty.out) > 0) + events |= POLLOUT; + server_poll_add(c->tty.fd, events, server_client_callback, c); + } +} + +/* Process a single client event. */ +void +server_client_callback(int fd, int events, void *data) +{ + struct client *c = data; + + if (c->flags & CLIENT_DEAD) + return; + + if (fd == c->ibuf.fd) { + if (events & (POLLERR|POLLNVAL|POLLHUP)) + goto client_lost; + + if (events & POLLOUT && msgbuf_write(&c->ibuf.w) < 0) + goto client_lost; + + if (c->flags & CLIENT_BAD) { + if (c->ibuf.w.queued == 0) + goto client_lost; + return; + } + + if (events & POLLIN && server_client_msg_dispatch(c) != 0) + goto client_lost; + } + + if (c->tty.fd != -1 && fd == c->tty.fd) { + if (c->flags & CLIENT_SUSPENDED || c->session == NULL) + return; + + if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0) + goto client_lost; + } + + return; + +client_lost: + server_client_lost(c); +} + +/* Client functions that need to happen every loop. */ +void +server_client_loop(void) +{ + struct client *c; + struct window *w; + struct window_pane *wp; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + server_client_handle_data(c); + if (c->session != NULL) { + server_client_check_timers(c); + server_client_check_redraw(c); + } + } + + /* + * Any windows will have been redrawn as part of clients, so clear + * their flags now. + */ + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + w->flags &= ~WINDOW_REDRAW; + TAILQ_FOREACH(wp, &w->panes, entry) + wp->flags &= ~PANE_REDRAW; + } +} + +/* Handle data input or output from client. */ +void +server_client_handle_data(struct client *c) +{ + struct window *w; + struct window_pane *wp; + struct screen *s; + struct options *oo; + struct timeval tv_add, tv_now; + struct key_binding *bd; + struct keylist *keylist; + struct mouse_event mouse; + int key, status, xtimeout, mode, isprefix; + u_int i; + + /* Check and update repeat flag. */ + if (gettimeofday(&tv_now, NULL) != 0) + fatal("gettimeofday failed"); + xtimeout = options_get_number(&c->session->options, "repeat-time"); + if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { + if (timercmp(&tv_now, &c->repeat_timer, >)) + c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); + } + + /* Process keys. */ + keylist = options_get_data(&c->session->options, "prefix"); + while (tty_keys_next(&c->tty, &key, &mouse) == 0) { + if (c->session == NULL) + return; + w = c->session->curw->window; + wp = w->active; /* could die */ + oo = &c->session->options; + + /* Update activity timer. */ + memcpy(&c->activity_time, &tv_now, sizeof c->activity_time); + memcpy(&c->session->activity_time, + &tv_now, sizeof c->session->activity_time); + + /* Special case: number keys jump to pane in identify mode. */ + if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { + wp = window_pane_at_index(w, key - '0'); + if (wp != NULL && window_pane_visible(wp)) + window_set_active_pane(w, wp); + server_clear_identify(c); + continue; + } + + status_message_clear(c); + server_clear_identify(c); + if (c->prompt_string != NULL) { + status_prompt_key(c, key); + continue; + } + + /* Check for mouse keys. */ + if (key == KEYC_MOUSE) { + if (options_get_number(oo, "mouse-select-pane")) { + window_set_active_at(w, mouse.x, mouse.y); + wp = w->active; + } + window_pane_mouse(wp, c, &mouse); + continue; + } + + /* Is this a prefix key? */ + isprefix = 0; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + if (key == ARRAY_ITEM(keylist, i)) { + isprefix = 1; + break; + } + } + + /* No previous prefix key. */ + if (!(c->flags & CLIENT_PREFIX)) { + if (isprefix) + c->flags |= CLIENT_PREFIX; + else { + /* Try as a non-prefix key binding. */ + if ((bd = key_bindings_lookup(key)) == NULL) + window_pane_key(wp, c, key); + else + key_bindings_dispatch(bd, c); + } + continue; + } + + /* Prefix key already pressed. Reset prefix and lookup key. */ + c->flags &= ~CLIENT_PREFIX; + if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { + /* If repeating, treat this as a key, else ignore. */ + if (c->flags & CLIENT_REPEAT) { + c->flags &= ~CLIENT_REPEAT; + if (isprefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + } + continue; + } + + /* If already repeating, but this key can't repeat, skip it. */ + if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { + c->flags &= ~CLIENT_REPEAT; + if (isprefix) + c->flags |= CLIENT_PREFIX; + else + window_pane_key(wp, c, key); + continue; + } + + /* If this key can repeat, reset the repeat flags and timer. */ + if (xtimeout != 0 && bd->can_repeat) { + c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; + + tv_add.tv_sec = xtimeout / 1000; + tv_add.tv_usec = (xtimeout % 1000) * 1000L; + timeradd(&tv_now, &tv_add, &c->repeat_timer); + } + + /* Dispatch the command. */ + key_bindings_dispatch(bd, c); + } + if (c->session == NULL) + return; + w = c->session->curw->window; + wp = w->active; + oo = &c->session->options; + s = wp->screen; + + /* + * Update cursor position and mode settings. The scroll region and + * attributes are cleared across poll(2) as this is the most likely + * time a user may interrupt tmux, for example with ~^Z in ssh(1). This + * is a compromise between excessive resets and likelihood of an + * interrupt. + * + * tty_region/tty_reset/tty_update_mode already take care of not + * resetting things that are already in their default state. + */ + tty_region(&c->tty, 0, c->tty.sy - 1); + + status = options_get_number(oo, "status"); + if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) + tty_cursor(&c->tty, 0, 0); + else + tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); + + mode = s->mode; + if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && + options_get_number(oo, "mouse-select-pane")) + mode |= MODE_MOUSE; + tty_update_mode(&c->tty, mode); + tty_reset(&c->tty); +} + +/* Check for client redraws. */ +void +server_client_check_redraw(struct client *c) +{ + struct session *s = c->session; + struct window_pane *wp; + int flags, redraw; + + flags = c->tty.flags & TTY_FREEZE; + c->tty.flags &= ~TTY_FREEZE; + + if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { + if (options_get_number(&s->options, "set-titles")) + server_client_set_title(c); + + if (c->message_string != NULL) + redraw = status_message_redraw(c); + else if (c->prompt_string != NULL) + redraw = status_prompt_redraw(c); + else + redraw = status_redraw(c); + if (!redraw) + c->flags &= ~CLIENT_STATUS; + } + + if (c->flags & CLIENT_REDRAW) { + screen_redraw_screen(c, 0); + c->flags &= ~CLIENT_STATUS; + } else { + TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { + if (wp->flags & PANE_REDRAW) + screen_redraw_pane(c, wp); + } + } + + if (c->flags & CLIENT_STATUS) + screen_redraw_screen(c, 1); + + c->tty.flags |= flags; + + c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); +} + +/* Set client title. */ +void +server_client_set_title(struct client *c) +{ + struct session *s = c->session; + const char *template; + char *title; + + template = options_get_string(&s->options, "set-titles-string"); + + title = status_replace(c, template, time(NULL)); + if (c->title == NULL || strcmp(title, c->title) != 0) { + if (c->title != NULL) + xfree(c->title); + c->title = xstrdup(title); + tty_set_title(&c->tty, c->title); + } + xfree(title); +} + +/* Check client timers. */ +void +server_client_check_timers(struct client *c) +{ + struct session *s = c->session; + struct job *job; + struct timeval tv; + u_int interval; + + if (gettimeofday(&tv, NULL) != 0) + fatal("gettimeofday failed"); + + if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) + server_clear_identify(c); + + if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) + status_message_clear(c); + + if (c->message_string != NULL || c->prompt_string != NULL) { + /* + * Don't need timed redraw for messages/prompts so bail now. + * The status timer isn't reset when they are redrawn anyway. + */ + return; + + } + if (!options_get_number(&s->options, "status")) + return; + + /* Check timer; resolution is only a second so don't be too clever. */ + interval = options_get_number(&s->options, "status-interval"); + if (interval == 0) + return; + if (tv.tv_sec < c->status_timer.tv_sec || + ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) { + /* Run the jobs for this client and schedule for redraw. */ + RB_FOREACH(job, jobs, &c->status_jobs) + job_run(job); + c->flags |= CLIENT_STATUS; + } +} + +/* Dispatch message from client. */ +int +server_client_msg_dispatch(struct client *c) +{ + struct imsg imsg; + struct msg_command_data commanddata; + struct msg_identify_data identifydata; + struct msg_environ_data environdata; + ssize_t n, datalen; + + if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) + return (-1); + + for (;;) { + if ((n = imsg_get(&c->ibuf, &imsg)) == -1) + return (-1); + if (n == 0) + return (0); + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + if (imsg.hdr.peerid != PROTOCOL_VERSION) { + server_write_client(c, MSG_VERSION, NULL, 0); + c->flags |= CLIENT_BAD; + imsg_free(&imsg); + continue; + } + + log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); + switch (imsg.hdr.type) { + case MSG_COMMAND: + if (datalen != sizeof commanddata) + fatalx("bad MSG_COMMAND size"); + memcpy(&commanddata, imsg.data, sizeof commanddata); + + server_client_msg_command(c, &commanddata); + break; + case MSG_IDENTIFY: + if (datalen != sizeof identifydata) + fatalx("bad MSG_IDENTIFY size"); + if (imsg.fd == -1) + fatalx("MSG_IDENTIFY missing fd"); + memcpy(&identifydata, imsg.data, sizeof identifydata); + + server_client_msg_identify(c, &identifydata, imsg.fd); + break; + case MSG_RESIZE: + if (datalen != 0) + fatalx("bad MSG_RESIZE size"); + + tty_resize(&c->tty); + recalculate_sizes(); + server_redraw_client(c); + break; + case MSG_EXITING: + if (datalen != 0) + fatalx("bad MSG_EXITING size"); + + c->session = NULL; + tty_close(&c->tty); + server_write_client(c, MSG_EXITED, NULL, 0); + break; + case MSG_WAKEUP: + case MSG_UNLOCK: + if (datalen != 0) + fatalx("bad MSG_WAKEUP size"); + + if (!(c->flags & CLIENT_SUSPENDED)) + break; + c->flags &= ~CLIENT_SUSPENDED; + + if (gettimeofday(&c->activity_time, NULL) != 0) + fatal("gettimeofday"); + if (c->session != NULL) { + memcpy(&c->session->activity_time, + &c->activity_time, + sizeof c->session->activity_time); + } + + tty_start_tty(&c->tty); + server_redraw_client(c); + recalculate_sizes(); + break; + case MSG_ENVIRON: + if (datalen != sizeof environdata) + fatalx("bad MSG_ENVIRON size"); + memcpy(&environdata, imsg.data, sizeof environdata); + + environdata.var[(sizeof environdata.var) - 1] = '\0'; + if (strchr(environdata.var, '=') != NULL) + environ_put(&c->environ, environdata.var); + break; + case MSG_SHELL: + if (datalen != 0) + fatalx("bad MSG_SHELL size"); + + server_client_msg_shell(c); + break; + default: + fatalx("unexpected message"); + } + + imsg_free(&imsg); + } +} + +/* Callback to send error message to client. */ +void printflike2 +server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct msg_print_data data; + va_list ap; + + va_start(ap, fmt); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data); +} + +/* Callback to send print message to client. */ +void printflike2 +server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct msg_print_data data; + va_list ap; + + va_start(ap, fmt); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); +} + +/* Callback to send print message to client, if not quiet. */ +void printflike2 +server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) +{ + struct msg_print_data data; + va_list ap; + + if (be_quiet) + return; + + va_start(ap, fmt); + xvsnprintf(data.msg, sizeof data.msg, fmt, ap); + va_end(ap); + + server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); +} + +/* Handle command message. */ +void +server_client_msg_command(struct client *c, struct msg_command_data *data) +{ + struct cmd_ctx ctx; + struct cmd_list *cmdlist = NULL; + struct cmd *cmd; + int argc; + char **argv, *cause; + + ctx.error = server_client_msg_error; + ctx.print = server_client_msg_print; + ctx.info = server_client_msg_info; + + ctx.msgdata = data; + ctx.curclient = NULL; + + ctx.cmdclient = c; + + argc = data->argc; + data->argv[(sizeof data->argv) - 1] = '\0'; + if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { + server_client_msg_error(&ctx, "command too long"); + goto error; + } + + if (argc == 0) { + argc = 1; + argv = xcalloc(1, sizeof *argv); + *argv = xstrdup("new-session"); + } + + if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { + server_client_msg_error(&ctx, "%s", cause); + cmd_free_argv(argc, argv); + goto error; + } + cmd_free_argv(argc, argv); + + if (data->pid != -1) { + TAILQ_FOREACH(cmd, cmdlist, qentry) { + if (cmd->entry->flags & CMD_CANTNEST) { + server_client_msg_error(&ctx, + "sessions should be nested with care. " + "unset $TMUX to force"); + goto error; + } + } + } + + if (cmd_list_exec(cmdlist, &ctx) != 1) + server_write_client(c, MSG_EXIT, NULL, 0); + cmd_list_free(cmdlist); + return; + +error: + if (cmdlist != NULL) + cmd_list_free(cmdlist); + server_write_client(c, MSG_EXIT, NULL, 0); +} + +/* Handle identify message. */ +void +server_client_msg_identify( + struct client *c, struct msg_identify_data *data, int fd) +{ + c->cwd = NULL; + data->cwd[(sizeof data->cwd) - 1] = '\0'; + if (*data->cwd != '\0') + c->cwd = xstrdup(data->cwd); + + data->term[(sizeof data->term) - 1] = '\0'; + tty_init(&c->tty, fd, data->term); + if (data->flags & IDENTIFY_UTF8) + c->tty.flags |= TTY_UTF8; + if (data->flags & IDENTIFY_256COLOURS) + c->tty.term_flags |= TERM_256COLOURS; + else if (data->flags & IDENTIFY_88COLOURS) + c->tty.term_flags |= TERM_88COLOURS; + + tty_resize(&c->tty); + + c->flags |= CLIENT_TERMINAL; +} + +/* Handle shell message. */ +void +server_client_msg_shell(struct client *c) +{ + struct msg_shell_data data; + const char *shell; + + shell = options_get_string(&global_s_options, "default-shell"); + + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) + strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); + + server_write_client(c, MSG_SHELL, &data, sizeof data); + c->flags |= CLIENT_BAD; /* it will die after exec */ +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/server-fn.c /tmp/wmlmc6MQoR/tmux-1.1/server-fn.c --- tmux-1.0/server-fn.c 2009-09-15 19:54:57.000000000 +0100 +++ tmux-1.1/server-fn.c 2009-10-12 01:37:41.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: server-fn.c,v 1.87 2009/09/13 20:37:37 tcunha Exp $ */ +/* $Id: server-fn.c,v 1.94 2009/10/12 00:37:41 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -18,15 +18,12 @@ #include -#include #include #include #include #include "tmux.h" -int server_lock_callback(void *, const char *); - void server_fill_environ(struct session *s, struct environ *env) { @@ -108,6 +105,19 @@ } void +server_redraw_session_group(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + server_redraw_session(s); + else { + TAILQ_FOREACH(s, &sg->sessions, gentry) + server_redraw_session(s); + } +} + +void server_status_session(struct session *s) { struct client *c; @@ -123,6 +133,19 @@ } void +server_status_session_group(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + server_status_session(s); + else { + TAILQ_FOREACH(s, &sg->sessions, gentry) + server_status_session(s); + } +} + +void server_redraw_window(struct window *w) { struct client *c; @@ -160,117 +183,52 @@ void server_lock(void) { - struct client *c; - static struct passwd *pw, pwstore; - static char pwbuf[_PW_BUF_LEN]; - u_int i; - - if (server_locked) - return; - - if (getpwuid_r(getuid(), &pwstore, pwbuf, sizeof pwbuf, &pw) != 0) { - server_locked_pw = NULL; - return; - } - server_locked_pw = pw; + struct client *c; + u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; - - status_prompt_clear(c); - status_prompt_set(c, - "Password:", server_lock_callback, NULL, c, PROMPT_HIDDEN); - server_redraw_client(c); + server_lock_client(c); } - - server_locked = 1; } -int -server_lock_callback(unused void *data, const char *s) -{ - return (server_unlock(s)); -} - -int -server_unlock(const char *s) +void +server_lock_session(struct session *s) { struct client *c; -#ifdef HAVE_LOGIN_CAP - login_cap_t *lc; -#endif u_int i; - char *out; - u_int failures, tries, backoff; - - if (!server_locked || server_locked_pw == NULL) - return (0); - server_activity = time(NULL); - if (server_activity < password_backoff) - return (-2); - - if (server_password != NULL) { - if (s == NULL) - return (-1); - out = crypt(s, server_password); - if (strcmp(out, server_password) != 0) - goto wrong; - } for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL) + if (c == NULL || c->session == NULL || c->session != s) continue; + server_lock_client(c); + } +} - status_prompt_clear(c); - server_redraw_client(c); - } - - server_locked = 0; - password_failures = 0; - password_backoff = 0; - return (0); - -wrong: - password_failures++; - password_backoff = 0; +void +server_lock_client(struct client *c) +{ + const char *cmd; + size_t cmdlen; + struct msg_lock_data lockdata; - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->prompt_buffer == NULL) - continue; + if (c->flags & CLIENT_SUSPENDED) + return; - *c->prompt_buffer = '\0'; - c->prompt_index = 0; - server_redraw_client(c); - } + cmd = options_get_string(&c->session->options, "lock-command"); + cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); + if (cmdlen >= sizeof lockdata.cmd) + return; + + tty_stop_tty(&c->tty); + tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); + tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); - /* - * Start slowing down after "login-backoff" attempts and reset every - * "login-tries" attempts. - */ -#ifdef HAVE_LOGIN_CAP - lc = login_getclass(server_locked_pw->pw_class); - if (lc != NULL) { - tries = login_getcapnum(lc, (char *) "login-tries", 10, 10); - backoff = login_getcapnum(lc, (char *) "login-backoff", 3, 3); - } else { - tries = 10; - backoff = 3; - } -#else - tries = 10; - backoff = 3; -#endif - failures = password_failures % tries; - if (failures > backoff) { - password_backoff = - server_activity + ((failures - backoff) * tries / 2); - return (-2); - } - return (-1); + c->flags |= CLIENT_SUSPENDED; + server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); } void @@ -288,11 +246,86 @@ continue; if (session_detach(s, wl)) - server_destroy_session(s); - else + server_destroy_session_group(s); + else { server_redraw_session(s); + server_status_session_group(s); + } + } +} + +int +server_link_window(struct session *src, struct winlink *srcwl, + struct session *dst, int dstidx, int killflag, int selectflag, char **cause) +{ + struct winlink *dstwl; + struct session_group *srcsg, *dstsg; + + srcsg = session_group_find(src); + dstsg = session_group_find(dst); + if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) { + xasprintf(cause, "sessions are grouped"); + return (-1); + } + + dstwl = NULL; + if (dstidx != -1) + dstwl = winlink_find_by_index(&dst->windows, dstidx); + if (dstwl != NULL) { + if (dstwl->window == srcwl->window) + return (0); + if (killflag) { + /* + * Can't use session_detach as it will destroy session + * if this makes it empty. + */ + session_alert_cancel(dst, dstwl); + winlink_stack_remove(&dst->lastw, dstwl); + winlink_remove(&dst->windows, dstwl); + + /* Force select/redraw if current. */ + if (dstwl == dst->curw) { + selectflag = 1; + dst->curw = NULL; + } + } + } + + if (dstidx == -1) + dstidx = -1 - options_get_number(&dst->options, "base-index"); + dstwl = session_attach(dst, srcwl->window, dstidx, cause); + if (dstwl == NULL) + return (-1); + + if (selectflag) + session_select(dst, dstwl->idx); + server_redraw_session_group(dst); + + return (0); +} + +void +server_unlink_window(struct session *s, struct winlink *wl) +{ + if (session_detach(s, wl)) + server_destroy_session_group(s); + else + server_redraw_session_group(s); +} + +void +server_destroy_session_group(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + server_destroy_session(s); + else { + TAILQ_FOREACH(s, &sg->sessions, gentry) + server_destroy_session(s); + TAILQ_REMOVE(&session_groups, sg, entry); + xfree(sg); } - recalculate_sizes(); } void @@ -321,7 +354,7 @@ tv.tv_usec = (delay % 1000) * 1000L; if (gettimeofday(&c->identify_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); timeradd(&c->identify_timer, &tv, &c->identify_timer); c->flags |= CLIENT_IDENTIFY; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/server-job.c /tmp/wmlmc6MQoR/tmux-1.1/server-job.c --- tmux-1.0/server-job.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/server-job.c 2009-11-02 21:38:26.000000000 +0000 @@ -0,0 +1,73 @@ +/* $Id: server-job.c,v 1.3 2009/11/02 21:38:26 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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 + +#include "tmux.h" + +/* Register jobs for poll. */ +void +server_job_prepare(void) +{ + struct job *job; + + SLIST_FOREACH(job, &all_jobs, lentry) { + if (job->fd == -1) + continue; + server_poll_add(job->fd, POLLIN, server_job_callback, job); + } +} + +/* Process a single job event. */ +void +server_job_callback(int fd, int events, void *data) +{ + struct job *job = data; + + if (job->fd == -1) + return; + + if (buffer_poll(fd, events, job->out, NULL) != 0) { + close(job->fd); + job->fd = -1; + } +} + +/* Job functions that happen once a loop. */ +void +server_job_loop(void) +{ + struct job *job; + +restart: + SLIST_FOREACH(job, &all_jobs, lentry) { + if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) + continue; + job->flags |= JOB_DONE; + + if (job->callbackfn != NULL) { + job->callbackfn(job); + if ((!job->flags & JOB_PERSIST)) { + job_free(job); + goto restart; + } + } + } +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/server-msg.c /tmp/wmlmc6MQoR/tmux-1.1/server-msg.c --- tmux-1.0/server-msg.c 2009-09-20 14:56:11.000000000 +0100 +++ tmux-1.1/server-msg.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,292 +0,0 @@ -/* $Id: server-msg.c,v 1.84 2009/09/15 23:52:30 tcunha Exp $ */ - -/* - * Copyright (c) 2007 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 -#include -#include -#include -#include - -#include "tmux.h" - -void server_msg_command(struct client *, struct msg_command_data *); -void server_msg_identify(struct client *, struct msg_identify_data *, int); -void server_msg_resize(struct client *, struct msg_resize_data *); - -void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...); -void printflike2 server_msg_command_print(struct cmd_ctx *, const char *, ...); -void printflike2 server_msg_command_info(struct cmd_ctx *, const char *, ...); - -int -server_msg_dispatch(struct client *c) -{ - struct imsg imsg; - struct msg_command_data commanddata; - struct msg_identify_data identifydata; - struct msg_resize_data resizedata; - struct msg_unlock_data unlockdata; - struct msg_environ_data environdata; - ssize_t n, datalen; - - if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) - return (-1); - - for (;;) { - if ((n = imsg_get(&c->ibuf, &imsg)) == -1) - return (-1); - if (n == 0) - return (0); - datalen = imsg.hdr.len - IMSG_HEADER_SIZE; - - if (imsg.hdr.peerid != PROTOCOL_VERSION) { - server_write_client(c, MSG_VERSION, NULL, 0); - c->flags |= CLIENT_BAD; - imsg_free(&imsg); - continue; - } - - log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); - switch (imsg.hdr.type) { - case MSG_COMMAND: - if (datalen != sizeof commanddata) - fatalx("bad MSG_COMMAND size"); - memcpy(&commanddata, imsg.data, sizeof commanddata); - - server_msg_command(c, &commanddata); - break; - case MSG_IDENTIFY: - if (datalen != sizeof identifydata) - fatalx("bad MSG_IDENTIFY size"); - memcpy(&identifydata, imsg.data, sizeof identifydata); - - server_msg_identify(c, &identifydata, imsg.fd); - break; - case MSG_RESIZE: - if (datalen != sizeof resizedata) - fatalx("bad MSG_RESIZE size"); - memcpy(&resizedata, imsg.data, sizeof resizedata); - - server_msg_resize(c, &resizedata); - break; - case MSG_EXITING: - if (datalen != 0) - fatalx("bad MSG_EXITING size"); - - c->session = NULL; - tty_close(&c->tty); - server_write_client(c, MSG_EXITED, NULL, 0); - break; - case MSG_UNLOCK: - if (datalen != sizeof unlockdata) - fatalx("bad MSG_UNLOCK size"); - memcpy(&unlockdata, imsg.data, sizeof unlockdata); - - unlockdata.pass[(sizeof unlockdata.pass) - 1] = '\0'; - switch (server_unlock(unlockdata.pass)) { - case -1: - server_write_error(c, "bad password"); - break; - case -2: - server_write_error(c, - "too many bad passwords, sleeping"); - break; - } - memset(&unlockdata, 0, sizeof unlockdata); - server_write_client(c, MSG_EXIT, NULL, 0); - break; - case MSG_WAKEUP: - if (datalen != 0) - fatalx("bad MSG_WAKEUP size"); - - c->flags &= ~CLIENT_SUSPENDED; - tty_start_tty(&c->tty); - server_redraw_client(c); - break; - case MSG_ENVIRON: - if (datalen != sizeof environdata) - fatalx("bad MSG_ENVIRON size"); - memcpy(&environdata, imsg.data, sizeof environdata); - - environdata.var[(sizeof environdata.var) - 1] = '\0'; - if (strchr(environdata.var, '=') != NULL) - environ_put(&c->environ, environdata.var); - break; - default: - fatalx("unexpected message"); - } - - imsg_free(&imsg); - } -} - -void printflike2 -server_msg_command_error(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct msg_print_data data; - va_list ap; - - va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); - va_end(ap); - - server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data); -} - -void printflike2 -server_msg_command_print(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct msg_print_data data; - va_list ap; - - va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); - va_end(ap); - - server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); -} - -void printflike2 -server_msg_command_info(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct msg_print_data data; - va_list ap; - - if (be_quiet) - return; - - va_start(ap, fmt); - xvsnprintf(data.msg, sizeof data.msg, fmt, ap); - va_end(ap); - - server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); -} - -void -server_msg_command(struct client *c, struct msg_command_data *data) -{ - struct cmd_ctx ctx; - struct cmd_list *cmdlist = NULL; - struct cmd *cmd; - int argc; - char **argv, *cause; - - server_activity = time(NULL); - - ctx.error = server_msg_command_error; - ctx.print = server_msg_command_print; - ctx.info = server_msg_command_info; - - ctx.msgdata = data; - ctx.curclient = NULL; - - ctx.cmdclient = c; - - argc = data->argc; - data->argv[(sizeof data->argv) - 1] = '\0'; - if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { - server_msg_command_error(&ctx, "command too long"); - goto error; - } - - if (argc == 0) { - argc = 1; - argv = xcalloc(1, sizeof *argv); - *argv = xstrdup("new-session"); - } - - if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { - server_msg_command_error(&ctx, "%s", cause); - cmd_free_argv(argc, argv); - goto error; - } - cmd_free_argv(argc, argv); - - if (data->pid != -1) { - TAILQ_FOREACH(cmd, cmdlist, qentry) { - if (cmd->entry->flags & CMD_CANTNEST) { - server_msg_command_error(&ctx, - "sessions should be nested with care. " - "unset $TMUX to force"); - goto error; - } - } - } - - if (cmd_list_exec(cmdlist, &ctx) != 1) - server_write_client(c, MSG_EXIT, NULL, 0); - cmd_list_free(cmdlist); - return; - -error: - if (cmdlist != NULL) - cmd_list_free(cmdlist); - server_write_client(c, MSG_EXIT, NULL, 0); -} - -void -server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) -{ - c->tty.sx = data->sx; - if (c->tty.sx == 0) - c->tty.sx = 80; - c->tty.sy = data->sy; - if (c->tty.sy == 0) - c->tty.sy = 24; - - c->cwd = NULL; - data->cwd[(sizeof data->cwd) - 1] = '\0'; - if (*data->cwd != '\0') - c->cwd = xstrdup(data->cwd); - - data->tty[(sizeof data->tty) - 1] = '\0'; - data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, fd, data->tty, data->term); - if (data->flags & IDENTIFY_UTF8) - c->tty.flags |= TTY_UTF8; - if (data->flags & IDENTIFY_256COLOURS) - c->tty.term_flags |= TERM_256COLOURS; - else if (data->flags & IDENTIFY_88COLOURS) - c->tty.term_flags |= TERM_88COLOURS; - if (data->flags & IDENTIFY_HASDEFAULTS) - c->tty.term_flags |= TERM_HASDEFAULTS; - - c->flags |= CLIENT_TERMINAL; -} - -void -server_msg_resize(struct client *c, struct msg_resize_data *data) -{ - c->tty.sx = data->sx; - if (c->tty.sx == 0) - c->tty.sx = 80; - c->tty.sy = data->sy; - if (c->tty.sy == 0) - c->tty.sy = 24; - - c->tty.cx = UINT_MAX; - c->tty.cy = UINT_MAX; - c->tty.rupper = UINT_MAX; - c->tty.rlower = UINT_MAX; - - recalculate_sizes(); - - /* Always redraw this client. */ - server_redraw_client(c); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/server-window.c /tmp/wmlmc6MQoR/tmux-1.1/server-window.c --- tmux-1.0/server-window.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/server-window.c 2009-11-04 22:47:29.000000000 +0000 @@ -0,0 +1,341 @@ +/* $Id: server-window.c,v 1.4 2009/11/04 22:47:29 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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 + +#include "tmux.h" + +int server_window_backoff(struct window_pane *); +int server_window_check_bell(struct session *, struct window *); +int server_window_check_activity(struct session *, struct window *); +int server_window_check_content( + struct session *, struct window *, struct window_pane *); +void server_window_check_alive(struct window *); + +/* Register windows for poll. */ +void +server_window_prepare(void) +{ + struct window *w; + struct window_pane *wp; + u_int i; + int events; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if ((w = ARRAY_ITEM(&windows, i)) == NULL) + continue; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->fd == -1) + continue; + events = 0; + if (!server_window_backoff(wp)) + events |= POLLIN; + if (BUFFER_USED(wp->out) > 0) + events |= POLLOUT; + server_poll_add( + wp->fd, events, server_window_callback, wp); + + if (wp->pipe_fd == -1) + continue; + events = 0; + if (BUFFER_USED(wp->pipe_buf) > 0) + events |= POLLOUT; + server_poll_add( + wp->pipe_fd, events, server_window_callback, wp); + } + } +} + +/* Check if this window should suspend reading. */ +int +server_window_backoff(struct window_pane *wp) +{ + struct client *c; + u_int i; + + if (!window_pane_visible(wp)) + return (0); + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0) + continue; + if (c->session->curw->window != wp->window) + continue; + if (BUFFER_USED(c->tty.out) > BACKOFF_THRESHOLD) + return (1); + } + return (0); +} + +/* Process a single window pane event. */ +void +server_window_callback(int fd, int events, void *data) +{ + struct window_pane *wp = data; + + if (wp->fd == -1) + return; + + if (fd == wp->fd) { + if (buffer_poll(fd, events, wp->in, wp->out) != 0) { + close(wp->fd); + wp->fd = -1; + } else + window_pane_parse(wp); + } + + if (fd == wp->pipe_fd) { + if (buffer_poll(fd, events, NULL, wp->pipe_buf) != 0) { + buffer_destroy(wp->pipe_buf); + close(wp->pipe_fd); + wp->pipe_fd = -1; + } + } +} + +/* Window functions that need to happen every loop. */ +void +server_window_loop(void) +{ + struct window *w; + struct window_pane *wp; + struct session *s; + u_int i, j; + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { + s = ARRAY_ITEM(&sessions, j); + if (s == NULL || !session_has(s, w)) + continue; + + if (server_window_check_bell(s, w) || + server_window_check_activity(s, w)) + server_status_session(s); + TAILQ_FOREACH(wp, &w->panes, entry) + server_window_check_content(s, w, wp); + } + w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); + + server_window_check_alive(w); + } + + set_window_names(); +} + +/* Check for bell in window. */ +int +server_window_check_bell(struct session *s, struct window *w) +{ + struct client *c; + u_int i; + int action, visual; + + if (!(w->flags & WINDOW_BELL)) + return (0); + + if (session_alert_has_window(s, w, WINDOW_BELL)) + return (0); + session_alert_add(s, w, WINDOW_BELL); + + action = options_get_number(&s->options, "bell-action"); + switch (action) { + case BELL_ANY: + if (s->flags & SESSION_UNATTACHED) + break; + visual = options_get_number(&s->options, "visual-bell"); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (!visual) { + tty_putcode(&c->tty, TTYC_BEL); + continue; + } + if (c->session->curw->window == w) { + status_message_set(c, "Bell in current window"); + continue; + } + status_message_set(c, "Bell in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + break; + case BELL_CURRENT: + if (s->flags & SESSION_UNATTACHED) + break; + visual = options_get_number(&s->options, "visual-bell"); + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + if (c->session->curw->window != w) + continue; + if (!visual) { + tty_putcode(&c->tty, TTYC_BEL); + continue; + } + status_message_set(c, "Bell in current window"); + } + break; + } + + return (1); +} + +/* Check for activity in window. */ +int +server_window_check_activity(struct session *s, struct window *w) +{ + struct client *c; + u_int i; + + if (!(w->flags & WINDOW_ACTIVITY)) + return (0); + if (s->curw->window == w) + return (0); + + if (!options_get_number(&w->options, "monitor-activity")) + return (0); + + if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) + return (0); + session_alert_add(s, w, WINDOW_ACTIVITY); + + if (s->flags & SESSION_UNATTACHED) + return (0); + if (options_get_number(&s->options, "visual-activity")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Activity in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + + return (1); +} + +/* Check for content change in window. */ +int +server_window_check_content( + struct session *s, struct window *w, struct window_pane *wp) +{ + struct client *c; + u_int i; + char *found, *ptr; + + if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ + return (0); + if (s->curw->window == w) + return (0); + + ptr = options_get_string(&w->options, "monitor-content"); + if (ptr == NULL || *ptr == '\0') + return (0); + + if (session_alert_has_window(s, w, WINDOW_CONTENT)) + return (0); + + if ((found = window_pane_search(wp, ptr, NULL)) == NULL) + return (0); + xfree(found); + + session_alert_add(s, w, WINDOW_CONTENT); + if (s->flags & SESSION_UNATTACHED) + return (0); + if (options_get_number(&s->options, "visual-content")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Content in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + + return (1); +} + +/* Check if window still exists. */ +void +server_window_check_alive(struct window *w) +{ + struct window_pane *wp, *wq; + struct options *oo = &w->options; + struct session *s; + struct winlink *wl; + u_int i; + int destroyed; + + destroyed = 1; + + wp = TAILQ_FIRST(&w->panes); + while (wp != NULL) { + wq = TAILQ_NEXT(wp, entry); + /* + * If the pane has died and the remain-on-exit flag is not set, + * remove the pane; otherwise, if the flag is set, don't allow + * the window to be destroyed (or it'll close when the last + * pane dies). + */ + if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) { + layout_close_pane(wp); + window_remove_pane(w, wp); + server_redraw_window(w); + } else + destroyed = 0; + wp = wq; + } + + if (!destroyed) + return; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + if (!session_has(s, w)) + continue; + + restart: + /* Detach window and either redraw or kill clients. */ + RB_FOREACH(wl, winlinks, &s->windows) { + if (wl->window != w) + continue; + if (session_detach(s, wl)) { + server_destroy_session_group(s); + break; + } + server_redraw_session(s); + server_status_session_group(s); + goto restart; + } + } + + recalculate_sizes(); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/session.c /tmp/wmlmc6MQoR/tmux-1.1/session.c --- tmux-1.0/session.c 2009-09-16 13:36:27.000000000 +0100 +++ tmux-1.1/session.c 2009-11-04 22:42:31.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: session.c,v 1.66 2009/09/16 12:36:27 nicm Exp $ */ +/* $Id: session.c,v 1.70 2009/11/04 22:42:31 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,12 +22,14 @@ #include #include #include +#include #include "tmux.h" /* Global session list. */ struct sessions sessions; struct sessions dead_sessions; +struct session_groups session_groups; struct winlink *session_next_activity(struct session *, struct winlink *); struct winlink *session_previous_activity(struct session *, struct winlink *); @@ -124,11 +126,12 @@ s->references = 0; s->flags = 0; - if (gettimeofday(&s->tv, NULL) != 0) - fatal("gettimeofday"); + if (gettimeofday(&s->creation_time, NULL) != 0) + fatal("gettimeofday failed"); + memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time); s->curw = NULL; - SLIST_INIT(&s->lastw); + TAILQ_INIT(&s->lastw); RB_INIT(&s->windows); SLIST_INIT(&s->alerts); @@ -161,11 +164,14 @@ s->name = xstrdup(name); else xasprintf(&s->name, "%u", i); - if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { - session_destroy(s); - return (NULL); + + if (cmd != NULL) { + if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { + session_destroy(s); + return (NULL); + } + session_select(s, RB_ROOT(&s->windows)->idx); } - session_select(s, RB_ROOT(&s->windows)->idx); log_debug("session %s created", s->name); @@ -189,13 +195,14 @@ if (s->tio != NULL) xfree(s->tio); + session_group_remove(s); session_alert_cancel(s, NULL); environ_free(&s->environ); options_free(&s->options); paste_free_stack(&s->buffers); - while (!SLIST_EMPTY(&s->lastw)) - winlink_stack_remove(&s->lastw, SLIST_FIRST(&s->lastw)); + while (!TAILQ_EMPTY(&s->lastw)) + winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); while (!RB_EMPTY(&s->windows)) winlink_remove(&s->windows, RB_ROOT(&s->windows)); @@ -265,6 +272,7 @@ if ((wl = winlink_add(&s->windows, w, idx)) == NULL) xasprintf(cause, "index in use: %d", idx); + session_group_synchronize_from(s); return (wl); } @@ -279,6 +287,7 @@ session_alert_cancel(s, wl); winlink_stack_remove(&s->lastw, wl); winlink_remove(&s->windows, wl); + session_group_synchronize_from(s); if (RB_EMPTY(&s->windows)) { session_destroy(s); return (1); @@ -405,7 +414,7 @@ { struct winlink *wl; - wl = SLIST_FIRST(&s->lastw); + wl = TAILQ_FIRST(&s->lastw); if (wl == NULL) return (-1); if (wl == s->curw) @@ -417,3 +426,169 @@ session_alert_cancel(s, wl); return (0); } + +/* Find the session group containing a session. */ +struct session_group * +session_group_find(struct session *target) +{ + struct session_group *sg; + struct session *s; + + TAILQ_FOREACH(sg, &session_groups, entry) { + TAILQ_FOREACH(s, &sg->sessions, gentry) { + if (s == target) + return (sg); + } + } + return (NULL); +} + +/* Find session group index. */ +u_int +session_group_index(struct session_group *sg) +{ + struct session_group *sg2; + u_int i; + + i = 0; + TAILQ_FOREACH(sg2, &session_groups, entry) { + if (sg == sg2) + return (i); + i++; + } + + fatalx("session group not found"); +} + +/* + * Add a session to the session group containing target, creating it if + * necessary. + */ +void +session_group_add(struct session *target, struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(target)) == NULL) { + sg = xmalloc(sizeof *sg); + TAILQ_INSERT_TAIL(&session_groups, sg, entry); + TAILQ_INIT(&sg->sessions); + TAILQ_INSERT_TAIL(&sg->sessions, target, gentry); + } + TAILQ_INSERT_TAIL(&sg->sessions, s, gentry); +} + +/* Remove a session from its group and destroy the group if empty. */ +void +session_group_remove(struct session *s) +{ + struct session_group *sg; + + if ((sg = session_group_find(s)) == NULL) + return; + TAILQ_REMOVE(&sg->sessions, s, gentry); + if (TAILQ_NEXT(TAILQ_FIRST(&sg->sessions), gentry) == NULL) + TAILQ_REMOVE(&sg->sessions, TAILQ_FIRST(&sg->sessions), gentry); + if (TAILQ_EMPTY(&sg->sessions)) { + TAILQ_REMOVE(&session_groups, sg, entry); + xfree(sg); + } +} + +/* Synchronize a session to its session group. */ +void +session_group_synchronize_to(struct session *s) +{ + struct session_group *sg; + struct session *target; + + if ((sg = session_group_find(s)) == NULL) + return; + + target = NULL; + TAILQ_FOREACH(target, &sg->sessions, gentry) { + if (target != s) + break; + } + session_group_synchronize1(target, s); +} + +/* Synchronize a session group to a session. */ +void +session_group_synchronize_from(struct session *target) +{ + struct session_group *sg; + struct session *s; + + if ((sg = session_group_find(target)) == NULL) + return; + + TAILQ_FOREACH(s, &sg->sessions, gentry) { + if (s != target) + session_group_synchronize1(target, s); + } +} + +/* + * Synchronize a session with a target session. This means destroying all + * winlinks then recreating them, then updating the current window, last window + * stack and alerts. + */ +void +session_group_synchronize1(struct session *target, struct session *s) +{ + struct winlinks old_windows, *ww; + struct winlink_stack old_lastw; + struct winlink *wl, *wl2; + struct session_alert *sa; + + /* Don't do anything if the session is empty (it'll be destroyed). */ + ww = &target->windows; + if (RB_EMPTY(ww)) + return; + + /* If the current window has vanished, move to the next now. */ + if (s->curw != NULL) { + while (winlink_find_by_index(ww, s->curw->idx) == NULL) + session_next(s, 0); + } + + /* Save the old pointer and reset it. */ + memcpy(&old_windows, &s->windows, sizeof old_windows); + RB_INIT(&s->windows); + + /* Link all the windows from the target. */ + RB_FOREACH(wl, winlinks, ww) + winlink_add(&s->windows, wl->window, wl->idx); + + /* Fix up the current window. */ + if (s->curw != NULL) + s->curw = winlink_find_by_index(&s->windows, s->curw->idx); + else + s->curw = winlink_find_by_index(&s->windows, target->curw->idx); + + /* Fix up the last window stack. */ + memcpy(&old_lastw, &s->lastw, sizeof old_lastw); + TAILQ_INIT(&s->lastw); + TAILQ_FOREACH(wl, &old_lastw, sentry) { + wl2 = winlink_find_by_index(&s->windows, wl->idx); + if (wl2 != NULL) + TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry); + } + + /* And update the alerts list. */ + SLIST_FOREACH(sa, &s->alerts, entry) { + wl = winlink_find_by_index(&s->windows, sa->wl->idx); + if (wl == NULL) + session_alert_cancel(s, sa->wl); + else + sa->wl = wl; + } + + /* Then free the old winlinks list. */ + while (!RB_EMPTY(&old_windows)) { + wl = RB_ROOT(&old_windows); + RB_REMOVE(winlinks, &old_windows, wl); + xfree(wl); + } +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/status.c /tmp/wmlmc6MQoR/tmux-1.1/status.c --- tmux-1.0/status.c 2009-09-15 19:54:57.000000000 +0100 +++ tmux-1.1/status.c 2009-11-04 23:12:32.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.118 2009/09/11 14:13:52 tcunha Exp $ */ +/* $Id: status.c,v 1.125 2009/11/04 23:12:32 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -29,7 +29,8 @@ #include "tmux.h" -char *status_replace_popen(char **); +char *status_job(struct client *, char **); +void status_job_callback(struct job *); size_t status_width(struct winlink *); char *status_print(struct session *, struct winlink *, struct grid_cell *); @@ -64,7 +65,7 @@ screen_init(&c->status, c->tty.sx, 1, 0); if (gettimeofday(&c->status_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); memcpy(&stdgc, &grid_default_cell, sizeof gc); colour_set_fg(&stdgc, options_get_number(&s->options, "status-fg")); colour_set_bg(&stdgc, options_get_number(&s->options, "status-bg")); @@ -104,14 +105,14 @@ utf8flag = options_get_number(&s->options, "status-utf8"); /* Work out the left and right strings. */ - left = status_replace(s, options_get_string( + left = status_replace(c, options_get_string( &s->options, "status-left"), c->status_timer.tv_sec); llen = options_get_number(&s->options, "status-left-length"); llen2 = screen_write_cstrlen(utf8flag, "%s", left); if (llen2 < llen) llen = llen2; - right = status_replace(s, options_get_string( + right = status_replace(c, options_get_string( &s->options, "status-right"), c->status_timer.tv_sec); rlen = options_get_number(&s->options, "status-right-length"); rlen2 = screen_write_cstrlen(utf8flag, "%s", right); @@ -317,15 +318,17 @@ } char * -status_replace(struct session *s, const char *fmt, time_t t) +status_replace(struct client *c, const char *fmt, time_t t) { + struct session *s = c->session; struct winlink *wl = s->curw; static char out[BUFSIZ]; char in[BUFSIZ], tmp[256], ch, *iptr, *optr, *ptr, *endptr; - char *savedptr; + char *savedptr; /* freed at end of each loop */ size_t len; long n; - + + strftime(in, sizeof in, fmt, localtime(&t)); in[(sizeof in) - 1] = '\0'; @@ -352,7 +355,7 @@ switch (*iptr++) { case '(': if (ptr == NULL) { - ptr = status_replace_popen(&iptr); + ptr = status_job(c, &iptr); if (ptr == NULL) break; savedptr = ptr; @@ -361,7 +364,7 @@ case 'H': if (ptr == NULL) { if (gethostname(tmp, sizeof tmp) != 0) - fatal("gethostname"); + fatal("gethostname failed"); ptr = tmp; } /* FALLTHROUGH */ @@ -374,8 +377,8 @@ case 'P': if (ptr == NULL) { xsnprintf(tmp, sizeof tmp, "%u", - window_pane_index(wl->window, - wl->window->active)); + window_pane_index(wl->window, + wl->window->active)); ptr = tmp; } /* FALLTHROUGH */ @@ -434,12 +437,12 @@ } char * -status_replace_popen(char **iptr) +status_job(struct client *c, char **iptr) { - FILE *f; - char *buf, *cmd, *ptr; - int lastesc; - size_t len; + struct job *job; + char *cmd; + int lastesc; + size_t len; if (**iptr == '\0') return (NULL); @@ -448,8 +451,6 @@ return (NULL); } - buf = NULL; - cmd = xmalloc(strlen(*iptr) + 1); len = 0; @@ -464,32 +465,44 @@ lastesc = 0; cmd[len++] = **iptr; } - if (**iptr == '\0') /* no terminating ) */ - goto out; + if (**iptr == '\0') /* no terminating ) */ { + xfree(cmd); + return (NULL); + } (*iptr)++; /* skip final ) */ cmd[len] = '\0'; - if ((f = popen(cmd, "r")) == NULL) - goto out; + job = job_get(&c->status_jobs, cmd); + if (job == NULL) { + job = job_add(&c->status_jobs, + JOB_PERSIST, c, cmd, status_job_callback, xfree, NULL); + job_run(job); + } + if (job->data == NULL) + return (xstrdup("")); + return (xstrdup(job->data)); +} - if ((buf = fgetln(f, &len)) == NULL) { - pclose(f); - goto out; - } - if (buf[len - 1] == '\n') { - buf[len - 1] = '\0'; - buf = xstrdup(buf); - } else { - ptr = xmalloc(len + 1); - memcpy(ptr, buf, len); - ptr[len] = '\0'; - buf = ptr; - } - pclose(f); +void +status_job_callback(struct job *job) +{ + char *buf; + size_t len; -out: - xfree(cmd); - return (buf); + len = BUFFER_USED(job->out); + buf = xmalloc(len + 1); + if (len != 0) + buffer_read(job->out, buf, len); + buf[len] = '\0'; + buf[strcspn(buf, "\n")] = '\0'; + + if (job->data != NULL) + xfree(job->data); + else + server_redraw_client(job->client); + job->data = xstrdup(buf); + + xfree(buf); } size_t @@ -516,7 +529,7 @@ gc->attr = attr; flag = ' '; - if (wl == SLIST_FIRST(&s->lastw)) + if (wl == TAILQ_FIRST(&s->lastw)) flag = '-'; if (wl == s->curw) { fg = options_get_number(oo, "window-status-current-fg"); @@ -565,7 +578,7 @@ tv.tv_usec = (delay % 1000) * 1000L; if (gettimeofday(&c->message_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); timeradd(&c->message_timer, &tv, &c->message_timer); c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); @@ -673,8 +686,6 @@ xfree(c->prompt_string); c->prompt_string = NULL; - if (c->prompt_flags & PROMPT_HIDDEN) - memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); c->prompt_buffer = NULL; @@ -739,26 +750,17 @@ left--; size = left; } - if (c->prompt_flags & PROMPT_HIDDEN) - size = 0; - else { - screen_write_puts(&ctx, &gc, - "%.*s", (int) left, c->prompt_buffer + off); - } + screen_write_puts( + &ctx, &gc, "%.*s", (int) left, c->prompt_buffer + off); for (i = len + size; i < c->tty.sx; i++) screen_write_putc(&ctx, &gc, ' '); /* Draw a fake cursor. */ ch = ' '; - if (c->prompt_flags & PROMPT_HIDDEN) - screen_write_cursormove(&ctx, len, 0); - else { - screen_write_cursormove(&ctx, - len + c->prompt_index - off, 0); - if (c->prompt_index < strlen(c->prompt_buffer)) - ch = c->prompt_buffer[c->prompt_index]; - } + screen_write_cursormove(&ctx, len + c->prompt_index - off, 0); + if (c->prompt_index < strlen(c->prompt_buffer)) + ch = c->prompt_buffer[c->prompt_index]; gc.attr ^= GRID_ATTR_REVERSE; screen_write_putc(&ctx, &gc, ch); } @@ -890,13 +892,8 @@ } break; case MODEKEYEDIT_HISTORYUP: - if (server_locked) - break; - if (ARRAY_LENGTH(&c->prompt_hdata) == 0) break; - if (c->prompt_flags & PROMPT_HIDDEN) - memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata, @@ -908,11 +905,6 @@ c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_HISTORYDOWN: - if (server_locked) - break; - - if (c->prompt_flags & PROMPT_HIDDEN) - memset(c->prompt_buffer, 0, strlen(c->prompt_buffer)); xfree(c->prompt_buffer); if (c->prompt_hindex != 0) { @@ -1003,9 +995,6 @@ void status_prompt_add_history(struct client *c) { - if (server_locked) - return; - if (ARRAY_LENGTH(&c->prompt_hdata) > 0 && strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0) return; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/tmux.1 /tmp/wmlmc6MQoR/tmux-1.1/tmux.1 --- tmux-1.0/tmux.1 2009-09-20 19:11:24.000000000 +0100 +++ tmux-1.1/tmux.1 2009-11-04 22:46:25.000000000 +0000 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.168 2009/09/19 18:53:01 tcunha Exp $ +.\" $Id: tmux.1,v 1.199 2009/11/04 22:46:25 tcunha Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 18 2009 $ +.Dd $Mdocdate: November 3 2009 $ .Dt TMUX 1 .Os .Sh NAME @@ -23,7 +23,8 @@ .Sh SYNOPSIS .Nm tmux .Bk -words -.Op Fl 28dlqUuv +.Op Fl 28lquv +.Op Fl c Ar shell-command .Op Fl f Ar file .Op Fl L Ar socket-name .Op Fl S Ar socket-path @@ -101,10 +102,15 @@ Like .Fl 2 , but indicates that the terminal supports 88 colours. -.It Fl d -Force +.It Fl c Ar shell-command +Execute +.Ar shell-command +using the default shell. +If necessary, the .Nm -to assume the terminal supports default colours. +server will be started to retrieve the +.Ic default-shell +option. .It Fl f Ar file Specify an alternative configuration file. By default, @@ -154,8 +160,6 @@ is specified, the default socket directory is not used and any .Fl L flag is ignored. -.It Fl U -Unlock the server. .It Fl u .Nm attempts to guess if the terminal is likely to support UTF-8 by checking the @@ -278,7 +282,7 @@ If a single match is found, it is used as the target session; multiple matches produce an error. If a session is omitted, the current session is used if available; if no -current session is available, the most recently created is chosen. +current session is available, the most recently used is chosen. .Pp .Ar target-window specifies a window in the form @@ -337,8 +341,6 @@ set-window-option -t:0 monitor-activity on new-window ; split-window -d - -bind-key D detach-client \e\; lock-server .Ed .Sh CLIENTS AND SESSIONS The following commands are available: @@ -386,10 +388,24 @@ .It Ic list-sessions .D1 (alias: Ic ls ) List all sessions managed by the server. +.It Xo Ic lock-client +.Op Fl t Ar target-client +.Xc +Lock +.Ar target-client , +see the +.Ic lock-server +command. +.It Xo Ic lock-session +.Op Fl t Ar target-session +.Xc +Lock all clients attached to +.Ar target-session . .It Xo Ic new-session .Op Fl d .Op Fl n Ar window-name .Op Fl s Ar session-name +.Op Fl t Ar target-session .Op Ar command .Xc .D1 (alias: Ic new ) @@ -406,6 +422,26 @@ If run from a terminal, any .Xr termios 4 special characters are saved and used for new windows in the new session. +.Pp +If +.Fl t +is given, the new session is +.Em grouped +with +.Ar target-session . +This means they share the same set of windows - all windows from +.Ar target-session +are linked to the new session and any subsequent new windows or windows being +closed are applied to both sessions. +The current and previous window and any session options remain independent and +either session may be killed without affecting the other. +Giving +.Fl n +or +.Ar command +are invalid if +.Fl t +is used. .It Ic refresh-client Op Fl t Ar target-client .D1 (alias: Ic refresh ) Refresh the current client if bound to a key, or a single client if one is given @@ -455,12 +491,6 @@ This is entered when a command which produces output, such as .Ic list-keys , is executed from a key binding. -.It Em scroll mode -This is entered with the -.Ic scroll-mode -command (bound to -.Ql = -by default) and permits the window history buffer to be inspected. .It Em copy mode This permits a section of a window or its history to be copied to a .Em paste buffer @@ -468,7 +498,7 @@ This mode is entered with the .Ic copy-mode command, bound to -.Ql [ +.Ql \&[ by default. .El .Pp @@ -477,7 +507,7 @@ .Ic mode-keys option). The following keys are supported as appropriate for the mode: -.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent +.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Clear selection" Ta "Escape" Ta "C-g" @@ -485,17 +515,24 @@ .It Li "Cursor down" Ta "j" Ta "Down" .It Li "Cursor left" Ta "h" Ta "Left" .It Li "Cursor right" Ta "l" Ta "Right" +.It Li "Cursor to bottom line" Ta "L" Ta "" +.It Li "Cursor to middle line" Ta "M" Ta "M-r" +.It Li "Cursor to top line" Ta "H" Ta "M-R" .It Li "Cursor up" Ta "k" Ta "Up" .It Li "Delete entire line" Ta "d" Ta "C-u" .It Li "Delete to end of line" Ta "D" Ta "C-k" .It Li "End of line" Ta "$" Ta "C-e" -.It Li "Goto line" Ta "g" Ta "g" +.It Li "Goto line" Ta ":" Ta "g" +.It Li "Half page down" Ta "C-d" Ta "M-Down" +.It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Next page" Ta "C-f" Ta "Page down" .It Li "Next word" Ta "w" Ta "M-f" .It Li "Paste buffer" Ta "p" Ta "C-y" -.It Li "Previous page" Ta "C-u" Ta "Page up" +.It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" .It Li "Quit mode" Ta "q" Ta "Escape" +.It Li "Scroll down" Ta "C-Down or J" Ta "C-Down" +.It Li "Scroll up" Ta "C-Up or K" Ta "C-Up" .It Li "Search again" Ta "n" Ta "n" .It Li "Search backward" Ta "?" Ta "C-r" .It Li "Search forward" Ta "/" Ta "C-s" @@ -518,7 +555,7 @@ .Em vi-copy and .Em emacs-copy -used in copy and scroll modes. +used in copy mode. The tables may be viewed with the .Ic list-keys command and keys modified or removed with @@ -539,16 +576,6 @@ The .Fl u option scrolls one page up. -.It Xo Ic scroll-mode -.Op Fl u -.Op Fl t Ar target-pane -.Xc -Enter scroll mode. -The -.Fl u -has the same meaning as in the -.Ic copy-mode -command. .El .Pp Each window displayed by @@ -696,7 +723,7 @@ keys. .It Ic down-pane Op Fl t Ar target-pane .D1 (alias: Ic downp ) -Move down a pane. +Change the active pane to the next pane (higher index). .It Xo Ic find-window .Op Fl t Ar target-window .Ar match-string @@ -711,10 +738,17 @@ choice list is shown. This command only works from inside .Nm . -.It Ic kill-pane Op Fl t Ar target-pane +.It Xo Ic kill-pane +.Op Fl a +.Op Fl t Ar target-pane +.Xc .D1 (alias: Ic killp ) Destroy the given pane. If no panes remain in the containing window, it is also destroyed. +The +.Fl a +option kills all but the pane given with +.Fl t . .It Ic kill-window Op Fl t Ar target-window .D1 (alias: Ic killw ) Kill the current window or the window at @@ -749,6 +783,10 @@ If .Fl d is given, the newly linked window is not selected. +.It Ic list-panes Op Fl t Ar target-window +.D1 (alias: Ic lsp ) +List the panes in the current window or in +.Ar target-window . .It Ic list-windows Op Fl t Ar target-session .D1 (alias: Ic lsw ) List windows in the current session or in @@ -810,6 +848,30 @@ If .Fl a is used, move to the next window with a bell, activity or content alert. +.It Xo Ic pipe-pane +.Op Fl o +.Op Fl t Ar target-pane +.Op Ar command +.Xc +.D1 (alias: Ic pipep ) +Pipe any output sent by the program in +.Ar target-pane +to a shell command. +A pane may only be piped to one command at a time, any existing pipe is +closed before +.Ar command +is executed. +If no +.Ar command +is given, the current pipe (if any) is closed. +.Pp +The +.Fl o +option only opens a new pipe if no previous pipe exists, allowing a pipe to +be toggled with a single key, for example: +.Bd -literal -offset indent +bind-key C-p pipe-pane -o 'cat >>~/output' +.Ed .It Xo Ic previous-window .Op Fl a .Op Fl t Ar target-session @@ -956,9 +1018,52 @@ destroyed. .It Ic up-pane Op Fl t Ar target-pane .D1 (alias: Ic upp ) -Move up a pane. +Change the active pane to the previous pane (lower index). .El .Sh KEY BINDINGS +.Nm +allows a command to be bound to most keys, with or without a prefix key. +When specifying keys, most represent themselves (for example +.Ql A +to +.Ql Z ) . +Ctrl keys may be prefixed with +.Ql C- +or +.Ql ^ , +and Alt (meta) with +.Ql M- . +In addition, the following special key names are accepted: +.Em BSpace , +.Em BTab , +.Em DC +(Delete), +.Em End , +.Em Enter , +.Em Escape , +.Em F1 +to +.Em F20 , +.Em Home , +.Em IC +(Insert), +.Em NPage +(Page Up), +.Em PPage +(Page Down), +.Em Space , +and +.Em Tab . +Note that to bind the +.Ql \&" +or +.Ql ' +keys, quotation marks are necessary, for example: +.Bd -literal -offset indent +bind-key '"' split-window +bind-key "'" select-prompt +.Ed +.Pp Commands related to key bindings are as follows: .Bl -tag -width Ds .It Xo Ic bind-key @@ -971,14 +1076,6 @@ .Ar key to .Ar command . -Keys may be specified prefixed with -.Ql C- -or -.Ql ^ -for Ctrl keys, or -.Ql M- -for Alt (meta) keys. -.Pp By default (without .Fl t ) the primary key bindings are modified (those normally activated with the prefix @@ -1048,6 +1145,7 @@ All arguments are sent sequentially from first to last. .It Ic send-prefix Op Fl t Ar target-pane Send the prefix key to a window as if it was pressed. +If multiple prefix keys are configured, only the first is sent. .It Xo Ic unbind-key .Op Fl cn .Op Fl t Ar key-table @@ -1212,17 +1310,33 @@ This setting applies only to new windows - existing window histories are not resized and retain the limit at the point they were created. .It Ic lock-after-time Ar number -Lock the server after +Lock the session (like the +.Ic lock-session +command) after .Ar number -seconds of inactivity. -The default is off (set to 0). -This has no effect as a session option; it must be set as a global option using -.Fl g . -When passwords are entered incorrectly, -.Nm -follows the behaviour of -.Xr login 1 -and ignores further password attempts for an increasing timeout. +seconds of inactivity, or the entire server (all sessions) if the +.Ic lock-server +option is set. +The default is not to lock (set to 0). +.It Ic lock-command Ar command +Command to run when locking each client. +The default is to run +.Xr lock 1 +with +.Fl np . +.It Xo Ic lock-server +.Op Ic on | off +.Xc +If this option is +.Ic on +(the default), +instead of each session locking individually as each has been +idle for +.Ic lock-after-time , +the entire server will lock after +.Em all +sessions would have locked. +This has no effect as a session option; it must be set as a global option. .It Ic message-attr Ar attributes Set status line message attributes, where .Ar attributes @@ -1258,8 +1372,19 @@ .Ic default . .It Ic message-fg Ar colour Set status line message foreground colour. -.It Ic prefix Ar key -Set the current prefix key. +.It Xo Ic mouse-select-pane +.Op Ic on | off +.Xc +If on, +.Nm +captures the mouse and when a window is split into multiple panes the mouse may +be used to select the current pane. +The mouse click is also passed through to the application as normal. +.It Ic prefix Ar keys +Set the keys accepted as a prefix key. +.Ar keys +is a comma-separated list of key names, each of which individually behave as +the prefix key. .It Ic repeat-time Ar time Allow multiple commands to be entered without pressing the prefix-key again in the specified @@ -1348,22 +1473,31 @@ The #(command) form executes .Ql command as a shell command and inserts the first line of its output. +Note that shell commands are only executed once at the interval specified by +the +.Ic status-interval +option: if the status line is redrawn in the meantime, the previous result is +used. +.Pp #[attributes] allows a comma-separated list of attributes to be specified, these may be .Ql fg=colour to set the foreground colour, .Ql bg=colour -to set the background colour, or one of the attributes described under the +to set the background colour, the name of one of the attributes (listed under the .Ic message-attr -option. +option) to turn an attribute on, or an attribute prefixed with +.Ql no +to turn one off, for example +.Ic nobright . Examples are: .Bd -literal -offset indent #(sysctl vm.loadavg) #[fg=yellow,bold]#(apm -l)%%#[default] [#S] .Ed .Pp -Where appropriate, these may be prefixed with a number to specify the maximum -length, for example +Where appropriate, special character sequences may be prefixed with a number to +specify the maximum length, for example .Ql #24T . .Pp By default, UTF-8 in @@ -1580,7 +1714,7 @@ .It Xo Ic mode-keys .Op Ic vi | emacs .Xc -Use vi or emacs-style key bindings in scroll, copy and choice modes. +Use vi or emacs-style key bindings in copy and choice modes. Key bindings default to emacs. .Pp .It Xo Ic mode-mouse @@ -1615,6 +1749,11 @@ .Ic respawn-window command. .Pp +.It Xo Ic synchronize-panes +.Op Ic on | off +.Xc +Duplicate input to any pane to all other panes in the same window, except +for panes that are not in output mode. .It Xo Ic utf8 .Op Ic on | off .Xc @@ -1701,6 +1840,7 @@ .Op Fl t Ar target-session .Ar name Op Ar value .Xc +.D1 (alias: Ic setenv ) Set or unset an environment variable. If .Fl g @@ -1717,6 +1857,7 @@ .Op Fl g .Op Fl t Ar target-session .Xc +.D1 (alias: Ic showenv ) Display the environment for .Ar target-session or the global environment with @@ -1958,25 +2099,21 @@ returns success. .It Ic lock-server .D1 (alias: Ic lock ) -Lock the server until a password is entered. +Lock each client individually by running the command specified by the +.Ic lock-command +option. +.It Ic run-shell Ar command +.D1 (alias: Ic run ) +Execute +.Ar command +in the background without creating a window. +After the command finishes, any output to stdout is displayed in output mode. +If +.Ar command +doesn't return success, the exit status is also displayed. .It Ic server-info .D1 (alias: Ic info ) Show server information and terminal details. -.It Xo Ic set-password -.Op Fl c -.Ar password -.Xc -.D1 (alias: Ic pass ) -Set the server password. -If the -.Fl c -option is given, a pre-encrypted password may be specified. -By default, the password is blank, thus any entered password will be accepted -when unlocking the server (see the -.Ic lock-server -command). -To prevent variable expansion when an encrypted password is read from a -configuration file, enclose it in single quotes ('). .El .Sh FILES .Bl -tag -width "/etc/tmux.confXXX" -compact diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/tmux.c /tmp/wmlmc6MQoR/tmux-1.1/tmux.c --- tmux-1.0/tmux.c 2009-09-20 19:11:24.000000000 +0100 +++ tmux-1.1/tmux.c 2009-11-04 23:09:09.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.172 2009/09/19 18:53:01 tcunha Exp $ */ +/* $Id: tmux.c,v 1.184 2009/11/04 23:09:09 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -29,14 +29,8 @@ #include "tmux.h" -#ifdef DEBUG -/* DragonFly uses an OpenBSD-like malloc() since 1.6 */ -#if defined(__OpenBSD__) || defined(__DragonFly__) -const char *malloc_options = "AFGJPX"; -#endif -#ifdef __FreeBSD__ -const char *_malloc_options = "AJX"; -#endif +#if defined(DEBUG) && defined(__OpenBSD__) +extern char *malloc_options; #endif volatile sig_atomic_t sigwinch; @@ -51,13 +45,6 @@ struct options global_w_options; /* window options */ struct environ global_environ; -int server_locked; -struct passwd *server_locked_pw; -u_int password_failures; -time_t password_backoff; -char *server_password; -time_t server_activity; - int debug_level; int be_quiet; time_t start_time; @@ -65,10 +52,10 @@ int login_shell; __dead void usage(void); +void fill_session(struct msg_command_data *); char *makesockpath(const char *); -int prepare_unlock(enum msgtype *, void **, size_t *, int); -int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); -int dispatch_imsg(struct client_ctx *, int *); +int dispatch_imsg(struct imsgbuf *, const char *, int *); +__dead void shell_exec(const char *, const char *); #ifndef HAVE_PROGNAME char *__progname = (char *) "tmux"; @@ -78,7 +65,7 @@ usage(void) { fprintf(stderr, - "usage: %s [-28dlqUuv] [-f file] [-L socket-name]\n" + "usage: %s [-28lquv] [-c shell-command] [-f file] [-L socket-name]\n" " [-S socket-path] [command [flags]]\n", __progname); exit(1); @@ -231,6 +218,44 @@ return (0); } +void +fill_session(struct msg_command_data *data) +{ + char *env, *ptr1, *ptr2, buf[256]; + size_t len; + const char *errstr; + long long ll; + + data->pid = -1; + if ((env = getenv("TMUX")) == NULL) + return; + + if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) + return; + for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) + ; + if (*ptr1 != ',') + return; + ptr1++; + ptr2++; + + len = ptr2 - ptr1 - 1; + if (len > (sizeof buf) - 1) + return; + memcpy(buf, ptr1, len); + buf[len] = '\0'; + + ll = strtonum(buf, 0, LONG_MAX, &errstr); + if (errstr != NULL) + return; + data->pid = ll; + + ll = strtonum(ptr2, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return; + data->idx = ll; +} + char * makesockpath(const char *label) { @@ -260,75 +285,31 @@ } int -prepare_unlock(enum msgtype *msg, void **buf, size_t *len, int argc) -{ - static struct msg_unlock_data unlockdata; - char *pass; - - if (argc != 0) { - log_warnx("can't specify a command when unlocking"); - return (-1); - } - - if ((pass = getpass("Password:")) == NULL) - return (-1); - - if (strlen(pass) >= sizeof unlockdata.pass) { - log_warnx("password too long"); - return (-1); - } - - strlcpy(unlockdata.pass, pass, sizeof unlockdata.pass); - memset(pass, 0, strlen(pass)); - - *buf = &unlockdata; - *len = sizeof unlockdata; - - *msg = MSG_UNLOCK; - return (0); -} - -int -prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) -{ - static struct msg_command_data cmddata; - - client_fill_session(&cmddata); - - cmddata.argc = argc; - if (cmd_pack_argv(argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { - log_warnx("command too long"); - return (-1); - } - - *buf = &cmddata; - *len = sizeof cmddata; - - *msg = MSG_COMMAND; - return (0); -} - -int main(int argc, char **argv) { - struct client_ctx cctx; struct cmd_list *cmdlist; struct cmd *cmd; - struct pollfd pfd; + struct pollfd pfd; enum msgtype msg; struct passwd *pw; struct options *so, *wo; - char *s, *path, *label, *home, *cause, **var; - char cwd[MAXPATHLEN]; + struct keylist *keylist; + struct imsgbuf *ibuf; + struct msg_command_data cmddata; + char *s, *shellcmd, *path, *label, *home, *cause; + char cwd[MAXPATHLEN], **var; void *buf; size_t len; - int retcode, opt, flags, unlock, cmdflags = 0; - int nfds; + int nfds, retcode, opt, flags, cmdflags = 0; - unlock = flags = 0; - label = path = NULL; +#if defined(DEBUG) && defined(__OpenBSD__) + malloc_options = (char *) "AFGJPX"; +#endif + + flags = 0; + shellcmd = label = path = NULL; login_shell = (**argv == '-'); - while ((opt = getopt(argc, argv, "28df:lL:qS:uUv")) != -1) { + while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { switch (opt) { case '2': flags |= IDENTIFY_256COLOURS; @@ -338,8 +319,10 @@ flags |= IDENTIFY_88COLOURS; flags &= ~IDENTIFY_256COLOURS; break; - case 'd': - flags |= IDENTIFY_HASDEFAULTS; + case 'c': + if (shellcmd != NULL) + xfree(shellcmd); + shellcmd = xstrdup(optarg); break; case 'f': if (cfg_file != NULL) @@ -365,19 +348,19 @@ case 'u': flags |= IDENTIFY_UTF8; break; - case 'U': - unlock = 1; - break; case 'v': debug_level++; break; - default: + default: usage(); - } - } + } + } argc -= optind; argv += optind; + if (shellcmd != NULL && argc != 0) + usage(); + log_open_tty(debug_level); siginit(); @@ -415,10 +398,12 @@ options_set_number(so, "display-time", 750); options_set_number(so, "history-limit", 2000); options_set_number(so, "lock-after-time", 0); + options_set_string(so, "lock-command", "lock -np"); + options_set_number(so, "lock-server", 1); options_set_number(so, "message-attr", 0); options_set_number(so, "message-bg", 3); options_set_number(so, "message-fg", 0); - options_set_number(so, "prefix", '\002'); + options_set_number(so, "mouse-select-pane", 0); options_set_number(so, "repeat-time", 500); options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-titles", 0); @@ -448,6 +433,11 @@ options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-content", 0); + keylist = xmalloc(sizeof *keylist); + ARRAY_INIT(keylist); + ARRAY_ADD(keylist, '\002'); + options_set_data(so, "prefix", keylist, xfree); + options_init(&global_w_options, NULL); wo = &global_w_options; options_set_number(wo, "aggressive-resize", 0); @@ -473,6 +463,7 @@ options_set_number(wo, "window-status-fg", 8); options_set_number(wo, "xterm-keys", 0); options_set_number(wo, "remain-on-exit", 0); + options_set_number(wo, "synchronize-panes", 0); if (flags & IDENTIFY_UTF8) { options_set_number(so, "status-utf8", 1); @@ -518,16 +509,27 @@ } xfree(label); - if (unlock) { - if (prepare_unlock(&msg, &buf, &len, argc) != 0) - exit(1); + if (shellcmd != NULL) { + msg = MSG_SHELL; + buf = NULL; + len = 0; } else { - if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) + fill_session(&cmddata); + + cmddata.argc = argc; + if (cmd_pack_argv( + argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { + log_warnx("command too long"); exit(1); + } + + msg = MSG_COMMAND; + buf = &cmddata; + len = sizeof cmddata; } - if (unlock) - cmdflags &= ~CMD_STARTSERVER; + if (shellcmd != NULL) + cmdflags |= CMD_STARTSERVER; else if (argc == 0) /* new-session is the default */ cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; else { @@ -550,19 +552,17 @@ cmd_list_free(cmdlist); } - memset(&cctx, 0, sizeof cctx); - if (client_init(path, &cctx, cmdflags, flags) != 0) + if ((ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); - client_write_server(&cctx, msg, buf, len); - memset(buf, 0, len); + imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); retcode = 0; for (;;) { - pfd.fd = cctx.ibuf.fd; + pfd.fd = ibuf->fd; pfd.events = POLLIN; - if (cctx.ibuf.w.queued != 0) + if (ibuf->w.queued != 0) pfd.events |= POLLOUT; if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { @@ -576,13 +576,13 @@ if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) fatalx("socket error"); - if (pfd.revents & POLLIN) { - if (dispatch_imsg(&cctx, &retcode) != 0) + if (pfd.revents & POLLIN) { + if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0) break; } if (pfd.revents & POLLOUT) { - if (msgbuf_write(&cctx.ibuf.w) < 0) + if (msgbuf_write(&ibuf->w) < 0) fatalx("msgbuf_write failed"); } } @@ -594,17 +594,18 @@ } int -dispatch_imsg(struct client_ctx *cctx, int *retcode) +dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) { struct imsg imsg; ssize_t n, datalen; struct msg_print_data printdata; + struct msg_shell_data shelldata; - if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) + if ((n = imsg_read(ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); for (;;) { - if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + if ((n = imsg_get(ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); @@ -632,8 +633,7 @@ if (datalen != 0) fatalx("bad MSG_READY size"); - *retcode = client_main(cctx); - return (-1); + client_main(); /* doesn't return */ case MSG_VERSION: if (datalen != 0) fatalx("bad MSG_VERSION size"); @@ -642,6 +642,13 @@ "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); *retcode = 1; return (-1); + case MSG_SHELL: + if (datalen != sizeof shelldata) + fatalx("bad MSG_SHELL size"); + memcpy(&shelldata, imsg.data, sizeof shelldata); + shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; + + shell_exec(shelldata.shell, shellcmd); default: fatalx("unexpected message"); } @@ -649,3 +656,26 @@ imsg_free(&imsg); } } + +__dead void +shell_exec(const char *shell, const char *shellcmd) +{ + const char *shellname, *ptr; + char *argv0; + + sigreset(); + + ptr = strrchr(shell, '/'); + if (ptr != NULL && *(ptr + 1) != '\0') + shellname = ptr + 1; + else + shellname = shell; + if (login_shell) + xasprintf(&argv0, "-%s", shellname); + else + xasprintf(&argv0, "%s", shellname); + setenv("SHELL", shell, 1); + + execl(shell, argv0, "-c", shellcmd, (char *) NULL); + fatal("execl failed"); +} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/tmux.h /tmp/wmlmc6MQoR/tmux-1.1/tmux.h --- tmux-1.0/tmux.h 2009-09-16 13:36:27.000000000 +0100 +++ tmux-1.1/tmux.h 2009-11-04 22:46:25.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.443 2009/09/16 12:36:27 nicm Exp $ */ +/* $Id: tmux.h,v 1.496 2009/11/04 22:46:25 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -21,7 +21,7 @@ #include "config.h" -#define PROTOCOL_VERSION 1 +#define PROTOCOL_VERSION 5 #include #include @@ -58,11 +58,14 @@ #define NAME_INTERVAL 500 /* Escape timer period, in milliseconds. */ -#define ESCAPE_PERIOD 250 +#define ESCAPE_PERIOD 500 /* Maximum poll timeout (when attached). */ #define POLL_TIMEOUT 50 +/* Maximum data to buffer for output before suspending reading from panes. */ +#define BACKOFF_THRESHOLD 1024 + /* * Maximum sizes of strings in message data. Don't forget to bump * PROTOCOL_VERSION if any of these change! @@ -161,23 +164,23 @@ KEYC_LEFT, KEYC_RIGHT, - /* Numeric keypad. Numbered from top-left, KPY_X. */ - KEYC_KP0_1, - KEYC_KP0_2, - KEYC_KP0_3, - KEYC_KP1_0, - KEYC_KP1_1, - KEYC_KP1_2, - KEYC_KP1_3, - KEYC_KP2_0, - KEYC_KP2_1, - KEYC_KP2_2, - KEYC_KP3_0, - KEYC_KP3_1, - KEYC_KP3_2, - KEYC_KP3_3, - KEYC_KP4_0, - KEYC_KP4_2, + /* Numeric keypad. */ + KEYC_KP_SLASH, + KEYC_KP_STAR, + KEYC_KP_MINUS, + KEYC_KP_SEVEN, + KEYC_KP_EIGHT, + KEYC_KP_NINE, + KEYC_KP_PLUS, + KEYC_KP_FOUR, + KEYC_KP_FIVE, + KEYC_KP_SIX, + KEYC_KP_ONE, + KEYC_KP_TWO, + KEYC_KP_THREE, + KEYC_KP_ENTER, + KEYC_KP_ZERO, + KEYC_KP_PERIOD, }; /* Termcap codes. */ @@ -192,9 +195,15 @@ TTYC_CNORM, /* cursor_normal, ve */ TTYC_COLORS, /* max_colors, Co */ TTYC_CSR, /* change_scroll_region, cs */ + TTYC_CUB, /* parm_left_cursor, LE */ + TTYC_CUB1, /* cursor_left, le */ TTYC_CUD, /* parm_down_cursor, DO */ TTYC_CUD1, /* cursor_down, do */ + TTYC_CUF, /* parm_right_cursor, RI */ + TTYC_CUF1, /* cursor_right, nd */ TTYC_CUP, /* cursor_address, cm */ + TTYC_CUU, /* parm_up_cursor, UP */ + TTYC_CUU1, /* cursor_up, up */ TTYC_DCH, /* parm_dch, DC */ TTYC_DCH1, /* delete_character, dc */ TTYC_DIM, /* enter_dim_mode, mh */ @@ -203,6 +212,8 @@ TTYC_EL, /* clr_eol, ce */ TTYC_EL1, /* clr_bol, cb */ TTYC_ENACS, /* ena_acs, eA */ + TTYC_HOME, /* cursor_home, ho */ + TTYC_HPA, /* column_address, ch */ TTYC_ICH, /* parm_ich, IC */ TTYC_ICH1, /* insert_character, ic */ TTYC_IL, /* parm_insert_line, IL */ @@ -216,8 +227,26 @@ TTYC_KCUD1, /* key_down, kd */ TTYC_KCUF1, /* key_right, kr */ TTYC_KCUU1, /* key_up, ku */ + TTYC_KDC2, + TTYC_KDC3, + TTYC_KDC4, + TTYC_KDC5, + TTYC_KDC6, + TTYC_KDC7, TTYC_KDCH1, /* key_dc, kD */ + TTYC_KDN2, + TTYC_KDN3, + TTYC_KDN4, + TTYC_KDN5, + TTYC_KDN6, + TTYC_KDN7, TTYC_KEND, /* key_end, ke */ + TTYC_KEND2, + TTYC_KEND3, + TTYC_KEND4, + TTYC_KEND5, + TTYC_KEND6, + TTYC_KEND7, TTYC_KF1, /* key_f1, k1 */ TTYC_KF10, /* key_f10, k; */ TTYC_KF11, /* key_f11, F1 */ @@ -229,8 +258,8 @@ TTYC_KF17, /* key_f17, F7 */ TTYC_KF18, /* key_f18, F8 */ TTYC_KF19, /* key_f19, F9 */ - TTYC_KF20, /* key_f20, F10 */ TTYC_KF2, /* key_f2, k2 */ + TTYC_KF20, /* key_f20, F10 */ TTYC_KF3, /* key_f3, k3 */ TTYC_KF4, /* key_f4, k4 */ TTYC_KF5, /* key_f5, k5 */ @@ -238,11 +267,53 @@ TTYC_KF7, /* key_f7, k7 */ TTYC_KF8, /* key_f8, k8 */ TTYC_KF9, /* key_f9, k9 */ + TTYC_KHOM2, + TTYC_KHOM3, + TTYC_KHOM4, + TTYC_KHOM5, + TTYC_KHOM6, + TTYC_KHOM7, TTYC_KHOME, /* key_home, kh */ + TTYC_KIC2, + TTYC_KIC3, + TTYC_KIC4, + TTYC_KIC5, + TTYC_KIC6, + TTYC_KIC7, TTYC_KICH1, /* key_ic, kI */ + TTYC_KLFT2, + TTYC_KLFT3, + TTYC_KLFT4, + TTYC_KLFT5, + TTYC_KLFT6, + TTYC_KLFT7, TTYC_KMOUS, /* key_mouse, Km */ TTYC_KNP, /* key_npage, kN */ + TTYC_KNXT2, + TTYC_KNXT3, + TTYC_KNXT4, + TTYC_KNXT5, + TTYC_KNXT6, + TTYC_KNXT7, TTYC_KPP, /* key_ppage, kP */ + TTYC_KPRV2, + TTYC_KPRV3, + TTYC_KPRV4, + TTYC_KPRV5, + TTYC_KPRV6, + TTYC_KPRV7, + TTYC_KRIT2, + TTYC_KRIT3, + TTYC_KRIT4, + TTYC_KRIT5, + TTYC_KRIT6, + TTYC_KRIT7, + TTYC_KUP2, + TTYC_KUP3, + TTYC_KUP4, + TTYC_KUP5, + TTYC_KUP6, + TTYC_KUP7, TTYC_OP, /* orig_pair, op */ TTYC_REV, /* enter_reverse_mode, mr */ TTYC_RI, /* scroll_reverse, sr */ @@ -259,6 +330,7 @@ TTYC_SMKX, /* keypad_xmit, ks */ TTYC_SMSO, /* enter_standout_mode, so */ TTYC_SMUL, /* enter_underline_mode, us */ + TTYC_VPA, /* row_address, cv */ TTYC_XENL, /* eat_newline_glitch, xn */ }; #define NTTYCODE (TTYC_XENL + 1) @@ -302,10 +374,12 @@ MSG_RESIZE, MSG_SHUTDOWN, MSG_SUSPEND, - MSG_UNLOCK, MSG_VERSION, MSG_WAKEUP, - MSG_ENVIRON + MSG_ENVIRON, + MSG_UNLOCK, + MSG_LOCK, + MSG_SHELL }; /* @@ -326,8 +400,6 @@ }; struct msg_identify_data { - char tty[TTY_NAME_MAX]; - char cwd[MAXPATHLEN]; char term[TERMINAL_LENGTH]; @@ -335,26 +407,21 @@ #define IDENTIFY_UTF8 0x1 #define IDENTIFY_256COLOURS 0x2 #define IDENTIFY_88COLOURS 0x4 -#define IDENTIFY_HASDEFAULTS 0x8 int flags; - - u_int sx; - u_int sy; }; -struct msg_resize_data { - u_int sx; - u_int sy; -}; - -struct msg_unlock_data { - char pass[PASS_MAX]; +struct msg_lock_data { + char cmd[COMMAND_LENGTH]; }; struct msg_environ_data { char var[ENVIRON_LENGTH]; }; +struct msg_shell_data { + char shell[MAXPATHLEN]; +}; + /* Mode key commands. */ enum mode_key_cmd { MODEKEY_NONE, @@ -389,6 +456,7 @@ /* Copy keys. */ MODEKEYCOPY_BACKTOINDENTATION, + MODEKEYCOPY_BOTTOMLINE, MODEKEYCOPY_CANCEL, MODEKEYCOPY_CLEARSELECTION, MODEKEYCOPY_COPYSELECTION, @@ -398,16 +466,20 @@ MODEKEYCOPY_HALFPAGEDOWN, MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_LEFT, + MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTWORD, MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_RIGHT, + MODEKEYCOPY_SCROLLDOWN, + MODEKEYCOPY_SCROLLUP, MODEKEYCOPY_SEARCHAGAIN, MODEKEYCOPY_SEARCHDOWN, MODEKEYCOPY_SEARCHUP, MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTSELECTION, + MODEKEYCOPY_TOPLINE, MODEKEYCOPY_UP, }; @@ -465,6 +537,23 @@ #define MODE_KKEYPAD 0x8 #define MODE_MOUSE 0x10 +/* + * A single UTF-8 character. + * + * The data member in this must be UTF8_SIZE to allow screen_write_copy to + * reinject stored UTF-8 data back into screen_write_cell after combining (ugh + * XXX XXX). + */ +#define UTF8_SIZE 9 +struct utf8_data { + u_char data[UTF8_SIZE]; + + size_t have; + size_t size; + + u_int width; +}; + /* Grid output. */ #if defined(DEBUG) && \ ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ @@ -504,7 +593,6 @@ } __packed; /* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */ -#define UTF8_SIZE 8 struct grid_utf8 { u_char width; u_char data[UTF8_SIZE]; @@ -542,13 +630,14 @@ enum { OPTIONS_STRING, OPTIONS_NUMBER, - OPTIONS_KEY, + OPTIONS_DATA, } type; - union { - char *string; - long long number; - int key; - } value; + + char *str; + long long num; + void *data; + + void (*freefn)(void *); SPLAY_ENTRY(options_entry) entry; }; @@ -558,6 +647,34 @@ struct options *parent; }; +/* Key list for prefix option. */ +ARRAY_DECL(keylist, int); + +/* Scheduled job. */ +struct job { + char *cmd; + pid_t pid; + int status; + + struct client *client; + + int fd; + struct buffer *out; + + void (*callbackfn)(struct job *); + void (*freefn)(void *); + void *data; + + int flags; +#define JOB_DONE 0x1 +#define JOB_PERSIST 0x2 /* don't free after callback */ + + RB_ENTRY(job) entry; + SLIST_ENTRY(job) lentry; +}; +RB_HEAD(jobs, job); +SLIST_HEAD(joblist, job); + /* Screen selection. */ struct screen_sel { int flag; @@ -632,9 +749,7 @@ #define STRING_APPLICATION 1 #define STRING_NAME 2 - u_char utf8_buf[4]; - u_int utf8_len; - u_int utf8_off; + struct utf8_data utf8data; u_char intermediate; void *(*state)(u_char, struct input_ctx *); @@ -649,13 +764,14 @@ */ struct client; struct window; +struct mouse_event; struct window_mode { struct screen *(*init)(struct window_pane *); void (*free)(struct window_pane *); void (*resize)(struct window_pane *, u_int, u_int); void (*key)(struct window_pane *, struct client *, int); void (*mouse)(struct window_pane *, - struct client *, u_char, u_char, u_char); + struct client *, struct mouse_event *); void (*timer)(struct window_pane *); }; @@ -685,6 +801,10 @@ struct input_ctx ictx; + int pipe_fd; + struct buffer *pipe_buf; + size_t pipe_off; + struct screen *screen; struct screen base; @@ -734,10 +854,10 @@ struct window *window; RB_ENTRY(winlink) entry; - SLIST_ENTRY(winlink) sentry; + TAILQ_ENTRY(winlink) sentry; }; RB_HEAD(winlinks, winlink); -SLIST_HEAD(winlink_stack, winlink); +TAILQ_HEAD(winlink_stack, winlink); /* Layout direction. */ enum layout_type { @@ -771,7 +891,6 @@ struct paste_buffer { char *data; size_t size; - struct timeval tv; }; ARRAY_DECL(paste_stack, struct paste_buffer *); @@ -792,9 +911,18 @@ SLIST_ENTRY(session_alert) entry; }; +struct session_group { + TAILQ_HEAD(, session) sessions; + + TAILQ_ENTRY(session_group) entry; +}; +TAILQ_HEAD(session_groups, session_group); + struct session { char *name; - struct timeval tv; + + struct timeval creation_time; + struct timeval activity_time; u_int sx; u_int sy; @@ -818,6 +946,8 @@ struct environ environ; int references; + + TAILQ_ENTRY(session) gentry; }; ARRAY_DECL(sessions, struct session *); @@ -839,10 +969,9 @@ struct tty_code codes[NTTYCODE]; -#define TERM_HASDEFAULTS 0x1 -#define TERM_256COLOURS 0x2 -#define TERM_88COLOURS 0x4 -#define TERM_EARLYWRAP 0x8 +#define TERM_256COLOURS 0x1 +#define TERM_88COLOURS 0x2 +#define TERM_EARLYWRAP 0x4 int flags; SLIST_ENTRY(tty_term) entry; @@ -914,21 +1043,37 @@ u_int orupper; u_int orlower; + + /* Saved last cell on line. */ + struct grid_cell last_cell; + struct grid_utf8 last_utf8; + u_int last_width; +}; + +/* Mouse input. */ +struct mouse_event { + u_char b; + u_char x; + u_char y; }; /* Client connection. */ struct client { struct imsgbuf ibuf; + struct timeval creation_time; + struct timeval activity_time; + struct environ environ; char *title; char *cwd; struct tty tty; - struct timeval status_timer; struct timeval repeat_timer; + struct timeval status_timer; + struct jobs status_jobs; struct screen status; #define CLIENT_TERMINAL 0x1 @@ -955,8 +1100,7 @@ void (*prompt_freefn)(void *); void *prompt_data; -#define PROMPT_HIDDEN 0x1 -#define PROMPT_SINGLE 0x2 +#define PROMPT_SINGLE 0x1 int prompt_flags; u_int prompt_hindex; @@ -970,19 +1114,6 @@ }; ARRAY_DECL(clients, struct client *); -/* Client context. */ -struct client_ctx { - struct imsgbuf ibuf; - - enum { - CCTX_DETACH, - CCTX_EXIT, - CCTX_DIED, - CCTX_SHUTDOWN - } exittype; - const char *errstr; -}; - /* Key/command line command. */ struct cmd_ctx { /* @@ -1086,7 +1217,7 @@ enum { SET_OPTION_STRING, SET_OPTION_NUMBER, - SET_OPTION_KEY, + SET_OPTION_KEYS, SET_OPTION_COLOUR, SET_OPTION_ATTRIBUTES, SET_OPTION_FLAG, @@ -1112,12 +1243,6 @@ extern struct options global_w_options; extern struct environ global_environ; extern char *cfg_file; -extern int server_locked; -extern struct passwd *server_locked_pw; -extern u_int password_failures; -extern time_t password_backoff; -extern char *server_password; -extern time_t server_activity; extern int debug_level; extern int be_quiet; extern time_t start_time; @@ -1160,11 +1285,29 @@ struct options_entry *options_find1(struct options *, const char *); struct options_entry *options_find(struct options *, const char *); void options_remove(struct options *, const char *); -void printflike3 options_set_string( +struct options_entry *printflike3 options_set_string( struct options *, const char *, const char *, ...); char *options_get_string(struct options *, const char *); -void options_set_number(struct options *, const char *, long long); +struct options_entry *options_set_number( + struct options *, const char *, long long); long long options_get_number(struct options *, const char *); +struct options_entry *options_set_data( + struct options *, const char *, void *, void (*)(void *)); +void *options_get_data(struct options *, const char *); + +/* job.c */ +extern struct joblist all_jobs; +int job_cmp(struct job *, struct job *); +RB_PROTOTYPE(jobs, job, entry, job_cmp); +void job_tree_init(struct jobs *); +void job_tree_free(struct jobs *); +struct job *job_get(struct jobs *, const char *); +struct job *job_add(struct jobs *, int, struct client *, + const char *, void (*)(struct job *), void (*)(void *), void *); +void job_remove(struct jobs *, struct job *); +void job_free(struct job *); +int job_run(struct job *); +void job_kill(struct job *); /* environ.c */ int environ_cmp(struct environ_entry *, struct environ_entry *); @@ -1179,21 +1322,24 @@ void environ_update(const char *, struct environ *, struct environ *); /* tty.c */ +void tty_raw(struct tty *, const char *); u_char tty_get_acs(struct tty *, u_char); void tty_attributes(struct tty *, const struct grid_cell *); void tty_reset(struct tty *); -void tty_region(struct tty *, u_int, u_int, u_int); -void tty_cursor(struct tty *, u_int, u_int, u_int, u_int); +void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); +void tty_region(struct tty *, u_int, u_int); +void tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int, u_int); +void tty_cursor(struct tty *, u_int, u_int); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_pututf8(struct tty *, const struct grid_utf8 *); -void tty_init(struct tty *, int, char *, char *); +void tty_init(struct tty *, int, char *); +void tty_resize(struct tty *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); -void tty_detect_utf8(struct tty *); void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); @@ -1236,14 +1382,16 @@ RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); -int tty_keys_next(struct tty *, int *, u_char *); +int tty_keys_next(struct tty *, int *, struct mouse_event *); /* options-cmd.c */ +const char *set_option_print( + const struct set_option_entry *, struct options_entry *); void set_option_string(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *, int); void set_option_number(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); -void set_option_key(struct cmd_ctx *, +void set_option_keys(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); void set_option_colour(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); @@ -1278,6 +1426,7 @@ void cmd_free(struct cmd *); size_t cmd_print(struct cmd *, char *, size_t); struct session *cmd_current_session(struct cmd_ctx *); +struct client *cmd_current_client(struct cmd_ctx *); struct client *cmd_find_client(struct cmd_ctx *, const char *); struct session *cmd_find_session(struct cmd_ctx *, const char *); struct winlink *cmd_find_window( @@ -1318,16 +1467,20 @@ extern const struct cmd_entry cmd_list_clients_entry; extern const struct cmd_entry cmd_list_commands_entry; extern const struct cmd_entry cmd_list_keys_entry; +extern const struct cmd_entry cmd_list_panes_entry; extern const struct cmd_entry cmd_list_sessions_entry; extern const struct cmd_entry cmd_list_windows_entry; extern const struct cmd_entry cmd_load_buffer_entry; +extern const struct cmd_entry cmd_lock_client_entry; extern const struct cmd_entry cmd_lock_server_entry; +extern const struct cmd_entry cmd_lock_session_entry; extern const struct cmd_entry cmd_move_window_entry; extern const struct cmd_entry cmd_new_session_entry; extern const struct cmd_entry cmd_new_window_entry; extern const struct cmd_entry cmd_next_layout_entry; extern const struct cmd_entry cmd_next_window_entry; extern const struct cmd_entry cmd_paste_buffer_entry; +extern const struct cmd_entry cmd_pipe_pane_entry; extern const struct cmd_entry cmd_previous_layout_entry; extern const struct cmd_entry cmd_previous_window_entry; extern const struct cmd_entry cmd_refresh_client_entry; @@ -1336,8 +1489,8 @@ extern const struct cmd_entry cmd_resize_pane_entry; extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_rotate_window_entry; +extern const struct cmd_entry cmd_run_shell_entry; extern const struct cmd_entry cmd_save_buffer_entry; -extern const struct cmd_entry cmd_scroll_mode_entry; extern const struct cmd_entry cmd_select_layout_entry; extern const struct cmd_entry cmd_select_pane_entry; extern const struct cmd_entry cmd_select_prompt_entry; @@ -1348,7 +1501,6 @@ extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_environment_entry; extern const struct cmd_entry cmd_set_option_entry; -extern const struct cmd_entry cmd_set_password_entry; extern const struct cmd_entry cmd_set_window_option_entry; extern const struct cmd_entry cmd_show_buffer_entry; extern const struct cmd_entry cmd_show_environment_entry; @@ -1402,14 +1554,8 @@ size_t cmd_buffer_print(struct cmd *, char *, size_t); /* client.c */ -int client_init(char *, struct client_ctx *, int, int); -int client_main(struct client_ctx *); -int client_msg_dispatch(struct client_ctx *); - -/* client-fn.c */ -void client_write_server(struct client_ctx *, enum msgtype, void *, size_t); -void client_fill_session(struct msg_command_data *); -void client_suspend(void); +struct imsgbuf *client_init(char *, int, int); +__dead void client_main(void); /* key-bindings.c */ extern struct key_bindings key_bindings; @@ -1434,9 +1580,24 @@ extern struct clients clients; extern struct clients dead_clients; int server_start(char *); +void server_poll_add(int, int, void (*)(int, int, void *), void *); -/* server-msg.c */ -int server_msg_dispatch(struct client *); +/* server-client.c */ +void server_client_create(int); +void server_client_lost(struct client *); +void server_client_prepare(void); +void server_client_callback(int, int, void *); +void server_client_loop(void); + +/* server-job.c */ +void server_job_prepare(void); +void server_job_callback(int, int, void *); +void server_job_loop(void); + +/* server-window.c */ +void server_window_prepare(void); +void server_window_callback(int, int, void *); +void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); @@ -1448,19 +1609,27 @@ void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *); +void server_redraw_session_group(struct session *); void server_status_session(struct session *); +void server_status_session_group(struct session *); void server_redraw_window(struct window *); void server_status_window(struct window *); void server_lock(void); +void server_lock_session(struct session *); +void server_lock_client(struct client *); int server_unlock(const char *); void server_kill_window(struct window *); +int server_link_window(struct session *, + struct winlink *, struct session *, int, int, int, char **); +void server_unlink_window(struct session *, struct winlink *); +void server_destroy_session_group(struct session *); void server_destroy_session(struct session *); void server_set_identify(struct client *); void server_clear_identify(struct client *); /* status.c */ int status_redraw(struct client *); -char *status_replace(struct session *, const char *, time_t); +char *status_replace(struct client *, const char *, time_t); void printflike2 status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); @@ -1481,7 +1650,11 @@ /* input-key.c */ void input_key(struct window_pane *, int); -void input_mouse(struct window_pane *, u_char, u_char, u_char); +void input_mouse(struct window_pane *, struct mouse_event *); + +/* xterm-keys.c */ +char *xterm_keys_lookup(int); +int xterm_keys_find(const char *, size_t, size_t *); /* colour.c */ void colour_set_fg(struct grid_cell *, int); @@ -1500,9 +1673,11 @@ struct grid *grid_create(u_int, u_int, u_int); void grid_destroy(struct grid *); int grid_compare(struct grid *, struct grid *); +void grid_collect_history(struct grid *); +void grid_scroll_history(struct grid *); +void grid_scroll_history_region(struct grid *, u_int, u_int); void grid_expand_line(struct grid *, u_int, u_int); void grid_expand_line_utf8(struct grid *, u_int, u_int); -void grid_scroll_line(struct grid *); const struct grid_cell *grid_peek_cell(struct grid *, u_int, u_int); struct grid_cell *grid_get_cell(struct grid *, u_int, u_int); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); @@ -1557,6 +1732,7 @@ struct screen_write_ctx *, struct grid_cell *, u_char); void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int, u_int, u_int, u_int); +void screen_write_backspace(struct screen_write_ctx *); void screen_write_cursorup(struct screen_write_ctx *, u_int); void screen_write_cursordown(struct screen_write_ctx *, u_int); void screen_write_cursorright(struct screen_write_ctx *, u_int); @@ -1576,14 +1752,15 @@ void screen_write_insertmode(struct screen_write_ctx *, int); void screen_write_mousemode(struct screen_write_ctx *, int); void screen_write_linefeed(struct screen_write_ctx *, int); +void screen_write_linefeedscreen(struct screen_write_ctx *, int); void screen_write_carriagereturn(struct screen_write_ctx *); void screen_write_kcursormode(struct screen_write_ctx *, int); void screen_write_kkeypadmode(struct screen_write_ctx *, int); void screen_write_clearendofscreen(struct screen_write_ctx *); void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); -void screen_write_cell( - struct screen_write_ctx *, const struct grid_cell *, u_char *); +void screen_write_cell(struct screen_write_ctx *, + const struct grid_cell *, const struct utf8_data *); /* screen-redraw.c */ void screen_redraw_screen(struct client *, int); @@ -1623,6 +1800,7 @@ const char *, struct environ *, struct termios *, u_int, u_int, u_int, char **); void window_destroy(struct window *); +void window_set_active_at(struct window *, u_int, u_int); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); void window_resize(struct window *, u_int, u_int); @@ -1643,7 +1821,7 @@ void window_pane_parse(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, int); void window_pane_mouse(struct window_pane *, - struct client *, u_char, u_char, u_char); + struct client *, struct mouse_event *); int window_pane_visible(struct window_pane *); char *window_pane_search( struct window_pane *, const char *, u_int *); @@ -1686,10 +1864,6 @@ extern const struct window_mode window_copy_mode; void window_copy_pageup(struct window_pane *); -/* window-scroll.c */ -extern const struct window_mode window_scroll_mode; -void window_scroll_pageup(struct window_pane *); - /* window-more.c */ extern const struct window_mode window_more_mode; void window_more_vadd(struct window_pane *, const char *, va_list); @@ -1710,6 +1884,7 @@ /* session.c */ extern struct sessions sessions; extern struct sessions dead_sessions; +extern struct session_groups session_groups; void session_alert_add(struct session *, struct window *, int); void session_alert_cancel(struct session *, struct winlink *); int session_alert_has(struct session *, struct winlink *, int); @@ -1730,10 +1905,18 @@ int session_previous(struct session *, int); int session_select(struct session *, int); int session_last(struct session *); +struct session_group *session_group_find(struct session *); +u_int session_group_index(struct session_group *); +void session_group_add(struct session *, struct session *); +void session_group_remove(struct session *); +void session_group_synchronize_to(struct session *); +void session_group_synchronize_from(struct session *); +void session_group_synchronize1(struct session *, struct session *); /* utf8.c */ void utf8_build(void); -int utf8_width(const u_char *); +int utf8_open(struct utf8_data *, u_char); +int utf8_append(struct utf8_data *, u_char); /* osdep-*.c */ char *osdep_get_name(int, char *); @@ -1750,7 +1933,7 @@ uint8_t buffer_read8(struct buffer *); /* buffer-poll.c */ -int buffer_poll(struct pollfd *, struct buffer *, struct buffer *); +int buffer_poll(int, int, struct buffer *, struct buffer *); /* log.c */ void log_open_tty(int); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/TODO /tmp/wmlmc6MQoR/tmux-1.1/TODO --- tmux-1.0/TODO 2009-09-20 18:52:16.000000000 +0100 +++ tmux-1.1/TODO 2009-11-02 21:26:58.000000000 +0000 @@ -9,45 +9,30 @@ - garbage collect window history (100 lines at a time?) if it hasn't been used in $x time (need window creation/use times) - lift SHRT_MAX limits for history? -- better mode features: search - flags to centre screen in window - better terminal emulation - activity/bell should be per-window not per-link? what if it is cur win in session not being watched? -- next prev word etc in command prompt; also ^K +- next prev word etc in command prompt - many more info() displays for various things -- backspace should perhaps wrap backwards over newlines which were not moved - down by a newline: screen and the OS X terminal does this but xterm and most - others do not. this might be hard: a flag for each grid line (top bit of size - maybe)? a single flag is insufficient as can't then tell when to /stop/ - unwrapping - input.c is too complicated. simplify? - use a better termcap internally instead of screen, perhaps xterm -- kill all but current pane - fix rxvt cursor fg issue (text under cursor can have non-white fg) -- client sx/sy should be in tty, then can let the terminal wrap at edge - to allow xterm to pick up it should be one line for its c/p - should be able to move to a hidden pane and it would be moved into view. pane number in status line/top-right would be cool for this - support other mouse modes (highlight etc) and use it in copy mode - set-remain-on-exit is a bit of a hack, some way to do it generically? - set-option should be set-session-option and should be overall global options - for stuff like mode keys? also quiet, utf8 and maybe other flags? -g is a bit unexpected in conf file - clear window title on exit - the output code (tty.c) could do with optimisation depending on term - capibilities + capabilities - would be nice to be able to use "--" to mark start of command w/ neww etc to avoid quoting -- goto line and search history in copy/scroll modes -- clone session command - make command sequences more usable: don't require space after ;, handle errors better -- key to switch to copy mode from scroll mode - attach should have a flag to create session if it doesn't exist -- rename split-window -> split-pane?? -- fix UTF-8 guesswork on sparc64, improve tty checks - choice and more mode would be better per client than per window? - hooks to which commands may be attached, for example: tmux add-hook "new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file @@ -59,48 +44,54 @@ - XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up when session is started - what about utmp etc? can tmux update it like screen? setgid? -- H/M/L commands in copy mode with vi-keys, for jumping to the top/middle/last - line on the screen -- split list-windows into separate list-windows and list-panes - warts on current naming: - display-time but message-fg/bg/attr - list-* vs show-* - server-info - up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-* -- pcvt25 doesn't work properly, why? (bce?) + - split-window -> split-pane?? - tidy up and prioritise todo list ;-) -- it is only possible to specify 8 colours to fg/bg options; should be able to - set 256 as well - neww and attach can create a session if none exists? would work fine with config file since - a way for force-width/height to apply to only one pane (how?) -- **** a command to run something without a window and send any output to the - window-more. if no output, info() a line saying "'%s' returned %d". so i can - bind mpc control commands to function keys ;-) - command to list what is actually running in each window with command line, pid (need some adaption of the osdep code) - string option to change/remove the symbols (*-+ etc) in status line + * or to set entire format, eg window-list-format '#N:#W#P' or something, + then could use embedded colours - support for bce - it would be nice if the start/end line keys in copy mode were aware of wrapped lines -- per session locking - some way to force a screen to use the entire terminal even if it is forced to be smaller by other clients. pan smaller terminal? (like screen F) -- idea of a "view" onto a window, need base x/y offsets for redraw -- a window option which means data is echoed to all panes in a window -- support running tmux from inside tmux [#(), if-shell] -- - generic system-like function which may take a callback - also sets up environment (TMUX) and has a timeout - for #(): command schedular, status line queues it with a time, run in - main loop, and uses most recent result -- can also be used for persistent - commands which never exit just continually output - for if-shell, callback?? - handle resize better in copy mode - way to copy stuff that is off screen due to resize -- fix line wrapping c&p problems in xterm etc - a way to address panes by name ("top-left") and position ("0,0") -- ability to specify multiple prefix keys - commands should be able to succeed or fail and have || or && for command lists - support the mouse wheel to scroll through history +- some way to KEEP a command running continually and just use its LAST line of + output +- bind commands to mouse buttons +- UTF-8 to a non-UTF-8 terminal should not be able to balls up + the terminal - www/ruby-addressable; make regress +- copy mode needs a tidy/cleanup +- things like display-message will leak job entries if #() is used +- message log +- an option to NOT remove message when key pressed +- would be nice to be able to press 0-9a-zA-Z to select window in choose-window + mode, also to start typing and it searches +- the wrapping stuff should work when redrawn from scroll mode too (screen_write_copy) +- ability to save history (to buffer?) +- multiple keys could be done with tables, ie have prefixes go and instead + bind -n ^A prefix-table "default" + where prefix-table sets command lookup table and sets prefix flag, then next key + is looked up in that table +- check fix UTF-8 and split-window? should be okay +- UTF-8 should be a pointer into a combined string buffer +- check irssi (term_charset) works with UTF-8 +- rectangle copy/paste +- half page/up down are missing from key table +- support esc-esc to quit in modes diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/tty.c /tmp/wmlmc6MQoR/tmux-1.1/tty.c --- tmux-1.0/tty.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/tty.c 2009-11-04 23:10:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.132 2009/09/11 14:13:52 tcunha Exp $ */ +/* $Id: tty.c,v 1.169 2009/11/04 23:10:43 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -29,13 +30,12 @@ void tty_fill_acs(struct tty *); -void tty_raw(struct tty *, const char *); - int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); -void tty_attributes_fg(struct tty *, const struct grid_cell *); -void tty_attributes_bg(struct tty *, const struct grid_cell *); +void tty_colours(struct tty *, const struct grid_cell *, int *); +void tty_colours_fg(struct tty *, const struct grid_cell *, int *); +void tty_colours_bg(struct tty *, const struct grid_cell *, int *); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( @@ -44,45 +44,63 @@ const struct grid_cell *, const struct grid_utf8 *); void -tty_init(struct tty *tty, int fd, char *path, char *term) +tty_init(struct tty *tty, int fd, char *term) { - tty->path = xstrdup(path); - tty->fd = fd; + char *path; + + memset(tty, 0, sizeof *tty); tty->log_fd = -1; if (term == NULL || *term == '\0') tty->termname = xstrdup("unknown"); else tty->termname = xstrdup(term); + + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + tty->fd = fd; + + if ((path = ttyname(fd)) == NULL) + fatalx("ttyname failed"); + tty->path = xstrdup(path); + tty->flags = 0; tty->term_flags = 0; } +void +tty_resize(struct tty *tty) +{ + struct winsize ws; + + if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) { + tty->sx = ws.ws_col; + tty->sy = ws.ws_row; + } + if (tty->sx == 0) + tty->sx = 80; + if (tty->sy == 0) + tty->sy = 24; + + tty->cx = UINT_MAX; + tty->cy = UINT_MAX; + + tty->rupper = UINT_MAX; + tty->rlower = UINT_MAX; +} + int tty_open(struct tty *tty, const char *overrides, char **cause) { - int mode; + int fd; - if (tty->fd == -1) { - tty->fd = open(tty->path, O_RDWR|O_NONBLOCK); - if (tty->fd == -1) { - xasprintf(cause, "%s: %s", tty->path, strerror(errno)); - return (-1); - } + if (debug_level > 3) { + fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); + tty->log_fd = fd; } - if ((mode = fcntl(tty->fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); - if (fcntl(tty->fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); - - if (debug_level > 3) - tty->log_fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644); - else - tty->log_fd = -1; - tty->term = tty_term_find(tty->termname, tty->fd, overrides, cause); if (tty->term == NULL) { tty_close(tty); @@ -93,7 +111,7 @@ tty->in = buffer_create(BUFSIZ); tty->out = buffer_create(BUFSIZ); - tty->flags &= TTY_UTF8; + tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_ESCAPE); tty_start_tty(tty); @@ -108,13 +126,18 @@ tty_start_tty(struct tty *tty) { struct termios tio; + int mode; #ifdef TIOCFLUSH int what; #endif -#if 0 - tty_detect_utf8(tty); -#endif + if (tty->fd == -1) + return; + + if ((mode = fcntl(tty->fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); if (tcgetattr(tty->fd, &tty->tio) != 0) fatal("tcgetattr failed"); @@ -125,7 +148,7 @@ tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL| ECHOPRT|ECHOKE|ECHOCTL|ISIG); tio.c_cc[VMIN] = 1; - tio.c_cc[VTIME] = 0; + tio.c_cc[VTIME] = 0; if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) fatal("tcsetattr failed"); @@ -163,6 +186,7 @@ tty_stop_tty(struct tty *tty) { struct winsize ws; + int mode; if (!(tty->flags & TTY_STARTED)) return; @@ -173,6 +197,10 @@ * because the fd is invalid. Things like ssh -t can easily leave us * with a dead tty. */ + if ((mode = fcntl(tty->fd, F_GETFL)) == -1) + return; + if (fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK) == -1) + return; if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1) return; if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) @@ -191,87 +219,6 @@ tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); } -#if 0 -void -tty_detect_utf8(struct tty *tty) -{ - struct pollfd pfd; - char buf[7]; - size_t len; - ssize_t n; - int nfds; - struct termios tio, old_tio; -#ifdef TIOCFLUSH - int what; -#endif - - if (tty->flags & TTY_UTF8) - return; - - /* - * If the terminal looks reasonably likely to support this, try to - * write a three-byte UTF-8 wide character to the terminal, then read - * the cursor position. - * - * XXX This entire function is a hack. - */ - - /* Check if the terminal looks sort of vt100. */ - if (strstr(tty_term_string(tty->term, TTYC_CLEAR), "[2J") == NULL || - strstr(tty_term_string(tty->term, TTYC_CUP), "H") == NULL) - return; - - if (tcgetattr(tty->fd, &old_tio) != 0) - fatal("tcgetattr failed"); - cfmakeraw(&tio); - if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) - fatal("tcsetattr failed"); - -#ifdef TIOCFLUSH - what = 0; - if (ioctl(tty->fd, TIOCFLUSH, &what) != 0) - fatal("ioctl(TIOCFLUSH)"); -#endif - -#define UTF8_TEST_DATA "\033[H\357\277\246\033[6n" - if (write(tty->fd, UTF8_TEST_DATA, (sizeof UTF8_TEST_DATA) - 1) == -1) - fatal("write failed"); -#undef UTF8_TEST_DATA - - len = 0; - for (;;) { - pfd.fd = tty->fd; - pfd.events = POLLIN; - - nfds = poll(&pfd, 1, 500); - if (nfds == -1) { - if (errno == EAGAIN || errno == EINTR) - continue; - fatal("poll failed"); - } - if (nfds == 0) - break; - if (pfd.revents & (POLLERR|POLLNVAL|POLLHUP)) - break; - if (!(pfd.revents & POLLIN)) - continue; - - if ((n = read(tty->fd, buf + len, 1)) != 1) - break; - buf[++len] = '\0'; - - if (len == (sizeof buf) - 1) { - if (strcmp(buf, "\033[1;3R") == 0) - tty->flags |= TTY_UTF8; - break; - } - } - - if (tcsetattr(tty->fd, TCSANOW, &old_tio) != 0) - fatal("tcsetattr failed"); -} -#endif - void tty_fill_acs(struct tty *tty) { @@ -386,9 +333,10 @@ if (tty->term->flags & TERM_EARLYWRAP) sx--; - if (tty->cx == sx) { - tty->cx = 0; - tty->cy++; + if (tty->cx >= sx) { + tty->cx = 1; + if (tty->cy != tty->rlower) + tty->cy++; } else tty->cx++; } @@ -400,7 +348,7 @@ void tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) { - u_int i, width; + u_int i; for (i = 0; i < UTF8_SIZE; i++) { if (gu->data[i] == 0xff) @@ -410,8 +358,7 @@ write(tty->log_fd, &gu->data[i], 1); } - width = utf8_width(gu->data); - tty->cx += width; + tty->cx += gu->width; } void @@ -499,17 +446,31 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) { const struct grid_cell *gc; + struct grid_line *gl; struct grid_cell tmpgc; const struct grid_utf8 *gu; u_int i, sx; + tty_update_mode(tty, tty->mode & ~MODE_CURSOR); + sx = screen_size_x(s); if (sx > s->grid->linedata[s->grid->hsize + py].cellsize) sx = s->grid->linedata[s->grid->hsize + py].cellsize; if (sx > tty->sx) sx = tty->sx; - tty_cursor(tty, 0, py, ox, oy); + /* + * Don't move the cursor to the start permission if it will wrap there + * itself. + */ + gl = NULL; + if (py != 0) + gl = &s->grid->linedata[s->grid->hsize + py - 1]; + if (oy + py == 0 || (gl != NULL && !(gl->flags & GRID_LINE_WRAPPED)) || + tty->cx < tty->sx || ox != 0 || + (oy + py != tty->cy + 1 && tty->cy != s->rlower + oy)) + tty_cursor(tty, ox, oy + py); + for (i = 0; i < sx; i++) { gc = grid_view_peek_cell(s->grid, i, py); @@ -520,24 +481,29 @@ if (screen_check_selection(s, i, py)) { memcpy(&tmpgc, &s->sel.cell, sizeof tmpgc); tmpgc.data = gc->data; - tmpgc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); - tmpgc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); + tmpgc.flags = gc->flags & + ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + tmpgc.flags |= s->sel.cell.flags & + (GRID_FLAG_FG256|GRID_FLAG_BG256); tty_cell(tty, &tmpgc, gu); } else tty_cell(tty, gc, gu); } - if (sx >= tty->sx) + if (sx >= tty->sx) { + tty_update_mode(tty, tty->mode); return; + } tty_reset(tty); - tty_cursor(tty, sx, py, ox, oy); + tty_cursor(tty, ox + sx, oy + py); if (screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else { for (i = sx; i < screen_size_x(s); i++) tty_putc(tty, ' '); } + tty_update_mode(tty, tty->mode); } void @@ -566,7 +532,6 @@ if (c->session->curw->window == wp->window) { if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL) continue; - tty_update_mode(&c->tty, c->tty.mode & ~MODE_CURSOR); cmdfn(&c->tty, ctx); } } @@ -586,7 +551,8 @@ tty_reset(tty); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + if (tty_term_has(tty->term, TTYC_ICH) || tty_term_has(tty->term, TTYC_ICH1)) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); @@ -613,7 +579,8 @@ tty_reset(tty); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + if (tty_term_has(tty->term, TTYC_DCH) || tty_term_has(tty->term, TTYC_DCH1)) tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); @@ -633,9 +600,9 @@ tty_reset(tty); - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num); } @@ -653,9 +620,9 @@ tty_reset(tty); - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num); } @@ -668,7 +635,8 @@ tty_reset(tty); - tty_cursor(tty, 0, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, ctx->ocy); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); @@ -687,7 +655,8 @@ tty_reset(tty); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); @@ -706,10 +675,10 @@ tty_reset(tty); if (wp->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_putcode(tty, TTYC_EL1); } else { - tty_cursor(tty, 0, ctx->ocy, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, ctx->ocy); for (i = 0; i < ctx->ocx + 1; i++) tty_putc(tty, ' '); } @@ -721,6 +690,9 @@ struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; + if (ctx->ocy != ctx->orupper) + return; + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { tty_redraw_region(tty, ctx); @@ -728,13 +700,11 @@ } tty_reset(tty); - - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); - - if (ctx->ocy == ctx->orupper) { - tty_cursor(tty, ctx->ocx, ctx->orupper, wp->xoff, wp->yoff); - tty_putcode(tty, TTYC_RI); - } + + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); + + tty_putcode(tty, TTYC_RI); } void @@ -743,20 +713,29 @@ struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; + if (ctx->ocy != ctx->orlower) + return; + if (wp->xoff != 0 || screen_size_x(s) < tty->sx || !tty_term_has(tty->term, TTYC_CSR)) { tty_redraw_region(tty, ctx); return; } - tty_reset(tty); - - tty_region(tty, ctx->orupper, ctx->orlower, wp->yoff); + /* + * If this line wrapped naturally (ctx->num is nonzero), don't do + * anything - the cursor can just be moved to the last cell and wrap + * naturally. + */ + if (ctx->num && !(tty->term->flags & TERM_EARLYWRAP)) + return; - if (ctx->ocy == ctx->orlower) { - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); - tty_putc(tty, '\n'); - } + tty_reset(tty); + + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + + tty_putc(tty, '\n'); } void @@ -768,13 +747,14 @@ tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); if (ctx->ocy != screen_size_y(s) - 1) { - tty_cursor(tty, 0, ctx->ocy + 1, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); for (i = ctx->ocy + 1; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i == screen_size_y(s) - 1) @@ -787,7 +767,7 @@ for (i = ctx->ocx; i < screen_size_x(s); i++) tty_putc(tty, ' '); for (j = ctx->ocy; j < screen_size_y(s); j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } @@ -803,8 +783,9 @@ tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); - tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); + tty_cursor_pane(tty, ctx, 0, 0); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < ctx->ocy; i++) { @@ -814,7 +795,7 @@ } } else { for (j = 0; j < ctx->ocy; j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } @@ -832,8 +813,9 @@ tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); - tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); + tty_cursor_pane(tty, ctx, 0, 0); + if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < screen_size_y(s); i++) { @@ -845,7 +827,7 @@ } } else { for (j = 0; j < screen_size_y(s); j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } @@ -861,10 +843,10 @@ tty_reset(tty); - tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); + tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); for (j = 0; j < screen_size_y(s); j++) { - tty_cursor(tty, 0, j, wp->xoff, wp->yoff); + tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, 'E'); } @@ -874,8 +856,31 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; + struct screen *s = wp->screen; + u_int cx; - tty_cursor(tty, ctx->ocx, ctx->ocy, wp->xoff, wp->yoff); + tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); + + /* Is the cursor in the very last position? */ + if (ctx->ocx > wp->sx - ctx->last_width) { + if (wp->xoff != 0 || wp->sx != tty->sx) { + /* + * The pane doesn't fill the entire line, the linefeed + * will already have happened, so just move the cursor. + */ + tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); + } else if (tty->cx < tty->sx) { + /* + * The cursor isn't in the last position already, so + * move as far left as possinble and redraw the last + * cell to move into the last position. + */ + cx = screen_size_x(s) - ctx->last_width; + tty_cursor_pane(tty, ctx, cx, ctx->ocy); + tty_cell(tty, &ctx->last_cell, &ctx->last_utf8); + } + } else + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_cell(tty, ctx->cell, ctx->utf8); } @@ -883,14 +888,13 @@ void tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) { - u_char *ptr = ctx->ptr; - size_t i; + struct window_pane *wp = ctx->wp; - for (i = 0; i < UTF8_SIZE; i++) { - if (ptr[i] == 0xff) - break; - tty_putc(tty, ptr[i]); - } + /* + * Cannot rely on not being a partial character, so just redraw the + * whole line. + */ + tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); } void @@ -944,63 +948,230 @@ memcpy(gc, &grid_default_cell, sizeof *gc); } +/* Set region inside pane. */ void -tty_region(struct tty *tty, u_int rupper, u_int rlower, u_int oy) +tty_region_pane( + struct tty *tty, const struct tty_ctx *ctx, u_int rupper, u_int rlower) { + struct window_pane *wp = ctx->wp; + + tty_region(tty, wp->yoff + rupper, wp->yoff + rlower); +} + +/* Set region at absolute position. */ +void +tty_region(struct tty *tty, u_int rupper, u_int rlower) +{ + if (tty->rlower == rlower && tty->rupper == rupper) + return; if (!tty_term_has(tty->term, TTYC_CSR)) return; - if (tty->rlower != oy + rlower || tty->rupper != oy + rupper) { - tty->rlower = oy + rlower; - tty->rupper = oy + rupper; - tty->cx = 0; - tty->cy = 0; - tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); - } + + tty->rupper = rupper; + tty->rlower = rlower; + + /* + * Some terminals (such as PuTTY) do not correctly reset the cursor to + * 0,0 if it is beyond the last column (they do not reset their wrap + * flag so further output causes a line feed). As a workaround, do an + * explicit move to 0 first. + */ + if (tty->cx >= tty->sx) + tty_cursor(tty, 0, tty->cy); + + tty->cx = 0; + tty->cy = 0; + + tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); +} + +/* Move cursor inside pane. */ +void +tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) +{ + struct window_pane *wp = ctx->wp; + + tty_cursor(tty, wp->xoff + cx, wp->yoff + cy); } +/* Move cursor to absolute position. */ void -tty_cursor(struct tty *tty, u_int cx, u_int cy, u_int ox, u_int oy) +tty_cursor(struct tty *tty, u_int cx, u_int cy) { - if (ox + cx == 0 && tty->cx != 0 && tty->cy == oy + cy) { - tty->cx = 0; + struct tty_term *term = tty->term; + u_int thisx, thisy; + int change; + + if (cx > tty->sx - 1) + cx = tty->sx - 1; + + thisx = tty->cx; + thisy = tty->cy; + + /* No change. */ + if (cx == thisx && cy == thisy) + return; + + /* Very end of the line, just use absolute movement. */ + if (thisx > tty->sx - 1) + goto absolute; + + /* Move to home position (0, 0). */ + if (cx == 0 && cy == 0 && tty_term_has(term, TTYC_HOME)) { + tty_putcode(tty, TTYC_HOME); + goto out; + } + + /* Zero on the next line. */ + if (cx == 0 && cy == thisy + 1 && thisy != tty->rlower) { tty_putc(tty, '\r'); - } else if (tty->cx != ox + cx || tty->cy != oy + cy) { - tty->cx = ox + cx; - tty->cy = oy + cy; - tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); + tty_putc(tty, '\n'); + goto out; } + + /* Moving column or row. */ + if (cy == thisy) { + /* + * Moving column only, row staying the same. + */ + + /* To left edge. */ + if (cx == 0) { + tty_putc(tty, '\r'); + goto out; + } + + /* One to the left. */ + if (cx == thisx - 1 && tty_term_has(term, TTYC_CUB1)) { + tty_putcode(tty, TTYC_CUB1); + goto out; + } + + /* One to the right. */ + if (cx == thisx + 1 && tty_term_has(term, TTYC_CUF1)) { + tty_putcode(tty, TTYC_CUF1); + goto out; + } + + /* Calculate difference. */ + change = thisx - cx; /* +ve left, -ve right */ + + /* + * Use HPA if change is larger than absolute, otherwise move + * the cursor with CUB/CUF. + */ + if (abs(change) > cx && tty_term_has(term, TTYC_HPA)) { + tty_putcode1(tty, TTYC_HPA, cx); + goto out; + } else if (change > 0 && tty_term_has(term, TTYC_CUB)) { + tty_putcode1(tty, TTYC_CUB, change); + goto out; + } else if (change < 0 && tty_term_has(term, TTYC_CUF)) { + tty_putcode1(tty, TTYC_CUF, -change); + goto out; + } + } else if (cx == thisx) { + /* + * Moving row only, column staying the same. + */ + + /* One above. */ + if (thisy != tty->rupper && + cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) { + tty_putcode(tty, TTYC_CUU1); + goto out; + } + + /* One below. */ + if (thisy != tty->rlower && + cy == thisy + 1 && tty_term_has(term, TTYC_CUD1)) { + tty_putcode(tty, TTYC_CUD1); + goto out; + } + + /* Calculate difference. */ + change = thisy - cy; /* +ve up, -ve down */ + + /* + * Try to use VPA if change is larger than absolute or if this change + * would cross the scroll region, otherwise use CUU/CUD. + */ + if (abs(change) > cy || + (change < 0 && cy - change > tty->rlower) || + (change > 0 && cy - change < tty->rupper)) { + if (tty_term_has(term, TTYC_VPA)) { + tty_putcode1(tty, TTYC_VPA, cy); + goto out; + } + } else if (change > 0 && tty_term_has(term, TTYC_CUU)) { + tty_putcode1(tty, TTYC_CUU, change); + goto out; + } else if (change < 0 && tty_term_has(term, TTYC_CUD)) { + tty_putcode1(tty, TTYC_CUD, -change); + goto out; + } + } + +absolute: + /* Absolute movement. */ + tty_putcode2(tty, TTYC_CUP, cy, cx); + +out: + tty->cx = cx; + tty->cy = cy; } void tty_attributes(struct tty *tty, const struct grid_cell *gc) { - struct grid_cell *tc = &tty->cell; + struct grid_cell *tc = &tty->cell, gc2; u_char changed; - u_int fg, bg, attr; + u_int new_attr; + + /* If the character is space, don't care about foreground. */ + if (gc->data == ' ' && !(gc->flags & GRID_FLAG_UTF8)) { + memcpy(&gc2, gc, sizeof gc2); + if (gc->attr & GRID_ATTR_REVERSE) + gc2.bg = tc->bg; + else + gc2.fg = tc->fg; + gc = &gc2; + } /* * If no setab, try to use the reverse attribute as a best-effort for a * non-default background. This is a bit of a hack but it doesn't do * any serious harm and makes a couple of applications happier. */ - fg = gc->fg; bg = gc->bg; attr = gc->attr; if (!tty_term_has(tty->term, TTYC_SETAB)) { - if (attr & GRID_ATTR_REVERSE) { - if (fg != 7 && fg != 8) - attr &= ~GRID_ATTR_REVERSE; + if (gc != &gc2) { + memcpy(&gc2, gc, sizeof gc2); + gc = &gc2; + } + + if (gc->attr & GRID_ATTR_REVERSE) { + if (gc->fg != 7 && gc->fg != 8) + gc2.attr &= ~GRID_ATTR_REVERSE; } else { - if (bg != 0 && bg != 8) - attr |= GRID_ATTR_REVERSE; + if (gc->bg != 0 && gc->bg != 8) + gc2.attr |= GRID_ATTR_REVERSE; } } /* If any bits are being cleared, reset everything. */ - if (tc->attr & ~attr) + if (tc->attr & ~gc->attr) tty_reset(tty); + /* + * Set the colours. This may call tty_reset() (so it comes next) and + * may add to (NOT remove) the desired attributes by changing new_attr. + */ + new_attr = gc->attr; + tty_colours(tty, gc, &new_attr); + /* Filter out attribute bits already set. */ - changed = attr & ~tc->attr; - tc->attr = attr; + changed = new_attr & ~tc->attr; + tc->attr = new_attr; /* Set the attributes. */ if (changed & GRID_ATTR_BRIGHT) @@ -1023,107 +1194,166 @@ tty_putcode(tty, TTYC_INVIS); if (changed & GRID_ATTR_CHARSET) tty_putcode(tty, TTYC_SMACS); - - /* Set foreground colour. */ - if (fg != tc->fg || - (gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)) { - tty_attributes_fg(tty, gc); - tc->fg = fg; - tc->flags &= ~GRID_FLAG_FG256; - tc->flags |= gc->flags & GRID_FLAG_FG256; - } - - /* Set background colour. */ - if (bg != tc->bg || - (gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)) { - tty_attributes_bg(tty, gc); - tc->bg = bg; - tc->flags &= ~GRID_FLAG_BG256; - tc->flags |= gc->flags & GRID_FLAG_BG256; - } } -int -tty_try_256(struct tty *tty, u_char colour, const char *type) +void +tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) { - char s[32]; - - if (!(tty->term->flags & TERM_256COLOURS) && - !(tty->term_flags & TERM_256COLOURS)) - return (-1); + struct grid_cell *tc = &tty->cell; + u_char fg = gc->fg, bg = gc->bg, flags = gc->flags; + int have_ax, fg_default, bg_default; - xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); - tty_puts(tty, s); - return (0); -} + /* No changes? Nothing is necessary. */ + if (fg == tc->fg && bg == tc->bg && + ((flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256)) == 0) + return; -int -tty_try_88(struct tty *tty, u_char colour, const char *type) -{ - char s[32]; + /* + * Is either the default colour? This is handled specially because the + * best solution might be to reset both colours to default, in which + * case if only one is default need to fall onward to set the other + * colour. + */ + fg_default = (fg == 8 && !(flags & GRID_FLAG_FG256)); + bg_default = (bg == 8 && !(flags & GRID_FLAG_BG256)); + if (fg_default || bg_default) { + /* + * If don't have AX but do have op, send sgr0 (op can't + * actually be used because it is sometimes the same as sgr0 + * and sometimes isn't). This resets both colours to default. + * + * Otherwise, try to set the default colour only as needed. + */ + have_ax = tty_term_has(tty->term, TTYC_AX); + if (!have_ax && tty_term_has(tty->term, TTYC_OP)) + tty_reset(tty); + else { + if (fg_default && + fg != tc->fg && !(tc->flags & GRID_FLAG_FG256)) { + if (have_ax) + tty_puts(tty, "\033[39m"); + else if (tc->fg != 7) + tty_putcode1(tty, TTYC_SETAF, 7); + tc->fg = 8; + tc->flags &= ~GRID_FLAG_FG256; + } + if (bg_default && + bg != tc->bg && !(tc->flags & GRID_FLAG_BG256)) { + if (have_ax) + tty_puts(tty, "\033[49m"); + else if (tc->bg != 0) + tty_putcode1(tty, TTYC_SETAB, 0); + tc->bg = 8; + tc->flags &= ~GRID_FLAG_BG256; + } + } + } - if (!(tty->term->flags & TERM_88COLOURS) && - !(tty->term_flags & TERM_88COLOURS)) - return (-1); - colour = colour_256to88(colour); + /* Set the foreground colour. */ + if (!fg_default && (fg != tc->fg || + ((flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)))) + tty_colours_fg(tty, gc, attr); - xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); - tty_puts(tty, s); - return (0); + /* + * Set the background colour. This must come after the foreground as + * tty_colour_fg() can call tty_reset(). + */ + if (!bg_default && (bg != tc->bg || + ((flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)))) + tty_colours_bg(tty, gc, attr); } void -tty_attributes_fg(struct tty *tty, const struct grid_cell *gc) +tty_colours_fg(struct tty *tty, const struct grid_cell *gc, int *attr) { - u_char fg; + struct grid_cell *tc = &tty->cell; + u_char fg = gc->fg; - fg = gc->fg; + /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_FG256) { + /* Try as 256 colours or translating to 88. */ if (tty_try_256(tty, fg, "38") == 0) - return; + goto save_fg; if (tty_try_88(tty, fg, "38") == 0) - return; + goto save_fg; + + /* Translate to 16-colour palette, updating bold if needed. */ fg = colour_256to16(fg); if (fg & 8) { fg &= 7; - tty_putcode(tty, TTYC_BOLD); - tty->cell.attr |= GRID_ATTR_BRIGHT; - } else if (tty->cell.attr & GRID_ATTR_BRIGHT) - tty_reset(tty); + (*attr) |= GRID_ATTR_BRIGHT; + } else + tty_reset(tty); /* turn off bold */ } - if (fg == 8 && - !(tty->term->flags & TERM_HASDEFAULTS) && - !(tty->term_flags & TERM_HASDEFAULTS)) - fg = 7; - if (fg == 8) - tty_puts(tty, "\033[39m"); - else - tty_putcode1(tty, TTYC_SETAF, fg); + /* Otherwise set the foreground colour. */ + tty_putcode1(tty, TTYC_SETAF, fg); + +save_fg: + /* Save the new values in the terminal current cell. */ + tc->fg = fg; + tc->flags &= ~GRID_FLAG_FG256; + tc->flags |= gc->flags & GRID_FLAG_FG256; } void -tty_attributes_bg(struct tty *tty, const struct grid_cell *gc) +tty_colours_bg(struct tty *tty, const struct grid_cell *gc, unused int *attr) { - u_char bg; + struct grid_cell *tc = &tty->cell; + u_char bg = gc->bg; - bg = gc->bg; + /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_BG256) { + /* Try as 256 colours or translating to 88. */ if (tty_try_256(tty, bg, "48") == 0) - return; + goto save_bg; if (tty_try_88(tty, bg, "48") == 0) - return; + goto save_bg; + + /* + * Translate to 16-colour palette. Bold background doesn't + * exist portably, so just discard the bold bit if set. + */ bg = colour_256to16(bg); if (bg & 8) bg &= 7; } - if (bg == 8 && - !(tty->term->flags & TERM_HASDEFAULTS) && - !(tty->term_flags & TERM_HASDEFAULTS)) - bg = 0; - if (bg == 8) - tty_puts(tty, "\033[49m"); - else - tty_putcode1(tty, TTYC_SETAB, bg); + /* Otherwise set the background colour. */ + tty_putcode1(tty, TTYC_SETAB, bg); + +save_bg: + /* Save the new values in the terminal current cell. */ + tc->bg = bg; + tc->flags &= ~GRID_FLAG_BG256; + tc->flags |= gc->flags & GRID_FLAG_BG256; +} + +int +tty_try_256(struct tty *tty, u_char colour, const char *type) +{ + char s[32]; + + if (!(tty->term->flags & TERM_256COLOURS) && + !(tty->term_flags & TERM_256COLOURS)) + return (-1); + + xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); + tty_puts(tty, s); + return (0); +} + +int +tty_try_88(struct tty *tty, u_char colour, const char *type) +{ + char s[32]; + + if (!(tty->term->flags & TERM_88COLOURS) && + !(tty->term_flags & TERM_88COLOURS)) + return (-1); + colour = colour_256to88(colour); + + xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); + tty_puts(tty, s); + return (0); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/tty-keys.c /tmp/wmlmc6MQoR/tmux-1.1/tty-keys.c --- tmux-1.0/tty-keys.c 2009-07-30 21:14:58.000000000 +0100 +++ tmux-1.1/tty-keys.c 2009-10-28 23:05:01.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: tty-keys.c,v 1.29 2009/07/28 22:37:02 tcunha Exp $ */ +/* $Id: tty-keys.c,v 1.38 2009/10/28 23:05:01 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -25,9 +25,12 @@ #include "tmux.h" +/* + * Handle keys input from the outside terminal. + */ + void tty_keys_add(struct tty *, const char *, int, int); -int tty_keys_parse_xterm(struct tty *, char *, size_t, size_t *); -int tty_keys_parse_mouse(struct tty *, char *, size_t, size_t *, u_char *); +int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); struct tty_key_ent { enum tty_code_code code; @@ -39,85 +42,145 @@ struct tty_key_ent tty_keys[] = { /* Function keys. */ - { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, - { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, - { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, - { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, - { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, - { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, - { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, - { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, - { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, - { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, - { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, - { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, - { TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL }, - { TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL }, - { TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL }, - { TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL }, - { TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL }, - { TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL }, - { TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL }, - { TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL }, - { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, - { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, - { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, - { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, - { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, - { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, - { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, + { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, + { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, + { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, + { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, + { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, + { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, + { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, + { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, + { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, + { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, + { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, + { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, + { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, + { TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL }, + { TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL }, + { TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL }, + { TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL }, + { TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL }, + { TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL }, + { TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL }, + { TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL }, + { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, + { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, + { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, + { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, + { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, + { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, + { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL }, /* Arrow keys. */ - { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, - { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, - - { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, - { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, - - { 0, "\033Oa", KEYC_UP | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Ob", KEYC_DOWN | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Oc", KEYC_RIGHT | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Od", KEYC_LEFT | KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[a", KEYC_UP | KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[b", KEYC_DOWN | KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[c", KEYC_RIGHT | KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[d", KEYC_LEFT | KEYC_SHIFT, TTYKEY_RAW }, - - { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, - { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, - { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, - { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, + { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, + { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, + + { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, + { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, + { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, + { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, + + { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, + { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, + { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, + { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, + + /* Special-case arrow keys for rxvt until terminfo has kRIT5 etc. */ + { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, + { 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, + + { 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW }, + { 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW }, /* - * Numeric keypad. termcap and terminfo are totally confusing for this. - * There are definitions for some keypad keys and for function keys, - * but these seem to now be used for the real function keys rather than - * for the keypad keys in application mode (which is different from - * what it says in the termcap file). So, we just hardcode the vt100 - * escape sequences here and always put the terminal into keypad_xmit - * mode. Translation of numbers mode/applications mode is done in - * input-keys.c. + * Numeric keypad. Just use the vt100 escape sequences here and always + * put the terminal into keypad_xmit mode. Translation of numbers + * mode/applications mode is done in input-keys.c. */ - { 0, "\033Oo", KEYC_KP0_1, TTYKEY_RAW }, - { 0, "\033Oj", KEYC_KP0_2, TTYKEY_RAW }, - { 0, "\033Om", KEYC_KP0_3, TTYKEY_RAW }, - { 0, "\033Ow", KEYC_KP1_0, TTYKEY_RAW }, - { 0, "\033Ox", KEYC_KP1_1, TTYKEY_RAW }, - { 0, "\033Oy", KEYC_KP1_2, TTYKEY_RAW }, - { 0, "\033Ok", KEYC_KP1_3, TTYKEY_RAW }, - { 0, "\033Ot", KEYC_KP2_0, TTYKEY_RAW }, - { 0, "\033Ou", KEYC_KP2_1, TTYKEY_RAW }, - { 0, "\033Ov", KEYC_KP2_2, TTYKEY_RAW }, - { 0, "\033Oq", KEYC_KP3_0, TTYKEY_RAW }, - { 0, "\033Or", KEYC_KP3_1, TTYKEY_RAW }, - { 0, "\033Os", KEYC_KP3_2, TTYKEY_RAW }, - { 0, "\033OM", KEYC_KP3_3, TTYKEY_RAW }, - { 0, "\033Op", KEYC_KP4_0, TTYKEY_RAW }, - { 0, "\033On", KEYC_KP4_2, TTYKEY_RAW }, + { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, + { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, + { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, + { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, + { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, + { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, + { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, + { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, + { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, + { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, + { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, + { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, + { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, + { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, + { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, + { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, + + /* Key and modifier capabilities. */ + { TTYC_KDC2, NULL, KEYC_DC|KEYC_SHIFT, 0 }, + { TTYC_KDC3, NULL, KEYC_DC|KEYC_ESCAPE, 0 }, + { TTYC_KDC4, NULL, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KDC5, NULL, KEYC_DC|KEYC_CTRL, 0 }, + { TTYC_KDC6, NULL, KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KDC7, NULL, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KDN2, NULL, KEYC_DOWN|KEYC_SHIFT, 0 }, + { TTYC_KDN3, NULL, KEYC_DOWN|KEYC_ESCAPE, 0 }, + { TTYC_KDN4, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KDN5, NULL, KEYC_DOWN|KEYC_CTRL, 0 }, + { TTYC_KDN6, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KDN7, NULL, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KEND2, NULL, KEYC_END|KEYC_SHIFT, 0 }, + { TTYC_KEND3, NULL, KEYC_END|KEYC_ESCAPE, 0 }, + { TTYC_KEND4, NULL, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KEND5, NULL, KEYC_END|KEYC_CTRL, 0 }, + { TTYC_KEND6, NULL, KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KEND7, NULL, KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KHOM2, NULL, KEYC_HOME|KEYC_SHIFT, 0 }, + { TTYC_KHOM3, NULL, KEYC_HOME|KEYC_ESCAPE, 0 }, + { TTYC_KHOM4, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KHOM5, NULL, KEYC_HOME|KEYC_CTRL, 0 }, + { TTYC_KHOM6, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KHOM7, NULL, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KIC2, NULL, KEYC_IC|KEYC_SHIFT, 0 }, + { TTYC_KIC3, NULL, KEYC_IC|KEYC_ESCAPE, 0 }, + { TTYC_KIC4, NULL, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KIC5, NULL, KEYC_IC|KEYC_CTRL, 0 }, + { TTYC_KIC6, NULL, KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KIC7, NULL, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KLFT2, NULL, KEYC_LEFT|KEYC_SHIFT, 0 }, + { TTYC_KLFT3, NULL, KEYC_LEFT|KEYC_ESCAPE, 0 }, + { TTYC_KLFT4, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KLFT5, NULL, KEYC_LEFT|KEYC_CTRL, 0 }, + { TTYC_KLFT6, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KLFT7, NULL, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KNXT2, NULL, KEYC_NPAGE|KEYC_SHIFT, 0 }, + { TTYC_KNXT3, NULL, KEYC_NPAGE|KEYC_ESCAPE, 0 }, + { TTYC_KNXT4, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KNXT5, NULL, KEYC_NPAGE|KEYC_CTRL, 0 }, + { TTYC_KNXT6, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KNXT7, NULL, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KPRV2, NULL, KEYC_PPAGE|KEYC_SHIFT, 0 }, + { TTYC_KPRV3, NULL, KEYC_PPAGE|KEYC_ESCAPE, 0 }, + { TTYC_KPRV4, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KPRV5, NULL, KEYC_PPAGE|KEYC_CTRL, 0 }, + { TTYC_KPRV6, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KPRV7, NULL, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KRIT2, NULL, KEYC_RIGHT|KEYC_SHIFT, 0 }, + { TTYC_KRIT3, NULL, KEYC_RIGHT|KEYC_ESCAPE, 0 }, + { TTYC_KRIT4, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KRIT5, NULL, KEYC_RIGHT|KEYC_CTRL, 0 }, + { TTYC_KRIT6, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KRIT7, NULL, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { TTYC_KUP2, NULL, KEYC_UP|KEYC_SHIFT, 0 }, + { TTYC_KUP3, NULL, KEYC_UP|KEYC_ESCAPE, 0 }, + { TTYC_KUP4, NULL, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE, 0 }, + { TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 }, + { TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 }, + { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 }, }; RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); @@ -231,7 +294,7 @@ } int -tty_keys_next(struct tty *tty, int *key, u_char *mouse) +tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) { struct tty_key *tk; struct timeval tv; @@ -269,14 +332,14 @@ } /* Not found. Is this a mouse key press? */ - *key = tty_keys_parse_mouse(tty, buf, len, &size, mouse); + *key = tty_keys_mouse(buf, len, &size, mouse); if (*key != KEYC_NONE) { buffer_remove(tty->in, size); goto found; } - /* Not found. Try to parse xterm-type arguments. */ - *key = tty_keys_parse_xterm(tty, buf, len, &size); + /* Not found. Try to parse a key with an xterm-style modifier. */ + *key = xterm_keys_find(buf, len, &size); if (*key != KEYC_NONE) { buffer_remove(tty->in, size); goto found; @@ -287,7 +350,7 @@ tv.tv_sec = 0; tv.tv_usec = ESCAPE_PERIOD * 1000L; if (gettimeofday(&tty->key_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); timeradd(&tty->key_timer, &tv, &tty->key_timer); tty->flags |= TTY_ESCAPE; @@ -317,7 +380,7 @@ /* If the timer hasn't expired, keep waiting. */ if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); if (timercmp(&tty->key_timer, &tv, >)) return (1); @@ -331,8 +394,7 @@ } int -tty_keys_parse_mouse( - unused struct tty *tty, char *buf, size_t len, size_t *size, u_char *mouse) +tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) { /* * Mouse sequences are \033[M followed by three characters indicating @@ -344,76 +406,13 @@ return (KEYC_NONE); *size = 6; - if (buf[3] < 32 || buf[4] < 33 || buf[5] < 33) + m->b = buf[3]; + m->x = buf[4]; + m->y = buf[5]; + if (m->b < 32 || m->x < 33 || m->y < 33) return (KEYC_NONE); - - mouse[0] = buf[3] - 32; - mouse[1] = buf[4] - 33; - mouse[2] = buf[5] - 33; + m->b -= 32; + m->x -= 33; + m->y -= 33; return (KEYC_MOUSE); } - -int -tty_keys_parse_xterm(struct tty *tty, char *buf, size_t len, size_t *size) -{ - struct tty_key *tk; - char tmp[5]; - size_t tmplen; - int key; - - /* - * xterm sequences with modifier keys are of the form: - * - * ^[[1;xD becomes ^[[D - * ^[[5;x~ becomes ^[[5~ - * - * This function is a bit of a hack. Need to figure out what exact - * format and meaning xterm outputs and fix it. XXX - */ - - log_debug("xterm input is: %.*s", (int) len, buf); - if (len != 6 || memcmp(buf, "\033[1;", 4) != 0) - return (KEYC_NONE); - *size = 6; - - tmplen = 0; - tmp[tmplen++] = '['; - if (buf[5] == '~') { - tmp[tmplen++] = buf[2]; - tmp[tmplen++] = '~'; - } else - tmp[tmplen++] = buf[5]; - log_debug("xterm output is: %.*s", (int) tmplen, tmp); - - tk = tty_keys_find(tty, tmp, tmplen, size); - if (tk == NULL) - return (KEYC_NONE); - key = tk->key; - - switch (buf[4]) { - case '8': - key |= KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL; - break; - case '7': - key |= KEYC_ESCAPE|KEYC_CTRL; - break; - case '6': - key |= KEYC_SHIFT|KEYC_CTRL; - break; - case '5': - key |= KEYC_CTRL; - break; - case '4': - key |= KEYC_SHIFT|KEYC_ESCAPE; - break; - case '3': - key |= KEYC_ESCAPE; - break; - case '2': - key |= KEYC_SHIFT; - break; - } - - *size = 6; - return (key); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/tty-term.c /tmp/wmlmc6MQoR/tmux-1.1/tty-term.c --- tmux-1.0/tty-term.c 2009-08-23 12:50:39.000000000 +0100 +++ tmux-1.1/tty-term.c 2009-10-28 23:01:44.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: tty-term.c,v 1.30 2009/08/23 11:50:39 nicm Exp $ */ +/* $Id: tty-term.c,v 1.35 2009/10/28 23:01:44 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -32,8 +32,8 @@ struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms); struct tty_term_code_entry tty_term_codes[NTTYCODE] = { - { TTYC_AX, TTYCODE_FLAG, "AX" }, { TTYC_ACSC, TTYCODE_STRING, "acsc" }, + { TTYC_AX, TTYCODE_FLAG, "AX" }, { TTYC_BEL, TTYCODE_STRING, "bel" }, { TTYC_BLINK, TTYCODE_STRING, "blink" }, { TTYC_BOLD, TTYCODE_STRING, "bold" }, @@ -42,9 +42,15 @@ { TTYC_CNORM, TTYCODE_STRING, "cnorm" }, { TTYC_COLORS, TTYCODE_NUMBER, "colors" }, { TTYC_CSR, TTYCODE_STRING, "csr" }, + { TTYC_CUB, TTYCODE_STRING, "cub" }, + { TTYC_CUB1, TTYCODE_STRING, "cub1" }, { TTYC_CUD, TTYCODE_STRING, "cud" }, { TTYC_CUD1, TTYCODE_STRING, "cud1" }, + { TTYC_CUF, TTYCODE_STRING, "cuf" }, + { TTYC_CUF1, TTYCODE_STRING, "cuf1" }, { TTYC_CUP, TTYCODE_STRING, "cup" }, + { TTYC_CUU, TTYCODE_STRING, "cuu" }, + { TTYC_CUU1, TTYCODE_STRING, "cuu1" }, { TTYC_DCH, TTYCODE_STRING, "dch" }, { TTYC_DCH1, TTYCODE_STRING, "dch1" }, { TTYC_DIM, TTYCODE_STRING, "dim" }, @@ -53,6 +59,8 @@ { TTYC_EL, TTYCODE_STRING, "el" }, { TTYC_EL1, TTYCODE_STRING, "el1" }, { TTYC_ENACS, TTYCODE_STRING, "enacs" }, + { TTYC_HOME, TTYCODE_STRING, "home" }, + { TTYC_HPA, TTYCODE_STRING, "hpa" }, { TTYC_ICH, TTYCODE_STRING, "ich" }, { TTYC_ICH1, TTYCODE_STRING, "ich1" }, { TTYC_IL, TTYCODE_STRING, "il" }, @@ -66,8 +74,26 @@ { TTYC_KCUD1, TTYCODE_STRING, "kcud1" }, { TTYC_KCUF1, TTYCODE_STRING, "kcuf1" }, { TTYC_KCUU1, TTYCODE_STRING, "kcuu1" }, + { TTYC_KDC2, TTYCODE_STRING, "kDC" }, + { TTYC_KDC3, TTYCODE_STRING, "kDC3" }, + { TTYC_KDC4, TTYCODE_STRING, "kDC4" }, + { TTYC_KDC5, TTYCODE_STRING, "kDC5" }, + { TTYC_KDC6, TTYCODE_STRING, "kDC6" }, + { TTYC_KDC7, TTYCODE_STRING, "kDC7" }, { TTYC_KDCH1, TTYCODE_STRING, "kdch1" }, + { TTYC_KDN2, TTYCODE_STRING, "kDN" }, + { TTYC_KDN3, TTYCODE_STRING, "kDN3" }, + { TTYC_KDN4, TTYCODE_STRING, "kDN4" }, + { TTYC_KDN5, TTYCODE_STRING, "kDN5" }, + { TTYC_KDN6, TTYCODE_STRING, "kDN6" }, + { TTYC_KDN7, TTYCODE_STRING, "kDN7" }, { TTYC_KEND, TTYCODE_STRING, "kend" }, + { TTYC_KEND2, TTYCODE_STRING, "kEND" }, + { TTYC_KEND3, TTYCODE_STRING, "kEND3" }, + { TTYC_KEND4, TTYCODE_STRING, "kEND4" }, + { TTYC_KEND5, TTYCODE_STRING, "kEND5" }, + { TTYC_KEND6, TTYCODE_STRING, "kEND6" }, + { TTYC_KEND7, TTYCODE_STRING, "kEND7" }, { TTYC_KF1, TTYCODE_STRING, "kf1" }, { TTYC_KF10, TTYCODE_STRING, "kf10" }, { TTYC_KF11, TTYCODE_STRING, "kf11" }, @@ -79,8 +105,8 @@ { TTYC_KF17, TTYCODE_STRING, "kf17" }, { TTYC_KF18, TTYCODE_STRING, "kf18" }, { TTYC_KF19, TTYCODE_STRING, "kf19" }, - { TTYC_KF20, TTYCODE_STRING, "kf20" }, { TTYC_KF2, TTYCODE_STRING, "kf2" }, + { TTYC_KF20, TTYCODE_STRING, "kf20" }, { TTYC_KF3, TTYCODE_STRING, "kf3" }, { TTYC_KF4, TTYCODE_STRING, "kf4" }, { TTYC_KF5, TTYCODE_STRING, "kf5" }, @@ -88,11 +114,53 @@ { TTYC_KF7, TTYCODE_STRING, "kf7" }, { TTYC_KF8, TTYCODE_STRING, "kf8" }, { TTYC_KF9, TTYCODE_STRING, "kf9" }, + { TTYC_KHOM2, TTYCODE_STRING, "kHOM" }, + { TTYC_KHOM3, TTYCODE_STRING, "kHOM3" }, + { TTYC_KHOM4, TTYCODE_STRING, "kHOM4" }, + { TTYC_KHOM5, TTYCODE_STRING, "kHOM5" }, + { TTYC_KHOM6, TTYCODE_STRING, "kHOM6" }, + { TTYC_KHOM7, TTYCODE_STRING, "kHOM7" }, { TTYC_KHOME, TTYCODE_STRING, "khome" }, + { TTYC_KIC2, TTYCODE_STRING, "kIC" }, + { TTYC_KIC3, TTYCODE_STRING, "kIC3" }, + { TTYC_KIC4, TTYCODE_STRING, "kIC4" }, + { TTYC_KIC5, TTYCODE_STRING, "kIC5" }, + { TTYC_KIC6, TTYCODE_STRING, "kIC6" }, + { TTYC_KIC7, TTYCODE_STRING, "kIC7" }, { TTYC_KICH1, TTYCODE_STRING, "kich1" }, + { TTYC_KLFT2, TTYCODE_STRING, "kLFT" }, + { TTYC_KLFT3, TTYCODE_STRING, "kLFT3" }, + { TTYC_KLFT4, TTYCODE_STRING, "kLFT4" }, + { TTYC_KLFT5, TTYCODE_STRING, "kLFT5" }, + { TTYC_KLFT6, TTYCODE_STRING, "kLFT6" }, + { TTYC_KLFT7, TTYCODE_STRING, "kLFT7" }, { TTYC_KMOUS, TTYCODE_STRING, "kmous" }, { TTYC_KNP, TTYCODE_STRING, "knp" }, + { TTYC_KNXT2, TTYCODE_STRING, "kNXT" }, + { TTYC_KNXT3, TTYCODE_STRING, "kNXT3" }, + { TTYC_KNXT4, TTYCODE_STRING, "kNXT4" }, + { TTYC_KNXT5, TTYCODE_STRING, "kNXT5" }, + { TTYC_KNXT6, TTYCODE_STRING, "kNXT6" }, + { TTYC_KNXT7, TTYCODE_STRING, "kNXT7" }, { TTYC_KPP, TTYCODE_STRING, "kpp" }, + { TTYC_KPRV2, TTYCODE_STRING, "kPRV" }, + { TTYC_KPRV3, TTYCODE_STRING, "kPRV3" }, + { TTYC_KPRV4, TTYCODE_STRING, "kPRV4" }, + { TTYC_KPRV5, TTYCODE_STRING, "kPRV5" }, + { TTYC_KPRV6, TTYCODE_STRING, "kPRV6" }, + { TTYC_KPRV7, TTYCODE_STRING, "kPRV7" }, + { TTYC_KRIT2, TTYCODE_STRING, "kRIT" }, + { TTYC_KRIT3, TTYCODE_STRING, "kRIT3" }, + { TTYC_KRIT4, TTYCODE_STRING, "kRIT4" }, + { TTYC_KRIT5, TTYCODE_STRING, "kRIT5" }, + { TTYC_KRIT6, TTYCODE_STRING, "kRIT6" }, + { TTYC_KRIT7, TTYCODE_STRING, "kRIT7" }, + { TTYC_KUP2, TTYCODE_STRING, "kUP" }, + { TTYC_KUP3, TTYCODE_STRING, "kUP3" }, + { TTYC_KUP4, TTYCODE_STRING, "kUP4" }, + { TTYC_KUP5, TTYCODE_STRING, "kUP5" }, + { TTYC_KUP6, TTYCODE_STRING, "kUP6" }, + { TTYC_KUP7, TTYCODE_STRING, "kUP7" }, { TTYC_OP, TTYCODE_STRING, "op" }, { TTYC_REV, TTYCODE_STRING, "rev" }, { TTYC_RI, TTYCODE_STRING, "ri" }, @@ -109,6 +177,7 @@ { TTYC_SMKX, TTYCODE_STRING, "smkx" }, { TTYC_SMSO, TTYCODE_STRING, "smso" }, { TTYC_SMUL, TTYCODE_STRING, "smul" }, + { TTYC_VPA, TTYCODE_STRING, "vpa" }, { TTYC_XENL, TTYCODE_FLAG, "xenl" }, }; @@ -338,22 +407,7 @@ goto error; } - /* - * Figure out if terminal support default colours. AX is a screen - * extension which indicates this. Also check if op (orig_pair) uses - * the default colours - if it does, this is a good indication the - * terminal supports them. - */ - if (tty_term_flag(term, TTYC_AX)) - term->flags |= TERM_HASDEFAULTS; - if (strcmp(tty_term_string(term, TTYC_OP), "\033[39;49m") == 0) - term->flags |= TERM_HASDEFAULTS; - - /* - * Try to figure out if we have 256 or 88 colours. The standard xterm - * definitions are broken (well, or the way they are parsed is: in any - * case they end up returning 8). So also do a hack. - */ + /* Figure out if we have 256 or 88 colours. */ if (tty_term_number(term, TTYC_COLORS) == 256) term->flags |= TERM_256COLOURS; if (tty_term_number(term, TTYC_COLORS) == 88) @@ -417,13 +471,13 @@ const char * tty_term_string1(struct tty_term *term, enum tty_code_code code, int a) { - return (tparm((char *) tty_term_string(term, code), a)); + return (tparm((char *) tty_term_string(term, code), a, 0, 0, 0, 0, 0, 0, 0, 0)); } const char * tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b) { - return (tparm((char *) tty_term_string(term, code), a, b)); + return (tparm((char *) tty_term_string(term, code), a, b, 0, 0, 0, 0, 0, 0, 0)); } int diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/utf8.c /tmp/wmlmc6MQoR/tmux-1.1/utf8.c --- tmux-1.0/utf8.c 2009-07-03 23:31:30.000000000 +0100 +++ tmux-1.1/utf8.c 2009-10-23 18:21:34.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: utf8.c,v 1.9 2009/06/25 16:21:32 nicm Exp $ */ +/* $Id: utf8.c,v 1.11 2009/10/23 17:21:34 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -196,9 +196,56 @@ struct utf8_width_entry *utf8_width_root = NULL; int utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *); -void utf8_print(struct utf8_width_entry *, int); -u_int utf8_combine(const u_char *); +u_int utf8_combine(const struct utf8_data *); +u_int utf8_width(const struct utf8_data *); +/* + * Open UTF-8 sequence. + * + * 11000010-11011111 C2-DF start of 2-byte sequence + * 11100000-11101111 E0-EF start of 3-byte sequence + * 11110000-11110100 F0-F4 start of 4-byte sequence + * + * Returns 1 if more UTF-8 to come, 0 if not UTF-8. + */ +int +utf8_open(struct utf8_data *utf8data, u_char ch) +{ + memset(utf8data, 0, sizeof *utf8data); + if (ch >= 0xc2 && ch <= 0xdf) + utf8data->size = 2; + else if (ch >= 0xe0 && ch <= 0xef) + utf8data->size = 3; + else if (ch >= 0xf0 && ch <= 0xf4) + utf8data->size = 4; + else + return (0); + utf8_append(utf8data, ch); + return (1); +} + +/* + * Append character to UTF-8, closing if finished. + * + * Returns 1 if more UTF-8 data to come, 0 if finished. + */ +int +utf8_append(struct utf8_data *utf8data, u_char ch) +{ + if (utf8data->have >= utf8data->size) + fatalx("UTF-8 character overflow"); + if (utf8data->size > sizeof utf8data->data) + fatalx("UTF-8 character size too large"); + + utf8data->data[utf8data->have++] = ch; + if (utf8data->have != utf8data->size) + return (1); + + utf8data->width = utf8_width(utf8data); + return (0); +} + +/* Check if two width tree entries overlap. */ int utf8_overlap( struct utf8_width_entry *item1, struct utf8_width_entry *item2) @@ -214,6 +261,7 @@ return (0); } +/* Build UTF-8 width tree. */ void utf8_build(void) { @@ -240,52 +288,50 @@ } } -void -utf8_print(struct utf8_width_entry *node, int n) -{ - log_debug("%*s%04x -> %04x", n, " ", node->first, node->last); - if (node->left != NULL) - utf8_print(node->left, n + 1); - if (node->right != NULL) - utf8_print(node->right, n + 1); -} - +/* Combine UTF-8 into 32-bit Unicode. */ u_int -utf8_combine(const u_char *data) +utf8_combine(const struct utf8_data *utf8data) { - u_int uvalue; + u_int value; - if (data[1] == 0xff) - uvalue = data[0]; - else if (data[2] == 0xff) { - uvalue = data[1] & 0x3f; - uvalue |= (data[0] & 0x1f) << 6; - } else if (data[3] == 0xff) { - uvalue = data[2] & 0x3f; - uvalue |= (data[1] & 0x3f) << 6; - uvalue |= (data[0] & 0x0f) << 12; - } else { - uvalue = data[3] & 0x3f; - uvalue |= (data[2] & 0x3f) << 6; - uvalue |= (data[1] & 0x3f) << 12; - uvalue |= (data[0] & 0x3f) << 18; + value = 0xff; + switch (utf8data->size) { + case 1: + value = utf8data->data[0]; + break; + case 2: + value = utf8data->data[1] & 0x3f; + value |= (utf8data->data[0] & 0x1f) << 6; + break; + case 3: + value = utf8data->data[2] & 0x3f; + value |= (utf8data->data[1] & 0x3f) << 6; + value |= (utf8data->data[0] & 0x0f) << 12; + break; + case 4: + value = utf8data->data[3] & 0x3f; + value |= (utf8data->data[2] & 0x3f) << 6; + value |= (utf8data->data[1] & 0x3f) << 12; + value |= (utf8data->data[0] & 0x3f) << 18; + break; } - return (uvalue); + return (value); } -int -utf8_width(const u_char *udata) +/* Lookup width of UTF-8 data in tree. */ +u_int +utf8_width(const struct utf8_data *utf8data) { struct utf8_width_entry *item; - u_int uvalue; + u_int value; - uvalue = utf8_combine(udata); + value = utf8_combine(utf8data); item = utf8_width_root; while (item != NULL) { - if (uvalue < item->first) + if (value < item->first) item = item->left; - else if (uvalue > item->last) + else if (value > item->last) item = item->right; else return (item->width); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/window.c /tmp/wmlmc6MQoR/tmux-1.1/window.c --- tmux-1.0/window.c 2009-09-16 13:36:28.000000000 +0100 +++ tmux-1.1/window.c 2009-10-23 18:41:20.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: window.c,v 1.107 2009/09/16 12:36:28 nicm Exp $ */ +/* $Id: window.c,v 1.117 2009/10/23 17:41:20 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -172,7 +172,7 @@ return; winlink_stack_remove(stack, wl); - SLIST_INSERT_HEAD(stack, wl, sentry); + TAILQ_INSERT_HEAD(stack, wl, sentry); } void @@ -182,10 +182,10 @@ if (wl == NULL) return; - - SLIST_FOREACH(wl2, stack, sentry) { + + TAILQ_FOREACH(wl2, stack, sentry) { if (wl2 == wl) { - SLIST_REMOVE(stack, wl, winlink, sentry); + TAILQ_REMOVE(stack, wl, sentry); return; } } @@ -302,6 +302,23 @@ } } +void +window_set_active_at(struct window *w, u_int x, u_int y) +{ + struct window_pane *wp; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + if (x < wp->xoff || x >= wp->xoff + wp->sx) + continue; + if (y < wp->yoff || y >= wp->yoff + wp->sy) + continue; + window_set_active_pane(w, wp); + break; + } +} + struct window_pane * window_add_pane(struct window *w, u_int hlimit) { @@ -406,6 +423,10 @@ wp->sx = sx; wp->sy = sy; + wp->pipe_fd = -1; + wp->pipe_buf = NULL; + wp->pipe_off = 0; + wp->saved_grid = NULL; screen_init(&wp->base, sx, sy, hlimit); @@ -429,6 +450,11 @@ if (wp->saved_grid != NULL) grid_destroy(wp->saved_grid); + if (wp->pipe_fd != -1) { + buffer_destroy(wp->pipe_buf); + close(wp->pipe_fd); + } + buffer_destroy(wp->in); buffer_destroy(wp->out); @@ -478,7 +504,7 @@ ws.ws_row = screen_size_y(&wp->base); if (gettimeofday(&wp->window->name_timer, NULL) != 0) - fatal("gettimeofday"); + fatal("gettimeofday failed"); tv.tv_sec = 0; tv.tv_usec = NAME_INTERVAL * 1000L; timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer); @@ -568,7 +594,7 @@ wp->mode->resize(wp, sx, sy); if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) -#ifdef __sun__ +#ifdef __sun /* * Some versions of Solaris apparently can return an error when * resizing; don't know why this happens, can't reproduce on @@ -591,7 +617,7 @@ if ((s = wp->mode->init(wp)) != NULL) wp->screen = s; - server_redraw_window(wp->window); + wp->flags |= PANE_REDRAW; return (0); } @@ -605,49 +631,72 @@ wp->mode = NULL; wp->screen = &wp->base; - server_redraw_window(wp->window); + wp->flags |= PANE_REDRAW; } void window_pane_parse(struct window_pane *wp) { + size_t new_size; + + if (wp->mode != NULL) + return; + + new_size = BUFFER_USED(wp->in) - wp->pipe_off; + if (wp->pipe_fd != -1 && new_size > 0) + buffer_write(wp->pipe_buf, BUFFER_OUT(wp->in), new_size); + input_parse(wp); + + wp->pipe_off = BUFFER_USED(wp->in); } void window_pane_key(struct window_pane *wp, struct client *c, int key) { - if (wp->fd == -1 || !window_pane_visible(wp)) + struct window_pane *wp2; + + if (!window_pane_visible(wp)) return; if (wp->mode != NULL) { if (wp->mode->key != NULL) wp->mode->key(wp, c, key); - } else - input_key(wp, key); + return; + } + + if (wp->fd == -1) + return; + input_key(wp, key); + if (options_get_number(&wp->window->options, "synchronize-panes")) { + TAILQ_FOREACH(wp2, &wp->window->panes, entry) { + if (wp2 == wp || wp2->mode != NULL) + continue; + if (wp2->fd != -1 && window_pane_visible(wp2)) + input_key(wp2, key); + } + } } void window_pane_mouse( - struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y) + struct window_pane *wp, struct client *c, struct mouse_event *m) { - if (wp->fd == -1 || !window_pane_visible(wp)) + if (!window_pane_visible(wp)) return; - /* XXX convert from 1-based? */ - - if (x < wp->xoff || x >= wp->xoff + wp->sx) + if (m->x < wp->xoff || m->x >= wp->xoff + wp->sx) return; - if (y < wp->yoff || y >= wp->yoff + wp->sy) + if (m->y < wp->yoff || m->y >= wp->yoff + wp->sy) return; - x -= wp->xoff; - y -= wp->yoff; + m->x -= wp->xoff; + m->y -= wp->yoff; if (wp->mode != NULL) { if (wp->mode->mouse != NULL) - wp->mode->mouse(wp, c, b, x, y); - } else - input_mouse(wp, b, x, y); + wp->mode->mouse(wp, c, m); + } else if (wp->fd != -1) + input_mouse(wp, m); } int diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/window-choose.c /tmp/wmlmc6MQoR/tmux-1.1/window-choose.c --- tmux-1.0/window-choose.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/window-choose.c 2009-10-12 01:18:19.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: window-choose.c,v 1.23 2009/09/11 14:13:52 tcunha Exp $ */ +/* $Id: window-choose.c,v 1.24 2009/10/12 00:18:19 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -27,7 +27,7 @@ void window_choose_resize(struct window_pane *, u_int, u_int); void window_choose_key(struct window_pane *, struct client *, int); void window_choose_mouse( - struct window_pane *, struct client *, u_char, u_char, u_char); + struct window_pane *, struct client *, struct mouse_event *); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( @@ -264,22 +264,22 @@ } void -window_choose_mouse(struct window_pane *wp, - unused struct client *c, u_char b, u_char x, u_char y) +window_choose_mouse( + struct window_pane *wp, unused struct client *c, struct mouse_event *m) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct window_choose_mode_item *item; u_int idx; - if ((b & 3) == 3) + if ((m->b & 3) == 3) return; - if (x >= screen_size_x(s)) + if (m->x >= screen_size_x(s)) return; - if (y >= screen_size_y(s)) + if (m->y >= screen_size_y(s)) return; - idx = data->top + y; + idx = data->top + m->y; if (idx >= ARRAY_LENGTH(&data->list)) return; data->selected = idx; diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/window-copy.c /tmp/wmlmc6MQoR/tmux-1.1/window-copy.c --- tmux-1.0/window-copy.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/window-copy.c 2009-10-23 18:17:20.000000000 +0100 @@ -1,4 +1,4 @@ -/* $Id: window-copy.c,v 1.86 2009/09/11 14:13:52 tcunha Exp $ */ +/* $Id: window-copy.c,v 1.90 2009/10/23 17:17:20 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -29,7 +29,7 @@ void window_copy_key(struct window_pane *, struct client *, int); int window_copy_key_input(struct window_pane *, int); void window_copy_mouse( - struct window_pane *, struct client *, u_char, u_char, u_char); + struct window_pane *, struct client *, struct mouse_event *); void window_copy_redraw_lines(struct window_pane *, u_int, u_int); void window_copy_redraw_screen(struct window_pane *); @@ -61,8 +61,8 @@ void window_copy_cursor_end_of_line(struct window_pane *); void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_right(struct window_pane *); -void window_copy_cursor_up(struct window_pane *); -void window_copy_cursor_down(struct window_pane *); +void window_copy_cursor_up(struct window_pane *, int); +void window_copy_cursor_down(struct window_pane *, int); void window_copy_cursor_next_word(struct window_pane *); void window_copy_cursor_previous_word(struct window_pane *); void window_copy_scroll_up(struct window_pane *, u_int); @@ -235,11 +235,17 @@ window_copy_cursor_right(wp); return; case MODEKEYCOPY_UP: - window_copy_cursor_up(wp); + window_copy_cursor_up(wp, 0); return; case MODEKEYCOPY_DOWN: - window_copy_cursor_down(wp); + window_copy_cursor_down(wp, 0); return; + case MODEKEYCOPY_SCROLLUP: + window_copy_cursor_up(wp, 1); + break; + case MODEKEYCOPY_SCROLLDOWN: + window_copy_cursor_down(wp, 1); + break; case MODEKEYCOPY_PREVIOUSPAGE: window_copy_pageup(wp); break; @@ -272,6 +278,24 @@ window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; + case MODEKEYCOPY_TOPLINE: + data->cx = 0; + data->cy = 0; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; + case MODEKEYCOPY_MIDDLELINE: + data->cx = 0; + data->cy = (screen_size_y(s) - 1) / 2; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; + case MODEKEYCOPY_BOTTOMLINE: + data->cx = 0; + data->cy = screen_size_y(s) - 1; + window_copy_update_selection(wp); + window_copy_redraw_screen(wp); + break; case MODEKEYCOPY_STARTSELECTION: window_copy_start_selection(wp); window_copy_redraw_screen(wp); @@ -412,20 +436,20 @@ } void -window_copy_mouse(struct window_pane *wp, - unused struct client *c, u_char b, u_char x, u_char y) +window_copy_mouse( + struct window_pane *wp, unused struct client *c, struct mouse_event *m) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - if ((b & 3) == 3) + if ((m->b & 3) == 3) return; - if (x >= screen_size_x(s)) + if (m->x >= screen_size_x(s)) return; - if (y >= screen_size_y(s)) + if (m->y >= screen_size_y(s)) return; - window_copy_update_cursor(wp, x, y); + window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); } @@ -1020,7 +1044,7 @@ struct window_copy_mode_data *data = wp->modedata; if (data->cx == 0) { - window_copy_cursor_up(wp); + window_copy_cursor_up(wp, 0); window_copy_cursor_end_of_line(wp); } else { window_copy_update_cursor(wp, data->cx - 1, data->cy); @@ -1040,7 +1064,7 @@ if (data->cx >= px) { window_copy_cursor_start_of_line(wp); - window_copy_cursor_down(wp); + window_copy_cursor_down(wp, 0); } else { window_copy_update_cursor(wp, data->cx + 1, data->cy); if (window_copy_update_selection(wp)) @@ -1049,7 +1073,7 @@ } void -window_copy_cursor_up(struct window_pane *wp) +window_copy_cursor_up(struct window_pane *wp, int scroll_only) { struct window_copy_mode_data *data = wp->modedata; u_int ox, oy, px, py; @@ -1062,9 +1086,11 @@ } data->cx = data->lastcx; - if (data->cy == 0) + if (scroll_only || data->cy == 0) { window_copy_scroll_down(wp, 1); - else { + if (scroll_only) + window_copy_redraw_lines(wp, data->cy, 2); + } else { window_copy_update_cursor(wp, data->cx, data->cy - 1); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 2); @@ -1077,7 +1103,7 @@ } void -window_copy_cursor_down(struct window_pane *wp) +window_copy_cursor_down(struct window_pane *wp, int scroll_only) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -1091,9 +1117,11 @@ } data->cx = data->lastcx; - if (data->cy == screen_size_y(s) - 1) + if (scroll_only || data->cy == screen_size_y(s) - 1) { window_copy_scroll_up(wp, 1); - else { + if (scroll_only && data->cy > 0) + window_copy_redraw_lines(wp, data->cy - 1, 2); + } else { window_copy_update_cursor(wp, data->cx, data->cy + 1); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy - 1, 2); @@ -1137,7 +1165,7 @@ } px = 0; - window_copy_cursor_down(wp); + window_copy_cursor_down(wp, 0); py =screen_hsize( &wp->base) + data->cy - data->oy; @@ -1185,7 +1213,7 @@ (screen_hsize(&wp->base) == 0 || data->oy >= screen_hsize(&wp->base) - 1)) goto out; - window_copy_cursor_up(wp); + window_copy_cursor_up(wp, 0); py = screen_hsize( &wp->base) + data->cy - data->oy; @@ -1222,7 +1250,10 @@ screen_write_deleteline(&ctx, ny); window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny); window_copy_write_line(wp, &ctx, 0); - window_copy_write_line(wp, &ctx, 1); + if (screen_size_y(s) > 1) + window_copy_write_line(wp, &ctx, 1); + if (screen_size_y(s) > 3) + window_copy_write_line(wp, &ctx, screen_size_y(s) - 2); if (s->sel.flag && screen_size_y(s) > ny) window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); screen_write_cursormove(&ctx, data->cx, data->cy); diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/window-scroll.c /tmp/wmlmc6MQoR/tmux-1.1/window-scroll.c --- tmux-1.0/window-scroll.c 2009-09-13 21:48:22.000000000 +0100 +++ tmux-1.1/window-scroll.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,323 +0,0 @@ -/* $Id: window-scroll.c,v 1.41 2009/09/11 14:13:52 tcunha Exp $ */ - -/* - * Copyright (c) 2007 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 - -#include "tmux.h" - -struct screen *window_scroll_init(struct window_pane *); -void window_scroll_free(struct window_pane *); -void window_scroll_resize(struct window_pane *, u_int, u_int); -void window_scroll_key(struct window_pane *, struct client *, int); - -void window_scroll_redraw_screen(struct window_pane *); -void window_scroll_write_line( - struct window_pane *, struct screen_write_ctx *, u_int); -void window_scroll_write_column( - struct window_pane *, struct screen_write_ctx *, u_int); - -void window_scroll_scroll_up(struct window_pane *); -void window_scroll_scroll_down(struct window_pane *); -void window_scroll_scroll_left(struct window_pane *); -void window_scroll_scroll_right(struct window_pane *); - -const struct window_mode window_scroll_mode = { - window_scroll_init, - window_scroll_free, - window_scroll_resize, - window_scroll_key, - NULL, - NULL, -}; - -struct window_scroll_mode_data { - struct screen screen; - - struct mode_key_data mdata; - - u_int ox; - u_int oy; -}; - -struct screen * -window_scroll_init(struct window_pane *wp) -{ - struct window_scroll_mode_data *data; - struct screen *s; - struct screen_write_ctx ctx; - u_int i; - int keys; - - wp->modedata = data = xmalloc(sizeof *data); - data->ox = 0; - data->oy = 0; - - s = &data->screen; - screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); - s->mode &= ~MODE_CURSOR; - - keys = options_get_number(&wp->window->options, "mode-keys"); - if (keys == MODEKEY_EMACS) - mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); - else - mode_key_init(&data->mdata, &mode_key_tree_vi_copy); - - screen_write_start(&ctx, NULL, s); - for (i = 0; i < screen_size_y(s); i++) - window_scroll_write_line(wp, &ctx, i); - screen_write_stop(&ctx); - - return (s); -} - -void -window_scroll_free(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - - screen_free(&data->screen); - xfree(data); -} - -void -window_scroll_pageup(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - u_int n; - - n = 1; - if (screen_size_y(s) > 2) - n = screen_size_y(s) - 2; - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); - else - data->oy += n; - - window_scroll_redraw_screen(wp); -} - -void -window_scroll_resize(struct window_pane *wp, u_int sx, u_int sy) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - screen_resize(s, sx, sy); - screen_write_start(&ctx, NULL, s); - for (i = 0; i < screen_size_y(s); i++) - window_scroll_write_line(wp, &ctx, i); - screen_write_stop(&ctx); -} - -void -window_scroll_key(struct window_pane *wp, unused struct client *c, int key) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - u_int n; - - switch (mode_key_lookup(&data->mdata, key)) { - case MODEKEYCOPY_CANCEL: - window_pane_reset_mode(wp); - break; - case MODEKEYCOPY_LEFT: - window_scroll_scroll_left(wp); - break; - case MODEKEYCOPY_RIGHT: - window_scroll_scroll_right(wp); - break; - case MODEKEYCOPY_UP: - window_scroll_scroll_up(wp); - break; - case MODEKEYCOPY_DOWN: - window_scroll_scroll_down(wp); - break; - case MODEKEYCOPY_PREVIOUSPAGE: - window_scroll_pageup(wp); - break; - case MODEKEYCOPY_NEXTPAGE: - n = 1; - if (screen_size_y(s) > 2) - n = screen_size_y(s) - 2; - if (data->oy < n) - data->oy = 0; - else - data->oy -= n; - window_scroll_redraw_screen(wp); - break; - case MODEKEYCOPY_HALFPAGEUP: - n = screen_size_y(s) / 2; - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); - else - data->oy += n; - window_scroll_redraw_screen(wp); - break; - case MODEKEYCOPY_HALFPAGEDOWN: - n = screen_size_y(s) / 2; - if (data->oy < n) - data->oy = 0; - else - data->oy -= n; - window_scroll_redraw_screen(wp); - break; - default: - break; - } -} - -void -window_scroll_write_line( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct options *oo = &wp->window->options; - struct grid_cell gc; - char hdr[32]; - size_t size; - - if (py == 0) { - memcpy(&gc, &grid_default_cell, sizeof gc); - size = xsnprintf(hdr, sizeof hdr, - "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base)); - colour_set_fg(&gc, options_get_number(oo, "mode-fg")); - colour_set_bg(&gc, options_get_number(oo, "mode-bg")); - gc.attr |= options_get_number(oo, "mode-attr"); - screen_write_cursormove(ctx, screen_size_x(s) - size, 0); - screen_write_puts(ctx, &gc, "%s", hdr); - memcpy(&gc, &grid_default_cell, sizeof gc); - } else - size = 0; - - screen_write_cursormove(ctx, 0, py); - screen_write_copy(ctx, &wp->base, data->ox, (screen_hsize(&wp->base) - - data->oy) + py, screen_size_x(s) - size, 1); -} - -void -window_scroll_write_column( - struct window_pane *wp, struct screen_write_ctx *ctx, u_int px) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - - screen_write_cursormove(ctx, px, 0); - screen_write_copy(ctx, &wp->base, data->ox + px, - screen_hsize(&wp->base) - data->oy, 1, screen_size_y(s)); -} - -void -window_scroll_redraw_screen(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - screen_write_start(&ctx, wp, NULL); - for (i = 0; i < screen_size_y(s); i++) - window_scroll_write_line(wp, &ctx, i); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_up(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen_write_ctx ctx; - - if (data->oy >= screen_hsize(&wp->base)) - return; - data->oy++; - - screen_write_start(&ctx, wp, NULL); - screen_write_cursormove(&ctx, 0, 0); - screen_write_insertline(&ctx, 1); - window_scroll_write_line(wp, &ctx, 0); - window_scroll_write_line(wp, &ctx, 1); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_down(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - - if (data->oy == 0) - return; - data->oy--; - - screen_write_start(&ctx, wp, NULL); - screen_write_cursormove(&ctx, 0, 0); - screen_write_deleteline(&ctx, 1); - window_scroll_write_line(wp, &ctx, screen_size_y(s) - 1); - window_scroll_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_right(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - if (data->ox >= SHRT_MAX) - return; - data->ox++; - - screen_write_start(&ctx, wp, NULL); - for (i = 1; i < screen_size_y(s); i++) { - screen_write_cursormove(&ctx, 0, i); - screen_write_deletecharacter(&ctx, 1); - } - window_scroll_write_column(wp, &ctx, screen_size_x(s) - 1); - window_scroll_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} - -void -window_scroll_scroll_left(struct window_pane *wp) -{ - struct window_scroll_mode_data *data = wp->modedata; - struct screen *s = &data->screen; - struct screen_write_ctx ctx; - u_int i; - - if (data->ox == 0) - return; - data->ox--; - - screen_write_start(&ctx, wp, NULL); - for (i = 1; i < screen_size_y(s); i++) { - screen_write_cursormove(&ctx, 0, i); - screen_write_insertcharacter(&ctx, 1); - } - window_scroll_write_column(wp, &ctx, 0); - window_scroll_write_line(wp, &ctx, 0); - screen_write_stop(&ctx); -} diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/xmalloc.c /tmp/wmlmc6MQoR/tmux-1.1/xmalloc.c --- tmux-1.0/xmalloc.c 2009-07-03 23:31:31.000000000 +0100 +++ tmux-1.1/xmalloc.c 2009-10-28 23:12:38.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: xmalloc.c,v 1.10 2009/06/25 16:47:00 nicm Exp $ */ +/* $Id: xmalloc.c,v 1.12 2009/10/28 23:12:38 tcunha Exp $ */ /* * Copyright (c) 2004 Nicholas Marriott @@ -29,28 +29,29 @@ char * xstrdup(const char *s) { - void *ptr; + char *ptr; size_t len; len = strlen(s) + 1; ptr = xmalloc(len); - return (strncpy(ptr, s, len)); + strlcpy(ptr, s, len); + return (ptr); } void * xcalloc(size_t nmemb, size_t size) { - void *ptr; + void *ptr; - if (size == 0 || nmemb == 0) + if (size == 0 || nmemb == 0) fatalx("zero size"); - if (SIZE_MAX / nmemb < size) - fatalx("nmemb * size > SIZE_MAX"); - if ((ptr = calloc(nmemb, size)) == NULL) + if (SIZE_MAX / nmemb < size) + fatalx("nmemb * size > SIZE_MAX"); + if ((ptr = calloc(nmemb, size)) == NULL) fatal("xcalloc failed"); - return (ptr); + return (ptr); } void * @@ -58,12 +59,12 @@ { void *ptr; - if (size == 0) - fatalx("zero size"); - if ((ptr = malloc(size)) == NULL) + if (size == 0) + fatalx("zero size"); + if ((ptr = malloc(size)) == NULL) fatal("xmalloc failed"); - return (ptr); + return (ptr); } void * @@ -73,13 +74,13 @@ void *newptr; if (newsize == 0) - fatalx("zero size"); - if (SIZE_MAX / nmemb < size) - fatalx("nmemb * size > SIZE_MAX"); - if ((newptr = realloc(oldptr, newsize)) == NULL) + fatalx("zero size"); + if (SIZE_MAX / nmemb < size) + fatalx("nmemb * size > SIZE_MAX"); + if ((newptr = realloc(oldptr, newsize)) == NULL) fatal("xrealloc failed"); - return (newptr); + return (newptr); } void @@ -93,12 +94,12 @@ int printflike2 xasprintf(char **ret, const char *fmt, ...) { - va_list ap; - int i; + va_list ap; + int i; - va_start(ap, fmt); - i = xvasprintf(ret, fmt, ap); - va_end(ap); + va_start(ap, fmt); + i = xvasprintf(ret, fmt, ap); + va_end(ap); return (i); } @@ -109,21 +110,21 @@ int i; i = vasprintf(ret, fmt, ap); - if (i < 0 || *ret == NULL) - fatal("xvasprintf failed"); + if (i < 0 || *ret == NULL) + fatal("xvasprintf failed"); - return (i); + return (i); } int printflike3 xsnprintf(char *buf, size_t len, const char *fmt, ...) { - va_list ap; - int i; + va_list ap; + int i; - va_start(ap, fmt); - i = xvsnprintf(buf, len, fmt, ap); - va_end(ap); + va_start(ap, fmt); + i = xvsnprintf(buf, len, fmt, ap); + va_end(ap); return (i); } @@ -137,8 +138,8 @@ fatalx("len > INT_MAX"); i = vsnprintf(buf, len, fmt, ap); - if (i < 0) - fatal("vsnprintf failed"); + if (i < 0) + fatal("vsnprintf failed"); - return (i); + return (i); } diff -Nru /tmp/aRgaAWP4uV/tmux-1.0/xterm-keys.c /tmp/wmlmc6MQoR/tmux-1.1/xterm-keys.c --- tmux-1.0/xterm-keys.c 1970-01-01 01:00:00.000000000 +0100 +++ tmux-1.1/xterm-keys.c 2009-10-28 23:05:43.000000000 +0000 @@ -0,0 +1,201 @@ +/* $Id: xterm-keys.c,v 1.2 2009/10/28 23:05:43 tcunha Exp $ */ + +/* + * Copyright (c) 2009 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 + +#include "tmux.h" + +/* + * xterm-style function keys append one of the following values before the last + * character: + * + * 2 Shift + * 3 Alt + * 4 Shift + Alt + * 5 Ctrl + * 6 Shift + Ctrl + * 7 Alt + Ctrl + * 8 Shift + Alt + Ctrl + * + * Rather than parsing them, just match against a table. + * + * There are two forms for F1-F4 (\\033O_P or \\033[1;_P). We accept either but + * always output the latter (it comes first in the table). + */ + +int xterm_keys_match(const char *, const char *, size_t); +int xterm_keys_modifiers(const char *, const char *, size_t); + +struct xterm_keys_entry { + int key; + const char *template; +}; + +struct xterm_keys_entry xterm_keys_table[] = { + { KEYC_F1, "\033[1;_P" }, + { KEYC_F1, "\033[O_P" }, + { KEYC_F2, "\033[1;_Q" }, + { KEYC_F2, "\033[O_Q" }, + { KEYC_F3, "\033[1;_R" }, + { KEYC_F3, "\033[O_R" }, + { KEYC_F4, "\033[1;_S" }, + { KEYC_F4, "\033[O_S" }, + { KEYC_F5, "\033[15;_~" }, + { KEYC_F6, "\033[17;_~" }, + { KEYC_F7, "\033[18;_~" }, + { KEYC_F8, "\033[19;_~" }, + { KEYC_F9, "\033[20;_~" }, + { KEYC_F10, "\033[21;_~" }, + { KEYC_F11, "\033[23;_~" }, + { KEYC_F12, "\033[24;_~" }, + { KEYC_F13, "\033[25;_~" }, + { KEYC_F14, "\033[26;_~" }, + { KEYC_F15, "\033[28;_~" }, + { KEYC_F16, "\033[29;_~" }, + { KEYC_F17, "\033[31;_~" }, + { KEYC_F18, "\033[32;_~" }, + { KEYC_F19, "\033[33;_~" }, + { KEYC_F20, "\033[34;_~" }, + { KEYC_UP, "\033[1;_A" }, + { KEYC_DOWN, "\033[1;_B" }, + { KEYC_RIGHT, "\033[1;_C" }, + { KEYC_LEFT, "\033[1;_D" }, + { KEYC_HOME, "\033[1;_H" }, + { KEYC_END, "\033[1;_F" }, + { KEYC_PPAGE, "\033[5;_~" }, + { KEYC_NPAGE, "\033[6;_~" }, + { KEYC_IC, "\033[2;_~" }, + { KEYC_DC, "\033[3;_~" }, +}; + +/* Match key against buffer, treating _ as a wildcard. */ +int +xterm_keys_match(const char *template, const char *buf, size_t len) +{ + size_t pos; + + if (len == 0 || len < strlen(template)) + return (0); + + pos = 0; + do { + if (*template != '_' && buf[pos] != *template) + return (0); + } while (pos++ != len && *++template != '\0'); + + return (1); +} + +/* Find modifiers based on template. */ +int +xterm_keys_modifiers(const char *template, const char *buf, size_t len) +{ + size_t idx; + + idx = strcspn(template, "_"); + if (idx >= len) + return (0); + switch (buf[idx]) { + case '2': + return (KEYC_SHIFT); + case '3': + return (KEYC_ESCAPE); + case '4': + return (KEYC_SHIFT|KEYC_ESCAPE); + case '5': + return (KEYC_CTRL); + case '6': + return (KEYC_SHIFT|KEYC_CTRL); + case '7': + return (KEYC_ESCAPE|KEYC_CTRL); + case '8': + return (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); + } + return (0); +} + +/* Lookup key from buffer against table. */ +int +xterm_keys_find(const char *buf, size_t len, size_t *size) +{ + struct xterm_keys_entry *entry; + u_int i; + + for (i = 0; i < nitems(xterm_keys_table); i++) { + entry = &xterm_keys_table[i]; + if (xterm_keys_match(entry->template, buf, len)) + break; + } + if (i == nitems(xterm_keys_table)) + return (KEYC_NONE); + *size = strlen(entry->template); + return (entry->key | xterm_keys_modifiers(entry->template, buf, len)); +} + +/* Lookup a key number from the table. */ +char * +xterm_keys_lookup(int key) +{ + struct xterm_keys_entry *entry; + u_int i; + int modifiers; + char *out; + +#define KEY_MODIFIERS(key, modifiers) \ + (((key) & (KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) == (modifiers)) + modifiers = 0; + if (KEY_MODIFIERS(key, KEYC_SHIFT)) + modifiers = 2; + else if (KEY_MODIFIERS(key, KEYC_ESCAPE)) + modifiers = 3; + else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE)) + modifiers = 4; + else if (KEY_MODIFIERS(key, KEYC_CTRL)) + modifiers = 5; + else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_CTRL)) + modifiers = 6; + else if (KEY_MODIFIERS(key, KEYC_ESCAPE|KEYC_CTRL)) + modifiers = 7; + else if (KEY_MODIFIERS(key, KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL)) + modifiers = 8; +#undef KEY_MODIFIERS + + /* + * If the key has no modifiers, return NULL and let it fall through to + * the normal lookup. + */ + if (modifiers == 0) + return (NULL); + + /* Otherwise, find the key in the table. */ + key &= ~(KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL); + for (i = 0; i < nitems(xterm_keys_table); i++) { + entry = &xterm_keys_table[i]; + if (key == entry->key) + break; + } + if (i == nitems(xterm_keys_table)) + return (NULL); + + /* Copy the template and replace the modifier. */ + out = xstrdup(entry->template); + out[strcspn(out, "_")] = '0' + modifiers; + return (out); +}