1 Commits
1.1 ... 1.0

Author SHA1 Message Date
no_author
be20fc8699 This commit was manufactured by cvs2svn to create tag 'TMUX_1_0'. 2009-09-20 18:54:22 +00:00
103 changed files with 4048 additions and 6055 deletions

54
CHANGES
View File

@@ -1,55 +1,3 @@
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 CHANGES FROM 0.9 TO 1.0, 20 Sept 2009
* Option to alter the format of the window title set by tmux. * Option to alter the format of the window title set by tmux.
@@ -1410,7 +1358,7 @@ The list of older changes is below.
(including mutt, emacs). No status bar yet and no key remapping or other (including mutt, emacs). No status bar yet and no key remapping or other
customisation. customisation.
$Id: CHANGES,v 1.301 2009-11-05 12:35:47 tcunha Exp $ $Id: CHANGES,v 1.300 2009-09-20 18:54:21 nicm Exp $
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr 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 LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms

View File

@@ -1,37 +1,16 @@
# $Id: GNUmakefile,v 1.120 2009-11-05 12:30:55 tcunha Exp $ # $Id: GNUmakefile,v 1.114 2009-09-20 18:54:21 nicm Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
.PHONY: clean .PHONY: clean
VERSION= 1.1 VERSION= 1.0
#FDEBUG= 1 #FDEBUG= 1
CC?= cc CC?= gcc
CFLAGS+= -DBUILD="\"$(VERSION)\"" CFLAGS+= -DBUILD="\"$(VERSION)\""
LDFLAGS+= -L/usr/local/lib LDFLAGS+= -L/usr/local/lib
LIBS+= LIBS+=
# Sun CC
ifneq ($(shell ($(CC) -V 2>&1|awk '/Sun C/' || true)), )
CFLAGS+=-erroff=E_EMPTY_DECLARATION
FDEBUG=
endif
ifdef FDEBUG ifdef FDEBUG
CFLAGS+= -g -ggdb -DDEBUG CFLAGS+= -g -ggdb -DDEBUG
CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
@@ -69,7 +48,7 @@ depend: $(SRCS)
$(CC) $(CPPFLAGS) $(CFLAGS) -MM $(SRCS) > .depend $(CC) $(CPPFLAGS) $(CFLAGS) -MM $(SRCS) > .depend
clean: clean:
rm -f tmux *.o *~ *.core *.log compat/*.o compat/*~ rm -f tmux *.o *~ *.core *.log compat/*.o
clean-depend: clean-depend:
rm -f .depend rm -f .depend

View File

@@ -1,24 +1,9 @@
# $Id: Makefile,v 1.153 2009-11-05 12:30:55 tcunha Exp $ # $Id: Makefile,v 1.149 2009-09-20 18:54:21 nicm Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
.SUFFIXES: .c .o .SUFFIXES: .c .o
.PHONY: clean .PHONY: clean
VERSION= 1.1 VERSION= 1.0
#FDEBUG= 1 #FDEBUG= 1
@@ -68,7 +53,7 @@ depend:
mkdep ${CPPFLAGS} ${CFLAGS} ${SRCS:M*.c} mkdep ${CPPFLAGS} ${CFLAGS} ${SRCS:M*.c}
clean: clean:
rm -f tmux *.o *~ *.core *.log compat/*.o compat/*~ rm -f tmux *.o *~ *.core *.log compat/*.o
clean-depend: clean-depend:
rm -f .depend rm -f .depend

29
NOTES
View File

@@ -4,17 +4,15 @@ tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a 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. simple, modern, BSD-licensed alternative to programs such as GNU screen.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still This 0.9 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 run on Solaris and AIX (although they hasn't been tested in a while). It is
usable, although there remain a number of missing features and some remaining usable, although there remain a number of missing features and some remaining
bugs are expected. bugs are expected.
If upgrading from 1.0, PLEASE NOTE: If upgrading from 0.5, PLEASE NOTE the following configuration file changes: it
- The internal locking mechanism has gone, so the set-password command and -U is now required to pass the -g flag to set-option or set-window-option to set
command line option have been removed. global options; remain-by-default and utf8-default are now gone, use global
- The -d command line flag was dropped. It will now automatically detect the window options (set-window-option -g) instead.
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 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 required and runs continuously unless killed by the user. Clients access the
@@ -39,14 +37,17 @@ The following is a summary of major features implemented in this version:
- Support for VT100 line drawing characters. - Support for VT100 line drawing characters.
- A large command set. - A large command set.
- Vertical window splitting and layout. - Vertical window splitting and layout.
- Automatic server locking on inactivity by running an external command. - Automatic server locking on inactivity.
- A configuration file. - A configuration file.
- UTF-8 support. - UTF-8 support.
A more extensive, but rough, todo list is included in the TODO file. 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 tmux also depends on several features of the client terminal (TERM), if these
are missing it may refuse to run, or not behave correctly. 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.
tmux supports UTF-8. To use it, the utf8 option must be set on each window; 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 this may be turned on for all windows by setting it as a global option, see
@@ -80,12 +81,6 @@ welcome. Please send by email to:
nicm@users.sf.net 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 <nicm@users.sf.net> -- Nicholas Marriott <nicm@users.sf.net>
$Id: NOTES,v 1.51 2009-11-05 12:35:47 tcunha Exp $ $Id: NOTES,v 1.49 2009-07-06 18:53:24 nicm Exp $

65
TODO
View File

@@ -9,30 +9,45 @@
- garbage collect window history (100 lines at a time?) if it hasn't been used - garbage collect window history (100 lines at a time?) if it hasn't been used
in $x time (need window creation/use times) in $x time (need window creation/use times)
- lift SHRT_MAX limits for history? - lift SHRT_MAX limits for history?
- better mode features: search
- flags to centre screen in window - flags to centre screen in window
- better terminal emulation - better terminal emulation
- activity/bell should be per-window not per-link? what if it is cur win in - activity/bell should be per-window not per-link? what if it is cur win in
session not being watched? session not being watched?
- next prev word etc in command prompt - next prev word etc in command prompt; also ^K
- many more info() displays for various things - 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? - input.c is too complicated. simplify?
- use a better termcap internally instead of screen, perhaps xterm - 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) - 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 - 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 number in status line/top-right would be cool for this
- support other mouse modes (highlight etc) and use it in copy mode - 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-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 - 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? also quiet, utf8 and maybe other flags?
-g is a bit unexpected in conf file -g is a bit unexpected in conf file
- clear window title on exit - clear window title on exit
- the output code (tty.c) could do with optimisation depending on term - the output code (tty.c) could do with optimisation depending on term
capabilities capibilities
- would be nice to be able to use "--" to mark start of command w/ neww etc - would be nice to be able to use "--" to mark start of command w/ neww etc
to avoid quoting 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 - make command sequences more usable: don't require space after ;, handle
errors better errors better
- key to switch to copy mode from scroll mode
- attach should have a flag to create session if it doesn't exist - 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? - choice and more mode would be better per client than per window?
- hooks to which commands may be attached, for example: tmux add-hook - hooks to which commands may be attached, for example: tmux add-hook
"new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file "new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
@@ -44,54 +59,48 @@
- XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up - XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up
when session is started when session is started
- what about utmp etc? can tmux update it like screen? setgid? - 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: - warts on current naming:
- display-time but message-fg/bg/attr - display-time but message-fg/bg/attr
- list-* vs show-* - list-* vs show-*
- server-info - server-info
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-* - up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
- split-window -> split-pane?? - pcvt25 doesn't work properly, why? (bce?)
- tidy up and prioritise todo list ;-) - 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? - neww and attach can create a session if none exists?
would work fine with config file since would work fine with config file since
- a way for force-width/height to apply to only one pane (how?) - 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, - command to list what is actually running in each window with command line,
pid (need some adaption of the osdep code) pid (need some adaption of the osdep code)
- string option to change/remove the symbols (*-+ etc) in status line - 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 - support for bce
- it would be nice if the start/end line keys in copy mode were aware of - it would be nice if the start/end line keys in copy mode were aware of
wrapped lines wrapped lines
- per session locking
- some way to force a screen to use the entire terminal even if it is forced - 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) to be smaller by other clients. pan smaller terminal? (like screen F)
-- idea of a "view" onto a window, need base x/y offsets -- idea of a "view" onto a window, need base x/y offsets
for redraw 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 - handle resize better in copy mode
- way to copy stuff that is off screen due to resize - 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") - 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 - commands should be able to succeed or fail and have || or && for command
lists lists
- support the mouse wheel to scroll through history - 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

View File

@@ -1,4 +1,4 @@
/* $Id: array.h,v 1.9 2009-11-02 21:34:32 tcunha Exp $ */ /* $Id: array.h,v 1.7 2008-09-29 16:58:02 nicm Exp $ */
/* /*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -85,7 +85,7 @@
ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \ ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \
} \ } \
(a)->num--; \ (a)->num--; \
if ((a)->num == 0) \ if ((a)->num == 0) \
ARRAY_FREE(a); \ ARRAY_FREE(a); \
} while (0) } while (0)
@@ -102,7 +102,7 @@
#define ARRAY_CONCAT(a, b) do { \ #define ARRAY_CONCAT(a, b) do { \
ARRAY_ENSURE(a, (b)->num); \ 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; \ (a)->num += (b)->num; \
} while (0) } while (0)

View File

@@ -1,4 +1,4 @@
/* $Id: buffer-poll.c,v 1.18 2009-10-23 17:49:47 tcunha Exp $ */ /* $Id: buffer-poll.c,v 1.16 2009-08-19 09:28:10 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -25,15 +25,15 @@
/* Fill buffers from socket based on poll results. */ /* Fill buffers from socket based on poll results. */
int int
buffer_poll(int fd, int events, struct buffer *in, struct buffer *out) buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out)
{ {
ssize_t n; ssize_t n;
if (events & (POLLERR|POLLNVAL)) if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
return (-1); return (-1);
if (in != NULL && events & POLLIN) { if (pfd->revents & POLLIN) {
buffer_ensure(in, BUFSIZ); buffer_ensure(in, BUFSIZ);
n = read(fd, BUFFER_IN(in), BUFFER_FREE(in)); n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in));
if (n == 0) if (n == 0)
return (-1); return (-1);
if (n == -1) { if (n == -1) {
@@ -41,10 +41,9 @@ buffer_poll(int fd, int events, struct buffer *in, struct buffer *out)
return (-1); return (-1);
} else } else
buffer_add(in, n); buffer_add(in, n);
} else if (events & POLLHUP) }
return (-1); if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) {
if (out != NULL && BUFFER_USED(out) > 0 && events & POLLOUT) { n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out));
n = write(fd, BUFFER_OUT(out), BUFFER_USED(out));
if (n == -1) { if (n == -1) {
if (errno != EINTR && errno != EAGAIN) if (errno != EINTR && errno != EAGAIN)
return (-1); return (-1);

6
cfg.c
View File

@@ -1,4 +1,4 @@
/* $Id: cfg.c,v 1.23 2009-10-28 23:12:38 tcunha Exp $ */ /* $Id: cfg.c,v 1.22 2009-08-24 16:27:03 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -53,9 +53,9 @@ cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
int int
load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause) load_cfg(const char *path, struct cmd_ctx *ctxin, char **cause)
{ {
FILE *f; FILE *f;
u_int n; u_int n;
char *buf, *line, *ptr; char *buf, *line, *ptr;
size_t len; size_t len;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_ctx ctx; struct cmd_ctx ctx;

90
client-fn.c Normal file
View File

@@ -0,0 +1,90 @@
/* $Id: client-fn.c,v 1.10 2009-08-14 21:04:04 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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);
}

275
client.c
View File

@@ -1,4 +1,4 @@
/* $Id: client.c,v 1.84 2009-11-02 21:41:16 tcunha Exp $ */ /* $Id: client.c,v 1.70 2009-09-03 21:06:30 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,23 +33,21 @@
#include "tmux.h" #include "tmux.h"
struct imsgbuf client_ibuf; void client_send_environ(struct client_ctx *);
const char *client_exitmsg; void client_handle_winch(struct client_ctx *);
void client_send_identify(int); int
void client_send_environ(void); client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags)
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 sockaddr_un sa;
size_t size; struct stat sb;
int fd, mode; struct msg_identify_data data;
struct winsize ws;
size_t size;
int fd, fd2, mode;
char *name, *term;
#ifdef HAVE_SETPROCTITLE #ifdef HAVE_SETPROCTITLE
char rpathbuf[MAXPATHLEN]; char rpathbuf[MAXPATHLEN];
#endif #endif
#ifdef HAVE_SETPROCTITLE #ifdef HAVE_SETPROCTITLE
@@ -58,6 +56,19 @@ client_init(char *path, int cmdflags, int flags)
setproctitle("client (%s)", rpathbuf); setproctitle("client (%s)", rpathbuf);
#endif #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); memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX; sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
@@ -67,17 +78,12 @@ client_init(char *path, int cmdflags, int flags)
} }
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed"); fatal("socket");
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
if (!(cmdflags & CMD_STARTSERVER)) if (errno == ECONNREFUSED) {
goto not_found; if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER))
switch (errno) {
case ECONNREFUSED:
if (unlink(path) != 0)
goto not_found; goto not_found;
/* FALLTHROUGH */
case ENOENT:
if ((fd = server_start(path)) == -1) if ((fd = server_start(path)) == -1)
goto start_failed; goto start_failed;
goto server_started; goto server_started;
@@ -90,73 +96,64 @@ server_started:
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) imsg_init(&cctx->ibuf, fd);
fatal("fcntl failed");
imsg_init(&client_ibuf, fd);
if (cmdflags & CMD_SENDENVIRON) if (cmdflags & CMD_SENDENVIRON)
client_send_environ(); client_send_environ(cctx);
if (isatty(STDIN_FILENO)) if (isatty(STDIN_FILENO)) {
client_send_identify(flags); if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
data.flags = flags;
data.sx = ws.ws_col;
data.sy = ws.ws_row;
return (&client_ibuf); 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);
}
return (0);
start_failed: start_failed:
log_warnx("server failed to start"); log_warnx("server failed to start");
return (NULL); return (1);
not_found: not_found:
log_warn("server not found"); log_warn("server not found");
return (NULL); return (1);
} }
void void
client_send_identify(int flags) client_send_environ(struct client_ctx *cctx)
{ {
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)
{
struct msg_environ_data data;
char **var; char **var;
struct msg_environ_data data;
for (var = environ; *var != NULL; var++) { for (var = environ; *var != NULL; var++) {
if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
continue; continue;
client_write_server(MSG_ENVIRON, &data, sizeof data); client_write_server(cctx, MSG_ENVIRON, &data, sizeof data);
} }
} }
void int
client_write_server(enum msgtype type, void *buf, size_t len) client_main(struct client_ctx *cctx)
{
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
}
__dead void
client_main(void)
{ {
struct pollfd pfd; struct pollfd pfd;
int n, nfds; int n, nfds;
@@ -171,34 +168,27 @@ client_main(void)
* MSG_READY switched to here. Process anything outstanding now so poll * MSG_READY switched to here. Process anything outstanding now so poll
* doesn't hang waiting for messages that have already arrived. * doesn't hang waiting for messages that have already arrived.
*/ */
if (client_dispatch() != 0) if (client_msg_dispatch(cctx) != 0)
goto out; goto out;
for (;;) { for (;;) {
if (sigterm) { if (sigterm)
client_exitmsg = "terminated"; client_write_server(cctx, MSG_EXITING, NULL, 0);
client_write_server(MSG_EXITING, NULL, 0);
}
if (sigchld) { if (sigchld) {
sigchld = 0;
waitpid(WAIT_ANY, NULL, WNOHANG); waitpid(WAIT_ANY, NULL, WNOHANG);
continue; sigchld = 0;
}
if (sigwinch) {
sigwinch = 0;
client_write_server(MSG_RESIZE, NULL, 0);
continue;
} }
if (sigwinch)
client_handle_winch(cctx);
if (sigcont) { if (sigcont) {
sigcont = 0;
siginit(); siginit();
client_write_server(MSG_WAKEUP, NULL, 0); client_write_server(cctx, MSG_WAKEUP, NULL, 0);
continue; sigcont = 0;
} }
pfd.fd = client_ibuf.fd; pfd.fd = cctx->ibuf.fd;
pfd.events = POLLIN; pfd.events = POLLIN;
if (client_ibuf.w.queued > 0) if (cctx->ibuf.w.queued > 0)
pfd.events |= POLLOUT; pfd.events |= POLLOUT;
if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
@@ -213,41 +203,75 @@ client_main(void)
fatalx("socket error"); fatalx("socket error");
if (pfd.revents & POLLIN) { if (pfd.revents & POLLIN) {
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) { if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) {
client_exitmsg = "lost server"; cctx->exittype = CCTX_DIED;
break; break;
} }
if (client_dispatch() != 0) if (client_msg_dispatch(cctx) != 0)
break; break;
} }
if (pfd.revents & POLLOUT) { if (pfd.revents & POLLOUT) {
if (msgbuf_write(&client_ibuf.w) < 0) { if (msgbuf_write(&cctx->ibuf.w) < 0) {
client_exitmsg = "lost server"; cctx->exittype = CCTX_DIED;
break; break;
} }
} }
} }
out: out:
/* Print the exit message, if any, and exit. */ if (sigterm) {
if (client_exitmsg != NULL) { printf("[terminated]\n");
if (!login_shell) return (1);
printf("[%s]\n", client_exitmsg); }
exit(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);
} }
exit(0); }
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;
} }
int int
client_dispatch(void) client_msg_dispatch(struct client_ctx *cctx)
{ {
struct imsg imsg; struct imsg imsg;
struct msg_lock_data lockdata; struct msg_print_data printdata;
ssize_t n, datalen; ssize_t n, datalen;
for (;;) { for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1) if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
fatalx("imsg_get failed"); fatalx("imsg_get failed");
if (n == 0) if (n == 0)
return (0); return (0);
@@ -258,15 +282,25 @@ client_dispatch(void)
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_DETACH size"); fatalx("bad MSG_DETACH size");
client_write_server(MSG_EXITING, NULL, 0); client_write_server(cctx, MSG_EXITING, NULL, 0);
client_exitmsg = "detached"; cctx->exittype = CCTX_DETACH;
break; 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: case MSG_EXIT:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_EXIT size"); fatalx("bad MSG_EXIT size");
client_write_server(MSG_EXITING, NULL, 0); client_write_server(cctx, MSG_EXITING, NULL, 0);
client_exitmsg = "exited"; cctx->exittype = CCTX_EXIT;
break; break;
case MSG_EXITED: case MSG_EXITED:
if (datalen != 0) if (datalen != 0)
@@ -278,8 +312,8 @@ client_dispatch(void)
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_SHUTDOWN size"); fatalx("bad MSG_SHUTDOWN size");
client_write_server(MSG_EXITING, NULL, 0); client_write_server(cctx, MSG_EXITING, NULL, 0);
client_exitmsg = "server exited"; cctx->exittype = CCTX_SHUTDOWN;
break; break;
case MSG_SUSPEND: case MSG_SUSPEND:
if (datalen != 0) if (datalen != 0)
@@ -287,15 +321,6 @@ client_dispatch(void)
client_suspend(); client_suspend();
break; 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: default:
fatalx("unexpected message"); fatalx("unexpected message");
} }
@@ -303,23 +328,3 @@ client_dispatch(void)
imsg_free(&imsg); 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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-break-pane.c,v 1.9 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-break-pane.c,v 1.8 2009-08-16 19:16:27 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -78,7 +78,6 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
session_select(s, wl->idx); session_select(s, wl->idx);
server_redraw_session(s); server_redraw_session(s);
server_status_session_group(s);
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-choose-session.c,v 1.14 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-choose-session.c,v 1.13 2009-09-07 23:59:19 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -54,9 +54,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_choose_session_data *cdata; struct cmd_choose_session_data *cdata;
struct winlink *wl; struct winlink *wl;
struct session *s; struct session *s;
struct session_group *sg;
u_int i, idx, cur; u_int i, idx, cur;
char tmp[64];
if (ctx->curclient == NULL) { if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively"); ctx->error(ctx, "must be run interactively");
@@ -78,18 +76,10 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
cur = idx; cur = idx;
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, window_choose_add(wl->window->active, i,
"%s: %u windows [%ux%u]%s%s", s->name, "%s: %u windows [%ux%u]%s", s->name,
winlink_count(&s->windows), s->sx, s->sy, winlink_count(&s->windows), s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); s->flags & SESSION_UNATTACHED ? "" : " (attached)");
} }
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-choose-window.c,v 1.18 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-choose-window.c,v 1.17 2009-09-07 23:59:19 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -89,7 +89,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
flag = '+'; flag = '+';
else if (wm == s->curw) else if (wm == s->curw)
flag = '*'; flag = '*';
else if (wm == TAILQ_FIRST(&s->lastw)) else if (wm == SLIST_FIRST(&s->lastw))
flag = '-'; flag = '-';
title = w->active->screen->title; title = w->active->screen->title;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-command-prompt.c,v 1.26 2009-09-22 14:06:40 tcunha Exp $ */ /* $Id: cmd-command-prompt.c,v 1.25 2009-08-25 13:53:39 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -90,7 +90,7 @@ cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause)
struct cmd_command_prompt_data *data; struct cmd_command_prompt_data *data;
int opt; int opt;
self->entry->init(self, KEYC_NONE); self->entry->init(self, 0);
data = self->data; data = self->data;
while ((opt = getopt(argc, argv, "p:t:")) != -1) { while ((opt = getopt(argc, argv, "p:t:")) != -1) {

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-copy-buffer.c,v 1.5 2009-09-22 14:06:40 tcunha Exp $ */ /* $Id: cmd-copy-buffer.c,v 1.4 2009-09-07 23:48:54 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -70,7 +70,7 @@ cmd_copy_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
const char *errstr; const char *errstr;
int n, opt; int n, opt;
self->entry->init(self, KEYC_NONE); self->entry->init(self, 0);
data = self->data; data = self->data;
while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) { while ((opt = getopt(argc, argv, "a:b:s:t:")) != -1) {

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-copy-mode.c,v 1.24 2009-10-06 14:14:06 tcunha Exp $ */ /* $Id: cmd-copy-mode.c,v 1.23 2009-08-20 11:37:46 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,35 +24,19 @@
* Enter copy mode. * Enter copy mode.
*/ */
void cmd_copy_mode_init(struct cmd *, int);
int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); int cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_copy_mode_entry = { const struct cmd_entry cmd_copy_mode_entry = {
"copy-mode", NULL, "copy-mode", NULL,
"[-u] " CMD_TARGET_PANE_USAGE, "[-u] " CMD_TARGET_PANE_USAGE,
0, CMD_CHFLAG('u'), 0, CMD_CHFLAG('u'),
cmd_copy_mode_init, cmd_target_init,
cmd_target_parse, cmd_target_parse,
cmd_copy_mode_exec, cmd_copy_mode_exec,
cmd_target_free, cmd_target_free,
NULL 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 int
cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-display-message.c,v 1.3 2009-10-11 23:55:26 tcunha Exp $ */ /* $Id: cmd-display-message.c,v 1.2 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -55,7 +55,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
else else
template = data->arg; template = data->arg;
msg = status_replace(c, template, time(NULL)); msg = status_replace(c->session, template, time(NULL));
status_message_set(c, "%s", msg); status_message_set(c, "%s", msg);
xfree(msg); xfree(msg);

View File

@@ -1,8 +1,7 @@
/* $Id: cmd-if-shell.c,v 1.7 2009-11-02 21:38:26 tcunha Exp $ */ /* $Id: cmd-if-shell.c,v 1.4 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,8 +17,9 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -28,90 +28,124 @@
* Executes a tmux command if a shell command returns true. * 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 *); 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);
void cmd_if_shell_callback(struct job *); struct cmd_if_shell_data {
void cmd_if_shell_free(void *); char *cmd;
char *sh_cmd;
};
const struct cmd_entry cmd_if_shell_entry = { const struct cmd_entry cmd_if_shell_entry = {
"if-shell", "if", "if-shell", "if",
"shell-command command", "shell-command command",
CMD_ARG2, 0, 0, 0,
cmd_target_init, cmd_if_shell_init,
cmd_target_parse, cmd_if_shell_parse,
cmd_if_shell_exec, cmd_if_shell_exec,
cmd_target_free, cmd_if_shell_free,
cmd_target_print cmd_if_shell_print
}; };
struct cmd_if_shell_data { void
char *cmd; cmd_if_shell_init(struct cmd *self, unused int arg)
struct cmd_ctx ctx; {
}; struct cmd_if_shell_data *data;
self->data = data = xmalloc(sizeof *data);
data->cmd = NULL;
data->sh_cmd = NULL;
}
int
cmd_if_shell_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_if_shell_data *data;
int opt;
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);
}
int int
cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_target_data *data = self->data; struct cmd_if_shell_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);
return (1); /* don't let client exit */
}
void
cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job->data;
struct cmd_ctx *ctx = &cdata->ctx;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
char *cause; char *cause;
int ret;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) if ((ret = system(data->sh_cmd)) < 0) {
return; ctx->error(ctx, "system error: %s", strerror(errno));
return (-1);
} else if (ret != 0)
return (0);
if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { if (cmd_string_parse(data->cmd, &cmdlist, &cause) != 0) {
if (cause != NULL) { if (cause != NULL) {
ctx->error(ctx, "%s", cause); ctx->error(ctx, "%s", cause);
xfree(cause); xfree(cause);
} }
return; return (-1);
} }
if (cmd_list_exec(cmdlist, ctx) < 0) { if (cmd_list_exec(cmdlist, ctx) < 0) {
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return; return (-1);
} }
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return (0);
} }
void void
cmd_if_shell_free(void *data) cmd_if_shell_free(struct cmd *self)
{ {
struct cmd_if_shell_data *cdata = data; struct cmd_if_shell_data *data = self->data;
struct cmd_ctx *ctx = &cdata->ctx;
if (ctx->cmdclient != NULL) { if (data->cmd != NULL)
ctx->cmdclient->references--; xfree(data->cmd);
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); if (data->sh_cmd != NULL)
} xfree(data->sh_cmd);
if (ctx->curclient != NULL) xfree(data);
ctx->curclient->references--; }
xfree(cdata->cmd); size_t
xfree(cdata); cmd_if_shell_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_if_shell_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->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);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-kill-pane.c,v 1.14 2009-10-25 10:41:03 tcunha Exp $ */ /* $Id: cmd-kill-pane.c,v 1.12 2009-07-30 20:45:20 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,8 +30,8 @@ int cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_kill_pane_entry = { const struct cmd_entry cmd_kill_pane_entry = {
"kill-pane", "killp", "kill-pane", "killp",
"[-a] " CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE,
0, CMD_CHFLAG('a'), 0, 0,
cmd_target_init, cmd_target_init,
cmd_target_parse, cmd_target_parse,
cmd_kill_pane_exec, cmd_kill_pane_exec,
@@ -44,7 +44,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct winlink *wl; struct winlink *wl;
struct window_pane *loopwp, *nextwp, *wp; struct window_pane *wp;
if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL) if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL)
return (-1); return (-1);
@@ -52,25 +52,11 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (window_count_panes(wl->window) == 1) { if (window_count_panes(wl->window) == 1) {
/* Only one pane, kill the window. */ /* Only one pane, kill the window. */
server_kill_window(wl->window); server_kill_window(wl->window);
recalculate_sizes();
return (0); return (0);
} }
if (data->chflags & CMD_CHFLAG('a')) { layout_close_pane(wp);
loopwp = TAILQ_FIRST(&wl->window->panes); window_remove_pane(wl->window, wp);
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); server_redraw_window(wl->window);
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-kill-session.c,v 1.15 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-kill-session.c,v 1.14 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -53,7 +53,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session == s) { if (c->session == s) {
c->session = NULL; c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0); server_write_client(c, MSG_EXIT, NULL, 0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-kill-window.c,v 1.20 2009-09-20 22:15:32 tcunha Exp $ */ /* $Id: cmd-kill-window.c,v 1.19 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -47,7 +47,6 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1); return (-1);
server_kill_window(wl->window); server_kill_window(wl->window);
recalculate_sizes();
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-link-window.c,v 1.35 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-link-window.c,v 1.32 2009-08-16 19:16:27 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -43,23 +43,55 @@ int
cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_srcdst_data *data = self->data; struct cmd_srcdst_data *data = self->data;
struct session *src, *dst; struct session *dst;
struct winlink *wl; struct winlink *wl_src, *wl_dst;
char *cause; char *cause;
int idx, kflag, dflag; int idx;
if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
return (-1); return (-1);
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1); return (-1);
kflag = data->chflags & CMD_CHFLAG('k'); wl_dst = NULL;
dflag = data->chflags & CMD_CHFLAG('d'); if (idx != -1)
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { wl_dst = winlink_find_by_index(&dst->windows, idx);
ctx->error(ctx, "can't link window: %s", cause); 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);
xfree(cause); xfree(cause);
return (-1); 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(); recalculate_sizes();
return (0); return (0);

View File

@@ -1,74 +0,0 @@
/* $Id: cmd-list-panes.c,v 1.2 2009-10-15 20:10:28 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-sessions.c,v 1.23 2009-11-04 22:42:31 tcunha Exp $ */ /* $Id: cmd-list-sessions.c,v 1.21 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -42,32 +42,23 @@ const struct cmd_entry cmd_list_sessions_entry = {
int int
cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{ {
struct session *s; struct session *s;
struct session_group *sg; char *tim;
char *tim, tmp[64]; u_int i;
u_int i, idx; time_t t;
time_t t;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i); s = ARRAY_ITEM(&sessions, i);
if (s == NULL) if (s == NULL)
continue; continue;
sg = session_group_find(s); t = s->tv.tv_sec;
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); tim = ctime(&t);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s", ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s",
s->name, winlink_count(&s->windows), tim, s->sx, s->sy, s->name, winlink_count(&s->windows), tim, s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); s->flags & SESSION_UNATTACHED ? "" : " (attached)");
} }
return (0); return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-windows.c,v 1.41 2009-10-12 00:08:12 tcunha Exp $ */ /* $Id: cmd-list-windows.c,v 1.40 2009-08-09 17:28:23 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,13 +45,42 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct session *s; struct session *s;
struct winlink *wl; 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) if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1); return (-1);
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ctx->print(ctx, "%d: %s [%ux%u]", w = wl->window;
wl->idx, wl->window->name, wl->window->sx, wl->window->sy); 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);
}
} }
return (0); return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-load-buffer.c,v 1.11 2009-10-28 23:10:05 tcunha Exp $ */ /* $Id: cmd-load-buffer.c,v 1.10 2009-09-07 23:48:54 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -56,14 +56,13 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((s = cmd_find_session(ctx, data->target)) == NULL) if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1); return (-1);
if ((f = fopen(data->arg, "rb")) == NULL) { if (stat(data->arg, &sb) < 0) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1); return (-1);
} }
if (fstat(fileno(f), &sb) < 0) { if ((f = fopen(data->arg, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
fclose(f);
return (-1); return (-1);
} }

View File

@@ -1,53 +0,0 @@
/* $Id: cmd-lock-client.c,v 1.1 2009-09-25 17:51:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* 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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-lock-server.c,v 1.7 2009-09-25 17:47:42 tcunha Exp $ */ /* $Id: cmd-lock-server.c,v 1.6 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,7 +45,6 @@ int
cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) cmd_lock_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
{ {
server_lock(); server_lock();
recalculate_sizes();
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-move-window.c,v 1.12 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-move-window.c,v 1.9 2009-08-16 19:16:27 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,23 +44,68 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_srcdst_data *data = self->data; struct cmd_srcdst_data *data = self->data;
struct session *src, *dst; struct session *src, *dst;
struct winlink *wl; struct winlink *wl_src, *wl_dst;
struct client *c;
u_int i;
int destroyed, idx;
char *cause; char *cause;
int idx, kflag, dflag;
if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL) if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1); return (-1);
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2) if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1); return (-1);
kflag = data->chflags & CMD_CHFLAG('k'); wl_dst = NULL;
dflag = data->chflags & CMD_CHFLAG('d'); if (idx != -1)
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { wl_dst = winlink_find_by_index(&dst->windows, idx);
ctx->error(ctx, "can't move window: %s", cause); 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);
xfree(cause); xfree(cause);
return (-1); return (-1);
} }
server_unlink_window(src, wl);
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);
}
recalculate_sizes(); recalculate_sizes();
return (0); return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-new-session.c,v 1.69 2009-10-12 00:49:06 tcunha Exp $ */ /* $Id: cmd-new-session.c,v 1.66 2009-09-16 12:36:27 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -20,6 +20,7 @@
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -34,7 +35,6 @@ void cmd_new_session_init(struct cmd *, int);
size_t cmd_new_session_print(struct cmd *, char *, size_t); size_t cmd_new_session_print(struct cmd *, char *, size_t);
struct cmd_new_session_data { struct cmd_new_session_data {
char *target;
char *newname; char *newname;
char *winname; char *winname;
char *cmd; char *cmd;
@@ -43,7 +43,7 @@ struct cmd_new_session_data {
const struct cmd_entry cmd_new_session_entry = { const struct cmd_entry cmd_new_session_entry = {
"new-session", "new", "new-session", "new",
"[-d] [-n window-name] [-s session-name] [-t target-session] [command]", "[-d] [-n window-name] [-s session-name] [command]",
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0, CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0,
cmd_new_session_init, cmd_new_session_init,
cmd_new_session_parse, cmd_new_session_parse,
@@ -59,7 +59,6 @@ cmd_new_session_init(struct cmd *self, unused int arg)
self->data = data = xmalloc(sizeof *data); self->data = data = xmalloc(sizeof *data);
data->flag_detached = 0; data->flag_detached = 0;
data->target = NULL;
data->newname = NULL; data->newname = NULL;
data->winname = NULL; data->winname = NULL;
data->cmd = NULL; data->cmd = NULL;
@@ -71,10 +70,10 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
struct cmd_new_session_data *data; struct cmd_new_session_data *data;
int opt; int opt;
self->entry->init(self, KEYC_NONE); self->entry->init(self, 0);
data = self->data; data = self->data;
while ((opt = getopt(argc, argv, "ds:t:n:")) != -1) { while ((opt = getopt(argc, argv, "ds:n:")) != -1) {
switch (opt) { switch (opt) {
case 'd': case 'd':
data->flag_detached = 1; data->flag_detached = 1;
@@ -83,10 +82,6 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
if (data->newname == NULL) if (data->newname == NULL)
data->newname = xstrdup(optarg); data->newname = xstrdup(optarg);
break; break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'n': case 'n':
if (data->winname == NULL) if (data->winname == NULL)
data->winname = xstrdup(optarg); data->winname = xstrdup(optarg);
@@ -100,9 +95,6 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
if (argc != 0 && argc != 1) if (argc != 0 && argc != 1)
goto usage; goto usage;
if (data->target != NULL && (argc == 1 || data->winname != NULL))
goto usage;
if (argc == 1) if (argc == 1)
data->cmd = xstrdup(argv[0]); data->cmd = xstrdup(argv[0]);
@@ -119,7 +111,7 @@ int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_new_session_data *data = self->data; struct cmd_new_session_data *data = self->data;
struct session *s, *groupwith; struct session *s;
struct window *w; struct window *w;
struct environ env; struct environ env;
struct termios tio, *tiop; struct termios tio, *tiop;
@@ -133,11 +125,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1); return (-1);
} }
groupwith = NULL;
if (data->target != NULL &&
(groupwith = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
/* /*
* There are three cases: * There are three cases:
* *
@@ -218,9 +205,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
sy = 1; sy = 1;
/* Figure out the command for the new window. */ /* Figure out the command for the new window. */
if (data->target != NULL) if (data->cmd != NULL)
cmd = NULL;
else if (data->cmd != NULL)
cmd = data->cmd; cmd = data->cmd;
else else
cmd = options_get_string(&global_s_options, "default-command"); cmd = options_get_string(&global_s_options, "default-command");
@@ -243,7 +228,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
environ_free(&env); environ_free(&env);
/* Set the initial window name if one given. */ /* Set the initial window name if one given. */
if (cmd != NULL && data->winname != NULL) { if (data->winname != NULL) {
w = s->curw->window; w = s->curw->window;
xfree(w->name); xfree(w->name);
@@ -252,16 +237,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
options_set_number(&w->options, "automatic-rename", 0); options_set_number(&w->options, "automatic-rename", 0);
} }
/*
* 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 * 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. * taking this session and needs to get MSG_READY and stay around.

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-new-window.c,v 1.39 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-new-window.c,v 1.37 2009-08-16 19:16:27 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -70,7 +70,7 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
struct cmd_new_window_data *data; struct cmd_new_window_data *data;
int opt; int opt;
self->entry->init(self, KEYC_NONE); self->entry->init(self, 0);
data = self->data; data = self->data;
while ((opt = getopt(argc, argv, "dkt:n:")) != -1) { while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
@@ -164,9 +164,9 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
if (!data->flag_detached) { if (!data->flag_detached) {
session_select(s, wl->idx); session_select(s, wl->idx);
server_redraw_session_group(s); server_redraw_session(s);
} else } else
server_status_session_group(s); server_status_session(s);
return (0); return (0);
} }

View File

@@ -1,125 +0,0 @@
/* $Id: cmd-pipe-pane.c,v 1.3 2009-10-23 17:26:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-rename-window.c,v 1.30 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-rename-window.c,v 1.29 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -53,7 +53,7 @@ cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
wl->window->name = xstrdup(data->arg); wl->window->name = xstrdup(data->arg);
options_set_number(&wl->window->options, "automatic-rename", 0); options_set_number(&wl->window->options, "automatic-rename", 0);
server_status_window(wl->window); server_status_session(s);
return (0); return (0);
} }

View File

@@ -1,137 +0,0 @@
/* $Id: cmd-run-shell.c,v 1.4 2009-11-02 21:38:26 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-save-buffer.c,v 1.9 2009-10-28 23:08:52 tcunha Exp $ */ /* $Id: cmd-save-buffer.c,v 1.8 2009-09-07 23:48:54 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -70,7 +70,6 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
f = fopen(data->arg, "ab"); f = fopen(data->arg, "ab");
else else
f = fopen(data->arg, "wb"); f = fopen(data->arg, "wb");
umask(mask);
if (f == NULL) { if (f == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno)); ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1); return (-1);
@@ -83,6 +82,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
fclose(f); fclose(f);
umask(mask);
return (0); return (0);
} }

View File

@@ -1,7 +1,7 @@
/* $Id: cmd-lock-session.c,v 1.1 2009-09-25 17:51:39 tcunha Exp $ */ /* $Id: cmd-scroll-mode.c,v 1.23 2009-08-20 11:37:46 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -21,33 +21,50 @@
#include "tmux.h" #include "tmux.h"
/* /*
* Lock all clients attached to a session. * Enter scroll mode.
*/ */
int cmd_lock_session_exec(struct cmd *, struct cmd_ctx *); void cmd_scroll_mode_init(struct cmd *, int);
int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_lock_session_entry = { const struct cmd_entry cmd_scroll_mode_entry = {
"lock-session", "locks", "scroll-mode", NULL,
CMD_TARGET_SESSION_USAGE, "[-u] " CMD_TARGET_PANE_USAGE,
0, 0, 0, CMD_CHFLAG('u'),
cmd_target_init, cmd_scroll_mode_init,
cmd_target_parse, cmd_target_parse,
cmd_lock_session_exec, cmd_scroll_mode_exec,
cmd_target_free, cmd_target_free,
cmd_target_print 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 int
cmd_lock_session_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct session *s; struct window_pane *wp;
if ((s = cmd_find_session(ctx, data->target)) == NULL) if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1); return (-1);
server_lock_session(s); window_pane_set_mode(wp, &window_scroll_mode);
recalculate_sizes(); if (wp->mode == &window_scroll_mode && data->chflags & CMD_CHFLAG('u'))
window_scroll_pageup(wp);
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-send-keys.c,v 1.22 2009-09-22 14:03:11 tcunha Exp $ */ /* $Id: cmd-send-keys.c,v 1.21 2009-08-20 11:37:46 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,6 +33,7 @@ size_t cmd_send_keys_print(struct cmd *, char *, size_t);
struct cmd_send_keys_data { struct cmd_send_keys_data {
char *target; char *target;
int idx;
u_int nkeys; u_int nkeys;
int *keys; int *keys;
}; };
@@ -57,6 +58,7 @@ cmd_send_keys_parse(struct cmd *self, int argc, char **argv, char **cause)
self->data = data = xmalloc(sizeof *data); self->data = data = xmalloc(sizeof *data);
data->target = NULL; data->target = NULL;
data->idx = -1;
data->nkeys = 0; data->nkeys = 0;
data->keys = NULL; data->keys = NULL;
@@ -141,6 +143,8 @@ cmd_send_keys_print(struct cmd *self, char *buf, size_t len)
return (off); return (off);
if (off < len && data->target != NULL) if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target); 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++) { for (i = 0; i < data->nkeys; i++) {
if (off >= len) if (off >= len)

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-send-prefix.c,v 1.27 2009-09-22 14:22:20 tcunha Exp $ */ /* $Id: cmd-send-prefix.c,v 1.26 2009-08-20 11:37:46 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -43,13 +43,13 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct session *s; struct session *s;
struct window_pane *wp; struct window_pane *wp;
struct keylist *keylist; int key;
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
return (-1); return (-1);
keylist = options_get_data(&s->options, "prefix"); key = options_get_number(&s->options, "prefix");
window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist)); window_pane_key(wp, ctx->curclient, key);
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-server-info.c,v 1.33 2009-11-04 22:42:31 tcunha Exp $ */ /* $Id: cmd-server-info.c,v 1.28 2009-09-07 23:59:19 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -55,7 +55,6 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
struct tty_code *code; struct tty_code *code;
struct tty_term_code_entry *ent; struct tty_term_code_entry *ent;
struct utsname un; struct utsname un;
struct job *job;
struct grid *gd; struct grid *gd;
struct grid_line *gl; struct grid_line *gl;
u_int i, j, k; u_int i, j, k;
@@ -69,10 +68,11 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
ctx->print(ctx, ctx->print(ctx,
"tmux " BUILD ", pid %ld, started %s", (long) getpid(), tim); "tmux " BUILD ", pid %ld, started %s", (long) getpid(), tim);
ctx->print(ctx, "socket path %s, debug level %d%s", ctx->print(ctx, "socket path %s, debug level %d%s%s",
socket_path, debug_level, be_quiet ? ", quiet" : ""); socket_path, debug_level, be_quiet ? ", quiet" : "",
if (uname(&un) == 0) { login_shell ? ", login shell" : "");
ctx->print(ctx, "system is %s %s %s %s", if (uname(&un) == 0) {
ctx->print(ctx, "system is %s %s %s %s",
un.sysname, un.release, un.version, un.machine); un.sysname, un.release, un.version, un.machine);
} }
if (cfg_file != NULL) if (cfg_file != NULL)
@@ -105,7 +105,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
if (s == NULL) if (s == NULL)
continue; continue;
t = s->creation_time.tv_sec; t = s->tv.tv_sec;
tim = ctime(&t); tim = ctime(&t);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
@@ -179,11 +179,5 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
} }
ctx->print(ctx, "%s", ""); 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); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-set-option.c,v 1.85 2009-11-02 21:38:26 tcunha Exp $ */ /* $Id: cmd-set-option.c,v 1.79 2009-09-19 18:53:01 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -62,13 +62,10 @@ const struct set_option_entry set_option_table[] = {
{ "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
{ "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "lock-after-time", 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-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "mouse-select-pane", SET_OPTION_FLAG, 0, 0, NULL }, { "prefix", SET_OPTION_KEY, 0, 0, NULL },
{ "prefix", SET_OPTION_KEYS, 0, 0, NULL },
{ "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, { "set-titles", SET_OPTION_FLAG, 0, 0, NULL },
@@ -108,10 +105,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
struct client *c; struct client *c;
struct options *oo; struct options *oo;
const struct set_option_entry *entry, *opt; const struct set_option_entry *entry, *opt;
struct jobs *jobs;
struct job *job, *nextjob;
u_int i; u_int i;
int try_again;
if (data->chflags & CMD_CHFLAG('g')) if (data->chflags & CMD_CHFLAG('g'))
oo = &global_s_options; oo = &global_s_options;
@@ -168,8 +162,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
case SET_OPTION_NUMBER: case SET_OPTION_NUMBER:
set_option_number(ctx, oo, entry, data->arg2); set_option_number(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_KEYS: case SET_OPTION_KEY:
set_option_keys(ctx, oo, entry, data->arg2); set_option_key(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_COLOUR: case SET_OPTION_COLOUR:
set_option_colour(ctx, oo, entry, data->arg2); set_option_colour(ctx, oo, entry, data->arg2);
@@ -187,36 +181,10 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
recalculate_sizes(); recalculate_sizes();
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
/* c = ARRAY_ITEM(&clients, i);
* Special-case: kill all persistent jobs if status-left, status-right if (c != NULL && c->session != NULL)
* 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); server_redraw_client(c);
}
} }
return (0); return (0);

145
cmd-set-password.c Normal file
View File

@@ -0,0 +1,145 @@
/* $Id: cmd-set-password.c,v 1.8 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-set-window-option.c,v 1.40 2009-10-09 13:07:04 tcunha Exp $ */ /* $Id: cmd-set-window-option.c,v 1.38 2009-08-11 14:42:59 nicm Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -64,7 +64,6 @@ const struct set_option_entry set_window_option_table[] = {
{ "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL },
{ "remain-on-exit", SET_OPTION_FLAG, 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 }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL },
{ "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL },
@@ -141,8 +140,8 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx)
case SET_OPTION_NUMBER: case SET_OPTION_NUMBER:
set_option_number(ctx, oo, entry, data->arg2); set_option_number(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_KEYS: case SET_OPTION_KEY:
set_option_keys(ctx, oo, entry, data->arg2); set_option_key(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_COLOUR: case SET_OPTION_COLOUR:
set_option_colour(ctx, oo, entry, data->arg2); set_option_colour(ctx, oo, entry, data->arg2);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-show-options.c,v 1.17 2009-09-22 13:56:02 tcunha Exp $ */ /* $Id: cmd-show-options.c,v 1.16 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,9 +46,9 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct session *s; struct session *s;
struct options *oo; struct options *oo;
struct options_entry *o;
const struct set_option_entry *entry; const struct set_option_entry *entry;
const char *optval; char *vs;
long long vn;
if (data->chflags & CMD_CHFLAG('g')) if (data->chflags & CMD_CHFLAG('g'))
oo = &global_s_options; oo = &global_s_options;
@@ -59,10 +59,46 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
for (entry = set_option_table; entry->name != NULL; entry++) { for (entry = set_option_table; entry->name != NULL; entry++) {
if ((o = options_find1(oo, entry->name)) == NULL) if (options_find1(oo, entry->name) == NULL)
continue; continue;
optval = set_option_print(entry, o);
ctx->print(ctx, "%s %s", entry->name, optval); 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;
}
} }
return (0); return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-show-window-options.c,v 1.13 2009-09-22 13:56:02 tcunha Exp $ */ /* $Id: cmd-show-window-options.c,v 1.12 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,9 +46,9 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct winlink *wl; struct winlink *wl;
struct options *oo; struct options *oo;
struct options_entry *o;
const struct set_option_entry *entry; const struct set_option_entry *entry;
const char *optval; char *vs;
long long vn;
if (data->chflags & CMD_CHFLAG('g')) if (data->chflags & CMD_CHFLAG('g'))
oo = &global_w_options; oo = &global_w_options;
@@ -59,10 +59,46 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
for (entry = set_window_option_table; entry->name != NULL; entry++) { for (entry = set_window_option_table; entry->name != NULL; entry++) {
if ((o = options_find1(oo, entry->name)) == NULL) if (options_find1(oo, entry->name) == NULL)
continue; continue;
optval = set_option_print(entry, o);
ctx->print(ctx, "%s %s", entry->name, optval); 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;
}
} }
return (0); return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-source-file.c,v 1.9 2009-09-22 14:06:40 tcunha Exp $ */ /* $Id: cmd-source-file.c,v 1.8 2009-08-24 16:27:03 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org> * Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
@@ -60,7 +60,7 @@ cmd_source_file_parse(struct cmd *self, int argc, char **argv, char **cause)
struct cmd_source_file_data *data; struct cmd_source_file_data *data;
int opt; int opt;
self->entry->init(self, KEYC_NONE); self->entry->init(self, 0);
data = self->data; data = self->data;
while ((opt = getopt(argc, argv, "")) != -1) { while ((opt = getopt(argc, argv, "")) != -1) {

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-split-window.c,v 1.28 2009-09-22 14:06:40 tcunha Exp $ */ /* $Id: cmd-split-window.c,v 1.27 2009-09-16 12:36:27 nicm Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -83,7 +83,7 @@ cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause)
int opt; int opt;
const char *errstr; const char *errstr;
self->entry->init(self, KEYC_NONE); self->entry->init(self, 0);
data = self->data; data = self->data;
while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) { while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) {

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-string.c,v 1.24 2009-10-28 23:12:38 tcunha Exp $ */ /* $Id: cmd-string.c,v 1.23 2009-08-09 17:48:55 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -204,33 +204,33 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
char *buf, *t; char *buf, *t;
size_t len; size_t len;
buf = NULL; buf = NULL;
len = 0; len = 0;
while ((ch = cmd_string_getc(s, p)) != endch) { while ((ch = cmd_string_getc(s, p)) != endch) {
switch (ch) { switch (ch) {
case EOF: case EOF:
goto error; goto error;
case '\\': case '\\':
if (!esc) if (!esc)
break; break;
switch (ch = cmd_string_getc(s, p)) { switch (ch = cmd_string_getc(s, p)) {
case EOF: case EOF:
goto error; goto error;
case 'e': case 'e':
ch = '\033'; ch = '\033';
break; break;
case 'r': case 'r':
ch = '\r'; ch = '\r';
break; break;
case 'n': case 'n':
ch = '\n'; ch = '\n';
break; break;
case 't': case 't':
ch = '\t'; ch = '\t';
break; break;
} }
break; break;
case '$': case '$':
if (!esc) if (!esc)
break; break;
@@ -241,13 +241,13 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
len += strlen(t); len += strlen(t);
xfree(t); xfree(t);
continue; continue;
} }
if (len >= SIZE_MAX - 2) if (len >= SIZE_MAX - 2)
goto error; goto error;
buf = xrealloc(buf, 1, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len++] = ch; buf[len++] = ch;
} }
buf = xrealloc(buf, 1, len + 1); buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0'; buf[len] = '\0';
@@ -272,7 +272,7 @@ cmd_string_variable(const char *s, size_t *p)
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \ ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
((ch) >= '0' && (ch) <= '9')) ((ch) >= '0' && (ch) <= '9'))
buf = NULL; buf = NULL;
len = 0; len = 0;
fch = EOF; fch = EOF;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-swap-window.c,v 1.18 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-swap-window.c,v 1.17 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,7 +44,6 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_srcdst_data *data = self->data; struct cmd_srcdst_data *data = self->data;
struct session *src, *dst; struct session *src, *dst;
struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst; struct winlink *wl_src, *wl_dst;
struct window *w; struct window *w;
@@ -53,14 +52,6 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL) if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL)
return (-1); 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) if (wl_dst->window == wl_src->window)
return (0); return (0);
@@ -73,12 +64,9 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if (src != dst) if (src != dst)
session_select(src, wl_src->idx); session_select(src, wl_src->idx);
} }
session_group_synchronize_from(src); server_redraw_session(src);
server_redraw_session_group(src); if (src != dst)
if (src != dst) { server_redraw_session(dst);
session_group_synchronize_from(dst);
server_redraw_session_group(dst);
}
recalculate_sizes(); recalculate_sizes();
return (0); return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-unlink-window.c,v 1.19 2009-10-11 23:38:16 tcunha Exp $ */ /* $Id: cmd-unlink-window.c,v 1.16 2009-07-28 22:12:16 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -42,29 +42,30 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct winlink *wl; struct winlink *wl;
struct window *w; struct session *s;
struct session *s, *s2; struct client *c;
struct session_group *sg; u_int i;
u_int references; int destroyed;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1); return (-1);
w = wl->window;
sg = session_group_find(s); if (!(data->chflags & CMD_CHFLAG('k')) && wl->window->references == 1) {
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"); ctx->error(ctx, "window is only linked to one session");
return (-1); return (-1);
} }
server_unlink_window(s, wl); 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);
}
recalculate_sizes(); recalculate_sizes();
return (0); return (0);

138
cmd.c
View File

@@ -1,4 +1,4 @@
/* $Id: cmd.c,v 1.130 2009-11-04 22:46:25 tcunha Exp $ */ /* $Id: cmd.c,v 1.115 2009-08-31 22:30:15 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -57,20 +57,16 @@ const struct cmd_entry *cmd_table[] = {
&cmd_list_clients_entry, &cmd_list_clients_entry,
&cmd_list_commands_entry, &cmd_list_commands_entry,
&cmd_list_keys_entry, &cmd_list_keys_entry,
&cmd_list_panes_entry,
&cmd_list_sessions_entry, &cmd_list_sessions_entry,
&cmd_list_windows_entry, &cmd_list_windows_entry,
&cmd_load_buffer_entry, &cmd_load_buffer_entry,
&cmd_lock_client_entry,
&cmd_lock_server_entry, &cmd_lock_server_entry,
&cmd_lock_session_entry,
&cmd_move_window_entry, &cmd_move_window_entry,
&cmd_new_session_entry, &cmd_new_session_entry,
&cmd_new_window_entry, &cmd_new_window_entry,
&cmd_next_layout_entry, &cmd_next_layout_entry,
&cmd_next_window_entry, &cmd_next_window_entry,
&cmd_paste_buffer_entry, &cmd_paste_buffer_entry,
&cmd_pipe_pane_entry,
&cmd_previous_layout_entry, &cmd_previous_layout_entry,
&cmd_previous_window_entry, &cmd_previous_window_entry,
&cmd_refresh_client_entry, &cmd_refresh_client_entry,
@@ -79,8 +75,8 @@ const struct cmd_entry *cmd_table[] = {
&cmd_resize_pane_entry, &cmd_resize_pane_entry,
&cmd_respawn_window_entry, &cmd_respawn_window_entry,
&cmd_rotate_window_entry, &cmd_rotate_window_entry,
&cmd_run_shell_entry,
&cmd_save_buffer_entry, &cmd_save_buffer_entry,
&cmd_scroll_mode_entry,
&cmd_select_layout_entry, &cmd_select_layout_entry,
&cmd_select_pane_entry, &cmd_select_pane_entry,
&cmd_select_prompt_entry, &cmd_select_prompt_entry,
@@ -91,6 +87,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_set_buffer_entry, &cmd_set_buffer_entry,
&cmd_set_environment_entry, &cmd_set_environment_entry,
&cmd_set_option_entry, &cmd_set_option_entry,
&cmd_set_password_entry,
&cmd_set_window_option_entry, &cmd_set_window_option_entry,
&cmd_show_buffer_entry, &cmd_show_buffer_entry,
&cmd_show_environment_entry, &cmd_show_environment_entry,
@@ -109,8 +106,7 @@ const struct cmd_entry *cmd_table[] = {
NULL NULL
}; };
struct session *cmd_choose_session(struct sessions *); struct session *cmd_newest_session(struct sessions *);
struct client *cmd_choose_client(struct clients *);
struct client *cmd_lookup_client(const char *); struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(const char *, int *); struct session *cmd_lookup_session(const char *, int *);
struct winlink *cmd_lookup_window(struct session *, const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *);
@@ -178,7 +174,7 @@ struct cmd *
cmd_parse(int argc, char **argv, char **cause) cmd_parse(int argc, char **argv, char **cause)
{ {
const struct cmd_entry **entryp, *entry; const struct cmd_entry **entryp, *entry;
struct cmd *cmd; struct cmd *cmd;
char s[BUFSIZ]; char s[BUFSIZ];
int opt, ambiguous = 0; int opt, ambiguous = 0;
@@ -262,6 +258,10 @@ usage:
int int
cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) 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)); return (cmd->entry->exec(cmd, ctx));
} }
@@ -284,10 +284,9 @@ cmd_print(struct cmd *cmd, char *buf, size_t len)
/* /*
* Figure out the current session. Use: 1) the current session, if the command * Figure out the current session. Use: 1) the current session, if the command
* context has one; 2) the most recently used session containing the pty of the * context has one; 2) the session containing the pty of the calling client, if
* calling client, if any; 3) the session specified in the TMUX variable from * any 3) the session specified in the TMUX variable from the environment (as
* the environment (as passed from the client); 4) the most recently used * passed from the client); 3) the newest session.
* session from all sessions.
*/ */
struct session * struct session *
cmd_current_session(struct cmd_ctx *ctx) cmd_current_session(struct cmd_ctx *ctx)
@@ -329,7 +328,7 @@ cmd_current_session(struct cmd_ctx *ctx)
ARRAY_ADD(&ss, s); ARRAY_ADD(&ss, s);
} }
s = cmd_choose_session(&ss); s = cmd_newest_session(&ss);
ARRAY_FREE(&ss); ARRAY_FREE(&ss);
if (s != NULL) if (s != NULL)
return (s); return (s);
@@ -346,92 +345,29 @@ cmd_current_session(struct cmd_ctx *ctx)
return (s); return (s);
} }
return (cmd_choose_session(&sessions)); return (cmd_newest_session(&sessions));
} }
/* Find the most recently used session from a list. */ /* Find the newest session. */
struct session * struct session *
cmd_choose_session(struct sessions *ss) cmd_newest_session(struct sessions *ss)
{ {
struct session *s, *sbest; struct session *s, *snewest;
struct timeval *tv = NULL; struct timeval *tv = NULL;
u_int i; u_int i;
sbest = NULL; snewest = NULL;
for (i = 0; i < ARRAY_LENGTH(ss); i++) { for (i = 0; i < ARRAY_LENGTH(ss); i++) {
if ((s = ARRAY_ITEM(ss, i)) == NULL) if ((s = ARRAY_ITEM(ss, i)) == NULL)
continue; continue;
if (tv == NULL || timercmp(&s->activity_time, tv, >)) { if (tv == NULL || timercmp(&s->tv, tv, >)) {
sbest = s; snewest = s;
tv = &s->activity_time; tv = &s->tv;
} }
} }
return (sbest); return (snewest);
}
/*
* 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 (cbest);
} }
/* Find the target client or report an error and return NULL. */ /* Find the target client or report an error and return NULL. */
@@ -444,7 +380,7 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg)
/* A NULL argument means the current client. */ /* A NULL argument means the current client. */
if (arg == NULL) if (arg == NULL)
return (cmd_current_client(ctx)); return (ctx->curclient);
tmparg = xstrdup(arg); tmparg = xstrdup(arg);
/* Trim a single trailing colon if any. */ /* Trim a single trailing colon if any. */
@@ -475,8 +411,7 @@ cmd_lookup_client(const char *name)
u_int i; u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); if ((c = ARRAY_ITEM(&clients, i)) == NULL)
if (c == NULL || c->session == NULL)
continue; continue;
path = c->tty.path; path = c->tty.path;
@@ -504,25 +439,19 @@ cmd_lookup_session(const char *name, int *ambiguous)
*ambiguous = 0; *ambiguous = 0;
/* /*
* Look for matches. First look for exact matches - session names must * Look for matches. Session names must be unique so an exact match
* be unique so an exact match can't be ambigious and can just be * can't be ambigious and can just be returned.
* returned.
*/
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (strcmp(name, s->name) == 0)
return (s);
}
/*
* Otherwise look for partial matches, returning early if it is found to
* be ambiguous.
*/ */
sfound = NULL; sfound = NULL;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL) if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue; continue;
/* Check for an exact match and return it if found. */
if (strcmp(name, s->name) == 0)
return (s);
/* Then check for pattern matches. */
if (strncmp(name, s->name, strlen(name)) == 0 || if (strncmp(name, s->name, strlen(name)) == 0 ||
fnmatch(name, s->name, 0) == 0) { fnmatch(name, s->name, 0) == 0) {
if (sfound != NULL) { if (sfound != NULL) {
@@ -532,6 +461,7 @@ cmd_lookup_session(const char *name, int *ambiguous)
sfound = s; sfound = s;
} }
} }
return (sfound); return (sfound);
} }
@@ -863,7 +793,7 @@ cmd_find_pane(struct cmd_ctx *ctx,
/* Get the current session. */ /* Get the current session. */
if ((s = cmd_current_session(ctx)) == NULL) { 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); return (NULL);
} }
if (sp != NULL) if (sp != NULL)

View File

@@ -1,4 +1,4 @@
/* $Id: compat.h,v 1.19 2009-10-06 15:32:21 tcunha Exp $ */ /* $Id: compat.h,v 1.17 2009-09-03 20:54:39 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -91,6 +91,10 @@ typedef uint64_t u_int64_t;
#include "compat/imsg.h" #include "compat/imsg.h"
#endif #endif
#ifdef HAVE_LOGIN_CAP
#include <login_cap.h>
#endif
#ifdef HAVE_BROKEN_CMSG_FIRSTHDR #ifdef HAVE_BROKEN_CMSG_FIRSTHDR
/* Broken on OS X. */ /* Broken on OS X. */
#undef CMSG_FIRSTHDR #undef CMSG_FIRSTHDR
@@ -138,10 +142,18 @@ typedef uint64_t u_int64_t;
} while (0) } while (0)
#endif #endif
#ifndef PASS_MAX
#define PASS_MAX 128
#endif
#ifndef TTY_NAME_MAX #ifndef TTY_NAME_MAX
#define TTY_NAME_MAX 32 #define TTY_NAME_MAX 32
#endif #endif
#ifndef _PW_BUF_LEN
#define _PW_BUF_LEN 1024
#endif
#ifndef HAVE_BZERO #ifndef HAVE_BZERO
#define bzero(buf, len) memset((buf), 0, (len)); #define bzero(buf, len) memset((buf), 0, (len));
#endif #endif

View File

@@ -1,4 +1,4 @@
/* $Id: forkpty-sunos.c,v 1.9 2009-10-15 07:11:25 nicm Exp $ */ /* $Id: forkpty-sunos.c,v 1.8 2009-09-20 18:31:16 nicm Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,7 +27,7 @@
#include "tmux.h" #include "tmux.h"
pid_t pid_t
forkpty(int *master, char *name, struct termios *tio, struct winsize *ws) forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws)
{ {
int slave; int slave;
char *path; char *path;
@@ -42,8 +42,6 @@ forkpty(int *master, char *name, struct termios *tio, struct winsize *ws)
if ((path = ptsname(*master)) == NULL) if ((path = ptsname(*master)) == NULL)
goto out; goto out;
if (name != NULL)
strlcpy(name, path, TTY_NAME_MAX);
if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1) if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1)
goto out; goto out;

30
configure vendored
View File

@@ -1,20 +1,5 @@
#!/bin/sh #!/bin/sh
# $Id: configure,v 1.43 2009-10-25 21:45:26 nicm Exp $ # $Id: configure,v 1.38 2009-09-20 17:51:54 nicm Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
TMUX_PLATFORM=${TMUX_PLATFORM:-`uname -s`} TMUX_PLATFORM=${TMUX_PLATFORM:-`uname -s`}
@@ -37,6 +22,7 @@ cat <<EOF >>$CONFIG_H
#undef HAVE_GETOPT #undef HAVE_GETOPT
#undef HAVE_IMSG #undef HAVE_IMSG
#undef HAVE_LIBUTIL_H #undef HAVE_LIBUTIL_H
#undef HAVE_LOGIN_CAP
#undef HAVE_PATHS_H #undef HAVE_PATHS_H
#undef HAVE_POLL #undef HAVE_POLL
#undef HAVE_PROGNAME #undef HAVE_PROGNAME
@@ -65,6 +51,7 @@ case $TMUX_PLATFORM in
#define HAVE_FGETLN #define HAVE_FGETLN
#define HAVE_FORKPTY #define HAVE_FORKPTY
#define HAVE_GETOPT #define HAVE_GETOPT
#define HAVE_LOGIN_CAP
#define HAVE_PATHS_H #define HAVE_PATHS_H
#define HAVE_POLL #define HAVE_POLL
#define HAVE_PROGNAME #define HAVE_PROGNAME
@@ -152,9 +139,15 @@ EOF
#define HAVE_STRLCPY #define HAVE_STRLCPY
EOF EOF
cat <<EOF >>$CONFIG_MK cat <<EOF >>$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 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 LIBS+= -lcurses -lsocket -lnsl
SRCS+= osdep-sunos.c \ SRCS+= osdep-unknown.c \
compat/asprintf.c \ compat/asprintf.c \
compat/daemon.c \ compat/daemon.c \
compat/fgetln.c \ compat/fgetln.c \
@@ -209,6 +202,7 @@ EOF
#define HAVE_FORKPTY #define HAVE_FORKPTY
#define HAVE_GETOPT #define HAVE_GETOPT
#define HAVE_LIBUTIL_H #define HAVE_LIBUTIL_H
#define HAVE_LOGIN_CAP
#define HAVE_PATHS_H #define HAVE_PATHS_H
#define HAVE_POLL #define HAVE_POLL
#define HAVE_PROGNAME #define HAVE_PROGNAME
@@ -218,6 +212,7 @@ EOF
#define HAVE_STRLCPY #define HAVE_STRLCPY
#define HAVE_STRTONUM #define HAVE_STRTONUM
#define HAVE_STRSEP #define HAVE_STRSEP
#define HAVE_TREE_H
#define HAVE_U_INT #define HAVE_U_INT
EOF EOF
cat <<EOF >>$CONFIG_MK cat <<EOF >>$CONFIG_MK
@@ -238,6 +233,7 @@ EOF
#define HAVE_FGETLN #define HAVE_FGETLN
#define HAVE_FORKPTY #define HAVE_FORKPTY
#define HAVE_GETOPT #define HAVE_GETOPT
#define HAVE_LOGIN_CAP
#define HAVE_PATHS_H #define HAVE_PATHS_H
#define HAVE_POLL #define HAVE_POLL
#define HAVE_PROGNAME #define HAVE_PROGNAME

View File

@@ -1,7 +1,3 @@
# $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 default-command zsh
set -g status-right "#(uptime|awk '{print $11}') #(date)" set -g status-right "#(uptime|awk '{print $11}') #(date)"

View File

@@ -1,66 +1,52 @@
# $Id: n-marriott.conf,v 1.10 2009-10-25 21:45:26 nicm Exp $
#
# By Nicholas Marriott. Public domain.
# Default global options. # Default global options.
set -g status-bg green set -g status-bg green
set -g status-right "%H:%M" # %d-%b-%y set -g status-right-length 60
set -g default-command "exec /bin/ksh -l"
set -g bell-action none set -g bell-action none
set -g lock-after-time 1800 set -g lock-after-time 1800
# Default global window options. # 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. # Prefix key.
set -g prefix C-a set -g prefix C-a
unbind C-b unbind C-b
bind C-a send-prefix bind C-a send-prefix
# Unlock password.
pass -c '$2a$06$7LpuTSfDjcz.KD3a9mdEuuJmC.zEq6RBqHWMjdv9/qqzrfWedUBHe'
# Keys to switch session. # Keys to switch session.
bind Q switchc -t0 bind q switchc -t0
bind W switchc -t1 bind w switchc -t1
bind E switchc -t2 bind e switchc -t2
# Other key bindings. # Other key bindings.
bind F1 selectw -t:10 bind i choose-window
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 m setw monitor-activity
bind y setw force-width 81 bind y setw force-width 81
bind u setw force-width 0 bind u setw force-width 0
bind -n F1 run-shell 'mpc toggle >/dev/null 2>&1' bind D detach \; lock
bind -n F2 run-shell 'mpc' bind N neww \; splitw -d
bind -n F3 run-shell 'mpc prev >/dev/null 2>&1'
bind -n F4 run-shell 'mpc next >/dev/null 2>&1' bind '~' split-window "exec top -s 0.5"
bind -n F5 run-shell 'mpc volume -5 >/dev/null 2>&1' bind "#" split-window "exec ncmpc -f ~/.ncmpc.conf"
bind -n F6 run-shell 'mpc volume +5 >/dev/null 2>&1' bind / command-prompt "split-window 'exec man %%'"
# First session. # First session.
new -d -s0 -nirssi 'exec ssh -t natalya exec sh ~/bin/tmux-start' new -d -s0 -nirssi 'exec ssh -t natalya screen -DRS irssi irssi'
setw -t0:0 monitor-activity on setw -t0:0 monitor-activity on
setw -t0:0 aggressive-resize on setw -t0:0 aggressive-resize on
set -t0 status-bg green set -t0 status-bg green
neww -d -ntodo 'exec emacs ~/TODO' neww -d -ntodo 'exec emacs ~/TODO'
setw -t0:1 aggressive-resize on setw -t0:1 aggressive-resize on
neww -d -ntodo2 'exec emacs ~/TODO2'
setw -t0:2 aggressive-resize on
neww -d -nncmpc 'exec ncmpc -f ~/.ncmpc.conf' neww -d -nncmpc 'exec ncmpc -f ~/.ncmpc.conf'
setw -t0:3 aggressive-resize on setw -t0:2 aggressive-resize on
neww -d -nmutt 'exec mutt' neww -d -nmutt 'exec mutt'
setw -t0:4 aggressive-resize on setw -t0:3 aggressive-resize on
neww -d neww -d
neww -d neww -d
neww -d neww -d
@@ -77,7 +63,6 @@ linkw -dk -t0 -s0:0
linkw -dk -t1 -s0:1 linkw -dk -t1 -s0:1
linkw -dk -t2 -s0:2 linkw -dk -t2 -s0:2
linkw -dk -t3 -s0:3 linkw -dk -t3 -s0:3
linkw -dk -t4 -s0:4
neww -d neww -d
neww -d neww -d
neww -d neww -d
@@ -92,7 +77,6 @@ linkw -dk -t0 -s0:0
linkw -dk -t1 -s0:1 linkw -dk -t1 -s0:1
linkw -dk -t2 -s0:2 linkw -dk -t2 -s0:2
linkw -dk -t3 -s0:3 linkw -dk -t3 -s0:3
linkw -dk -t4 -s0:4
neww -d neww -d
neww -d neww -d
neww -d neww -d

11
examples/n-marriott.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/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

View File

@@ -1,6 +1,4 @@
# $Id: screen-keys.conf,v 1.5 2009-10-25 21:58:05 nicm Exp $ # $Id: screen-keys.conf,v 1.3 2009-08-07 12:09:50 nicm Exp $
#
# By Nicholas Marriott. Public domain.
# #
# This configuration file binds many of the common GNU screen key bindings to # 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 # appropriate tmux key bindings. Note that for some key bindings there is no
@@ -75,13 +73,13 @@ bind w list-windows
# quit \ # quit \
unbind \ unbind \
bind \ confirm-before "kill-server" bind \ kill-server
# kill K k # kill K k
unbind K unbind K
bind K confirm-before "kill-window" bind K kill-window
unbind k unbind k
bind k confirm-before "kill-window" bind k kill-window
# redisplay ^L l # redisplay ^L l
unbind ^L unbind ^L

View File

@@ -1,104 +0,0 @@
# $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'

View File

@@ -1,8 +1,7 @@
" Vim syntax file " Vim syntax file
" Language: tmux(1) configuration file " Language: tmux(1) configuration file
" Maintainer: Tiago Cunha <me@tiagocunha.org> " Maintainer: Tiago Cunha <me@tiagocunha.org>
" Last Change: $Date: 2009-10-25 22:16:55 $ " Last Change: $Date: 2009-09-19 18:53:56 $
" License: This file is placed in the public domain.
if version < 600 if version < 600
syntax clear syntax clear
@@ -24,14 +23,14 @@ syn keyword tmuxCmds send-prefix refresh[-client] killw kill-window lsc
syn keyword tmuxCmds list-clients linkw link-window unlinkw unlink-window syn keyword tmuxCmds list-clients linkw link-window unlinkw unlink-window
syn keyword tmuxCmds next[-window] send[-keys] swapw swap-window syn keyword tmuxCmds next[-window] send[-keys] swapw swap-window
syn keyword tmuxCmds rename[-session] kill-session switchc switch-client syn keyword tmuxCmds rename[-session] kill-session switchc switch-client
syn keyword tmuxCmds has[-session] copy-mode pasteb paste-buffer syn keyword tmuxCmds has[-session] scroll-mode copy-mode pasteb paste-buffer
syn keyword tmuxCmds new[-session] start[-server] kill-server setw 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 set-window-option show[-options] showw show-window-options
syn keyword tmuxCmds command-prompt setb set-buffer showb show-buffer lsb 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 list-buffers deleteb delete-buffer lscm list-commands
syn keyword tmuxCmds movew move-window select-prompt respawnw respawn-window 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 source[-file] info server-info clock-mode lock[-server]
syn keyword tmuxCmds saveb save-buffer downp down-pane killp syn keyword tmuxCmds pass set-password saveb save-buffer downp down-pane killp
syn keyword tmuxCmds kill-pane resizep resize-pane selectp select-pane swapp 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 swap-pane splitw split-window upp up-pane choose-session
syn keyword tmuxCmds choose-window loadb load-buffer copyb copy-buffer suspendc syn keyword tmuxCmds choose-window loadb load-buffer copyb copy-buffer suspendc
@@ -39,9 +38,7 @@ syn keyword tmuxCmds suspend-client findw find-window breakp break-pane nextl
syn keyword tmuxCmds next-layout rotatew rotate-window confirm[-before] syn keyword tmuxCmds next-layout rotatew rotate-window confirm[-before]
syn keyword tmuxCmds clearhist clear-history selectl select-layout if[-shell] syn keyword tmuxCmds clearhist clear-history selectl select-layout if[-shell]
syn keyword tmuxCmds display[-message] set-environment show-environment syn keyword tmuxCmds display[-message] set-environment show-environment
syn keyword tmuxCmds choose-client displayp display-panes run[-shell] lockc syn keyword tmuxCmds choose-client displayp display-panes
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 prefix status status-fg status-bg bell-action
syn keyword tmuxOptsSet default-command history-limit status-left status-right syn keyword tmuxOptsSet default-command history-limit status-left status-right
@@ -55,8 +52,7 @@ syn keyword tmuxOptsSet terminal-overrides status-left-attr status-left-bg
syn keyword tmuxOptsSet status-left-fg status-right-attr status-right-bg 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 status-right-fg update-environment base-index
syn keyword tmuxOptsSet display-panes-colour display-panes-time default-shell syn keyword tmuxOptsSet display-panes-colour display-panes-time default-shell
syn keyword tmuxOptsSet set-titles-string lock-command lock-server syn keyword tmuxOptsSet set-titles-string
syn keyword tmuxOptsSet mouse-select-pane
syn keyword tmuxOptsSetw monitor-activity aggressive-resize force-width syn keyword tmuxOptsSetw monitor-activity aggressive-resize force-width
syn keyword tmuxOptsSetw force-height remain-on-exit uft8 mode-fg mode-bg syn keyword tmuxOptsSetw force-height remain-on-exit uft8 mode-fg mode-bg
@@ -65,7 +61,7 @@ syn keyword tmuxOptsSetw xterm-keys mode-attr window-status-attr
syn keyword tmuxOptsSetw window-status-bg window-status-fg automatic-rename 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 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-attr window-status-current-bg
syn keyword tmuxOptsSetw window-status-current-fg mode-mouse synchronize-panes syn keyword tmuxOptsSetw window-status-current-fg mode-mouse
syn keyword tmuxTodo FIXME NOTE TODO XXX contained syn keyword tmuxTodo FIXME NOTE TODO XXX contained

View File

@@ -1,4 +1,4 @@
/* $Id: grid-view.c,v 1.19 2009-10-15 01:55:12 tcunha Exp $ */ /* $Id: grid-view.c,v 1.18 2009-07-14 06:40:33 nicm Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -92,20 +92,15 @@ grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower)
{ {
GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower);
if (gd->flags & GRID_HISTORY) { if (gd->flags & GRID_HISTORY && rupper == 0 && rlower == gd->sy - 1) {
grid_collect_history(gd); grid_scroll_line(gd);
if (rupper == 0 && rlower == gd->sy - 1) return;
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. */ /* Scroll region down. */

72
grid.c
View File

@@ -1,4 +1,4 @@
/* $Id: grid.c,v 1.34 2009-10-15 01:55:12 tcunha Exp $ */ /* $Id: grid.c,v 1.33 2009-09-15 23:54:57 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -161,80 +161,32 @@ grid_compare(struct grid *ga, struct grid *gb)
return (0); 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 void
grid_collect_history(struct grid *gd) grid_scroll_line(struct grid *gd)
{ {
u_int yy; u_int yy;
GRID_DEBUG(gd, ""); GRID_DEBUG(gd, "");
if (gd->hsize < gd->hlimit) if (gd->hsize >= gd->hlimit) {
return; /* If the limit is hit, free the bottom 10% and shift up. */
yy = gd->hlimit / 10;
if (yy < 1)
yy = 1;
yy = gd->hlimit / 10; grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy);
if (yy < 1) gd->hsize -= yy;
yy = 1; }
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; yy = gd->hsize + gd->sy;
gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata);
memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]);
gd->hsize++; 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++;
}
/* Expand line to fit to cell. */ /* Expand line to fit to cell. */
void void
grid_expand_line(struct grid *gd, u_int py, u_int sx) grid_expand_line(struct grid *gd, u_int py, u_int sx)

View File

@@ -1,4 +1,4 @@
/* $Id: input-keys.c,v 1.39 2009-10-28 23:05:01 tcunha Exp $ */ /* $Id: input-keys.c,v 1.29 2009-07-28 22:37:02 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,13 +24,6 @@
#include "tmux.h" #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 { struct input_key_ent {
int key; int key;
const char *data; const char *data;
@@ -38,138 +31,111 @@ struct input_key_ent {
int flags; int flags;
#define INPUTKEY_KEYPAD 0x1 /* keypad key */ #define INPUTKEY_KEYPAD 0x1 /* keypad key */
#define INPUTKEY_CURSOR 0x2 /* cursor 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[] = { struct input_key_ent input_keys[] = {
/* Backspace key. */ /* Backspace key. */
{ KEYC_BSPACE, "\177", 0 }, { KEYC_BSPACE, "\177", 0 },
/* Function keys. */ /* Function keys. */
{ KEYC_F1, "\033OP", 0 }, { KEYC_F1, "\033OP", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F2, "\033OQ", 0 }, { KEYC_F2, "\033OQ", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F3, "\033OR", 0 }, { KEYC_F3, "\033OR", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F4, "\033OS", 0 }, { KEYC_F4, "\033OS", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F5, "\033[15~", 0 }, { KEYC_F5, "\033[15~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F5|KEYC_CTRL, "\033[15^", 0 }, { KEYC_F6, "\033[17~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F6, "\033[17~", 0 }, { KEYC_F7, "\033[18~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F6|KEYC_CTRL, "\033[17^", 0 }, { KEYC_F8, "\033[19~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F7, "\033[18~", 0 }, { KEYC_F9, "\033[20~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F7|KEYC_CTRL, "\033[18^", 0 }, { KEYC_F10, "\033[21~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F8, "\033[19~", 0 }, { KEYC_F11, "\033[23~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F8|KEYC_CTRL, "\033[19^", 0 }, { KEYC_F12, "\033[24~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F9, "\033[20~", 0 }, { KEYC_F13, "\033[25~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F9|KEYC_CTRL, "\033[20^", 0 }, { KEYC_F14, "\033[26~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F10, "\033[21~", 0 }, { KEYC_F15, "\033[28~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F10|KEYC_CTRL, "\033[21^", 0 }, { KEYC_F16, "\033[29~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F11, "\033[23~", 0 }, { KEYC_F17, "\033[31~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F1|KEYC_CTRL, "\033[23^", 0 }, { KEYC_F18, "\033[32~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F12, "\033[24~", 0 }, { KEYC_F19, "\033[33~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F12|KEYC_CTRL, "\033[24^", 0 }, { KEYC_F20, "\033[34~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F13, "\033[25~", 0 }, { KEYC_IC, "\033[2~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F13|KEYC_CTRL, "\033[25^", 0 }, { KEYC_DC, "\033[3~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F14, "\033[26~", 0 }, { KEYC_HOME, "\033[1~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F14|KEYC_CTRL, "\033[26^", 0 }, { KEYC_END, "\033[4~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F15, "\033[28~", 0 }, { KEYC_NPAGE, "\033[6~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F15|KEYC_CTRL, "\033[28^", 0 }, { KEYC_PPAGE, "\033[5~", INPUTKEY_CTRL|INPUTKEY_XTERM },
{ KEYC_F16, "\033[29~", 0 }, { KEYC_BTAB, "\033[Z", INPUTKEY_CTRL },
{ 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. */
* Arrow keys. Cursor versions must come first. The codes are toggled { KEYC_UP | KEYC_CTRL, "\033Oa", 0 },
* between CSI and SS3 versions when ctrl is pressed. { KEYC_DOWN | KEYC_CTRL, "\033Ob", 0 },
*/ { KEYC_RIGHT | KEYC_CTRL, "\033Oc", 0 },
{ KEYC_UP|KEYC_CTRL, "\033[A", INPUTKEY_CURSOR }, { KEYC_LEFT | KEYC_CTRL, "\033Od", 0 },
{ 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_UP | KEYC_SHIFT, "\033[a", 0 },
{ KEYC_DOWN, "\033OB", INPUTKEY_CURSOR }, { KEYC_DOWN | KEYC_SHIFT, "\033[b", 0 },
{ KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR }, { KEYC_RIGHT | KEYC_SHIFT, "\033[c", 0 },
{ KEYC_LEFT, "\033OD", INPUTKEY_CURSOR }, { KEYC_LEFT | KEYC_SHIFT, "\033[d", 0 },
{ KEYC_UP|KEYC_CTRL, "\033OA", 0 }, { KEYC_UP, "\033OA", INPUTKEY_CURSOR },
{ KEYC_DOWN|KEYC_CTRL, "\033OB", 0 }, { KEYC_DOWN, "\033OB", INPUTKEY_CURSOR },
{ KEYC_RIGHT|KEYC_CTRL, "\033OC", 0 }, { KEYC_RIGHT, "\033OC", INPUTKEY_CURSOR },
{ KEYC_LEFT|KEYC_CTRL, "\033OD", 0 }, { KEYC_LEFT, "\033OD", INPUTKEY_CURSOR },
{ KEYC_UP, "\033[A", 0 }, { KEYC_UP, "\033[A", 0 },
{ KEYC_DOWN, "\033[B", 0 }, { KEYC_DOWN, "\033[B", 0 },
{ KEYC_RIGHT, "\033[C", 0 }, { KEYC_RIGHT, "\033[C", 0 },
{ KEYC_LEFT, "\033[D", 0 }, { KEYC_LEFT, "\033[D", 0 },
/* Keypad keys. Keypad versions must come first. */ /* Keypad keys. Keypad versions must come first. */
{ KEYC_KP_SLASH, "/", INPUTKEY_KEYPAD }, { KEYC_KP0_1, "/", INPUTKEY_KEYPAD },
{ KEYC_KP_STAR, "*", INPUTKEY_KEYPAD }, { KEYC_KP0_2, "*", INPUTKEY_KEYPAD },
{ KEYC_KP_MINUS, "-", INPUTKEY_KEYPAD }, { KEYC_KP0_3, "-", INPUTKEY_KEYPAD },
{ KEYC_KP_SEVEN, "7", INPUTKEY_KEYPAD }, { KEYC_KP1_0, "7", INPUTKEY_KEYPAD },
{ KEYC_KP_EIGHT, "8", INPUTKEY_KEYPAD }, { KEYC_KP1_1, "8", INPUTKEY_KEYPAD },
{ KEYC_KP_NINE, "9", INPUTKEY_KEYPAD }, { KEYC_KP1_2, "9", INPUTKEY_KEYPAD },
{ KEYC_KP_PLUS, "+", INPUTKEY_KEYPAD }, { KEYC_KP1_3, "+", INPUTKEY_KEYPAD },
{ KEYC_KP_FOUR, "4", INPUTKEY_KEYPAD }, { KEYC_KP2_0, "4", INPUTKEY_KEYPAD },
{ KEYC_KP_FIVE, "5", INPUTKEY_KEYPAD }, { KEYC_KP2_1, "5", INPUTKEY_KEYPAD },
{ KEYC_KP_SIX, "6", INPUTKEY_KEYPAD }, { KEYC_KP2_2, "6", INPUTKEY_KEYPAD },
{ KEYC_KP_ONE, "1", INPUTKEY_KEYPAD }, { KEYC_KP3_0, "1", INPUTKEY_KEYPAD },
{ KEYC_KP_TWO, "2", INPUTKEY_KEYPAD }, { KEYC_KP3_1, "2", INPUTKEY_KEYPAD },
{ KEYC_KP_THREE, "3", INPUTKEY_KEYPAD }, { KEYC_KP3_2, "3", INPUTKEY_KEYPAD },
{ KEYC_KP_ENTER, "\n", INPUTKEY_KEYPAD }, { KEYC_KP3_3, "\n", INPUTKEY_KEYPAD }, /* this can be CRLF too? */
{ KEYC_KP_ZERO, "0", INPUTKEY_KEYPAD }, { KEYC_KP4_0, "0", INPUTKEY_KEYPAD },
{ KEYC_KP_PERIOD, ".", INPUTKEY_KEYPAD }, { KEYC_KP4_2, ".", INPUTKEY_KEYPAD },
{ KEYC_KP0_1, "\033Oo", 0 },
{ KEYC_KP_SLASH, "\033Oo", 0 }, { KEYC_KP0_2, "\033Oj", 0 },
{ KEYC_KP_STAR, "\033Oj", 0 }, { KEYC_KP0_3, "\033Om", 0 },
{ KEYC_KP_MINUS, "\033Om", 0 }, { KEYC_KP1_0, "\033Ow", 0 },
{ KEYC_KP_SEVEN, "\033Ow", 0 }, { KEYC_KP1_1, "\033Ox", 0 },
{ KEYC_KP_EIGHT, "\033Ox", 0 }, { KEYC_KP1_2, "\033Oy", 0 },
{ KEYC_KP_NINE, "\033Oy", 0 }, { KEYC_KP1_3, "\033Ok", 0 },
{ KEYC_KP_PLUS, "\033Ok", 0 }, { KEYC_KP2_0, "\033Ot", 0 },
{ KEYC_KP_FOUR, "\033Ot", 0 }, { KEYC_KP2_1, "\033Ou", 0 },
{ KEYC_KP_FIVE, "\033Ou", 0 }, { KEYC_KP2_2, "\033Ov", 0 },
{ KEYC_KP_SIX, "\033Ov", 0 }, { KEYC_KP3_0, "\033Oq", 0 },
{ KEYC_KP_ONE, "\033Oq", 0 }, { KEYC_KP3_1, "\033Or", 0 },
{ KEYC_KP_TWO, "\033Or", 0 }, { KEYC_KP3_2, "\033Os", 0 },
{ KEYC_KP_THREE, "\033Os", 0 }, { KEYC_KP3_3, "\033OM", 0 },
{ KEYC_KP_ENTER, "\033OM", 0 }, { KEYC_KP4_0, "\033Op", 0 },
{ KEYC_KP_ZERO, "\033Op", 0 }, { KEYC_KP4_2, "\033On", 0 },
{ KEYC_KP_PERIOD, "\033On", 0 },
}; };
/* Translate a key code into an output key sequence. */ /* Translate a key code from client into an output key sequence. */
void void
input_key(struct window_pane *wp, int key) input_key(struct window_pane *wp, int key)
{ {
struct input_key_ent *ike; struct input_key_ent *ike;
u_int i; u_int i;
char ch;
size_t dlen; size_t dlen;
char *out; int xterm_keys;
log_debug2("writing key 0x%x", key); 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_NONE && (key & ~KEYC_ESCAPE) < 0x100) {
if (key & KEYC_ESCAPE) if (key & KEYC_ESCAPE)
buffer_write8(wp->out, '\033'); buffer_write8(wp->out, '\033');
@@ -177,19 +143,6 @@ input_key(struct window_pane *wp, int key)
return; 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++) { for (i = 0; i < nitems(input_keys); i++) {
ike = &input_keys[i]; ike = &input_keys[i];
@@ -202,6 +155,12 @@ input_key(struct window_pane *wp, int key)
if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key) if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key)
break; 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) if (ike->key == key)
break; break;
} }
@@ -210,22 +169,62 @@ input_key(struct window_pane *wp, int key)
return; return;
} }
dlen = strlen(ike->data); dlen = strlen(ike->data);
log_debug2("found key 0x%x: \"%s\"", key, ike->data); log_debug2("found key 0x%x: \"%s\"", key, ike->data);
/* Prefix a \033 for escape. */ /*
* 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.
*/
if (key & KEYC_ESCAPE) if (key & KEYC_ESCAPE)
buffer_write8(wp->out, '\033'); 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); buffer_write(wp->out, ike->data, dlen);
} }
/* Translate mouse and output. */ /* Handle input mouse. */
void void
input_mouse(struct window_pane *wp, struct mouse_event *m) input_mouse(struct window_pane *wp, u_char b, u_char x, u_char y)
{ {
if (wp->screen->mode & MODE_MOUSE) { if (wp->screen->mode & MODE_MOUSE) {
buffer_write(wp->out, "\033[M", 3); buffer_write(wp->out, "\033[M", 3);
buffer_write8(wp->out, m->b + 32); buffer_write8(wp->out, b + 32);
buffer_write8(wp->out, m->x + 33); buffer_write8(wp->out, x + 33);
buffer_write8(wp->out, m->y + 33); buffer_write8(wp->out, y + 33);
} }
} }

80
input.c
View File

@@ -1,4 +1,4 @@
/* $Id: input.c,v 1.101 2009-10-28 23:12:38 tcunha Exp $ */ /* $Id: input.c,v 1.95 2009-08-21 21:07:20 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -128,7 +128,7 @@ input_sequence_cmp(const void *a, const void *b)
void void
input_new_argument(struct input_ctx *ictx) input_new_argument(struct input_ctx *ictx)
{ {
struct input_arg *arg; struct input_arg *arg;
ARRAY_EXPAND(&ictx->args, 1); ARRAY_EXPAND(&ictx->args, 1);
@@ -139,7 +139,7 @@ input_new_argument(struct input_ctx *ictx)
int int
input_add_argument(struct input_ctx *ictx, u_char ch) input_add_argument(struct input_ctx *ictx, u_char ch)
{ {
struct input_arg *arg; struct input_arg *arg;
if (ARRAY_LENGTH(&ictx->args) == 0) if (ARRAY_LENGTH(&ictx->args) == 0)
return (0); return (0);
@@ -572,14 +572,15 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx)
void void
input_state_utf8(u_char ch, struct input_ctx *ictx) input_state_utf8(u_char ch, struct input_ctx *ictx)
{ {
log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch); log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch);
if (utf8_append(&ictx->utf8data, ch)) ictx->utf8_buf[ictx->utf8_off++] = ch;
return; /* more to come */ if (--ictx->utf8_len != 0)
return;
input_state(ictx, input_state_first); input_state(ictx, input_state_first);
ictx->cell.flags |= GRID_FLAG_UTF8; ictx->cell.flags |= GRID_FLAG_UTF8;
screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
ictx->cell.flags &= ~GRID_FLAG_UTF8; ictx->cell.flags &= ~GRID_FLAG_UTF8;
} }
@@ -589,17 +590,40 @@ input_handle_character(u_char ch, struct input_ctx *ictx)
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) {
if (utf8_open(&ictx->utf8data, ch)) { /*
log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", * UTF-8 sequence.
ictx->utf8data.size, ictx->off, ch, ch); *
* 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);
input_state(ictx, input_state_utf8); 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; return;
} }
} }
log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
ictx->cell.data = ch; ictx->cell.data = ch;
screen_write_cell(&ictx->ctx, &ictx->cell, NULL); screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
} }
void void
@@ -622,7 +646,7 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx)
ictx->wp->window->flags |= WINDOW_BELL; ictx->wp->window->flags |= WINDOW_BELL;
break; break;
case '\010': /* BS */ case '\010': /* BS */
screen_write_backspace(&ictx->ctx); screen_write_cursorleft(&ictx->ctx, 1);
break; break;
case '\011': /* TAB */ case '\011': /* TAB */
/* Don't tab beyond the end of the line. */ /* Don't tab beyond the end of the line. */
@@ -792,7 +816,7 @@ input_handle_sequence(u_char ch, struct input_ctx *ictx)
{ {
struct input_sequence_entry *entry, find; struct input_sequence_entry *entry, find;
struct screen *s = ictx->ctx.s; struct screen *s = ictx->ctx.s;
u_int i; u_int i;
struct input_arg *iarg; struct input_arg *iarg;
log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, " log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, "
@@ -1161,10 +1185,6 @@ input_handle_sequence_sm(struct input_ctx *ictx)
screen_write_kcursormode(&ictx->ctx, 1); screen_write_kcursormode(&ictx->ctx, 1);
log_debug("kcursor on"); log_debug("kcursor on");
break; break;
case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0);
screen_write_clearscreen(&ictx->ctx);
break;
case 25: /* TCEM */ case 25: /* TCEM */
screen_write_cursormode(&ictx->ctx, 1); screen_write_cursormode(&ictx->ctx, 1);
log_debug("cursor on"); log_debug("cursor on");
@@ -1237,10 +1257,6 @@ input_handle_sequence_rm(struct input_ctx *ictx)
screen_write_kcursormode(&ictx->ctx, 0); screen_write_kcursormode(&ictx->ctx, 0);
log_debug("kcursor off"); log_debug("kcursor off");
break; break;
case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0);
screen_write_clearscreen(&ictx->ctx);
break;
case 25: /* TCEM */ case 25: /* TCEM */
screen_write_cursormode(&ictx->ctx, 0); screen_write_cursormode(&ictx->ctx, 0);
log_debug("cursor off"); log_debug("cursor off");
@@ -1470,28 +1486,6 @@ input_handle_sequence_sgr(struct input_ctx *ictx)
gc->flags &= ~GRID_FLAG_BG256; gc->flags &= ~GRID_FLAG_BG256;
gc->bg = 8; gc->bg = 8;
break; 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;
} }
} }
} }

196
job.c
View File

@@ -1,196 +0,0 @@
/* $Id: job.c,v 1.9 2009-11-02 21:38:26 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#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;
}

View File

@@ -1,4 +1,4 @@
/* $Id: key-bindings.c,v 1.83 2009-10-06 14:14:07 tcunha Exp $ */ /* $Id: key-bindings.c,v 1.82 2009-08-31 22:30:15 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -122,6 +122,7 @@ key_bindings_init(void)
{ '8', 0, &cmd_select_window_entry }, { '8', 0, &cmd_select_window_entry },
{ '9', 0, &cmd_select_window_entry }, { '9', 0, &cmd_select_window_entry },
{ ':', 0, &cmd_command_prompt_entry }, { ':', 0, &cmd_command_prompt_entry },
{ '=', 0, &cmd_scroll_mode_entry },
{ '?', 0, &cmd_list_keys_entry }, { '?', 0, &cmd_list_keys_entry },
{ '[', 0, &cmd_copy_mode_entry }, { '[', 0, &cmd_copy_mode_entry },
{ '\'', 0, &cmd_select_prompt_entry }, { '\'', 0, &cmd_select_prompt_entry },
@@ -149,7 +150,7 @@ key_bindings_init(void)
{ '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ KEYC_PPAGE, 0, &cmd_copy_mode_entry }, { KEYC_PPAGE, 0, &cmd_scroll_mode_entry },
{ 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry }, { 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry },
{ 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry }, { 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry },
{ KEYC_UP, 0, &cmd_up_pane_entry }, { KEYC_UP, 0, &cmd_up_pane_entry },

View File

@@ -1,4 +1,4 @@
/* $Id: key-string.c,v 1.25 2009-10-28 22:53:03 tcunha Exp $ */ /* $Id: key-string.c,v 1.22 2009-07-28 23:13:00 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -57,7 +57,6 @@ struct {
{ "PPage", KEYC_PPAGE }, { "PPage", KEYC_PPAGE },
{ "Tab", '\011' }, { "Tab", '\011' },
{ "BTab", KEYC_BTAB }, { "BTab", KEYC_BTAB },
{ "Space", ' ' },
{ "BSpace", KEYC_BSPACE }, { "BSpace", KEYC_BSPACE },
{ "Enter", '\r' }, { "Enter", '\r' },
{ "Escape", '\033' }, { "Escape", '\033' },
@@ -69,22 +68,22 @@ struct {
{ "Right", KEYC_RIGHT }, { "Right", KEYC_RIGHT },
/* Numeric keypad. */ /* Numeric keypad. */
{ "KP/", KEYC_KP_SLASH }, { "KP/", KEYC_KP0_1 },
{ "KP*", KEYC_KP_STAR }, { "KP*", KEYC_KP0_2 },
{ "KP-", KEYC_KP_MINUS }, { "KP-", KEYC_KP0_3 },
{ "KP7", KEYC_KP_SEVEN }, { "KP7", KEYC_KP1_0 },
{ "KP8", KEYC_KP_EIGHT }, { "KP8", KEYC_KP1_1 },
{ "KP9", KEYC_KP_NINE }, { "KP9", KEYC_KP1_2 },
{ "KP+", KEYC_KP_PLUS }, { "KP+", KEYC_KP1_3 },
{ "KP4", KEYC_KP_FOUR }, { "KP4", KEYC_KP2_0 },
{ "KP5", KEYC_KP_FIVE }, { "KP5", KEYC_KP2_1 },
{ "KP6", KEYC_KP_SIX }, { "KP6", KEYC_KP2_2 },
{ "KP1", KEYC_KP_ONE }, { "KP1", KEYC_KP3_0 },
{ "KP2", KEYC_KP_TWO }, { "KP2", KEYC_KP3_1 },
{ "KP3", KEYC_KP_THREE }, { "KP3", KEYC_KP3_2 },
{ "KPEnter", KEYC_KP_ENTER }, { "KPEnter", KEYC_KP3_3 },
{ "KP0", KEYC_KP_ZERO }, { "KP0", KEYC_KP4_0 },
{ "KP.", KEYC_KP_PERIOD }, { "KP.", KEYC_KP4_2 },
}; };
int int
@@ -121,8 +120,6 @@ key_string_lookup_string(const char *string)
if (ptr[1] == '\0') { if (ptr[1] == '\0') {
if (ptr[0] == 32) if (ptr[0] == 32)
return (0); return (0);
if (ptr[0] == 63)
return (KEYC_BSPACE);
if (ptr[0] >= 64 && ptr[0] <= 95) if (ptr[0] >= 64 && ptr[0] <= 95)
return (ptr[0] - 64); return (ptr[0] - 64);
if (ptr[0] >= 97 && ptr[0] <= 122) if (ptr[0] >= 97 && ptr[0] <= 122)

View File

@@ -1,4 +1,4 @@
/* $Id: mode-key.c,v 1.34 2009-10-15 01:52:47 tcunha Exp $ */ /* $Id: mode-key.c,v 1.28 2009-09-02 22:45:17 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -77,7 +77,6 @@ struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
/* Copy keys command strings. */ /* Copy keys command strings. */
struct mode_key_cmdstr mode_key_cmdstr_copy[] = { struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" }, { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" },
{ MODEKEYCOPY_BOTTOMLINE, "bottom-line" },
{ MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_CANCEL, "cancel" },
{ MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, { MODEKEYCOPY_CLEARSELECTION, "clear-selection" },
{ MODEKEYCOPY_COPYSELECTION, "copy-selection" }, { MODEKEYCOPY_COPYSELECTION, "copy-selection" },
@@ -85,20 +84,16 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_ENDOFLINE, "end-of-line" }, { MODEKEYCOPY_ENDOFLINE, "end-of-line" },
{ MODEKEYCOPY_GOTOLINE, "goto-line" }, { MODEKEYCOPY_GOTOLINE, "goto-line" },
{ MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_LEFT, "cursor-left" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
{ MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTPAGE, "page-down" },
{ MODEKEYCOPY_NEXTWORD, "next-word" }, { MODEKEYCOPY_NEXTWORD, "next-word" },
{ MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" },
{ MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" },
{ MODEKEYCOPY_RIGHT, "cursor-right" }, { MODEKEYCOPY_RIGHT, "cursor-right" },
{ MODEKEYCOPY_SCROLLDOWN, "scroll-down" },
{ MODEKEYCOPY_SCROLLUP, "scroll-up" },
{ MODEKEYCOPY_SEARCHAGAIN, "search-again" }, { MODEKEYCOPY_SEARCHAGAIN, "search-again" },
{ MODEKEYCOPY_SEARCHDOWN, "search-forward" }, { MODEKEYCOPY_SEARCHDOWN, "search-forward" },
{ MODEKEYCOPY_SEARCHUP, "search-backward" }, { MODEKEYCOPY_SEARCHUP, "search-backward" },
{ MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" },
{ MODEKEYCOPY_STARTSELECTION, "begin-selection" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" },
{ MODEKEYCOPY_TOPLINE, "top-line" },
{ MODEKEYCOPY_UP, "cursor-up" }, { MODEKEYCOPY_UP, "cursor-up" },
{ 0, NULL } { 0, NULL }
@@ -160,15 +155,9 @@ struct mode_key_tree mode_key_tree_vi_choice;
const struct mode_key_entry mode_key_vi_copy[] = { const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION }, { ' ', 0, MODEKEYCOPY_STARTSELECTION },
{ '$', 0, MODEKEYCOPY_ENDOFLINE }, { '$', 0, MODEKEYCOPY_ENDOFLINE },
{ '/', 0, MODEKEYCOPY_SEARCHDOWN }, { '/', 0, MODEKEYCOPY_SEARCHUP },
{ '0', 0, MODEKEYCOPY_STARTOFLINE }, { '0', 0, MODEKEYCOPY_STARTOFLINE },
{ ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHDOWN },
{ '?', 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 }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL },
{ '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN },
@@ -179,6 +168,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '\r', 0, MODEKEYCOPY_COPYSELECTION }, { '\r', 0, MODEKEYCOPY_COPYSELECTION },
{ '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION },
{ 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'g', 0, MODEKEYCOPY_GOTOLINE },
{ 'h', 0, MODEKEYCOPY_LEFT }, { 'h', 0, MODEKEYCOPY_LEFT },
{ 'j', 0, MODEKEYCOPY_DOWN }, { 'j', 0, MODEKEYCOPY_DOWN },
{ 'k', 0, MODEKEYCOPY_UP }, { 'k', 0, MODEKEYCOPY_UP },
@@ -187,13 +177,11 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ 'q', 0, MODEKEYCOPY_CANCEL }, { 'q', 0, MODEKEYCOPY_CANCEL },
{ 'w', 0, MODEKEYCOPY_NEXTWORD }, { 'w', 0, MODEKEYCOPY_NEXTWORD },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, { KEYC_LEFT, 0, MODEKEYCOPY_LEFT },
{ KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE },
{ KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP },
{ KEYC_UP, 0, MODEKEYCOPY_UP }, { KEYC_UP, 0, MODEKEYCOPY_UP },
{ 0, -1, 0 } { 0, -1, 0 }
@@ -203,7 +191,7 @@ struct mode_key_tree mode_key_tree_vi_copy;
/* emacs editing keys. */ /* emacs editing keys. */
const struct mode_key_entry mode_key_emacs_edit[] = { const struct mode_key_entry mode_key_emacs_edit[] = {
{ '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE },
{ '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT }, { '\002' /* C-p */, 0, MODEKEYEDIT_CURSORLEFT },
{ '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL },
{ '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE },
{ '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE },
@@ -233,13 +221,9 @@ struct mode_key_tree mode_key_tree_emacs_edit;
/* emacs choice selection keys. */ /* emacs choice selection keys. */
const struct mode_key_entry mode_key_emacs_choice[] = { const struct mode_key_entry mode_key_emacs_choice[] = {
{ '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, { '\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 }, { '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL },
{ '\r', 0, MODEKEYCHOICE_CHOOSE }, { '\r', 0, MODEKEYCHOICE_CHOOSE },
{ 'q', 0, MODEKEYCHOICE_CANCEL }, { 'q', 0, MODEKEYCHOICE_CANCEL },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP },
{ KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN },
{ KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN },
{ KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP },
@@ -272,18 +256,14 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION },
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, { 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
{ 'q', 0, MODEKEYCOPY_CANCEL }, { 'q', 0, MODEKEYCOPY_CANCEL },
{ 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN }, { KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, { KEYC_LEFT, 0, MODEKEYCOPY_LEFT },
{ KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE },
{ KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP },
{ KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP }, { KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP },
{ KEYC_UP, 0, MODEKEYCOPY_UP }, { KEYC_UP, 0, MODEKEYCOPY_UP },

10
names.c
View File

@@ -1,4 +1,4 @@
/* $Id: names.c,v 1.17 2009-10-12 00:03:04 tcunha Exp $ */ /* $Id: names.c,v 1.15 2009-09-02 01:02:44 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -36,7 +36,7 @@ set_window_names(void)
struct timeval tv, tv2; struct timeval tv, tv2;
if (gettimeofday(&tv, NULL) != 0) if (gettimeofday(&tv, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
w = ARRAY_ITEM(&windows, i); w = ARRAY_ITEM(&windows, i);
@@ -73,12 +73,6 @@ set_window_names(void)
xfree(name); xfree(name);
} }
if (w->active->fd == -1) {
xasprintf(&name, "%s[dead]", wname);
xfree(wname);
wname = name;
}
if (strcmp(wname, w->name) == 0) if (strcmp(wname, w->name) == 0)
xfree(wname); xfree(wname);
else { else {

View File

@@ -1,4 +1,4 @@
/* $Id: options-cmd.c,v 1.8 2009-09-22 14:22:20 tcunha Exp $ */ /* $Id: options-cmd.c,v 1.5 2009-08-09 16:48:34 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -23,59 +23,11 @@
#include "tmux.h" #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 void
set_option_string(struct cmd_ctx *ctx, struct options *oo, set_option_string(struct cmd_ctx *ctx, struct options *oo,
const struct set_option_entry *entry, char *value, int append) const struct set_option_entry *entry, char *value, int append)
{ {
struct options_entry *o; char *oldvalue, *newvalue;
char *oldvalue, *newvalue;
if (value == NULL) { if (value == NULL) {
ctx->error(ctx, "empty value"); ctx->error(ctx, "empty value");
@@ -88,9 +40,8 @@ set_option_string(struct cmd_ctx *ctx, struct options *oo,
} else } else
newvalue = value; newvalue = value;
o = options_set_string(oo, entry->name, "%s", newvalue); options_set_string(oo, entry->name, "%s", newvalue);
ctx->info( ctx->info(ctx, "set option: %s -> %s", entry->name, newvalue);
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o));
if (newvalue != value) if (newvalue != value)
xfree(newvalue); xfree(newvalue);
@@ -100,9 +51,8 @@ void
set_option_number(struct cmd_ctx *ctx, struct options *oo, set_option_number(struct cmd_ctx *ctx, struct options *oo,
const struct set_option_entry *entry, char *value) const struct set_option_entry *entry, char *value)
{ {
struct options_entry *o; long long number;
long long number; const char *errstr;
const char *errstr;
if (value == NULL) { if (value == NULL) {
ctx->error(ctx, "empty value"); ctx->error(ctx, "empty value");
@@ -114,52 +64,35 @@ set_option_number(struct cmd_ctx *ctx, struct options *oo,
ctx->error(ctx, "value is %s: %s", errstr, value); ctx->error(ctx, "value is %s: %s", errstr, value);
return; return;
} }
options_set_number(oo, entry->name, number);
o = options_set_number(oo, entry->name, number); ctx->info(ctx, "set option: %s -> %lld", entry->name, number);
ctx->info(
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o));
} }
void void
set_option_keys(struct cmd_ctx *ctx, struct options *oo, set_option_key(struct cmd_ctx *ctx, struct options *oo,
const struct set_option_entry *entry, char *value) const struct set_option_entry *entry, char *value)
{ {
struct options_entry *o; int key;
struct keylist *keylist;
char *copyvalue, *ptr, *str;
int key;
if (value == NULL) { if (value == NULL) {
ctx->error(ctx, "empty value"); ctx->error(ctx, "empty value");
return; return;
} }
keylist = xmalloc(sizeof *keylist); if ((key = key_string_lookup_string(value)) == KEYC_NONE) {
ARRAY_INIT(keylist); ctx->error(ctx, "unknown key: %s", value);
return;
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);
} }
xfree(copyvalue); options_set_number(oo, entry->name, key);
ctx->info(ctx,
o = options_set_data(oo, entry->name, keylist, xfree); "set option: %s -> %s", entry->name, key_string_lookup_key(key));
ctx->info(
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o));
} }
void void
set_option_colour(struct cmd_ctx *ctx, struct options *oo, set_option_colour(struct cmd_ctx *ctx, struct options *oo,
const struct set_option_entry *entry, char *value) const struct set_option_entry *entry, char *value)
{ {
struct options_entry *o; int colour;
int colour;
if (value == NULL) { if (value == NULL) {
ctx->error(ctx, "empty value"); ctx->error(ctx, "empty value");
@@ -171,17 +104,16 @@ set_option_colour(struct cmd_ctx *ctx, struct options *oo,
return; return;
} }
o = options_set_number(oo, entry->name, colour); options_set_number(oo, entry->name, colour);
ctx->info( ctx->info(ctx,
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); "set option: %s -> %s", entry->name, colour_tostring(colour));
} }
void void
set_option_attributes(struct cmd_ctx *ctx, struct options *oo, set_option_attributes(struct cmd_ctx *ctx, struct options *oo,
const struct set_option_entry *entry, char *value) const struct set_option_entry *entry, char *value)
{ {
struct options_entry *o; int attr;
int attr;
if (value == NULL) { if (value == NULL) {
ctx->error(ctx, "empty value"); ctx->error(ctx, "empty value");
@@ -193,17 +125,16 @@ set_option_attributes(struct cmd_ctx *ctx, struct options *oo,
return; return;
} }
o = options_set_number(oo, entry->name, attr); options_set_number(oo, entry->name, attr);
ctx->info( ctx->info(ctx,
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); "set option: %s -> %s", entry->name, attributes_tostring(attr));
} }
void void
set_option_flag(struct cmd_ctx *ctx, struct options *oo, set_option_flag(struct cmd_ctx *ctx, struct options *oo,
const struct set_option_entry *entry, char *value) const struct set_option_entry *entry, char *value)
{ {
struct options_entry *o; int flag;
int flag;
if (value == NULL || *value == '\0') if (value == NULL || *value == '\0')
flag = !options_get_number(oo, entry->name); flag = !options_get_number(oo, entry->name);
@@ -222,18 +153,17 @@ set_option_flag(struct cmd_ctx *ctx, struct options *oo,
} }
} }
o = options_set_number(oo, entry->name, flag); options_set_number(oo, entry->name, flag);
ctx->info( ctx->info(ctx,
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); "set option: %s -> %s", entry->name, flag ? "on" : "off");
} }
void void
set_option_choice(struct cmd_ctx *ctx, struct options *oo, set_option_choice(struct cmd_ctx *ctx, struct options *oo,
const struct set_option_entry *entry, char *value) const struct set_option_entry *entry, char *value)
{ {
struct options_entry *o; const char **choicep;
const char **choicep; int n, choice = -1;
int n, choice = -1;
if (value == NULL) { if (value == NULL) {
ctx->error(ctx, "empty value"); ctx->error(ctx, "empty value");
@@ -257,7 +187,7 @@ set_option_choice(struct cmd_ctx *ctx, struct options *oo,
return; return;
} }
o = options_set_number(oo, entry->name, choice); options_set_number(oo, entry->name, choice);
ctx->info( ctx->info(ctx,
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); "set option: %s -> %s", entry->name, entry->choices[choice]);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: options.c,v 1.9 2009-09-22 14:22:20 tcunha Exp $ */ /* $Id: options.c,v 1.6 2009-07-22 17:46:53 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -53,9 +53,7 @@ options_free(struct options *oo)
SPLAY_REMOVE(options_tree, &oo->tree, o); SPLAY_REMOVE(options_tree, &oo->tree, o);
xfree(o->name); xfree(o->name);
if (o->type == OPTIONS_STRING) if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->value.string);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
xfree(o); xfree(o);
} }
} }
@@ -96,13 +94,11 @@ options_remove(struct options *oo, const char *name)
SPLAY_REMOVE(options_tree, &oo->tree, o); SPLAY_REMOVE(options_tree, &oo->tree, o);
xfree(o->name); xfree(o->name);
if (o->type == OPTIONS_STRING) if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->value.string);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
xfree(o); xfree(o);
} }
struct options_entry *printflike3 void printflike3
options_set_string(struct options *oo, const char *name, const char *fmt, ...) options_set_string(struct options *oo, const char *name, const char *fmt, ...)
{ {
struct options_entry *o; struct options_entry *o;
@@ -113,15 +109,12 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...)
o->name = xstrdup(name); o->name = xstrdup(name);
SPLAY_INSERT(options_tree, &oo->tree, o); SPLAY_INSERT(options_tree, &oo->tree, o);
} else if (o->type == OPTIONS_STRING) } else if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->value.string);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
va_start(ap, fmt); va_start(ap, fmt);
o->type = OPTIONS_STRING; o->type = OPTIONS_STRING;
xvasprintf(&o->str, fmt, ap); xvasprintf(&o->value.string, fmt, ap);
va_end(ap); va_end(ap);
return (o);
} }
char * char *
@@ -133,10 +126,10 @@ options_get_string(struct options *oo, const char *name)
fatalx("missing option"); fatalx("missing option");
if (o->type != OPTIONS_STRING) if (o->type != OPTIONS_STRING)
fatalx("option not a string"); fatalx("option not a string");
return (o->str); return (o->value.string);
} }
struct options_entry * void
options_set_number(struct options *oo, const char *name, long long value) options_set_number(struct options *oo, const char *name, long long value)
{ {
struct options_entry *o; struct options_entry *o;
@@ -146,13 +139,11 @@ options_set_number(struct options *oo, const char *name, long long value)
o->name = xstrdup(name); o->name = xstrdup(name);
SPLAY_INSERT(options_tree, &oo->tree, o); SPLAY_INSERT(options_tree, &oo->tree, o);
} else if (o->type == OPTIONS_STRING) } else if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->value.string);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
o->type = OPTIONS_NUMBER; o->type = OPTIONS_NUMBER;
o->num = value; o->value.number = value;
return (o);
} }
long long long long
@@ -164,38 +155,5 @@ options_get_number(struct options *oo, const char *name)
fatalx("missing option"); fatalx("missing option");
if (o->type != OPTIONS_NUMBER) if (o->type != OPTIONS_NUMBER)
fatalx("option not a number"); fatalx("option not a number");
return (o->num); return (o->value.number);
}
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);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: osdep-netbsd.c,v 1.9 2009-09-24 12:30:22 nicm Exp $ */ /* $Id: osdep-netbsd.c,v 1.8 2009-08-09 18:00:45 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -77,7 +77,7 @@ osdep_get_name(int fd, __unused char *tty)
return (NULL); return (NULL);
buf = NULL; buf = NULL;
len = sizeof(bestp); len = sizeof(p);
mib[0] = CTL_KERN; mib[0] = CTL_KERN;
mib[1] = KERN_PROC2; mib[1] = KERN_PROC2;
mib[2] = KERN_PROC_PGRP; mib[2] = KERN_PROC_PGRP;

View File

@@ -1,65 +0,0 @@
/* $Id: osdep-sunos.c,v 1.2 2009-10-15 07:11:25 nicm Exp $ */
/*
* Copyright (c) 2009 Todd Carson <toc@daybefore.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <procfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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));
}

View File

@@ -1,4 +1,4 @@
/* $Id: paste.c,v 1.11 2009-11-04 22:39:20 tcunha Exp $ */ /* $Id: paste.c,v 1.9 2009-09-07 23:48:54 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -116,6 +116,8 @@ paste_add(struct paste_stack *ps, u_char *data, size_t size, u_int limit)
pb->data = data; pb->data = data;
pb->size = size; pb->size = size;
if (gettimeofday(&pb->tv, NULL) != 0)
fatal("gettimeofday");
} }
int int
@@ -131,6 +133,8 @@ paste_replace(struct paste_stack *ps, u_int idx, u_char *data, size_t size)
pb->data = data; pb->data = data;
pb->size = size; pb->size = size;
if (gettimeofday(&pb->tv, NULL) != 0)
fatal("gettimeofday");
return (0); return (0);
} }

View File

@@ -1,4 +1,4 @@
/* $Id: resize.c,v 1.24 2009-09-25 17:47:42 tcunha Exp $ */ /* $Id: resize.c,v 1.23 2009-07-20 15:42:05 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -60,7 +60,7 @@ recalculate_sizes(void)
ssx = ssy = UINT_MAX; ssx = ssy = UINT_MAX;
for (j = 0; j < ARRAY_LENGTH(&clients); j++) { for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j); c = ARRAY_ITEM(&clients, j);
if (c == NULL || c->flags & CLIENT_SUSPENDED) if (c == NULL)
continue; continue;
if (c->session == s) { if (c->session == s) {
if (c->tty.sx < ssx) if (c->tty.sx < ssx)

View File

@@ -1,4 +1,4 @@
/* $Id: screen-redraw.c,v 1.49 2009-10-28 23:17:28 tcunha Exp $ */ /* $Id: screen-redraw.c,v 1.47 2009-09-11 14:13:52 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -195,7 +195,7 @@ screen_redraw_screen(struct client *c, int status_only)
for (i = 0; i < tty->sx; i++) { for (i = 0; i < tty->sx; i++) {
type = screen_redraw_check_cell(c, i, j); type = screen_redraw_check_cell(c, i, j);
if (type != CELL_INSIDE) { if (type != CELL_INSIDE) {
tty_cursor(tty, i, j); tty_cursor(tty, i, j, 0, 0);
tty_putc(tty, border[type]); tty_putc(tty, border[type]);
} }
} }
@@ -239,7 +239,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct session *s = c->session; struct session *s = c->session;
struct grid_cell gc; struct grid_cell gc;
u_int idx, px, py, i, j, xoff, yoff; u_int idx, px, py, i, j;
int colour; int colour;
char buf[16], *ptr; char buf[16], *ptr;
size_t len; size_t len;
@@ -251,13 +251,11 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
return; return;
colour = options_get_number(&s->options, "display-panes-colour"); colour = options_get_number(&s->options, "display-panes-colour");
px = wp->sx / 2; py = wp->sy / 2; px = wp->sx / 2;
xoff = wp->xoff; yoff = wp->yoff; py = wp->sy / 2;
if (wp->sx < len * 6 || wp->sy < 5) { if (wp->sx < len * 6 || wp->sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py); tty_cursor(tty, px - len / 2, py, wp->xoff, wp->yoff);
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
gc.data = '_'; /* not space */
colour_set_fg(&gc, colour); colour_set_fg(&gc, colour);
tty_attributes(tty, &gc); tty_attributes(tty, &gc);
tty_puts(tty, buf); tty_puts(tty, buf);
@@ -268,7 +266,6 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
py -= 2; py -= 2;
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
gc.data = '_'; /* not space */
colour_set_bg(&gc, colour); colour_set_bg(&gc, colour);
tty_attributes(tty, &gc); tty_attributes(tty, &gc);
for (ptr = buf; *ptr != '\0'; ptr++) { for (ptr = buf; *ptr != '\0'; ptr++) {
@@ -278,7 +275,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
for (j = 0; j < 5; j++) { for (j = 0; j < 5; j++) {
for (i = px; i < px + 5; i++) { for (i = px; i < px + 5; i++) {
tty_cursor(tty, xoff + i, yoff + py + j); tty_cursor(tty, i, py + j, wp->xoff, wp->yoff);
if (clock_table[idx][j][i - px]) if (clock_table[idx][j][i - px])
tty_putc(tty, ' '); tty_putc(tty, ' ');
} }

View File

@@ -1,4 +1,4 @@
/* $Id: screen-write.c,v 1.83 2009-10-23 17:16:24 tcunha Exp $ */ /* $Id: screen-write.c,v 1.73 2009-09-15 23:54:57 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -22,10 +22,8 @@
#include "tmux.h" #include "tmux.h"
void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *);
void screen_write_overwrite(struct screen_write_ctx *); 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. */ /* Initialise writing with a window. */
void void
@@ -93,11 +91,10 @@ screen_write_cstrlen(int utf8flag, const char *fmt, ...)
size_t printflike2 size_t printflike2
screen_write_strlen(int utf8flag, const char *fmt, ...) screen_write_strlen(int utf8flag, const char *fmt, ...)
{ {
va_list ap; va_list ap;
char *msg; char *msg;
struct utf8_data utf8data; u_char *ptr, utf8buf[4];
u_char *ptr; size_t left, size = 0;
size_t left, size = 0;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&msg, fmt, ap); xvasprintf(&msg, fmt, ap);
@@ -105,17 +102,24 @@ screen_write_strlen(int utf8flag, const char *fmt, ...)
ptr = msg; ptr = msg;
while (*ptr != '\0') { while (*ptr != '\0') {
if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { if (utf8flag && *ptr > 0x7f) {
ptr++; memset(utf8buf, 0xff, sizeof utf8buf);
left = strlen(ptr); left = strlen(ptr);
if (left < utf8data.size - 1) if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
break; memcpy(utf8buf, ptr, 2);
while (utf8_append(&utf8data, *ptr)) 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;
ptr++; ptr++;
ptr++; }
size += utf8_width(utf8buf);
size += utf8data.width;
} else { } else {
size++; size++;
ptr++; ptr++;
@@ -154,38 +158,47 @@ void
screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap) struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap)
{ {
char *msg; char *msg;
struct utf8_data utf8data; u_char *ptr, utf8buf[4];
u_char *ptr; size_t left, size = 0;
size_t left, size = 0; int width;
xvasprintf(&msg, fmt, ap); xvasprintf(&msg, fmt, ap);
ptr = msg; ptr = msg;
while (*ptr != '\0') { while (*ptr != '\0') {
if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { if (utf8flag && *ptr > 0x7f) {
ptr++; memset(utf8buf, 0xff, sizeof utf8buf);
left = strlen(ptr); left = strlen(ptr);
if (left < utf8data.size - 1) if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
break; memcpy(utf8buf, ptr, 2);
while (utf8_append(&utf8data, *ptr)) 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;
ptr++; ptr++;
ptr++; }
if (maxlen > 0 && width = utf8_width(utf8buf);
size + utf8data.width > (size_t) maxlen) { if (maxlen > 0 && size + width > (size_t) maxlen) {
while (size < (size_t) maxlen) { while (size < (size_t) maxlen) {
screen_write_putc(ctx, gc, ' '); screen_write_putc(ctx, gc, ' ');
size++; size++;
} }
break; break;
} }
size += utf8data.width; size += width;
gc->flags |= GRID_FLAG_UTF8; gc->flags |= GRID_FLAG_UTF8;
screen_write_cell(ctx, gc, &utf8data); screen_write_cell(ctx, gc, utf8buf);
gc->flags &= ~GRID_FLAG_UTF8; gc->flags &= ~GRID_FLAG_UTF8;
} else { } else {
if (maxlen > 0 && size + 1 > (size_t) maxlen) if (maxlen > 0 && size + 1 > (size_t) maxlen)
break; break;
@@ -205,11 +218,11 @@ screen_write_cnputs(struct screen_write_ctx *ctx,
ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...) ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...)
{ {
struct grid_cell lgc; struct grid_cell lgc;
struct utf8_data utf8data;
va_list ap; va_list ap;
char *msg; char *msg;
u_char *ptr, *last; u_char *ptr, *last, utf8buf[4];
size_t left, size = 0; size_t left, size = 0;
int width;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&msg, fmt, ap); xvasprintf(&msg, fmt, ap);
@@ -233,29 +246,38 @@ screen_write_cnputs(struct screen_write_ctx *ctx,
continue; continue;
} }
if (utf8flag && *ptr > 0x7f && utf8_open(&utf8data, *ptr)) { if (utf8flag && *ptr > 0x7f) {
ptr++; memset(utf8buf, 0xff, sizeof utf8buf);
left = strlen(ptr); left = strlen(ptr);
if (left < utf8data.size - 1) if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
break; memcpy(utf8buf, ptr, 2);
while (utf8_append(&utf8data, *ptr)) 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;
ptr++; ptr++;
ptr++; }
if (maxlen > 0 && width = utf8_width(utf8buf);
size + utf8data.width > (size_t) maxlen) { if (maxlen > 0 && size + width > (size_t) maxlen) {
while (size < (size_t) maxlen) { while (size < (size_t) maxlen) {
screen_write_putc(ctx, gc, ' '); screen_write_putc(ctx, gc, ' ');
size++; size++;
} }
break; break;
} }
size += utf8data.width; size += width;
lgc.flags |= GRID_FLAG_UTF8; lgc.flags |= GRID_FLAG_UTF8;
screen_write_cell(ctx, &lgc, &utf8data); screen_write_cell(ctx, &lgc, utf8buf);
lgc.flags &= ~GRID_FLAG_UTF8; lgc.flags &= ~GRID_FLAG_UTF8;
} else { } else {
if (maxlen > 0 && size + 1 > (size_t) maxlen) if (maxlen > 0 && size + 1 > (size_t) maxlen)
break; break;
@@ -325,10 +347,6 @@ screen_write_parsestyle(
bg = defgc->bg; bg = defgc->bg;
} else } else
return; return;
} else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
if ((val = attributes_fromstring(tmp + 2)) == -1)
return;
attr &= ~val;
} else { } else {
if ((val = attributes_fromstring(tmp)) == -1) if ((val = attributes_fromstring(tmp)) == -1)
return; return;
@@ -352,9 +370,8 @@ screen_write_copy(struct screen_write_ctx *ctx,
struct grid *gd = src->grid; struct grid *gd = src->grid;
struct grid_line *gl; struct grid_line *gl;
const struct grid_cell *gc; const struct grid_cell *gc;
const struct grid_utf8 *gu; u_char *udata;
struct utf8_data utf8data; u_int xx, yy, cx, cy, ax, bx;
u_int xx, yy, cx, cy, ax, bx, i;
cx = s->cx; cx = s->cx;
cy = s->cy; cy = s->cy;
@@ -375,30 +392,21 @@ screen_write_copy(struct screen_write_ctx *ctx,
bx = gl->cellsize; bx = gl->cellsize;
else else
bx = px + nx; bx = px + nx;
for (xx = ax; xx < bx; xx++) { for (xx = ax; xx < bx; xx++) {
udata = NULL;
if (xx >= gl->cellsize) if (xx >= gl->cellsize)
gc = &grid_default_cell; gc = &grid_default_cell;
else else {
gc = &gl->celldata[xx]; gc = &gl->celldata[xx];
if (gc->flags & GRID_FLAG_UTF8) { if (gc->flags & GRID_FLAG_UTF8)
gu = &gl->utf8data[xx]; udata = gl->utf8data[xx].data;
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, &utf8data); screen_write_cell(ctx, gc, udata);
} }
if (px + nx == gd->sx && px + nx > gl->cellsize) if (px + nx == gd->sx && px + nx > gl->cellsize)
screen_write_clearendofline(ctx); screen_write_clearendofline(ctx);
} else } else
screen_write_clearline(ctx); screen_write_clearline(ctx);
cy++; cy++;
screen_write_cursormove(ctx, cx, cy); screen_write_cursormove(ctx, cx, cy);
} }
@@ -406,14 +414,9 @@ screen_write_copy(struct screen_write_ctx *ctx,
/* Set up context for TTY command. */ /* Set up context for TTY command. */
void void
screen_write_initctx( screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
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; ttyctx->wp = ctx->wp;
@@ -422,23 +425,6 @@ screen_write_initctx(
ttyctx->orlower = s->rlower; ttyctx->orlower = s->rlower;
ttyctx->orupper = s->rupper; 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. */ /* Cursor up by ny. */
@@ -523,25 +509,6 @@ screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
s->cx -= nx; 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. */ /* VT100 alignment test. */
void void
screen_write_alignmenttest(struct screen_write_ctx *ctx) screen_write_alignmenttest(struct screen_write_ctx *ctx)
@@ -551,7 +518,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
struct grid_cell gc; struct grid_cell gc;
u_int xx, yy; u_int xx, yy;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
gc.data = 'E'; gc.data = 'E';
@@ -565,7 +532,6 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
s->cy = 0; s->cy = 0;
s->rupper = 0; s->rupper = 0;
s->rlower = screen_size_y(s) - 1; s->rlower = screen_size_y(s) - 1;
tty_write(tty_cmd_alignmenttest, &ttyctx); tty_write(tty_cmd_alignmenttest, &ttyctx);
@@ -586,7 +552,7 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
if (nx == 0) if (nx == 0)
return; return;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
if (s->cx <= screen_size_x(s) - 1) if (s->cx <= screen_size_x(s) - 1)
grid_view_insert_cells(s->grid, s->cx, s->cy, nx); grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
@@ -610,7 +576,7 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
if (nx == 0) if (nx == 0)
return; return;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
if (s->cx <= screen_size_x(s) - 1) if (s->cx <= screen_size_x(s) - 1)
grid_view_delete_cells(s->grid, s->cx, s->cy, nx); grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
@@ -635,7 +601,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0) if (ny == 0)
return; return;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
grid_view_insert_lines(s->grid, s->cy, ny); grid_view_insert_lines(s->grid, s->cy, ny);
@@ -649,7 +615,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0) if (ny == 0)
return; return;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
if (s->cy < s->rupper || s->cy > s->rlower) if (s->cy < s->rupper || s->cy > s->rlower)
grid_view_insert_lines(s->grid, s->cy, ny); grid_view_insert_lines(s->grid, s->cy, ny);
@@ -676,7 +642,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0) if (ny == 0)
return; return;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
grid_view_delete_lines(s->grid, s->cy, ny); grid_view_delete_lines(s->grid, s->cy, ny);
@@ -690,7 +656,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
if (ny == 0) if (ny == 0)
return; return;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
if (s->cy < s->rupper || s->cy > s->rlower) if (s->cy < s->rupper || s->cy > s->rlower)
grid_view_delete_lines(s->grid, s->cy, ny); grid_view_delete_lines(s->grid, s->cy, ny);
@@ -708,7 +674,7 @@ screen_write_clearline(struct screen_write_ctx *ctx)
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
@@ -723,7 +689,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx; u_int sx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
sx = screen_size_x(s); sx = screen_size_x(s);
@@ -741,7 +707,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx; u_int sx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
sx = screen_size_x(s); sx = screen_size_x(s);
@@ -787,7 +753,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx)
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
if (s->cy == s->rupper) if (s->cy == s->rupper)
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
@@ -843,15 +809,15 @@ screen_write_mousemode(struct screen_write_ctx *ctx, int state)
s->mode &= ~MODE_MOUSE; s->mode &= ~MODE_MOUSE;
} }
/* Line feed. */ /* Line feed (down with scroll). */
void void
screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct grid_line *gl; struct grid_line *gl;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
gl = &s->grid->linedata[s->grid->hsize + s->cy]; gl = &s->grid->linedata[s->grid->hsize + s->cy];
if (wrapped) if (wrapped)
@@ -864,7 +830,6 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
else if (s->cy < screen_size_y(s) - 1) else if (s->cy < screen_size_y(s) - 1)
s->cy++; s->cy++;
ttyctx.num = wrapped;
tty_write(tty_cmd_linefeed, &ttyctx); tty_write(tty_cmd_linefeed, &ttyctx);
} }
@@ -909,7 +874,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx, sy; u_int sx, sy;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
sx = screen_size_x(s); sx = screen_size_x(s);
sy = screen_size_y(s); sy = screen_size_y(s);
@@ -929,7 +894,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx; u_int sx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
sx = screen_size_x(s); sx = screen_size_x(s);
@@ -950,7 +915,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx)
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx);
grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s));
@@ -959,15 +924,15 @@ screen_write_clearscreen(struct screen_write_ctx *ctx)
/* Write cell data. */ /* Write cell data. */
void void
screen_write_cell(struct screen_write_ctx *ctx, screen_write_cell(
const struct grid_cell *gc, const struct utf8_data *utf8data) struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct grid *gd = s->grid; struct grid *gd = s->grid;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
struct grid_utf8 gu; struct grid_utf8 gu, *tmp_gu;
u_int width, xx; u_int width, xx, i;
struct grid_cell tmp_gc, *tmp_gcp; struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp;
int insert = 0; int insert = 0;
/* Ignore padding. */ /* Ignore padding. */
@@ -975,33 +940,48 @@ screen_write_cell(struct screen_write_ctx *ctx,
return; return;
/* Find character width. */ /* Find character width. */
if (gc->flags & GRID_FLAG_UTF8) if (gc->flags & GRID_FLAG_UTF8) {
width = utf8data->width; width = utf8_width(udata);
else
gu.width = width;
memcpy(&gu.data, udata, sizeof gu.data);
} else
width = 1; width = 1;
/* /* If the width is zero, combine onto the previous character. */
* 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;
/*
* If the width is zero, combine onto the previous character, if
* there is space.
*/
if (width == 0) { if (width == 0) {
if (screen_write_combine(ctx, utf8data) == 0) { if (s->cx == 0)
screen_write_initctx(ctx, &ttyctx, 0); return;
tty_write(tty_cmd_utf8character, &ttyctx); 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);
for (i = 0; i < UTF8_SIZE; i++) {
if (tmp_gu->data[i] == 0xff)
break;
}
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; return;
} }
/* Initialise the redraw context, saving the last cell. */ /* If the character is wider than the screen, don't print it. */
screen_write_initctx(ctx, &ttyctx, 1); if (width > screen_size_x(s)) {
memcpy(&tmp_gc, gc, sizeof tmp_gc);
tmp_gc.data = '_';
width = 1;
gc = &tmp_gc;
}
/* If in insert mode, make space for the cells. */ /* If in insert mode, make space for the cells. */
if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) { if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) {
@@ -1012,8 +992,8 @@ screen_write_cell(struct screen_write_ctx *ctx,
/* Check this will fit on the current line and wrap if not. */ /* Check this will fit on the current line and wrap if not. */
if (s->cx > screen_size_x(s) - width) { if (s->cx > screen_size_x(s) - width) {
screen_write_carriagereturn(ctx);
screen_write_linefeed(ctx, 1); screen_write_linefeed(ctx, 1);
s->cx = 0; /* carriage return */
} }
/* Sanity checks. */ /* Sanity checks. */
@@ -1035,17 +1015,11 @@ screen_write_cell(struct screen_write_ctx *ctx,
/* Set the cell. */ /* Set the cell. */
grid_view_set_cell(gd, s->cx, s->cy, gc); 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); grid_view_set_utf8(gd, s->cx, s->cy, &gu);
}
/* Move the cursor. */ /* Move the cursor. */
screen_write_initctx(ctx, &ttyctx);
s->cx += width; s->cx += width;
/* Draw to the screen if necessary. */ /* Draw to the screen if necessary. */
@@ -1055,13 +1029,11 @@ screen_write_cell(struct screen_write_ctx *ctx,
} }
ttyctx.utf8 = &gu; ttyctx.utf8 = &gu;
if (screen_check_selection(s, s->cx - width, s->cy)) { if (screen_check_selection(s, s->cx - width, s->cy)) {
memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2);
tmp_gc.data = gc->data; tmp_gc2.data = gc->data;
tmp_gc.flags = gc->flags & tmp_gc2.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
~(GRID_FLAG_FG256|GRID_FLAG_BG256); tmp_gc2.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256);
tmp_gc.flags |= s->sel.cell.flags & ttyctx.cell = &tmp_gc2;
(GRID_FLAG_FG256|GRID_FLAG_BG256);
ttyctx.cell = &tmp_gc;
tty_write(tty_cmd_cell, &ttyctx); tty_write(tty_cmd_cell, &ttyctx);
} else { } else {
ttyctx.cell = gc; ttyctx.cell = gc;
@@ -1069,55 +1041,6 @@ screen_write_cell(struct screen_write_ctx *ctx,
} }
} }
/* 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 * 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 * cell on the screen, so following cells must not be drawn by marking them as

View File

@@ -1,768 +0,0 @@
/* $Id: server-client.c,v 1.12 2009-11-04 22:46:25 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#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 */
}

View File

@@ -1,4 +1,4 @@
/* $Id: server-fn.c,v 1.94 2009-10-12 00:37:41 tcunha Exp $ */ /* $Id: server-fn.c,v 1.87 2009-09-13 20:37:37 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,12 +18,15 @@
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
int server_lock_callback(void *, const char *);
void void
server_fill_environ(struct session *s, struct environ *env) server_fill_environ(struct session *s, struct environ *env)
{ {
@@ -104,19 +107,6 @@ server_redraw_session(struct session *s)
} }
} }
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 void
server_status_session(struct session *s) server_status_session(struct session *s)
{ {
@@ -132,19 +122,6 @@ server_status_session(struct session *s)
} }
} }
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 void
server_redraw_window(struct window *w) server_redraw_window(struct window *w)
{ {
@@ -183,52 +160,117 @@ server_status_window(struct window *w)
void void
server_lock(void) server_lock(void)
{ {
struct client *c; struct client *c;
u_int i; 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;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL) if (c == NULL || c->session == NULL)
continue; continue;
server_lock_client(c);
status_prompt_clear(c);
status_prompt_set(c,
"Password:", server_lock_callback, NULL, c, PROMPT_HIDDEN);
server_redraw_client(c);
} }
server_locked = 1;
} }
void int
server_lock_session(struct session *s) server_lock_callback(unused void *data, const char *s)
{
return (server_unlock(s));
}
int
server_unlock(const char *s)
{ {
struct client *c; struct client *c;
#ifdef HAVE_LOGIN_CAP
login_cap_t *lc;
#endif
u_int i; 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++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL || c->session != s) if (c == NULL)
continue; continue;
server_lock_client(c);
status_prompt_clear(c);
server_redraw_client(c);
} }
}
void server_locked = 0;
server_lock_client(struct client *c) password_failures = 0;
{ password_backoff = 0;
const char *cmd; return (0);
size_t cmdlen;
struct msg_lock_data lockdata;
if (c->flags & CLIENT_SUSPENDED) wrong:
return; password_failures++;
password_backoff = 0;
cmd = options_get_string(&c->session->options, "lock-command"); for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); c = ARRAY_ITEM(&clients, i);
if (cmdlen >= sizeof lockdata.cmd) if (c == NULL || c->prompt_buffer == NULL)
return; continue;
tty_stop_tty(&c->tty); *c->prompt_buffer = '\0';
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); c->prompt_index = 0;
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); server_redraw_client(c);
}
c->flags |= CLIENT_SUSPENDED; /*
server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); * 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);
} }
void void
@@ -246,86 +288,11 @@ server_kill_window(struct window *w)
continue; continue;
if (session_detach(s, wl)) if (session_detach(s, wl))
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); server_destroy_session(s);
TAILQ_REMOVE(&session_groups, sg, entry); else
xfree(sg); server_redraw_session(s);
} }
recalculate_sizes();
} }
void void
@@ -354,7 +321,7 @@ server_set_identify(struct client *c)
tv.tv_usec = (delay % 1000) * 1000L; tv.tv_usec = (delay % 1000) * 1000L;
if (gettimeofday(&c->identify_timer, NULL) != 0) if (gettimeofday(&c->identify_timer, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
timeradd(&c->identify_timer, &tv, &c->identify_timer); timeradd(&c->identify_timer, &tv, &c->identify_timer);
c->flags |= CLIENT_IDENTIFY; c->flags |= CLIENT_IDENTIFY;

View File

@@ -1,73 +0,0 @@
/* $Id: server-job.c,v 1.3 2009-11-02 21:38:26 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#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;
}
}
}
}

292
server-msg.c Normal file
View File

@@ -0,0 +1,292 @@
/* $Id: server-msg.c,v 1.84 2009-09-15 23:52:30 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#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);
}

View File

@@ -1,341 +0,0 @@
/* $Id: server-window.c,v 1.4 2009-11-04 22:47:29 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#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();
}

1201
server.c

File diff suppressed because it is too large Load Diff

197
session.c
View File

@@ -1,4 +1,4 @@
/* $Id: session.c,v 1.70 2009-11-04 22:42:31 tcunha Exp $ */ /* $Id: session.c,v 1.66 2009-09-16 12:36:27 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -22,14 +22,12 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <time.h>
#include "tmux.h" #include "tmux.h"
/* Global session list. */ /* Global session list. */
struct sessions sessions; struct sessions sessions;
struct sessions dead_sessions; struct sessions dead_sessions;
struct session_groups session_groups;
struct winlink *session_next_activity(struct session *, struct winlink *); struct winlink *session_next_activity(struct session *, struct winlink *);
struct winlink *session_previous_activity(struct session *, struct winlink *); struct winlink *session_previous_activity(struct session *, struct winlink *);
@@ -126,12 +124,11 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->references = 0; s->references = 0;
s->flags = 0; s->flags = 0;
if (gettimeofday(&s->creation_time, NULL) != 0) if (gettimeofday(&s->tv, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time);
s->curw = NULL; s->curw = NULL;
TAILQ_INIT(&s->lastw); SLIST_INIT(&s->lastw);
RB_INIT(&s->windows); RB_INIT(&s->windows);
SLIST_INIT(&s->alerts); SLIST_INIT(&s->alerts);
@@ -164,14 +161,11 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->name = xstrdup(name); s->name = xstrdup(name);
else else
xasprintf(&s->name, "%u", i); xasprintf(&s->name, "%u", i);
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
if (cmd != NULL) { session_destroy(s);
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { return (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); log_debug("session %s created", s->name);
@@ -195,14 +189,13 @@ session_destroy(struct session *s)
if (s->tio != NULL) if (s->tio != NULL)
xfree(s->tio); xfree(s->tio);
session_group_remove(s);
session_alert_cancel(s, NULL); session_alert_cancel(s, NULL);
environ_free(&s->environ); environ_free(&s->environ);
options_free(&s->options); options_free(&s->options);
paste_free_stack(&s->buffers); paste_free_stack(&s->buffers);
while (!TAILQ_EMPTY(&s->lastw)) while (!SLIST_EMPTY(&s->lastw))
winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); winlink_stack_remove(&s->lastw, SLIST_FIRST(&s->lastw));
while (!RB_EMPTY(&s->windows)) while (!RB_EMPTY(&s->windows))
winlink_remove(&s->windows, RB_ROOT(&s->windows)); winlink_remove(&s->windows, RB_ROOT(&s->windows));
@@ -272,7 +265,6 @@ session_attach(struct session *s, struct window *w, int idx, char **cause)
if ((wl = winlink_add(&s->windows, w, idx)) == NULL) if ((wl = winlink_add(&s->windows, w, idx)) == NULL)
xasprintf(cause, "index in use: %d", idx); xasprintf(cause, "index in use: %d", idx);
session_group_synchronize_from(s);
return (wl); return (wl);
} }
@@ -287,7 +279,6 @@ session_detach(struct session *s, struct winlink *wl)
session_alert_cancel(s, wl); session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl); winlink_remove(&s->windows, wl);
session_group_synchronize_from(s);
if (RB_EMPTY(&s->windows)) { if (RB_EMPTY(&s->windows)) {
session_destroy(s); session_destroy(s);
return (1); return (1);
@@ -414,7 +405,7 @@ session_last(struct session *s)
{ {
struct winlink *wl; struct winlink *wl;
wl = TAILQ_FIRST(&s->lastw); wl = SLIST_FIRST(&s->lastw);
if (wl == NULL) if (wl == NULL)
return (-1); return (-1);
if (wl == s->curw) if (wl == s->curw)
@@ -426,169 +417,3 @@ session_last(struct session *s)
session_alert_cancel(s, wl); session_alert_cancel(s, wl);
return (0); 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);
}
}

129
status.c
View File

@@ -1,4 +1,4 @@
/* $Id: status.c,v 1.125 2009-11-04 23:12:32 tcunha Exp $ */ /* $Id: status.c,v 1.118 2009-09-11 14:13:52 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,8 +29,7 @@
#include "tmux.h" #include "tmux.h"
char *status_job(struct client *, char **); char *status_replace_popen(char **);
void status_job_callback(struct job *);
size_t status_width(struct winlink *); size_t status_width(struct winlink *);
char *status_print(struct session *, struct winlink *, struct grid_cell *); char *status_print(struct session *, struct winlink *, struct grid_cell *);
@@ -65,7 +64,7 @@ status_redraw(struct client *c)
screen_init(&c->status, c->tty.sx, 1, 0); screen_init(&c->status, c->tty.sx, 1, 0);
if (gettimeofday(&c->status_timer, NULL) != 0) if (gettimeofday(&c->status_timer, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
memcpy(&stdgc, &grid_default_cell, sizeof gc); memcpy(&stdgc, &grid_default_cell, sizeof gc);
colour_set_fg(&stdgc, options_get_number(&s->options, "status-fg")); colour_set_fg(&stdgc, options_get_number(&s->options, "status-fg"));
colour_set_bg(&stdgc, options_get_number(&s->options, "status-bg")); colour_set_bg(&stdgc, options_get_number(&s->options, "status-bg"));
@@ -105,14 +104,14 @@ status_redraw(struct client *c)
utf8flag = options_get_number(&s->options, "status-utf8"); utf8flag = options_get_number(&s->options, "status-utf8");
/* Work out the left and right strings. */ /* Work out the left and right strings. */
left = status_replace(c, options_get_string( left = status_replace(s, options_get_string(
&s->options, "status-left"), c->status_timer.tv_sec); &s->options, "status-left"), c->status_timer.tv_sec);
llen = options_get_number(&s->options, "status-left-length"); llen = options_get_number(&s->options, "status-left-length");
llen2 = screen_write_cstrlen(utf8flag, "%s", left); llen2 = screen_write_cstrlen(utf8flag, "%s", left);
if (llen2 < llen) if (llen2 < llen)
llen = llen2; llen = llen2;
right = status_replace(c, options_get_string( right = status_replace(s, options_get_string(
&s->options, "status-right"), c->status_timer.tv_sec); &s->options, "status-right"), c->status_timer.tv_sec);
rlen = options_get_number(&s->options, "status-right-length"); rlen = options_get_number(&s->options, "status-right-length");
rlen2 = screen_write_cstrlen(utf8flag, "%s", right); rlen2 = screen_write_cstrlen(utf8flag, "%s", right);
@@ -318,17 +317,15 @@ out:
} }
char * char *
status_replace(struct client *c, const char *fmt, time_t t) status_replace(struct session *s, const char *fmt, time_t t)
{ {
struct session *s = c->session;
struct winlink *wl = s->curw; struct winlink *wl = s->curw;
static char out[BUFSIZ]; static char out[BUFSIZ];
char in[BUFSIZ], tmp[256], ch, *iptr, *optr, *ptr, *endptr; char in[BUFSIZ], tmp[256], ch, *iptr, *optr, *ptr, *endptr;
char *savedptr; /* freed at end of each loop */ char *savedptr;
size_t len; size_t len;
long n; long n;
strftime(in, sizeof in, fmt, localtime(&t)); strftime(in, sizeof in, fmt, localtime(&t));
in[(sizeof in) - 1] = '\0'; in[(sizeof in) - 1] = '\0';
@@ -355,7 +352,7 @@ status_replace(struct client *c, const char *fmt, time_t t)
switch (*iptr++) { switch (*iptr++) {
case '(': case '(':
if (ptr == NULL) { if (ptr == NULL) {
ptr = status_job(c, &iptr); ptr = status_replace_popen(&iptr);
if (ptr == NULL) if (ptr == NULL)
break; break;
savedptr = ptr; savedptr = ptr;
@@ -364,7 +361,7 @@ status_replace(struct client *c, const char *fmt, time_t t)
case 'H': case 'H':
if (ptr == NULL) { if (ptr == NULL) {
if (gethostname(tmp, sizeof tmp) != 0) if (gethostname(tmp, sizeof tmp) != 0)
fatal("gethostname failed"); fatal("gethostname");
ptr = tmp; ptr = tmp;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
@@ -377,8 +374,8 @@ status_replace(struct client *c, const char *fmt, time_t t)
case 'P': case 'P':
if (ptr == NULL) { if (ptr == NULL) {
xsnprintf(tmp, sizeof tmp, "%u", xsnprintf(tmp, sizeof tmp, "%u",
window_pane_index(wl->window, window_pane_index(wl->window,
wl->window->active)); wl->window->active));
ptr = tmp; ptr = tmp;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
@@ -437,12 +434,12 @@ status_replace(struct client *c, const char *fmt, time_t t)
} }
char * char *
status_job(struct client *c, char **iptr) status_replace_popen(char **iptr)
{ {
struct job *job; FILE *f;
char *cmd; char *buf, *cmd, *ptr;
int lastesc; int lastesc;
size_t len; size_t len;
if (**iptr == '\0') if (**iptr == '\0')
return (NULL); return (NULL);
@@ -451,6 +448,8 @@ status_job(struct client *c, char **iptr)
return (NULL); return (NULL);
} }
buf = NULL;
cmd = xmalloc(strlen(*iptr) + 1); cmd = xmalloc(strlen(*iptr) + 1);
len = 0; len = 0;
@@ -465,44 +464,32 @@ status_job(struct client *c, char **iptr)
lastesc = 0; lastesc = 0;
cmd[len++] = **iptr; cmd[len++] = **iptr;
} }
if (**iptr == '\0') /* no terminating ) */ { if (**iptr == '\0') /* no terminating ) */
xfree(cmd); goto out;
return (NULL);
}
(*iptr)++; /* skip final ) */ (*iptr)++; /* skip final ) */
cmd[len] = '\0'; cmd[len] = '\0';
job = job_get(&c->status_jobs, cmd); if ((f = popen(cmd, "r")) == NULL)
if (job == NULL) { goto out;
job = job_add(&c->status_jobs,
JOB_PERSIST, c, cmd, status_job_callback, xfree, NULL); if ((buf = fgetln(f, &len)) == NULL) {
job_run(job); pclose(f);
goto out;
} }
if (job->data == NULL) if (buf[len - 1] == '\n') {
return (xstrdup("")); buf[len - 1] = '\0';
return (xstrdup(job->data)); buf = xstrdup(buf);
} } else {
ptr = xmalloc(len + 1);
memcpy(ptr, buf, len);
ptr[len] = '\0';
buf = ptr;
}
pclose(f);
void out:
status_job_callback(struct job *job) xfree(cmd);
{ return (buf);
char *buf;
size_t len;
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 size_t
@@ -529,7 +516,7 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc)
gc->attr = attr; gc->attr = attr;
flag = ' '; flag = ' ';
if (wl == TAILQ_FIRST(&s->lastw)) if (wl == SLIST_FIRST(&s->lastw))
flag = '-'; flag = '-';
if (wl == s->curw) { if (wl == s->curw) {
fg = options_get_number(oo, "window-status-current-fg"); fg = options_get_number(oo, "window-status-current-fg");
@@ -578,7 +565,7 @@ status_message_set(struct client *c, const char *fmt, ...)
tv.tv_usec = (delay % 1000) * 1000L; tv.tv_usec = (delay % 1000) * 1000L;
if (gettimeofday(&c->message_timer, NULL) != 0) if (gettimeofday(&c->message_timer, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
timeradd(&c->message_timer, &tv, &c->message_timer); timeradd(&c->message_timer, &tv, &c->message_timer);
c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE);
@@ -686,6 +673,8 @@ status_prompt_clear(struct client *c)
xfree(c->prompt_string); xfree(c->prompt_string);
c->prompt_string = NULL; c->prompt_string = NULL;
if (c->prompt_flags & PROMPT_HIDDEN)
memset(c->prompt_buffer, 0, strlen(c->prompt_buffer));
xfree(c->prompt_buffer); xfree(c->prompt_buffer);
c->prompt_buffer = NULL; c->prompt_buffer = NULL;
@@ -750,17 +739,26 @@ status_prompt_redraw(struct client *c)
left--; left--;
size = left; size = left;
} }
screen_write_puts( if (c->prompt_flags & PROMPT_HIDDEN)
&ctx, &gc, "%.*s", (int) left, c->prompt_buffer + off); size = 0;
else {
screen_write_puts(&ctx, &gc,
"%.*s", (int) left, c->prompt_buffer + off);
}
for (i = len + size; i < c->tty.sx; i++) for (i = len + size; i < c->tty.sx; i++)
screen_write_putc(&ctx, &gc, ' '); screen_write_putc(&ctx, &gc, ' ');
/* Draw a fake cursor. */ /* Draw a fake cursor. */
ch = ' '; ch = ' ';
screen_write_cursormove(&ctx, len + c->prompt_index - off, 0); if (c->prompt_flags & PROMPT_HIDDEN)
if (c->prompt_index < strlen(c->prompt_buffer)) screen_write_cursormove(&ctx, len, 0);
ch = c->prompt_buffer[c->prompt_index]; 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];
}
gc.attr ^= GRID_ATTR_REVERSE; gc.attr ^= GRID_ATTR_REVERSE;
screen_write_putc(&ctx, &gc, ch); screen_write_putc(&ctx, &gc, ch);
} }
@@ -892,8 +890,13 @@ status_prompt_key(struct client *c, int key)
} }
break; break;
case MODEKEYEDIT_HISTORYUP: case MODEKEYEDIT_HISTORYUP:
if (server_locked)
break;
if (ARRAY_LENGTH(&c->prompt_hdata) == 0) if (ARRAY_LENGTH(&c->prompt_hdata) == 0)
break; break;
if (c->prompt_flags & PROMPT_HIDDEN)
memset(c->prompt_buffer, 0, strlen(c->prompt_buffer));
xfree(c->prompt_buffer); xfree(c->prompt_buffer);
c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata, c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata,
@@ -905,6 +908,11 @@ status_prompt_key(struct client *c, int key)
c->flags |= CLIENT_STATUS; c->flags |= CLIENT_STATUS;
break; break;
case MODEKEYEDIT_HISTORYDOWN: 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); xfree(c->prompt_buffer);
if (c->prompt_hindex != 0) { if (c->prompt_hindex != 0) {
@@ -995,6 +1003,9 @@ status_prompt_key(struct client *c, int key)
void void
status_prompt_add_history(struct client *c) status_prompt_add_history(struct client *c)
{ {
if (server_locked)
return;
if (ARRAY_LENGTH(&c->prompt_hdata) > 0 && if (ARRAY_LENGTH(&c->prompt_hdata) > 0 &&
strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0) strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0)
return; return;

289
tmux.1
View File

@@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.199 2009-11-04 22:46:25 tcunha Exp $ .\" $Id: tmux.1,v 1.168 2009-09-19 18:53:01 tcunha Exp $
.\" .\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\" .\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: November 3 2009 $ .Dd $Mdocdate: September 18 2009 $
.Dt TMUX 1 .Dt TMUX 1
.Os .Os
.Sh NAME .Sh NAME
@@ -23,8 +23,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm tmux .Nm tmux
.Bk -words .Bk -words
.Op Fl 28lquv .Op Fl 28dlqUuv
.Op Fl c Ar shell-command
.Op Fl f Ar file .Op Fl f Ar file
.Op Fl L Ar socket-name .Op Fl L Ar socket-name
.Op Fl S Ar socket-path .Op Fl S Ar socket-path
@@ -102,15 +101,10 @@ to assume the terminal supports 256 colours.
Like Like
.Fl 2 , .Fl 2 ,
but indicates that the terminal supports 88 colours. but indicates that the terminal supports 88 colours.
.It Fl c Ar shell-command .It Fl d
Execute Force
.Ar shell-command
using the default shell.
If necessary, the
.Nm .Nm
server will be started to retrieve the to assume the terminal supports default colours.
.Ic default-shell
option.
.It Fl f Ar file .It Fl f Ar file
Specify an alternative configuration file. Specify an alternative configuration file.
By default, By default,
@@ -160,6 +154,8 @@ If
is specified, the default socket directory is not used and any is specified, the default socket directory is not used and any
.Fl L .Fl L
flag is ignored. flag is ignored.
.It Fl U
Unlock the server.
.It Fl u .It Fl u
.Nm .Nm
attempts to guess if the terminal is likely to support UTF-8 by checking the attempts to guess if the terminal is likely to support UTF-8 by checking the
@@ -282,7 +278,7 @@ pattern.
If a single match is found, it is used as the target session; multiple matches If a single match is found, it is used as the target session; multiple matches
produce an error. produce an error.
If a session is omitted, the current session is used if available; if no If a session is omitted, the current session is used if available; if no
current session is available, the most recently used is chosen. current session is available, the most recently created is chosen.
.Pp .Pp
.Ar target-window .Ar target-window
specifies a window in the form specifies a window in the form
@@ -341,6 +337,8 @@ rename-session -tfirst newname
set-window-option -t:0 monitor-activity on set-window-option -t:0 monitor-activity on
new-window ; split-window -d new-window ; split-window -d
bind-key D detach-client \e\; lock-server
.Ed .Ed
.Sh CLIENTS AND SESSIONS .Sh CLIENTS AND SESSIONS
The following commands are available: The following commands are available:
@@ -388,24 +386,10 @@ List the syntax of all commands supported by
.It Ic list-sessions .It Ic list-sessions
.D1 (alias: Ic ls ) .D1 (alias: Ic ls )
List all sessions managed by the server. 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 .It Xo Ic new-session
.Op Fl d .Op Fl d
.Op Fl n Ar window-name .Op Fl n Ar window-name
.Op Fl s Ar session-name .Op Fl s Ar session-name
.Op Fl t Ar target-session
.Op Ar command .Op Ar command
.Xc .Xc
.D1 (alias: Ic new ) .D1 (alias: Ic new )
@@ -422,26 +406,6 @@ are the name of and command to execute in the initial window.
If run from a terminal, any If run from a terminal, any
.Xr termios 4 .Xr termios 4
special characters are saved and used for new windows in the new session. 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 .It Ic refresh-client Op Fl t Ar target-client
.D1 (alias: Ic refresh ) .D1 (alias: Ic refresh )
Refresh the current client if bound to a key, or a single client if one is given Refresh the current client if bound to a key, or a single client if one is given
@@ -491,6 +455,12 @@ The others are:
This is entered when a command which produces output, such as This is entered when a command which produces output, such as
.Ic list-keys , .Ic list-keys ,
is executed from a key binding. 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 .It Em copy mode
This permits a section of a window or its history to be copied to a This permits a section of a window or its history to be copied to a
.Em paste buffer .Em paste buffer
@@ -498,7 +468,7 @@ for later insertion into another window.
This mode is entered with the This mode is entered with the
.Ic copy-mode .Ic copy-mode
command, bound to command, bound to
.Ql \&[ .Ql [
by default. by default.
.El .El
.Pp .Pp
@@ -507,7 +477,7 @@ The keys available depend on whether emacs or vi mode is selected
.Ic mode-keys .Ic mode-keys
option). option).
The following keys are supported as appropriate for the mode: The following keys are supported as appropriate for the mode:
.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXX" "emacs" -offset indent .Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
.It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Back to indentation" Ta "^" Ta "M-m"
.It Li "Clear selection" Ta "Escape" Ta "C-g" .It Li "Clear selection" Ta "Escape" Ta "C-g"
@@ -515,24 +485,17 @@ The following keys are supported as appropriate for the mode:
.It Li "Cursor down" Ta "j" Ta "Down" .It Li "Cursor down" Ta "j" Ta "Down"
.It Li "Cursor left" Ta "h" Ta "Left" .It Li "Cursor left" Ta "h" Ta "Left"
.It Li "Cursor right" Ta "l" Ta "Right" .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 "Cursor up" Ta "k" Ta "Up"
.It Li "Delete entire line" Ta "d" Ta "C-u" .It Li "Delete entire line" Ta "d" Ta "C-u"
.It Li "Delete to end of line" Ta "D" Ta "C-k" .It Li "Delete to end of line" Ta "D" Ta "C-k"
.It Li "End of line" Ta "$" Ta "C-e" .It Li "End of line" Ta "$" Ta "C-e"
.It Li "Goto line" Ta ":" Ta "g" .It Li "Goto line" Ta "g" 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 page" Ta "C-f" Ta "Page down"
.It Li "Next word" Ta "w" Ta "M-f" .It Li "Next word" Ta "w" Ta "M-f"
.It Li "Paste buffer" Ta "p" Ta "C-y" .It Li "Paste buffer" Ta "p" Ta "C-y"
.It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous page" Ta "C-u" Ta "Page up"
.It Li "Previous word" Ta "b" Ta "M-b" .It Li "Previous word" Ta "b" Ta "M-b"
.It Li "Quit mode" Ta "q" Ta "Escape" .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 again" Ta "n" Ta "n"
.It Li "Search backward" Ta "?" Ta "C-r" .It Li "Search backward" Ta "?" Ta "C-r"
.It Li "Search forward" Ta "/" Ta "C-s" .It Li "Search forward" Ta "/" Ta "C-s"
@@ -555,7 +518,7 @@ command) or in output mode; and
.Em vi-copy .Em vi-copy
and and
.Em emacs-copy .Em emacs-copy
used in copy mode. used in copy and scroll modes.
The tables may be viewed with the The tables may be viewed with the
.Ic list-keys .Ic list-keys
command and keys modified or removed with command and keys modified or removed with
@@ -576,6 +539,16 @@ Enter copy mode.
The The
.Fl u .Fl u
option scrolls one page up. 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 .El
.Pp .Pp
Each window displayed by Each window displayed by
@@ -723,7 +696,7 @@ to
keys. keys.
.It Ic down-pane Op Fl t Ar target-pane .It Ic down-pane Op Fl t Ar target-pane
.D1 (alias: Ic downp ) .D1 (alias: Ic downp )
Change the active pane to the next pane (higher index). Move down a pane.
.It Xo Ic find-window .It Xo Ic find-window
.Op Fl t Ar target-window .Op Fl t Ar target-window
.Ar match-string .Ar match-string
@@ -738,17 +711,10 @@ If only one window is matched, it'll be automatically selected, otherwise a
choice list is shown. choice list is shown.
This command only works from inside This command only works from inside
.Nm . .Nm .
.It Xo Ic kill-pane .It Ic kill-pane Op Fl t Ar target-pane
.Op Fl a
.Op Fl t Ar target-pane
.Xc
.D1 (alias: Ic killp ) .D1 (alias: Ic killp )
Destroy the given pane. Destroy the given pane.
If no panes remain in the containing window, it is also destroyed. 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 .It Ic kill-window Op Fl t Ar target-window
.D1 (alias: Ic killw ) .D1 (alias: Ic killw )
Kill the current window or the window at Kill the current window or the window at
@@ -783,10 +749,6 @@ exists, it is killed, otherwise an error is generated.
If If
.Fl d .Fl d
is given, the newly linked window is not selected. 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 .It Ic list-windows Op Fl t Ar target-session
.D1 (alias: Ic lsw ) .D1 (alias: Ic lsw )
List windows in the current session or in List windows in the current session or in
@@ -848,30 +810,6 @@ Move to the next window in the session.
If If
.Fl a .Fl a
is used, move to the next window with a bell, activity or content alert. 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 .It Xo Ic previous-window
.Op Fl a .Op Fl a
.Op Fl t Ar target-session .Op Fl t Ar target-session
@@ -1018,52 +956,9 @@ is specified and the window is linked to only one session, it is unlinked and
destroyed. destroyed.
.It Ic up-pane Op Fl t Ar target-pane .It Ic up-pane Op Fl t Ar target-pane
.D1 (alias: Ic upp ) .D1 (alias: Ic upp )
Change the active pane to the previous pane (lower index). Move up a pane.
.El .El
.Sh KEY BINDINGS .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: Commands related to key bindings are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Xo Ic bind-key .It Xo Ic bind-key
@@ -1076,6 +971,14 @@ Bind key
.Ar key .Ar key
to to
.Ar command . .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 By default (without
.Fl t ) .Fl t )
the primary key bindings are modified (those normally activated with the prefix the primary key bindings are modified (those normally activated with the prefix
@@ -1145,7 +1048,6 @@ characters.
All arguments are sent sequentially from first to last. All arguments are sent sequentially from first to last.
.It Ic send-prefix Op Fl t Ar target-pane .It Ic send-prefix Op Fl t Ar target-pane
Send the prefix key to a window as if it was pressed. 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 .It Xo Ic unbind-key
.Op Fl cn .Op Fl cn
.Op Fl t Ar key-table .Op Fl t Ar key-table
@@ -1310,33 +1212,17 @@ Set the maximum number of lines held in window history.
This setting applies only to new windows - existing window histories are not This setting applies only to new windows - existing window histories are not
resized and retain the limit at the point they were created. resized and retain the limit at the point they were created.
.It Ic lock-after-time Ar number .It Ic lock-after-time Ar number
Lock the session (like the Lock the server after
.Ic lock-session
command) after
.Ar number .Ar number
seconds of inactivity, or the entire server (all sessions) if the seconds of inactivity.
.Ic lock-server The default is off (set to 0).
option is set. This has no effect as a session option; it must be set as a global option using
The default is not to lock (set to 0). .Fl g .
.It Ic lock-command Ar command When passwords are entered incorrectly,
Command to run when locking each client. .Nm
The default is to run follows the behaviour of
.Xr lock 1 .Xr login 1
with and ignores further password attempts for an increasing timeout.
.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 .It Ic message-attr Ar attributes
Set status line message attributes, where Set status line message attributes, where
.Ar attributes .Ar attributes
@@ -1372,19 +1258,8 @@ from the 256-colour palette, or
.Ic default . .Ic default .
.It Ic message-fg Ar colour .It Ic message-fg Ar colour
Set status line message foreground colour. Set status line message foreground colour.
.It Xo Ic mouse-select-pane .It Ic prefix Ar key
.Op Ic on | off Set the current prefix key.
.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 .It Ic repeat-time Ar time
Allow multiple commands to be entered without pressing the prefix-key again Allow multiple commands to be entered without pressing the prefix-key again
in the specified in the specified
@@ -1473,31 +1348,22 @@ may contain any of the following special character sequences:
The #(command) form executes The #(command) form executes
.Ql command .Ql command
as a shell command and inserts the first line of its output. 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, #[attributes] allows a comma-separated list of attributes to be specified,
these may be these may be
.Ql fg=colour .Ql fg=colour
to set the foreground colour, to set the foreground colour,
.Ql bg=colour .Ql bg=colour
to set the background colour, the name of one of the attributes (listed under the to set the background colour, or one of the attributes described under the
.Ic message-attr .Ic message-attr
option) to turn an attribute on, or an attribute prefixed with option.
.Ql no
to turn one off, for example
.Ic nobright .
Examples are: Examples are:
.Bd -literal -offset indent .Bd -literal -offset indent
#(sysctl vm.loadavg) #(sysctl vm.loadavg)
#[fg=yellow,bold]#(apm -l)%%#[default] [#S] #[fg=yellow,bold]#(apm -l)%%#[default] [#S]
.Ed .Ed
.Pp .Pp
Where appropriate, special character sequences may be prefixed with a number to Where appropriate, these may be prefixed with a number to specify the maximum
specify the maximum length, for example length, for example
.Ql #24T . .Ql #24T .
.Pp .Pp
By default, UTF-8 in By default, UTF-8 in
@@ -1714,7 +1580,7 @@ Set window modes foreground colour.
.It Xo Ic mode-keys .It Xo Ic mode-keys
.Op Ic vi | emacs .Op Ic vi | emacs
.Xc .Xc
Use vi or emacs-style key bindings in copy and choice modes. Use vi or emacs-style key bindings in scroll, copy and choice modes.
Key bindings default to emacs. Key bindings default to emacs.
.Pp .Pp
.It Xo Ic mode-mouse .It Xo Ic mode-mouse
@@ -1749,11 +1615,6 @@ The window may be reactivated with the
.Ic respawn-window .Ic respawn-window
command. command.
.Pp .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 .It Xo Ic utf8
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -1840,7 +1701,6 @@ Commands to alter and view the environment are:
.Op Fl t Ar target-session .Op Fl t Ar target-session
.Ar name Op Ar value .Ar name Op Ar value
.Xc .Xc
.D1 (alias: Ic setenv )
Set or unset an environment variable. Set or unset an environment variable.
If If
.Fl g .Fl g
@@ -1857,7 +1717,6 @@ new process.
.Op Fl g .Op Fl g
.Op Fl t Ar target-session .Op Fl t Ar target-session
.Xc .Xc
.D1 (alias: Ic showenv )
Display the environment for Display the environment for
.Ar target-session .Ar target-session
or the global environment with or the global environment with
@@ -2099,21 +1958,25 @@ if
returns success. returns success.
.It Ic lock-server .It Ic lock-server
.D1 (alias: Ic lock ) .D1 (alias: Ic lock )
Lock each client individually by running the command specified by the Lock the server until a password is entered.
.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 .It Ic server-info
.D1 (alias: Ic info ) .D1 (alias: Ic info )
Show server information and terminal details. 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 .El
.Sh FILES .Sh FILES
.Bl -tag -width "/etc/tmux.confXXX" -compact .Bl -tag -width "/etc/tmux.confXXX" -compact

246
tmux.c
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.184 2009-11-04 23:09:09 tcunha Exp $ */ /* $Id: tmux.c,v 1.172 2009-09-19 18:53:01 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,8 +29,14 @@
#include "tmux.h" #include "tmux.h"
#if defined(DEBUG) && defined(__OpenBSD__) #ifdef DEBUG
extern char *malloc_options; /* 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
#endif #endif
volatile sig_atomic_t sigwinch; volatile sig_atomic_t sigwinch;
@@ -45,6 +51,13 @@ struct options global_s_options; /* session options */
struct options global_w_options; /* window options */ struct options global_w_options; /* window options */
struct environ global_environ; 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 debug_level;
int be_quiet; int be_quiet;
time_t start_time; time_t start_time;
@@ -52,10 +65,10 @@ char *socket_path;
int login_shell; int login_shell;
__dead void usage(void); __dead void usage(void);
void fill_session(struct msg_command_data *);
char *makesockpath(const char *); char *makesockpath(const char *);
int dispatch_imsg(struct imsgbuf *, const char *, int *); int prepare_unlock(enum msgtype *, void **, size_t *, int);
__dead void shell_exec(const char *, const char *); int prepare_cmd(enum msgtype *, void **, size_t *, int, char **);
int dispatch_imsg(struct client_ctx *, int *);
#ifndef HAVE_PROGNAME #ifndef HAVE_PROGNAME
char *__progname = (char *) "tmux"; char *__progname = (char *) "tmux";
@@ -65,7 +78,7 @@ __dead void
usage(void) usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"usage: %s [-28lquv] [-c shell-command] [-f file] [-L socket-name]\n" "usage: %s [-28dlqUuv] [-f file] [-L socket-name]\n"
" [-S socket-path] [command [flags]]\n", " [-S socket-path] [command [flags]]\n",
__progname); __progname);
exit(1); exit(1);
@@ -218,44 +231,6 @@ areshell(const char *shell)
return (0); 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 * char *
makesockpath(const char *label) makesockpath(const char *label)
{ {
@@ -284,32 +259,76 @@ makesockpath(const char *label)
return (path); return (path);
} }
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 int
main(int argc, char **argv) main(int argc, char **argv)
{ {
struct client_ctx cctx;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd *cmd; struct cmd *cmd;
struct pollfd pfd; struct pollfd pfd;
enum msgtype msg; enum msgtype msg;
struct passwd *pw; struct passwd *pw;
struct options *so, *wo; struct options *so, *wo;
struct keylist *keylist; char *s, *path, *label, *home, *cause, **var;
struct imsgbuf *ibuf; char cwd[MAXPATHLEN];
struct msg_command_data cmddata;
char *s, *shellcmd, *path, *label, *home, *cause;
char cwd[MAXPATHLEN], **var;
void *buf; void *buf;
size_t len; size_t len;
int nfds, retcode, opt, flags, cmdflags = 0; int retcode, opt, flags, unlock, cmdflags = 0;
int nfds;
#if defined(DEBUG) && defined(__OpenBSD__) unlock = flags = 0;
malloc_options = (char *) "AFGJPX"; label = path = NULL;
#endif
flags = 0;
shellcmd = label = path = NULL;
login_shell = (**argv == '-'); login_shell = (**argv == '-');
while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { while ((opt = getopt(argc, argv, "28df:lL:qS:uUv")) != -1) {
switch (opt) { switch (opt) {
case '2': case '2':
flags |= IDENTIFY_256COLOURS; flags |= IDENTIFY_256COLOURS;
@@ -319,10 +338,8 @@ main(int argc, char **argv)
flags |= IDENTIFY_88COLOURS; flags |= IDENTIFY_88COLOURS;
flags &= ~IDENTIFY_256COLOURS; flags &= ~IDENTIFY_256COLOURS;
break; break;
case 'c': case 'd':
if (shellcmd != NULL) flags |= IDENTIFY_HASDEFAULTS;
xfree(shellcmd);
shellcmd = xstrdup(optarg);
break; break;
case 'f': case 'f':
if (cfg_file != NULL) if (cfg_file != NULL)
@@ -348,19 +365,19 @@ main(int argc, char **argv)
case 'u': case 'u':
flags |= IDENTIFY_UTF8; flags |= IDENTIFY_UTF8;
break; break;
case 'U':
unlock = 1;
break;
case 'v': case 'v':
debug_level++; debug_level++;
break; break;
default: default:
usage(); usage();
} }
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (shellcmd != NULL && argc != 0)
usage();
log_open_tty(debug_level); log_open_tty(debug_level);
siginit(); siginit();
@@ -398,12 +415,10 @@ main(int argc, char **argv)
options_set_number(so, "display-time", 750); options_set_number(so, "display-time", 750);
options_set_number(so, "history-limit", 2000); options_set_number(so, "history-limit", 2000);
options_set_number(so, "lock-after-time", 0); 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-attr", 0);
options_set_number(so, "message-bg", 3); options_set_number(so, "message-bg", 3);
options_set_number(so, "message-fg", 0); options_set_number(so, "message-fg", 0);
options_set_number(so, "mouse-select-pane", 0); options_set_number(so, "prefix", '\002');
options_set_number(so, "repeat-time", 500); options_set_number(so, "repeat-time", 500);
options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-remain-on-exit", 0);
options_set_number(so, "set-titles", 0); options_set_number(so, "set-titles", 0);
@@ -433,11 +448,6 @@ main(int argc, char **argv)
options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-bell", 0);
options_set_number(so, "visual-content", 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); options_init(&global_w_options, NULL);
wo = &global_w_options; wo = &global_w_options;
options_set_number(wo, "aggressive-resize", 0); options_set_number(wo, "aggressive-resize", 0);
@@ -463,7 +473,6 @@ main(int argc, char **argv)
options_set_number(wo, "window-status-fg", 8); options_set_number(wo, "window-status-fg", 8);
options_set_number(wo, "xterm-keys", 0); options_set_number(wo, "xterm-keys", 0);
options_set_number(wo, "remain-on-exit", 0); options_set_number(wo, "remain-on-exit", 0);
options_set_number(wo, "synchronize-panes", 0);
if (flags & IDENTIFY_UTF8) { if (flags & IDENTIFY_UTF8) {
options_set_number(so, "status-utf8", 1); options_set_number(so, "status-utf8", 1);
@@ -509,27 +518,16 @@ main(int argc, char **argv)
} }
xfree(label); xfree(label);
if (shellcmd != NULL) { if (unlock) {
msg = MSG_SHELL; if (prepare_unlock(&msg, &buf, &len, argc) != 0)
buf = NULL; exit(1);
len = 0; } else {
} 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); exit(1);
}
msg = MSG_COMMAND;
buf = &cmddata;
len = sizeof cmddata;
} }
if (shellcmd != NULL) if (unlock)
cmdflags |= CMD_STARTSERVER; cmdflags &= ~CMD_STARTSERVER;
else if (argc == 0) /* new-session is the default */ else if (argc == 0) /* new-session is the default */
cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON;
else { else {
@@ -552,17 +550,19 @@ main(int argc, char **argv)
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }
if ((ibuf = client_init(path, cmdflags, flags)) == NULL) memset(&cctx, 0, sizeof cctx);
if (client_init(path, &cctx, cmdflags, flags) != 0)
exit(1); exit(1);
xfree(path); xfree(path);
imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); client_write_server(&cctx, msg, buf, len);
memset(buf, 0, len);
retcode = 0; retcode = 0;
for (;;) { for (;;) {
pfd.fd = ibuf->fd; pfd.fd = cctx.ibuf.fd;
pfd.events = POLLIN; pfd.events = POLLIN;
if (ibuf->w.queued != 0) if (cctx.ibuf.w.queued != 0)
pfd.events |= POLLOUT; pfd.events |= POLLOUT;
if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
@@ -576,13 +576,13 @@ main(int argc, char **argv)
if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
fatalx("socket error"); fatalx("socket error");
if (pfd.revents & POLLIN) { if (pfd.revents & POLLIN) {
if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0) if (dispatch_imsg(&cctx, &retcode) != 0)
break; break;
} }
if (pfd.revents & POLLOUT) { if (pfd.revents & POLLOUT) {
if (msgbuf_write(&ibuf->w) < 0) if (msgbuf_write(&cctx.ibuf.w) < 0)
fatalx("msgbuf_write failed"); fatalx("msgbuf_write failed");
} }
} }
@@ -594,18 +594,17 @@ main(int argc, char **argv)
} }
int int
dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) dispatch_imsg(struct client_ctx *cctx, int *retcode)
{ {
struct imsg imsg; struct imsg imsg;
ssize_t n, datalen; ssize_t n, datalen;
struct msg_print_data printdata; struct msg_print_data printdata;
struct msg_shell_data shelldata;
if ((n = imsg_read(ibuf)) == -1 || n == 0) if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0)
fatalx("imsg_read failed"); fatalx("imsg_read failed");
for (;;) { for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1) if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
fatalx("imsg_get failed"); fatalx("imsg_get failed");
if (n == 0) if (n == 0)
return (0); return (0);
@@ -633,7 +632,8 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_READY size"); fatalx("bad MSG_READY size");
client_main(); /* doesn't return */ *retcode = client_main(cctx);
return (-1);
case MSG_VERSION: case MSG_VERSION:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_VERSION size"); fatalx("bad MSG_VERSION size");
@@ -642,13 +642,6 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
*retcode = 1; *retcode = 1;
return (-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: default:
fatalx("unexpected message"); fatalx("unexpected message");
} }
@@ -656,26 +649,3 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
imsg_free(&imsg); 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");
}

403
tmux.h
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.496 2009-11-04 22:46:25 tcunha Exp $ */ /* $Id: tmux.h,v 1.443 2009-09-16 12:36:27 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -21,7 +21,7 @@
#include "config.h" #include "config.h"
#define PROTOCOL_VERSION 5 #define PROTOCOL_VERSION 1
#include <sys/param.h> #include <sys/param.h>
#include <sys/time.h> #include <sys/time.h>
@@ -58,14 +58,11 @@ extern char **environ;
#define NAME_INTERVAL 500 #define NAME_INTERVAL 500
/* Escape timer period, in milliseconds. */ /* Escape timer period, in milliseconds. */
#define ESCAPE_PERIOD 500 #define ESCAPE_PERIOD 250
/* Maximum poll timeout (when attached). */ /* Maximum poll timeout (when attached). */
#define POLL_TIMEOUT 50 #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 * Maximum sizes of strings in message data. Don't forget to bump
* PROTOCOL_VERSION if any of these change! * PROTOCOL_VERSION if any of these change!
@@ -164,23 +161,23 @@ enum key_code {
KEYC_LEFT, KEYC_LEFT,
KEYC_RIGHT, KEYC_RIGHT,
/* Numeric keypad. */ /* Numeric keypad. Numbered from top-left, KPY_X. */
KEYC_KP_SLASH, KEYC_KP0_1,
KEYC_KP_STAR, KEYC_KP0_2,
KEYC_KP_MINUS, KEYC_KP0_3,
KEYC_KP_SEVEN, KEYC_KP1_0,
KEYC_KP_EIGHT, KEYC_KP1_1,
KEYC_KP_NINE, KEYC_KP1_2,
KEYC_KP_PLUS, KEYC_KP1_3,
KEYC_KP_FOUR, KEYC_KP2_0,
KEYC_KP_FIVE, KEYC_KP2_1,
KEYC_KP_SIX, KEYC_KP2_2,
KEYC_KP_ONE, KEYC_KP3_0,
KEYC_KP_TWO, KEYC_KP3_1,
KEYC_KP_THREE, KEYC_KP3_2,
KEYC_KP_ENTER, KEYC_KP3_3,
KEYC_KP_ZERO, KEYC_KP4_0,
KEYC_KP_PERIOD, KEYC_KP4_2,
}; };
/* Termcap codes. */ /* Termcap codes. */
@@ -195,15 +192,9 @@ enum tty_code_code {
TTYC_CNORM, /* cursor_normal, ve */ TTYC_CNORM, /* cursor_normal, ve */
TTYC_COLORS, /* max_colors, Co */ TTYC_COLORS, /* max_colors, Co */
TTYC_CSR, /* change_scroll_region, cs */ TTYC_CSR, /* change_scroll_region, cs */
TTYC_CUB, /* parm_left_cursor, LE */
TTYC_CUB1, /* cursor_left, le */
TTYC_CUD, /* parm_down_cursor, DO */ TTYC_CUD, /* parm_down_cursor, DO */
TTYC_CUD1, /* cursor_down, do */ TTYC_CUD1, /* cursor_down, do */
TTYC_CUF, /* parm_right_cursor, RI */
TTYC_CUF1, /* cursor_right, nd */
TTYC_CUP, /* cursor_address, cm */ TTYC_CUP, /* cursor_address, cm */
TTYC_CUU, /* parm_up_cursor, UP */
TTYC_CUU1, /* cursor_up, up */
TTYC_DCH, /* parm_dch, DC */ TTYC_DCH, /* parm_dch, DC */
TTYC_DCH1, /* delete_character, dc */ TTYC_DCH1, /* delete_character, dc */
TTYC_DIM, /* enter_dim_mode, mh */ TTYC_DIM, /* enter_dim_mode, mh */
@@ -212,8 +203,6 @@ enum tty_code_code {
TTYC_EL, /* clr_eol, ce */ TTYC_EL, /* clr_eol, ce */
TTYC_EL1, /* clr_bol, cb */ TTYC_EL1, /* clr_bol, cb */
TTYC_ENACS, /* ena_acs, eA */ TTYC_ENACS, /* ena_acs, eA */
TTYC_HOME, /* cursor_home, ho */
TTYC_HPA, /* column_address, ch */
TTYC_ICH, /* parm_ich, IC */ TTYC_ICH, /* parm_ich, IC */
TTYC_ICH1, /* insert_character, ic */ TTYC_ICH1, /* insert_character, ic */
TTYC_IL, /* parm_insert_line, IL */ TTYC_IL, /* parm_insert_line, IL */
@@ -227,26 +216,8 @@ enum tty_code_code {
TTYC_KCUD1, /* key_down, kd */ TTYC_KCUD1, /* key_down, kd */
TTYC_KCUF1, /* key_right, kr */ TTYC_KCUF1, /* key_right, kr */
TTYC_KCUU1, /* key_up, ku */ TTYC_KCUU1, /* key_up, ku */
TTYC_KDC2,
TTYC_KDC3,
TTYC_KDC4,
TTYC_KDC5,
TTYC_KDC6,
TTYC_KDC7,
TTYC_KDCH1, /* key_dc, kD */ TTYC_KDCH1, /* key_dc, kD */
TTYC_KDN2,
TTYC_KDN3,
TTYC_KDN4,
TTYC_KDN5,
TTYC_KDN6,
TTYC_KDN7,
TTYC_KEND, /* key_end, ke */ TTYC_KEND, /* key_end, ke */
TTYC_KEND2,
TTYC_KEND3,
TTYC_KEND4,
TTYC_KEND5,
TTYC_KEND6,
TTYC_KEND7,
TTYC_KF1, /* key_f1, k1 */ TTYC_KF1, /* key_f1, k1 */
TTYC_KF10, /* key_f10, k; */ TTYC_KF10, /* key_f10, k; */
TTYC_KF11, /* key_f11, F1 */ TTYC_KF11, /* key_f11, F1 */
@@ -258,8 +229,8 @@ enum tty_code_code {
TTYC_KF17, /* key_f17, F7 */ TTYC_KF17, /* key_f17, F7 */
TTYC_KF18, /* key_f18, F8 */ TTYC_KF18, /* key_f18, F8 */
TTYC_KF19, /* key_f19, F9 */ TTYC_KF19, /* key_f19, F9 */
TTYC_KF2, /* key_f2, k2 */
TTYC_KF20, /* key_f20, F10 */ TTYC_KF20, /* key_f20, F10 */
TTYC_KF2, /* key_f2, k2 */
TTYC_KF3, /* key_f3, k3 */ TTYC_KF3, /* key_f3, k3 */
TTYC_KF4, /* key_f4, k4 */ TTYC_KF4, /* key_f4, k4 */
TTYC_KF5, /* key_f5, k5 */ TTYC_KF5, /* key_f5, k5 */
@@ -267,53 +238,11 @@ enum tty_code_code {
TTYC_KF7, /* key_f7, k7 */ TTYC_KF7, /* key_f7, k7 */
TTYC_KF8, /* key_f8, k8 */ TTYC_KF8, /* key_f8, k8 */
TTYC_KF9, /* key_f9, k9 */ TTYC_KF9, /* key_f9, k9 */
TTYC_KHOM2,
TTYC_KHOM3,
TTYC_KHOM4,
TTYC_KHOM5,
TTYC_KHOM6,
TTYC_KHOM7,
TTYC_KHOME, /* key_home, kh */ TTYC_KHOME, /* key_home, kh */
TTYC_KIC2,
TTYC_KIC3,
TTYC_KIC4,
TTYC_KIC5,
TTYC_KIC6,
TTYC_KIC7,
TTYC_KICH1, /* key_ic, kI */ TTYC_KICH1, /* key_ic, kI */
TTYC_KLFT2,
TTYC_KLFT3,
TTYC_KLFT4,
TTYC_KLFT5,
TTYC_KLFT6,
TTYC_KLFT7,
TTYC_KMOUS, /* key_mouse, Km */ TTYC_KMOUS, /* key_mouse, Km */
TTYC_KNP, /* key_npage, kN */ TTYC_KNP, /* key_npage, kN */
TTYC_KNXT2,
TTYC_KNXT3,
TTYC_KNXT4,
TTYC_KNXT5,
TTYC_KNXT6,
TTYC_KNXT7,
TTYC_KPP, /* key_ppage, kP */ 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_OP, /* orig_pair, op */
TTYC_REV, /* enter_reverse_mode, mr */ TTYC_REV, /* enter_reverse_mode, mr */
TTYC_RI, /* scroll_reverse, sr */ TTYC_RI, /* scroll_reverse, sr */
@@ -330,7 +259,6 @@ enum tty_code_code {
TTYC_SMKX, /* keypad_xmit, ks */ TTYC_SMKX, /* keypad_xmit, ks */
TTYC_SMSO, /* enter_standout_mode, so */ TTYC_SMSO, /* enter_standout_mode, so */
TTYC_SMUL, /* enter_underline_mode, us */ TTYC_SMUL, /* enter_underline_mode, us */
TTYC_VPA, /* row_address, cv */
TTYC_XENL, /* eat_newline_glitch, xn */ TTYC_XENL, /* eat_newline_glitch, xn */
}; };
#define NTTYCODE (TTYC_XENL + 1) #define NTTYCODE (TTYC_XENL + 1)
@@ -374,12 +302,10 @@ enum msgtype {
MSG_RESIZE, MSG_RESIZE,
MSG_SHUTDOWN, MSG_SHUTDOWN,
MSG_SUSPEND, MSG_SUSPEND,
MSG_UNLOCK,
MSG_VERSION, MSG_VERSION,
MSG_WAKEUP, MSG_WAKEUP,
MSG_ENVIRON, MSG_ENVIRON
MSG_UNLOCK,
MSG_LOCK,
MSG_SHELL
}; };
/* /*
@@ -400,6 +326,8 @@ struct msg_command_data {
}; };
struct msg_identify_data { struct msg_identify_data {
char tty[TTY_NAME_MAX];
char cwd[MAXPATHLEN]; char cwd[MAXPATHLEN];
char term[TERMINAL_LENGTH]; char term[TERMINAL_LENGTH];
@@ -407,21 +335,26 @@ struct msg_identify_data {
#define IDENTIFY_UTF8 0x1 #define IDENTIFY_UTF8 0x1
#define IDENTIFY_256COLOURS 0x2 #define IDENTIFY_256COLOURS 0x2
#define IDENTIFY_88COLOURS 0x4 #define IDENTIFY_88COLOURS 0x4
#define IDENTIFY_HASDEFAULTS 0x8
int flags; int flags;
u_int sx;
u_int sy;
}; };
struct msg_lock_data { struct msg_resize_data {
char cmd[COMMAND_LENGTH]; u_int sx;
u_int sy;
};
struct msg_unlock_data {
char pass[PASS_MAX];
}; };
struct msg_environ_data { struct msg_environ_data {
char var[ENVIRON_LENGTH]; char var[ENVIRON_LENGTH];
}; };
struct msg_shell_data {
char shell[MAXPATHLEN];
};
/* Mode key commands. */ /* Mode key commands. */
enum mode_key_cmd { enum mode_key_cmd {
MODEKEY_NONE, MODEKEY_NONE,
@@ -456,7 +389,6 @@ enum mode_key_cmd {
/* Copy keys. */ /* Copy keys. */
MODEKEYCOPY_BACKTOINDENTATION, MODEKEYCOPY_BACKTOINDENTATION,
MODEKEYCOPY_BOTTOMLINE,
MODEKEYCOPY_CANCEL, MODEKEYCOPY_CANCEL,
MODEKEYCOPY_CLEARSELECTION, MODEKEYCOPY_CLEARSELECTION,
MODEKEYCOPY_COPYSELECTION, MODEKEYCOPY_COPYSELECTION,
@@ -466,20 +398,16 @@ enum mode_key_cmd {
MODEKEYCOPY_HALFPAGEDOWN, MODEKEYCOPY_HALFPAGEDOWN,
MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_HALFPAGEUP,
MODEKEYCOPY_LEFT, MODEKEYCOPY_LEFT,
MODEKEYCOPY_MIDDLELINE,
MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTPAGE,
MODEKEYCOPY_NEXTWORD, MODEKEYCOPY_NEXTWORD,
MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSPAGE,
MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_PREVIOUSWORD,
MODEKEYCOPY_RIGHT, MODEKEYCOPY_RIGHT,
MODEKEYCOPY_SCROLLDOWN,
MODEKEYCOPY_SCROLLUP,
MODEKEYCOPY_SEARCHAGAIN, MODEKEYCOPY_SEARCHAGAIN,
MODEKEYCOPY_SEARCHDOWN, MODEKEYCOPY_SEARCHDOWN,
MODEKEYCOPY_SEARCHUP, MODEKEYCOPY_SEARCHUP,
MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTOFLINE,
MODEKEYCOPY_STARTSELECTION, MODEKEYCOPY_STARTSELECTION,
MODEKEYCOPY_TOPLINE,
MODEKEYCOPY_UP, MODEKEYCOPY_UP,
}; };
@@ -537,23 +465,6 @@ struct mode_key_table {
#define MODE_KKEYPAD 0x8 #define MODE_KKEYPAD 0x8
#define MODE_MOUSE 0x10 #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. */ /* Grid output. */
#if defined(DEBUG) && \ #if defined(DEBUG) && \
((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
@@ -593,6 +504,7 @@ struct grid_cell {
} __packed; } __packed;
/* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */ /* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */
#define UTF8_SIZE 8
struct grid_utf8 { struct grid_utf8 {
u_char width; u_char width;
u_char data[UTF8_SIZE]; u_char data[UTF8_SIZE];
@@ -630,14 +542,13 @@ struct options_entry {
enum { enum {
OPTIONS_STRING, OPTIONS_STRING,
OPTIONS_NUMBER, OPTIONS_NUMBER,
OPTIONS_DATA, OPTIONS_KEY,
} type; } type;
union {
char *str; char *string;
long long num; long long number;
void *data; int key;
} value;
void (*freefn)(void *);
SPLAY_ENTRY(options_entry) entry; SPLAY_ENTRY(options_entry) entry;
}; };
@@ -647,34 +558,6 @@ struct options {
struct options *parent; 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. */ /* Screen selection. */
struct screen_sel { struct screen_sel {
int flag; int flag;
@@ -749,7 +632,9 @@ struct input_ctx {
#define STRING_APPLICATION 1 #define STRING_APPLICATION 1
#define STRING_NAME 2 #define STRING_NAME 2
struct utf8_data utf8data; u_char utf8_buf[4];
u_int utf8_len;
u_int utf8_off;
u_char intermediate; u_char intermediate;
void *(*state)(u_char, struct input_ctx *); void *(*state)(u_char, struct input_ctx *);
@@ -764,14 +649,13 @@ struct input_ctx {
*/ */
struct client; struct client;
struct window; struct window;
struct mouse_event;
struct window_mode { struct window_mode {
struct screen *(*init)(struct window_pane *); struct screen *(*init)(struct window_pane *);
void (*free)(struct window_pane *); void (*free)(struct window_pane *);
void (*resize)(struct window_pane *, u_int, u_int); void (*resize)(struct window_pane *, u_int, u_int);
void (*key)(struct window_pane *, struct client *, int); void (*key)(struct window_pane *, struct client *, int);
void (*mouse)(struct window_pane *, void (*mouse)(struct window_pane *,
struct client *, struct mouse_event *); struct client *, u_char, u_char, u_char);
void (*timer)(struct window_pane *); void (*timer)(struct window_pane *);
}; };
@@ -801,10 +685,6 @@ struct window_pane {
struct input_ctx ictx; struct input_ctx ictx;
int pipe_fd;
struct buffer *pipe_buf;
size_t pipe_off;
struct screen *screen; struct screen *screen;
struct screen base; struct screen base;
@@ -854,10 +734,10 @@ struct winlink {
struct window *window; struct window *window;
RB_ENTRY(winlink) entry; RB_ENTRY(winlink) entry;
TAILQ_ENTRY(winlink) sentry; SLIST_ENTRY(winlink) sentry;
}; };
RB_HEAD(winlinks, winlink); RB_HEAD(winlinks, winlink);
TAILQ_HEAD(winlink_stack, winlink); SLIST_HEAD(winlink_stack, winlink);
/* Layout direction. */ /* Layout direction. */
enum layout_type { enum layout_type {
@@ -891,6 +771,7 @@ struct layout_cell {
struct paste_buffer { struct paste_buffer {
char *data; char *data;
size_t size; size_t size;
struct timeval tv;
}; };
ARRAY_DECL(paste_stack, struct paste_buffer *); ARRAY_DECL(paste_stack, struct paste_buffer *);
@@ -911,18 +792,9 @@ struct session_alert {
SLIST_ENTRY(session_alert) entry; 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 { struct session {
char *name; char *name;
struct timeval tv;
struct timeval creation_time;
struct timeval activity_time;
u_int sx; u_int sx;
u_int sy; u_int sy;
@@ -946,8 +818,6 @@ struct session {
struct environ environ; struct environ environ;
int references; int references;
TAILQ_ENTRY(session) gentry;
}; };
ARRAY_DECL(sessions, struct session *); ARRAY_DECL(sessions, struct session *);
@@ -969,9 +839,10 @@ struct tty_term {
struct tty_code codes[NTTYCODE]; struct tty_code codes[NTTYCODE];
#define TERM_256COLOURS 0x1 #define TERM_HASDEFAULTS 0x1
#define TERM_88COLOURS 0x2 #define TERM_256COLOURS 0x2
#define TERM_EARLYWRAP 0x4 #define TERM_88COLOURS 0x4
#define TERM_EARLYWRAP 0x8
int flags; int flags;
SLIST_ENTRY(tty_term) entry; SLIST_ENTRY(tty_term) entry;
@@ -1043,37 +914,21 @@ struct tty_ctx {
u_int orupper; u_int orupper;
u_int orlower; 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. */ /* Client connection. */
struct client { struct client {
struct imsgbuf ibuf; struct imsgbuf ibuf;
struct timeval creation_time;
struct timeval activity_time;
struct environ environ; struct environ environ;
char *title; char *title;
char *cwd; char *cwd;
struct tty tty; struct tty tty;
struct timeval status_timer;
struct timeval repeat_timer; struct timeval repeat_timer;
struct timeval status_timer;
struct jobs status_jobs;
struct screen status; struct screen status;
#define CLIENT_TERMINAL 0x1 #define CLIENT_TERMINAL 0x1
@@ -1100,7 +955,8 @@ struct client {
void (*prompt_freefn)(void *); void (*prompt_freefn)(void *);
void *prompt_data; void *prompt_data;
#define PROMPT_SINGLE 0x1 #define PROMPT_HIDDEN 0x1
#define PROMPT_SINGLE 0x2
int prompt_flags; int prompt_flags;
u_int prompt_hindex; u_int prompt_hindex;
@@ -1114,6 +970,19 @@ struct client {
}; };
ARRAY_DECL(clients, struct client *); 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. */ /* Key/command line command. */
struct cmd_ctx { struct cmd_ctx {
/* /*
@@ -1217,7 +1086,7 @@ struct set_option_entry {
enum { enum {
SET_OPTION_STRING, SET_OPTION_STRING,
SET_OPTION_NUMBER, SET_OPTION_NUMBER,
SET_OPTION_KEYS, SET_OPTION_KEY,
SET_OPTION_COLOUR, SET_OPTION_COLOUR,
SET_OPTION_ATTRIBUTES, SET_OPTION_ATTRIBUTES,
SET_OPTION_FLAG, SET_OPTION_FLAG,
@@ -1243,6 +1112,12 @@ extern struct options global_s_options;
extern struct options global_w_options; extern struct options global_w_options;
extern struct environ global_environ; extern struct environ global_environ;
extern char *cfg_file; 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 debug_level;
extern int be_quiet; extern int be_quiet;
extern time_t start_time; extern time_t start_time;
@@ -1285,29 +1160,11 @@ void options_free(struct options *);
struct options_entry *options_find1(struct options *, const char *); struct options_entry *options_find1(struct options *, const char *);
struct options_entry *options_find(struct options *, const char *); struct options_entry *options_find(struct options *, const char *);
void options_remove(struct options *, const char *); void options_remove(struct options *, const char *);
struct options_entry *printflike3 options_set_string( void printflike3 options_set_string(
struct options *, const char *, const char *, ...); struct options *, const char *, const char *, ...);
char *options_get_string(struct options *, const char *); char *options_get_string(struct options *, const char *);
struct options_entry *options_set_number( void options_set_number(struct options *, const char *, long long);
struct options *, const char *, long long);
long long options_get_number(struct options *, const char *); 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 */ /* environ.c */
int environ_cmp(struct environ_entry *, struct environ_entry *); int environ_cmp(struct environ_entry *, struct environ_entry *);
@@ -1322,24 +1179,21 @@ void environ_unset(struct environ *, const char *);
void environ_update(const char *, struct environ *, struct environ *); void environ_update(const char *, struct environ *, struct environ *);
/* tty.c */ /* tty.c */
void tty_raw(struct tty *, const char *);
u_char tty_get_acs(struct tty *, u_char); u_char tty_get_acs(struct tty *, u_char);
void tty_attributes(struct tty *, const struct grid_cell *); void tty_attributes(struct tty *, const struct grid_cell *);
void tty_reset(struct tty *); void tty_reset(struct tty *);
void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); void tty_region(struct tty *, u_int, u_int, u_int);
void tty_region(struct tty *, u_int, u_int); void tty_cursor(struct tty *, u_int, u_int, 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_putcode(struct tty *, enum tty_code_code);
void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode1(struct tty *, enum tty_code_code, int);
void tty_putcode2(struct tty *, enum tty_code_code, int, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int);
void tty_puts(struct tty *, const char *); void tty_puts(struct tty *, const char *);
void tty_putc(struct tty *, u_char); void tty_putc(struct tty *, u_char);
void tty_pututf8(struct tty *, const struct grid_utf8 *); void tty_pututf8(struct tty *, const struct grid_utf8 *);
void tty_init(struct tty *, int, char *); void tty_init(struct tty *, int, char *, char *);
void tty_resize(struct tty *);
void tty_start_tty(struct tty *); void tty_start_tty(struct tty *);
void tty_stop_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_set_title(struct tty *, const char *);
void tty_update_mode(struct tty *, int); void tty_update_mode(struct tty *, int);
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int);
@@ -1382,16 +1236,14 @@ int tty_keys_cmp(struct tty_key *, struct tty_key *);
RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp);
void tty_keys_init(struct tty *); void tty_keys_init(struct tty *);
void tty_keys_free(struct tty *); void tty_keys_free(struct tty *);
int tty_keys_next(struct tty *, int *, struct mouse_event *); int tty_keys_next(struct tty *, int *, u_char *);
/* options-cmd.c */ /* options-cmd.c */
const char *set_option_print(
const struct set_option_entry *, struct options_entry *);
void set_option_string(struct cmd_ctx *, void set_option_string(struct cmd_ctx *,
struct options *, const struct set_option_entry *, char *, int); struct options *, const struct set_option_entry *, char *, int);
void set_option_number(struct cmd_ctx *, void set_option_number(struct cmd_ctx *,
struct options *, const struct set_option_entry *, char *); struct options *, const struct set_option_entry *, char *);
void set_option_keys(struct cmd_ctx *, void set_option_key(struct cmd_ctx *,
struct options *, const struct set_option_entry *, char *); struct options *, const struct set_option_entry *, char *);
void set_option_colour(struct cmd_ctx *, void set_option_colour(struct cmd_ctx *,
struct options *, const struct set_option_entry *, char *); struct options *, const struct set_option_entry *, char *);
@@ -1426,7 +1278,6 @@ int cmd_exec(struct cmd *, struct cmd_ctx *);
void cmd_free(struct cmd *); void cmd_free(struct cmd *);
size_t cmd_print(struct cmd *, char *, size_t); size_t cmd_print(struct cmd *, char *, size_t);
struct session *cmd_current_session(struct cmd_ctx *); 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 client *cmd_find_client(struct cmd_ctx *, const char *);
struct session *cmd_find_session(struct cmd_ctx *, const char *); struct session *cmd_find_session(struct cmd_ctx *, const char *);
struct winlink *cmd_find_window( struct winlink *cmd_find_window(
@@ -1467,20 +1318,16 @@ extern const struct cmd_entry cmd_list_buffers_entry;
extern const struct cmd_entry cmd_list_clients_entry; 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_commands_entry;
extern const struct cmd_entry cmd_list_keys_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_sessions_entry;
extern const struct cmd_entry cmd_list_windows_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_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_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_move_window_entry;
extern const struct cmd_entry cmd_new_session_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_new_window_entry;
extern const struct cmd_entry cmd_next_layout_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_next_window_entry;
extern const struct cmd_entry cmd_paste_buffer_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_layout_entry;
extern const struct cmd_entry cmd_previous_window_entry; extern const struct cmd_entry cmd_previous_window_entry;
extern const struct cmd_entry cmd_refresh_client_entry; extern const struct cmd_entry cmd_refresh_client_entry;
@@ -1489,8 +1336,8 @@ extern const struct cmd_entry cmd_rename_window_entry;
extern const struct cmd_entry cmd_resize_pane_entry; extern const struct cmd_entry cmd_resize_pane_entry;
extern const struct cmd_entry cmd_respawn_window_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_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_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_layout_entry;
extern const struct cmd_entry cmd_select_pane_entry; extern const struct cmd_entry cmd_select_pane_entry;
extern const struct cmd_entry cmd_select_prompt_entry; extern const struct cmd_entry cmd_select_prompt_entry;
@@ -1501,6 +1348,7 @@ extern const struct cmd_entry cmd_server_info_entry;
extern const struct cmd_entry cmd_set_buffer_entry; 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_environment_entry;
extern const struct cmd_entry cmd_set_option_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_set_window_option_entry;
extern const struct cmd_entry cmd_show_buffer_entry; extern const struct cmd_entry cmd_show_buffer_entry;
extern const struct cmd_entry cmd_show_environment_entry; extern const struct cmd_entry cmd_show_environment_entry;
@@ -1554,8 +1402,14 @@ void cmd_buffer_free(struct cmd *);
size_t cmd_buffer_print(struct cmd *, char *, size_t); size_t cmd_buffer_print(struct cmd *, char *, size_t);
/* client.c */ /* client.c */
struct imsgbuf *client_init(char *, int, int); int client_init(char *, struct client_ctx *, int, int);
__dead void client_main(void); 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);
/* key-bindings.c */ /* key-bindings.c */
extern struct key_bindings key_bindings; extern struct key_bindings key_bindings;
@@ -1580,24 +1434,9 @@ const char *key_string_lookup_key(int);
extern struct clients clients; extern struct clients clients;
extern struct clients dead_clients; extern struct clients dead_clients;
int server_start(char *); int server_start(char *);
void server_poll_add(int, int, void (*)(int, int, void *), void *);
/* server-client.c */ /* server-msg.c */
void server_client_create(int); int server_msg_dispatch(struct client *);
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 */ /* server-fn.c */
void server_fill_environ(struct session *, struct environ *); void server_fill_environ(struct session *, struct environ *);
@@ -1609,27 +1448,19 @@ void server_write_session(
void server_redraw_client(struct client *); void server_redraw_client(struct client *);
void server_status_client(struct client *); void server_status_client(struct client *);
void server_redraw_session(struct session *); void server_redraw_session(struct session *);
void server_redraw_session_group(struct session *);
void server_status_session(struct session *); void server_status_session(struct session *);
void server_status_session_group(struct session *);
void server_redraw_window(struct window *); void server_redraw_window(struct window *);
void server_status_window(struct window *); void server_status_window(struct window *);
void server_lock(void); void server_lock(void);
void server_lock_session(struct session *);
void server_lock_client(struct client *);
int server_unlock(const char *); int server_unlock(const char *);
void server_kill_window(struct window *); 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_destroy_session(struct session *);
void server_set_identify(struct client *); void server_set_identify(struct client *);
void server_clear_identify(struct client *); void server_clear_identify(struct client *);
/* status.c */ /* status.c */
int status_redraw(struct client *); int status_redraw(struct client *);
char *status_replace(struct client *, const char *, time_t); char *status_replace(struct session *, const char *, time_t);
void printflike2 status_message_set(struct client *, const char *, ...); void printflike2 status_message_set(struct client *, const char *, ...);
void status_message_clear(struct client *); void status_message_clear(struct client *);
int status_message_redraw(struct client *); int status_message_redraw(struct client *);
@@ -1650,11 +1481,7 @@ void input_parse(struct window_pane *);
/* input-key.c */ /* input-key.c */
void input_key(struct window_pane *, int); void input_key(struct window_pane *, int);
void input_mouse(struct window_pane *, struct mouse_event *); void input_mouse(struct window_pane *, u_char, u_char, u_char);
/* xterm-keys.c */
char *xterm_keys_lookup(int);
int xterm_keys_find(const char *, size_t, size_t *);
/* colour.c */ /* colour.c */
void colour_set_fg(struct grid_cell *, int); void colour_set_fg(struct grid_cell *, int);
@@ -1673,11 +1500,9 @@ extern const struct grid_cell grid_default_cell;
struct grid *grid_create(u_int, u_int, u_int); struct grid *grid_create(u_int, u_int, u_int);
void grid_destroy(struct grid *); void grid_destroy(struct grid *);
int grid_compare(struct grid *, 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(struct grid *, u_int, u_int);
void grid_expand_line_utf8(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); 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); 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 *); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *);
@@ -1732,7 +1557,6 @@ void screen_write_putc(
struct screen_write_ctx *, struct grid_cell *, u_char); struct screen_write_ctx *, struct grid_cell *, u_char);
void screen_write_copy(struct screen_write_ctx *, void screen_write_copy(struct screen_write_ctx *,
struct screen *, u_int, u_int, u_int, u_int); 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_cursorup(struct screen_write_ctx *, u_int);
void screen_write_cursordown(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); void screen_write_cursorright(struct screen_write_ctx *, u_int);
@@ -1752,15 +1576,14 @@ void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int);
void screen_write_insertmode(struct screen_write_ctx *, int); void screen_write_insertmode(struct screen_write_ctx *, int);
void screen_write_mousemode(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_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_carriagereturn(struct screen_write_ctx *);
void screen_write_kcursormode(struct screen_write_ctx *, int); void screen_write_kcursormode(struct screen_write_ctx *, int);
void screen_write_kkeypadmode(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_clearendofscreen(struct screen_write_ctx *);
void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearstartofscreen(struct screen_write_ctx *);
void screen_write_clearscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *);
void screen_write_cell(struct screen_write_ctx *, void screen_write_cell(
const struct grid_cell *, const struct utf8_data *); struct screen_write_ctx *, const struct grid_cell *, u_char *);
/* screen-redraw.c */ /* screen-redraw.c */
void screen_redraw_screen(struct client *, int); void screen_redraw_screen(struct client *, int);
@@ -1800,7 +1623,6 @@ struct window *window_create(const char *, const char *, const char *,
const char *, struct environ *, struct termios *, const char *, struct environ *, struct termios *,
u_int, u_int, u_int, char **); u_int, u_int, u_int, char **);
void window_destroy(struct window *); 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 *); void window_set_active_pane(struct window *, struct window_pane *);
struct window_pane *window_add_pane(struct window *, u_int); struct window_pane *window_add_pane(struct window *, u_int);
void window_resize(struct window *, u_int, u_int); void window_resize(struct window *, u_int, u_int);
@@ -1821,7 +1643,7 @@ void window_pane_reset_mode(struct window_pane *);
void window_pane_parse(struct window_pane *); void window_pane_parse(struct window_pane *);
void window_pane_key(struct window_pane *, struct client *, int); void window_pane_key(struct window_pane *, struct client *, int);
void window_pane_mouse(struct window_pane *, void window_pane_mouse(struct window_pane *,
struct client *, struct mouse_event *); struct client *, u_char, u_char, u_char);
int window_pane_visible(struct window_pane *); int window_pane_visible(struct window_pane *);
char *window_pane_search( char *window_pane_search(
struct window_pane *, const char *, u_int *); struct window_pane *, const char *, u_int *);
@@ -1864,6 +1686,10 @@ extern const struct window_mode window_clock_mode;
extern const struct window_mode window_copy_mode; extern const struct window_mode window_copy_mode;
void window_copy_pageup(struct window_pane *); 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 */ /* window-more.c */
extern const struct window_mode window_more_mode; extern const struct window_mode window_more_mode;
void window_more_vadd(struct window_pane *, const char *, va_list); void window_more_vadd(struct window_pane *, const char *, va_list);
@@ -1884,7 +1710,6 @@ char *default_window_name(struct window *);
/* session.c */ /* session.c */
extern struct sessions sessions; extern struct sessions sessions;
extern struct sessions dead_sessions; extern struct sessions dead_sessions;
extern struct session_groups session_groups;
void session_alert_add(struct session *, struct window *, int); void session_alert_add(struct session *, struct window *, int);
void session_alert_cancel(struct session *, struct winlink *); void session_alert_cancel(struct session *, struct winlink *);
int session_alert_has(struct session *, struct winlink *, int); int session_alert_has(struct session *, struct winlink *, int);
@@ -1905,18 +1730,10 @@ int session_next(struct session *, int);
int session_previous(struct session *, int); int session_previous(struct session *, int);
int session_select(struct session *, int); int session_select(struct session *, int);
int session_last(struct session *); 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 */ /* utf8.c */
void utf8_build(void); void utf8_build(void);
int utf8_open(struct utf8_data *, u_char); int utf8_width(const u_char *);
int utf8_append(struct utf8_data *, u_char);
/* osdep-*.c */ /* osdep-*.c */
char *osdep_get_name(int, char *); char *osdep_get_name(int, char *);
@@ -1933,7 +1750,7 @@ void buffer_write8(struct buffer *, uint8_t);
uint8_t buffer_read8(struct buffer *); uint8_t buffer_read8(struct buffer *);
/* buffer-poll.c */ /* buffer-poll.c */
int buffer_poll(int, int, struct buffer *, struct buffer *); int buffer_poll(struct pollfd *, struct buffer *, struct buffer *);
/* log.c */ /* log.c */
void log_open_tty(int); void log_open_tty(int);

View File

@@ -1,6 +1,6 @@
# $Id: dist.mk,v 1.7 2009-11-05 12:32:46 tcunha Exp $ # $Id: dist.mk,v 1.5 2009-09-20 18:54:21 nicm Exp $
VERSION= 1.1 VERSION= 1.0
DISTDIR= tmux-${VERSION} DISTDIR= tmux-${VERSION}
DISTFILES= *.[ch] Makefile GNUmakefile configure tmux.1 \ DISTFILES= *.[ch] Makefile GNUmakefile configure tmux.1 \
@@ -19,7 +19,7 @@ dist:
-f ${DISTDIR}.tar.gz ${DISTFILES} -f ${DISTDIR}.tar.gz ${DISTFILES}
upload-index.html: update-index.html upload-index.html: update-index.html
scp www/index.html www/main.css www/images/*.png \ scp www/index.html www/images/*.png \
nicm,tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs nicm,tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
rm -f www/index.html www/images/small-* rm -f www/index.html www/images/small-*

View File

@@ -1,4 +1,4 @@
/* $Id: tty-keys.c,v 1.38 2009-10-28 23:05:01 tcunha Exp $ */ /* $Id: tty-keys.c,v 1.29 2009-07-28 22:37:02 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -25,12 +25,9 @@
#include "tmux.h" #include "tmux.h"
/*
* Handle keys input from the outside terminal.
*/
void tty_keys_add(struct tty *, const char *, int, int); void tty_keys_add(struct tty *, const char *, int, int);
int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *); 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 *);
struct tty_key_ent { struct tty_key_ent {
enum tty_code_code code; enum tty_code_code code;
@@ -42,145 +39,85 @@ struct tty_key_ent {
struct tty_key_ent tty_keys[] = { struct tty_key_ent tty_keys[] = {
/* Function keys. */ /* Function keys. */
{ TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, { TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL },
{ TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL }, { TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL },
{ TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL }, { TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL },
{ TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL }, { TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL },
{ TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL }, { TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL },
{ TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL }, { TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL },
{ TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL }, { TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL },
{ TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL }, { TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL },
{ TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL }, { TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL },
{ TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL }, { TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL },
{ TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL }, { TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL },
{ TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL }, { TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL },
{ TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL }, { TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL },
{ TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL }, { TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL },
{ TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL }, { TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL },
{ TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL }, { TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL },
{ TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL }, { TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL },
{ TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL }, { TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL },
{ TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL }, { TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL },
{ TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL }, { TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL },
{ TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL }, { TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL },
{ TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL }, { TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL },
{ TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL }, { TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL },
{ TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL }, { TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL },
{ TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL }, { TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL },
{ TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL }, { TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL },
{ TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL }, { TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL },
{ TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL },
/* Arrow keys. */ /* Arrow keys. */
{ 0, "\033OA", KEYC_UP, TTYKEY_RAW }, { 0, "\033OA", KEYC_UP, TTYKEY_RAW },
{ 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW },
{ 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW },
{ 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW },
{ 0, "\033[A", KEYC_UP, TTYKEY_RAW }, { 0, "\033[A", KEYC_UP, TTYKEY_RAW },
{ 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW },
{ 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW },
{ 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW },
{ TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL }, { 0, "\033Oa", KEYC_UP | KEYC_CTRL, TTYKEY_RAW },
{ TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL }, { 0, "\033Ob", KEYC_DOWN | KEYC_CTRL, TTYKEY_RAW },
{ TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL }, { 0, "\033Oc", KEYC_RIGHT | KEYC_CTRL, TTYKEY_RAW },
{ TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL }, { 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 },
/* Special-case arrow keys for rxvt until terminfo has kRIT5 etc. */ { TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL },
{ 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, { TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL },
{ 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, { TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL },
{ 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, { TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL },
{ 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. Just use the vt100 escape sequences here and always * Numeric keypad. termcap and terminfo are totally confusing for this.
* put the terminal into keypad_xmit mode. Translation of numbers * There are definitions for some keypad keys and for function keys,
* mode/applications mode is done in input-keys.c. * 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.
*/ */
{ 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, { 0, "\033Oo", KEYC_KP0_1, TTYKEY_RAW },
{ 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, { 0, "\033Oj", KEYC_KP0_2, TTYKEY_RAW },
{ 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, { 0, "\033Om", KEYC_KP0_3, TTYKEY_RAW },
{ 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, { 0, "\033Ow", KEYC_KP1_0, TTYKEY_RAW },
{ 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, { 0, "\033Ox", KEYC_KP1_1, TTYKEY_RAW },
{ 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, { 0, "\033Oy", KEYC_KP1_2, TTYKEY_RAW },
{ 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, { 0, "\033Ok", KEYC_KP1_3, TTYKEY_RAW },
{ 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, { 0, "\033Ot", KEYC_KP2_0, TTYKEY_RAW },
{ 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, { 0, "\033Ou", KEYC_KP2_1, TTYKEY_RAW },
{ 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, { 0, "\033Ov", KEYC_KP2_2, TTYKEY_RAW },
{ 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, { 0, "\033Oq", KEYC_KP3_0, TTYKEY_RAW },
{ 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, { 0, "\033Or", KEYC_KP3_1, TTYKEY_RAW },
{ 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, { 0, "\033Os", KEYC_KP3_2, TTYKEY_RAW },
{ 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, { 0, "\033OM", KEYC_KP3_3, TTYKEY_RAW },
{ 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, { 0, "\033Op", KEYC_KP4_0, TTYKEY_RAW },
{ 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, { 0, "\033On", KEYC_KP4_2, 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); RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp);
@@ -294,7 +231,7 @@ tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size)
} }
int int
tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse) tty_keys_next(struct tty *tty, int *key, u_char *mouse)
{ {
struct tty_key *tk; struct tty_key *tk;
struct timeval tv; struct timeval tv;
@@ -332,14 +269,14 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse)
} }
/* Not found. Is this a mouse key press? */ /* Not found. Is this a mouse key press? */
*key = tty_keys_mouse(buf, len, &size, mouse); *key = tty_keys_parse_mouse(tty, buf, len, &size, mouse);
if (*key != KEYC_NONE) { if (*key != KEYC_NONE) {
buffer_remove(tty->in, size); buffer_remove(tty->in, size);
goto found; goto found;
} }
/* Not found. Try to parse a key with an xterm-style modifier. */ /* Not found. Try to parse xterm-type arguments. */
*key = xterm_keys_find(buf, len, &size); *key = tty_keys_parse_xterm(tty, buf, len, &size);
if (*key != KEYC_NONE) { if (*key != KEYC_NONE) {
buffer_remove(tty->in, size); buffer_remove(tty->in, size);
goto found; goto found;
@@ -350,7 +287,7 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse)
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = ESCAPE_PERIOD * 1000L; tv.tv_usec = ESCAPE_PERIOD * 1000L;
if (gettimeofday(&tty->key_timer, NULL) != 0) if (gettimeofday(&tty->key_timer, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
timeradd(&tty->key_timer, &tv, &tty->key_timer); timeradd(&tty->key_timer, &tv, &tty->key_timer);
tty->flags |= TTY_ESCAPE; tty->flags |= TTY_ESCAPE;
@@ -380,7 +317,7 @@ tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse)
/* If the timer hasn't expired, keep waiting. */ /* If the timer hasn't expired, keep waiting. */
if (gettimeofday(&tv, NULL) != 0) if (gettimeofday(&tv, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
if (timercmp(&tty->key_timer, &tv, >)) if (timercmp(&tty->key_timer, &tv, >))
return (1); return (1);
@@ -394,7 +331,8 @@ found:
} }
int int
tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m) tty_keys_parse_mouse(
unused struct tty *tty, char *buf, size_t len, size_t *size, u_char *mouse)
{ {
/* /*
* Mouse sequences are \033[M followed by three characters indicating * Mouse sequences are \033[M followed by three characters indicating
@@ -406,13 +344,76 @@ tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m)
return (KEYC_NONE); return (KEYC_NONE);
*size = 6; *size = 6;
m->b = buf[3]; if (buf[3] < 32 || buf[4] < 33 || buf[5] < 33)
m->x = buf[4];
m->y = buf[5];
if (m->b < 32 || m->x < 33 || m->y < 33)
return (KEYC_NONE); return (KEYC_NONE);
m->b -= 32;
m->x -= 33; mouse[0] = buf[3] - 32;
m->y -= 33; mouse[1] = buf[4] - 33;
mouse[2] = buf[5] - 33;
return (KEYC_MOUSE); 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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: tty-term.c,v 1.35 2009-10-28 23:01:44 tcunha Exp $ */ /* $Id: tty-term.c,v 1.30 2009-08-23 11:50:39 nicm Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -32,8 +32,8 @@ char *tty_term_strip(const char *);
struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms); struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms);
struct tty_term_code_entry tty_term_codes[NTTYCODE] = { struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_ACSC, TTYCODE_STRING, "acsc" },
{ TTYC_AX, TTYCODE_FLAG, "AX" }, { TTYC_AX, TTYCODE_FLAG, "AX" },
{ TTYC_ACSC, TTYCODE_STRING, "acsc" },
{ TTYC_BEL, TTYCODE_STRING, "bel" }, { TTYC_BEL, TTYCODE_STRING, "bel" },
{ TTYC_BLINK, TTYCODE_STRING, "blink" }, { TTYC_BLINK, TTYCODE_STRING, "blink" },
{ TTYC_BOLD, TTYCODE_STRING, "bold" }, { TTYC_BOLD, TTYCODE_STRING, "bold" },
@@ -42,15 +42,9 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_CNORM, TTYCODE_STRING, "cnorm" }, { TTYC_CNORM, TTYCODE_STRING, "cnorm" },
{ TTYC_COLORS, TTYCODE_NUMBER, "colors" }, { TTYC_COLORS, TTYCODE_NUMBER, "colors" },
{ TTYC_CSR, TTYCODE_STRING, "csr" }, { TTYC_CSR, TTYCODE_STRING, "csr" },
{ TTYC_CUB, TTYCODE_STRING, "cub" },
{ TTYC_CUB1, TTYCODE_STRING, "cub1" },
{ TTYC_CUD, TTYCODE_STRING, "cud" }, { TTYC_CUD, TTYCODE_STRING, "cud" },
{ TTYC_CUD1, TTYCODE_STRING, "cud1" }, { TTYC_CUD1, TTYCODE_STRING, "cud1" },
{ TTYC_CUF, TTYCODE_STRING, "cuf" },
{ TTYC_CUF1, TTYCODE_STRING, "cuf1" },
{ TTYC_CUP, TTYCODE_STRING, "cup" }, { TTYC_CUP, TTYCODE_STRING, "cup" },
{ TTYC_CUU, TTYCODE_STRING, "cuu" },
{ TTYC_CUU1, TTYCODE_STRING, "cuu1" },
{ TTYC_DCH, TTYCODE_STRING, "dch" }, { TTYC_DCH, TTYCODE_STRING, "dch" },
{ TTYC_DCH1, TTYCODE_STRING, "dch1" }, { TTYC_DCH1, TTYCODE_STRING, "dch1" },
{ TTYC_DIM, TTYCODE_STRING, "dim" }, { TTYC_DIM, TTYCODE_STRING, "dim" },
@@ -59,8 +53,6 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_EL, TTYCODE_STRING, "el" }, { TTYC_EL, TTYCODE_STRING, "el" },
{ TTYC_EL1, TTYCODE_STRING, "el1" }, { TTYC_EL1, TTYCODE_STRING, "el1" },
{ TTYC_ENACS, TTYCODE_STRING, "enacs" }, { TTYC_ENACS, TTYCODE_STRING, "enacs" },
{ TTYC_HOME, TTYCODE_STRING, "home" },
{ TTYC_HPA, TTYCODE_STRING, "hpa" },
{ TTYC_ICH, TTYCODE_STRING, "ich" }, { TTYC_ICH, TTYCODE_STRING, "ich" },
{ TTYC_ICH1, TTYCODE_STRING, "ich1" }, { TTYC_ICH1, TTYCODE_STRING, "ich1" },
{ TTYC_IL, TTYCODE_STRING, "il" }, { TTYC_IL, TTYCODE_STRING, "il" },
@@ -74,26 +66,8 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_KCUD1, TTYCODE_STRING, "kcud1" }, { TTYC_KCUD1, TTYCODE_STRING, "kcud1" },
{ TTYC_KCUF1, TTYCODE_STRING, "kcuf1" }, { TTYC_KCUF1, TTYCODE_STRING, "kcuf1" },
{ TTYC_KCUU1, TTYCODE_STRING, "kcuu1" }, { 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_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_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_KF1, TTYCODE_STRING, "kf1" },
{ TTYC_KF10, TTYCODE_STRING, "kf10" }, { TTYC_KF10, TTYCODE_STRING, "kf10" },
{ TTYC_KF11, TTYCODE_STRING, "kf11" }, { TTYC_KF11, TTYCODE_STRING, "kf11" },
@@ -105,8 +79,8 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_KF17, TTYCODE_STRING, "kf17" }, { TTYC_KF17, TTYCODE_STRING, "kf17" },
{ TTYC_KF18, TTYCODE_STRING, "kf18" }, { TTYC_KF18, TTYCODE_STRING, "kf18" },
{ TTYC_KF19, TTYCODE_STRING, "kf19" }, { TTYC_KF19, TTYCODE_STRING, "kf19" },
{ TTYC_KF2, TTYCODE_STRING, "kf2" },
{ TTYC_KF20, TTYCODE_STRING, "kf20" }, { TTYC_KF20, TTYCODE_STRING, "kf20" },
{ TTYC_KF2, TTYCODE_STRING, "kf2" },
{ TTYC_KF3, TTYCODE_STRING, "kf3" }, { TTYC_KF3, TTYCODE_STRING, "kf3" },
{ TTYC_KF4, TTYCODE_STRING, "kf4" }, { TTYC_KF4, TTYCODE_STRING, "kf4" },
{ TTYC_KF5, TTYCODE_STRING, "kf5" }, { TTYC_KF5, TTYCODE_STRING, "kf5" },
@@ -114,53 +88,11 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_KF7, TTYCODE_STRING, "kf7" }, { TTYC_KF7, TTYCODE_STRING, "kf7" },
{ TTYC_KF8, TTYCODE_STRING, "kf8" }, { TTYC_KF8, TTYCODE_STRING, "kf8" },
{ TTYC_KF9, TTYCODE_STRING, "kf9" }, { 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_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_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_KMOUS, TTYCODE_STRING, "kmous" },
{ TTYC_KNP, TTYCODE_STRING, "knp" }, { 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_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_OP, TTYCODE_STRING, "op" },
{ TTYC_REV, TTYCODE_STRING, "rev" }, { TTYC_REV, TTYCODE_STRING, "rev" },
{ TTYC_RI, TTYCODE_STRING, "ri" }, { TTYC_RI, TTYCODE_STRING, "ri" },
@@ -177,7 +109,6 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_SMKX, TTYCODE_STRING, "smkx" }, { TTYC_SMKX, TTYCODE_STRING, "smkx" },
{ TTYC_SMSO, TTYCODE_STRING, "smso" }, { TTYC_SMSO, TTYCODE_STRING, "smso" },
{ TTYC_SMUL, TTYCODE_STRING, "smul" }, { TTYC_SMUL, TTYCODE_STRING, "smul" },
{ TTYC_VPA, TTYCODE_STRING, "vpa" },
{ TTYC_XENL, TTYCODE_FLAG, "xenl" }, { TTYC_XENL, TTYCODE_FLAG, "xenl" },
}; };
@@ -407,7 +338,22 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
goto error; goto error;
} }
/* Figure out if we have 256 or 88 colours. */ /*
* 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.
*/
if (tty_term_number(term, TTYC_COLORS) == 256) if (tty_term_number(term, TTYC_COLORS) == 256)
term->flags |= TERM_256COLOURS; term->flags |= TERM_256COLOURS;
if (tty_term_number(term, TTYC_COLORS) == 88) if (tty_term_number(term, TTYC_COLORS) == 88)
@@ -471,13 +417,13 @@ tty_term_string(struct tty_term *term, enum tty_code_code code)
const char * const char *
tty_term_string1(struct tty_term *term, enum tty_code_code code, int a) tty_term_string1(struct tty_term *term, enum tty_code_code code, int a)
{ {
return (tparm((char *) tty_term_string(term, code), a, 0, 0, 0, 0, 0, 0, 0, 0)); return (tparm((char *) tty_term_string(term, code), a));
} }
const char * const char *
tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b) 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, 0, 0, 0, 0, 0, 0, 0)); return (tparm((char *) tty_term_string(term, code), a, b));
} }
int int

756
tty.c

File diff suppressed because it is too large Load Diff

122
utf8.c
View File

@@ -1,4 +1,4 @@
/* $Id: utf8.c,v 1.11 2009-10-23 17:21:34 tcunha Exp $ */ /* $Id: utf8.c,v 1.9 2009-06-25 16:21:32 nicm Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -196,56 +196,9 @@ struct utf8_width_entry utf8_width_table[] = {
struct utf8_width_entry *utf8_width_root = NULL; struct utf8_width_entry *utf8_width_root = NULL;
int utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *); int utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *);
u_int utf8_combine(const struct utf8_data *); void utf8_print(struct utf8_width_entry *, int);
u_int utf8_width(const struct utf8_data *); u_int utf8_combine(const u_char *);
/*
* 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 int
utf8_overlap( utf8_overlap(
struct utf8_width_entry *item1, struct utf8_width_entry *item2) struct utf8_width_entry *item1, struct utf8_width_entry *item2)
@@ -261,7 +214,6 @@ utf8_overlap(
return (0); return (0);
} }
/* Build UTF-8 width tree. */
void void
utf8_build(void) utf8_build(void)
{ {
@@ -288,50 +240,52 @@ utf8_build(void)
} }
} }
/* Combine UTF-8 into 32-bit Unicode. */ void
u_int utf8_print(struct utf8_width_entry *node, int n)
utf8_combine(const struct utf8_data *utf8data)
{ {
u_int value; log_debug("%*s%04x -> %04x", n, " ", node->first, node->last);
if (node->left != NULL)
value = 0xff; utf8_print(node->left, n + 1);
switch (utf8data->size) { if (node->right != NULL)
case 1: utf8_print(node->right, n + 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 (value);
} }
/* Lookup width of UTF-8 data in tree. */
u_int u_int
utf8_width(const struct utf8_data *utf8data) utf8_combine(const u_char *data)
{
u_int uvalue;
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;
}
return (uvalue);
}
int
utf8_width(const u_char *udata)
{ {
struct utf8_width_entry *item; struct utf8_width_entry *item;
u_int value; u_int uvalue;
value = utf8_combine(utf8data); uvalue = utf8_combine(udata);
item = utf8_width_root; item = utf8_width_root;
while (item != NULL) { while (item != NULL) {
if (value < item->first) if (uvalue < item->first)
item = item->left; item = item->left;
else if (value > item->last) else if (uvalue > item->last)
item = item->right; item = item->right;
else else
return (item->width); return (item->width);

View File

@@ -1,4 +1,4 @@
/* $Id: window-choose.c,v 1.24 2009-10-12 00:18:19 tcunha Exp $ */ /* $Id: window-choose.c,v 1.23 2009-09-11 14:13:52 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,7 +27,7 @@ void window_choose_free(struct window_pane *);
void window_choose_resize(struct window_pane *, u_int, u_int); void window_choose_resize(struct window_pane *, u_int, u_int);
void window_choose_key(struct window_pane *, struct client *, int); void window_choose_key(struct window_pane *, struct client *, int);
void window_choose_mouse( void window_choose_mouse(
struct window_pane *, struct client *, struct mouse_event *); struct window_pane *, struct client *, u_char, u_char, u_char);
void window_choose_redraw_screen(struct window_pane *); void window_choose_redraw_screen(struct window_pane *);
void window_choose_write_line( void window_choose_write_line(
@@ -264,22 +264,22 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key)
} }
void void
window_choose_mouse( window_choose_mouse(struct window_pane *wp,
struct window_pane *wp, unused struct client *c, struct mouse_event *m) unused struct client *c, u_char b, u_char x, u_char y)
{ {
struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
struct window_choose_mode_item *item; struct window_choose_mode_item *item;
u_int idx; u_int idx;
if ((m->b & 3) == 3) if ((b & 3) == 3)
return; return;
if (m->x >= screen_size_x(s)) if (x >= screen_size_x(s))
return; return;
if (m->y >= screen_size_y(s)) if (y >= screen_size_y(s))
return; return;
idx = data->top + m->y; idx = data->top + y;
if (idx >= ARRAY_LENGTH(&data->list)) if (idx >= ARRAY_LENGTH(&data->list))
return; return;
data->selected = idx; data->selected = idx;

View File

@@ -1,4 +1,4 @@
/* $Id: window-copy.c,v 1.90 2009-10-23 17:17:20 tcunha Exp $ */ /* $Id: window-copy.c,v 1.86 2009-09-11 14:13:52 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,7 +29,7 @@ void window_copy_resize(struct window_pane *, u_int, u_int);
void window_copy_key(struct window_pane *, struct client *, int); void window_copy_key(struct window_pane *, struct client *, int);
int window_copy_key_input(struct window_pane *, int); int window_copy_key_input(struct window_pane *, int);
void window_copy_mouse( void window_copy_mouse(
struct window_pane *, struct client *, struct mouse_event *); struct window_pane *, struct client *, u_char, u_char, u_char);
void window_copy_redraw_lines(struct window_pane *, u_int, u_int); void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
void window_copy_redraw_screen(struct window_pane *); void window_copy_redraw_screen(struct window_pane *);
@@ -61,8 +61,8 @@ void window_copy_cursor_back_to_indentation(struct window_pane *);
void window_copy_cursor_end_of_line(struct window_pane *); void window_copy_cursor_end_of_line(struct window_pane *);
void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_left(struct window_pane *);
void window_copy_cursor_right(struct window_pane *); void window_copy_cursor_right(struct window_pane *);
void window_copy_cursor_up(struct window_pane *, int); void window_copy_cursor_up(struct window_pane *);
void window_copy_cursor_down(struct window_pane *, int); void window_copy_cursor_down(struct window_pane *);
void window_copy_cursor_next_word(struct window_pane *); void window_copy_cursor_next_word(struct window_pane *);
void window_copy_cursor_previous_word(struct window_pane *); void window_copy_cursor_previous_word(struct window_pane *);
void window_copy_scroll_up(struct window_pane *, u_int); void window_copy_scroll_up(struct window_pane *, u_int);
@@ -235,17 +235,11 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
window_copy_cursor_right(wp); window_copy_cursor_right(wp);
return; return;
case MODEKEYCOPY_UP: case MODEKEYCOPY_UP:
window_copy_cursor_up(wp, 0); window_copy_cursor_up(wp);
return; return;
case MODEKEYCOPY_DOWN: case MODEKEYCOPY_DOWN:
window_copy_cursor_down(wp, 0); window_copy_cursor_down(wp);
return; return;
case MODEKEYCOPY_SCROLLUP:
window_copy_cursor_up(wp, 1);
break;
case MODEKEYCOPY_SCROLLDOWN:
window_copy_cursor_down(wp, 1);
break;
case MODEKEYCOPY_PREVIOUSPAGE: case MODEKEYCOPY_PREVIOUSPAGE:
window_copy_pageup(wp); window_copy_pageup(wp);
break; break;
@@ -278,24 +272,6 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
window_copy_update_selection(wp); window_copy_update_selection(wp);
window_copy_redraw_screen(wp); window_copy_redraw_screen(wp);
break; 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: case MODEKEYCOPY_STARTSELECTION:
window_copy_start_selection(wp); window_copy_start_selection(wp);
window_copy_redraw_screen(wp); window_copy_redraw_screen(wp);
@@ -436,20 +412,20 @@ window_copy_key_input(struct window_pane *wp, int key)
} }
void void
window_copy_mouse( window_copy_mouse(struct window_pane *wp,
struct window_pane *wp, unused struct client *c, struct mouse_event *m) unused struct client *c, u_char b, u_char x, u_char y)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
if ((m->b & 3) == 3) if ((b & 3) == 3)
return; return;
if (m->x >= screen_size_x(s)) if (x >= screen_size_x(s))
return; return;
if (m->y >= screen_size_y(s)) if (y >= screen_size_y(s))
return; return;
window_copy_update_cursor(wp, m->x, m->y); window_copy_update_cursor(wp, x, y);
if (window_copy_update_selection(wp)) if (window_copy_update_selection(wp))
window_copy_redraw_screen(wp); window_copy_redraw_screen(wp);
} }
@@ -1044,7 +1020,7 @@ window_copy_cursor_left(struct window_pane *wp)
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
if (data->cx == 0) { if (data->cx == 0) {
window_copy_cursor_up(wp, 0); window_copy_cursor_up(wp);
window_copy_cursor_end_of_line(wp); window_copy_cursor_end_of_line(wp);
} else { } else {
window_copy_update_cursor(wp, data->cx - 1, data->cy); window_copy_update_cursor(wp, data->cx - 1, data->cy);
@@ -1064,7 +1040,7 @@ window_copy_cursor_right(struct window_pane *wp)
if (data->cx >= px) { if (data->cx >= px) {
window_copy_cursor_start_of_line(wp); window_copy_cursor_start_of_line(wp);
window_copy_cursor_down(wp, 0); window_copy_cursor_down(wp);
} else { } else {
window_copy_update_cursor(wp, data->cx + 1, data->cy); window_copy_update_cursor(wp, data->cx + 1, data->cy);
if (window_copy_update_selection(wp)) if (window_copy_update_selection(wp))
@@ -1073,7 +1049,7 @@ window_copy_cursor_right(struct window_pane *wp)
} }
void void
window_copy_cursor_up(struct window_pane *wp, int scroll_only) window_copy_cursor_up(struct window_pane *wp)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
u_int ox, oy, px, py; u_int ox, oy, px, py;
@@ -1086,11 +1062,9 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
} }
data->cx = data->lastcx; data->cx = data->lastcx;
if (scroll_only || data->cy == 0) { if (data->cy == 0)
window_copy_scroll_down(wp, 1); window_copy_scroll_down(wp, 1);
if (scroll_only) else {
window_copy_redraw_lines(wp, data->cy, 2);
} else {
window_copy_update_cursor(wp, data->cx, data->cy - 1); window_copy_update_cursor(wp, data->cx, data->cy - 1);
if (window_copy_update_selection(wp)) if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 2); window_copy_redraw_lines(wp, data->cy, 2);
@@ -1103,7 +1077,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
} }
void void
window_copy_cursor_down(struct window_pane *wp, int scroll_only) window_copy_cursor_down(struct window_pane *wp)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
@@ -1117,11 +1091,9 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
} }
data->cx = data->lastcx; data->cx = data->lastcx;
if (scroll_only || data->cy == screen_size_y(s) - 1) { if (data->cy == screen_size_y(s) - 1)
window_copy_scroll_up(wp, 1); window_copy_scroll_up(wp, 1);
if (scroll_only && data->cy > 0) else {
window_copy_redraw_lines(wp, data->cy - 1, 2);
} else {
window_copy_update_cursor(wp, data->cx, data->cy + 1); window_copy_update_cursor(wp, data->cx, data->cy + 1);
if (window_copy_update_selection(wp)) if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy - 1, 2); window_copy_redraw_lines(wp, data->cy - 1, 2);
@@ -1165,7 +1137,7 @@ window_copy_cursor_next_word(struct window_pane *wp)
} }
px = 0; px = 0;
window_copy_cursor_down(wp, 0); window_copy_cursor_down(wp);
py =screen_hsize( py =screen_hsize(
&wp->base) + data->cy - data->oy; &wp->base) + data->cy - data->oy;
@@ -1213,7 +1185,7 @@ window_copy_cursor_previous_word(struct window_pane *wp)
(screen_hsize(&wp->base) == 0 || (screen_hsize(&wp->base) == 0 ||
data->oy >= screen_hsize(&wp->base) - 1)) data->oy >= screen_hsize(&wp->base) - 1))
goto out; goto out;
window_copy_cursor_up(wp, 0); window_copy_cursor_up(wp);
py = screen_hsize( py = screen_hsize(
&wp->base) + data->cy - data->oy; &wp->base) + data->cy - data->oy;
@@ -1250,10 +1222,7 @@ window_copy_scroll_up(struct window_pane *wp, u_int ny)
screen_write_deleteline(&ctx, ny); screen_write_deleteline(&ctx, ny);
window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, 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, 0);
if (screen_size_y(s) > 1) window_copy_write_line(wp, &ctx, 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) if (s->sel.flag && screen_size_y(s) > ny)
window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1);
screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_cursormove(&ctx, data->cx, data->cy);

323
window-scroll.c Normal file
View File

@@ -0,0 +1,323 @@
/* $Id: window-scroll.c,v 1.41 2009-09-11 14:13:52 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#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);
}

View File

@@ -1,4 +1,4 @@
/* $Id: window.c,v 1.117 2009-10-23 17:41:20 tcunha Exp $ */ /* $Id: window.c,v 1.107 2009-09-16 12:36:28 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -172,7 +172,7 @@ winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
return; return;
winlink_stack_remove(stack, wl); winlink_stack_remove(stack, wl);
TAILQ_INSERT_HEAD(stack, wl, sentry); SLIST_INSERT_HEAD(stack, wl, sentry);
} }
void void
@@ -183,9 +183,9 @@ winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl)
if (wl == NULL) if (wl == NULL)
return; return;
TAILQ_FOREACH(wl2, stack, sentry) { SLIST_FOREACH(wl2, stack, sentry) {
if (wl2 == wl) { if (wl2 == wl) {
TAILQ_REMOVE(stack, wl, sentry); SLIST_REMOVE(stack, wl, winlink, sentry);
return; return;
} }
} }
@@ -302,23 +302,6 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
} }
} }
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 * struct window_pane *
window_add_pane(struct window *w, u_int hlimit) window_add_pane(struct window *w, u_int hlimit)
{ {
@@ -423,10 +406,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->sx = sx; wp->sx = sx;
wp->sy = sy; wp->sy = sy;
wp->pipe_fd = -1;
wp->pipe_buf = NULL;
wp->pipe_off = 0;
wp->saved_grid = NULL; wp->saved_grid = NULL;
screen_init(&wp->base, sx, sy, hlimit); screen_init(&wp->base, sx, sy, hlimit);
@@ -450,11 +429,6 @@ window_pane_destroy(struct window_pane *wp)
if (wp->saved_grid != NULL) if (wp->saved_grid != NULL)
grid_destroy(wp->saved_grid); 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->in);
buffer_destroy(wp->out); buffer_destroy(wp->out);
@@ -504,7 +478,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
ws.ws_row = screen_size_y(&wp->base); ws.ws_row = screen_size_y(&wp->base);
if (gettimeofday(&wp->window->name_timer, NULL) != 0) if (gettimeofday(&wp->window->name_timer, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday");
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = NAME_INTERVAL * 1000L; tv.tv_usec = NAME_INTERVAL * 1000L;
timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer); timeradd(&wp->window->name_timer, &tv, &wp->window->name_timer);
@@ -594,7 +568,7 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
wp->mode->resize(wp, sx, sy); wp->mode->resize(wp, sx, sy);
if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
#ifdef __sun #ifdef __sun__
/* /*
* Some versions of Solaris apparently can return an error when * Some versions of Solaris apparently can return an error when
* resizing; don't know why this happens, can't reproduce on * resizing; don't know why this happens, can't reproduce on
@@ -617,7 +591,7 @@ window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
if ((s = wp->mode->init(wp)) != NULL) if ((s = wp->mode->init(wp)) != NULL)
wp->screen = s; wp->screen = s;
wp->flags |= PANE_REDRAW; server_redraw_window(wp->window);
return (0); return (0);
} }
@@ -631,72 +605,49 @@ window_pane_reset_mode(struct window_pane *wp)
wp->mode = NULL; wp->mode = NULL;
wp->screen = &wp->base; wp->screen = &wp->base;
wp->flags |= PANE_REDRAW; server_redraw_window(wp->window);
} }
void void
window_pane_parse(struct window_pane *wp) 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); input_parse(wp);
wp->pipe_off = BUFFER_USED(wp->in);
} }
void void
window_pane_key(struct window_pane *wp, struct client *c, int key) window_pane_key(struct window_pane *wp, struct client *c, int key)
{ {
struct window_pane *wp2; if (wp->fd == -1 || !window_pane_visible(wp))
if (!window_pane_visible(wp))
return; return;
if (wp->mode != NULL) { if (wp->mode != NULL) {
if (wp->mode->key != NULL) if (wp->mode->key != NULL)
wp->mode->key(wp, c, key); wp->mode->key(wp, c, key);
return; } else
} input_key(wp, key);
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 void
window_pane_mouse( window_pane_mouse(
struct window_pane *wp, struct client *c, struct mouse_event *m) struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y)
{ {
if (!window_pane_visible(wp)) if (wp->fd == -1 || !window_pane_visible(wp))
return; return;
if (m->x < wp->xoff || m->x >= wp->xoff + wp->sx) /* XXX convert from 1-based? */
if (x < wp->xoff || x >= wp->xoff + wp->sx)
return; return;
if (m->y < wp->yoff || m->y >= wp->yoff + wp->sy) if (y < wp->yoff || y >= wp->yoff + wp->sy)
return; return;
m->x -= wp->xoff; x -= wp->xoff;
m->y -= wp->yoff; y -= wp->yoff;
if (wp->mode != NULL) { if (wp->mode != NULL) {
if (wp->mode->mouse != NULL) if (wp->mode->mouse != NULL)
wp->mode->mouse(wp, c, m); wp->mode->mouse(wp, c, b, x, y);
} else if (wp->fd != -1) } else
input_mouse(wp, m); input_mouse(wp, b, x, y);
} }
int int

BIN
www/images/tmux1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
www/images/tmux2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
www/images/tmux6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,74 +1,24 @@
<?xml version="1.0" encoding="utf-8"?> <!-- $Id: index.html.in,v 1.2 2009-08-05 16:39:28 nicm Exp $ -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <html>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <head>
<html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml"> <meta http-equiv="content-type" content="text/html; charset=UTF-8">
<head> <title>tmux</title>
<title>tmux</title> </head>
<link rel="stylesheet" type="text/css" media="screen" href="main.css"/> <body>
</head> <b>Welcome to the tmux website, such as it is!</b>
<body> <p>tmux is a &quot;terminal multiplexer&quot;, it enables a number of terminals (or windows) 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.</p>
<div id="body-wrapper"> <p><a href="http://downloads.sourceforge.net/tmux/tmux-%%VERSION%%.tar.gz">Download tmux %%VERSION%%.</a></p>
<div id="left-menu-container"> <p>Please see the <a href="http://tmux.cvs.sourceforge.net/viewvc/*checkout*/tmux/tmux/NOTES">release notes</a> and <a href="http://tmux.cvs.sourceforge.net/viewvc/*checkout*/tmux/tmux/FAQ">FAQ</a>.</p>
<p id="upper-left-title">tmux</p> <p>Also available are: <a href="http://tmux.cvs.sourceforge.net/viewvc/*checkout*/tmux/tmux/CHANGES">the change log</a> (up to CVS HEAD), <a href="http://sf.net/projects/tmux">the project page</a> and <a href="https://sourceforge.net/mail/?group_id=200378">mailing lists</a>. An IRC channel, #tmux, is on the Freenode network.</p>
<ul id="left-menu"> <b>Screenshots</b>
<li><a href="http://downloads.sourceforge.net/tmux/tmux-1.0.tar.gz">Download</a></li> <table><tr>
<li><a href="http://tmux.cvs.sourceforge.net/viewvc/*checkout*/tmux/tmux/NOTES">Release Notes</a> <td><a href="tmux1.png"><img src="small-tmux1.png"></a></td>
<li><a href="http://tmux.cvs.sourceforge.net/viewvc/*checkout*/tmux/tmux/CHANGES">Changelog</a></li> <td><a href="tmux2.png"><img src="small-tmux2.png"></a></td>
<li><a href="http://tmux.cvs.sourceforge.net/viewvc/*checkout*/tmux/tmux/FAQ">FAQ</a></li> <td><a href="tmux3.png"><img src="small-tmux3.png"></a></td>
<li><a href="http://tmux.cvs.sourceforge.net/viewvc/tmux/tmux/examples/">Examples</a></li> </tr><tr>
<li>&nbsp;</li> <td><a href="tmux4.png"><img src="small-tmux4.png"></a></td>
<li class="menu-headings">Source Code</li> <td><a href="tmux5.png"><img src="small-tmux5.png"></a></td>
<li><a href="http://tmux.cvs.sf.net/viewvc/tmux/tmux/">SourceForge</a></li> <td><a href="tmux6.png"><img src="small-tmux6.png"></a></td>
<li><a href="http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/tmux/">OpenBSD</a></li> </tr></table>
<li>&nbsp;</li> </body>
<li class="menu-headings">Support</li>
<li><a href="https://lists.sourceforge.net/lists/listinfo/tmux-users">tmux-users</a></li>
<li><a href="https://lists.sourceforge.net/lists/listinfo/tmux-cvs">tmux-cvs</a></li>
<li>IRC: #tmux on Freenode</li>
<li><a href="http://sf.net/projects/tmux">SourceForge Project Page</a></li>
</ul>
</div>
<div id="main-content-wrapper">
<p>tmux is a terminal multiplexer: it enables a number of terminals (or
windows), each running a separate program, to be created, accessed, and
controlled from a single screen. tmux may be detached from a screen and
continue running in the background, then later reattached.</p>
<p>tmux uses a client-server model. The server holds multiple sessions and each
window is a independent entity which may be freely linked to multiple sessions,
moved between sessions and otherwise manipulated. Each session may be attached
to (display and accept keyboard input from) multiple clients.</p>
<p>tmux is intended to be a modern, BSD-licensed alternative to programs such
as GNU screen. Major features include:</p>
<ul>
<li>A powerful, consistent, well-documented and easily scriptable command
interface.</li>
<li>A window may be split horizontally and vertically into panes.</li>
<li>Panes can be freely moved and resized, or arranged into one of four preset
layouts. </li>
<li>Support for UTF-8 and 256-colour terminals.</li>
<li>Copy and paste with multiple buffers.</li>
<li>Interactive menus to select windows, sessions or clients.</li>
<li>Change the current window by searching for text in the target.</li>
<li>Terminal locking, manually or after a timeout.</li>
<li>A clean, easily extended, BSD-licensed codebase, under active
development.</li>
</ul>
<p>tmux is part of the <a href="http://www.openbsd.org">OpenBSD</a> base
system. The portable version is hosted on SourceForge and runs on Linux,
FreeBSD, NetBSD, Solaris and AIX.</p>
<div id="screenshots">
<a href="tmux3.png"><img src="small-tmux3.png"></a>
<a href="tmux4.png"><img src="small-tmux4.png"></a>
<a href="tmux5.png"><img src="small-tmux5.png"></a>
</div>
</div>
</div>
</body>
</html> </html>

Some files were not shown because too many files have changed in this diff Show More