1 Commits
1.4 ... 1.2

Author SHA1 Message Date
no_author
cd1ae9e79b This commit was manufactured by cvs2svn to create tag 'TMUX_1_2'. 2010-03-10 15:18:50 +00:00
103 changed files with 3924 additions and 6304 deletions

89
CHANGES
View File

@@ -1,90 +1,3 @@
CHANGES FROM 1.3 TO 1.4, 27 December 2010
* Window bell reporting fixed.
* Show which pane is active in the list-panes output.
* Backoff reworked.
* Prevent the server from dying when switching into copy mode when already
in a different mode.
* Reset running jobs when the status line is enabled or disabled.
* Simplify xterm modifier detection.
* Avoid crashing in copy mode if the screen size is too small for the
indicator.
* Flags -n and -p added to switch-client.
* Use UTF-8 line drawing characters on UTF-8 terminals, thus fixing some
terminals (eg putty) which disable the vt100 ACS mode switching sequences
in UTF-8 mode. On terminals without ACS, use ASCII equivalents.
* New server option exit-unattached added.
* New session option destroy-unattached added.
* Fall back on normal session choice method if $TMUX exists but is invalid
rather than rejecting.
* Mark repeating keys with "(repeat)" in the key list.
* When removing a pane, don't change the active pane unless the active pane
is actually the one being removed.
* New command last-pane added.
* AIX fixes.
* Flag -a added to unbind-key.
* Add XAUTHORITY to update-environment.
* More info regarding window and pane flags is now shown in list-*.
* If VISUAL or EDITOR contains "vi" configure mode-keys and status-key to vi.
* New window option monitor-silence and session option visual-silence added.
* In the built-in layouts distribute the panes more evenly.
* Set the default value of main-pane-width to 80 instead of 81.
* Command-line flag -V added.
* Instead of keeping a per-client prompt history make it global.
* Fix rectangle copy to behave like emacs (the cursor is not part of the
selection on the right edge but on the left it is).
* Flag -l added to switch-client.
* Retrieve environment variables from the global environment rather than
getenv(3), thus allowing them to be updated during the configuration file.
* New window options other-pane-{height,width} added.
* More minor bugs fixed and manpage improvements.
CHANGES FROM 1.2 TO 1.3, 18 July 2010
* New input parser.
* Flags to move through panes -UDLR added to select-pane.
* Commands up-pane, and down-pane removed, since equivalent behaviour is now
available through the target flag (-t:+ and -t:-).
* Jump-forward/backward in copy move (based on vi's F, and f commands).
* Make paste-buffer accept a pane as a target.
* Flag -a added to new-window to insert a window after an existing one, moving
windows up if necessary.
* Merge more mode into copy mode.
* Run job commands explicitly in the global environment (which can be modified
with setenv -g), rather than with the environment tmux started with.
* Use the machine's hostname as the default title, instead of an empty string.
* Prevent double free if the window option remain-on-exit is set.
* Key string conversions rewritten.
* Mark zombie windows as dead in the choose-window list.
* Tiled layout added.
* Signal handling reworked.
* Reset SIGCHLD after fork to fix problems with some shells.
* Select-prompt command removed. Therefore, bound ' to command-prompt -p index
"select-window -t:%%" by default.
* Catch SIGHUP and terminate if running as a client, thus avoiding clients from
being left hanging around when, for instance, a SSH session is disconnected.
* Solaris 9 fixes (such as adding compat {get,set}env(3) code).
* Accept none instead of default for attributes.
* Window options window-status-alert-{alert,bg,fg} added.
* Flag -s added to the paste-buffer command to specify a custom separator.
* Allow dragging to make a selection in copy mode if the mode-mouse option is
set.
* Support the mouse scroll wheel.
* Make pipe-pane accept special character sequences (eg #I).
* Fix problems with window sizing when starting tmux from .xinitrc.
* Give tmux sockets (but not the containing folder) group permissions.
* Extend the target flags (ie -t) to accept an offset (for example -t:+2), and
make it wrap windows, and panes.
* New command choose-buffer added.
* New server option detach-on-destroy to set what happens to a client when the
session it is attached to is destroyed. If on (default), the client is
detached. Otherwise, the client is switched to the most recently active of
the remaining sessions.
* The commands load-buffer, and save-buffer now accept a dash (-) as the file
to read from stdin, or write to stdout.
* Custom layouts added.
* Additional code reduction, bug fixes, and manpage enhancements.
CHANGES FROM 1.1 TO 1.2, 10 March 2010
* Switch to libevent.
@@ -1554,7 +1467,7 @@ The list of older changes is below.
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
$Id: CHANGES,v 1.304 2010-12-27 21:37:42 tcunha Exp $
$Id: CHANGES,v 1.302 2010-03-10 15:18:11 tcunha Exp $
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms

173
FAQ
View File

@@ -12,99 +12,29 @@ tmux frequently asked questions
* and derivatives. *
******************************************************************************
* How is tmux different from GNU screen?
* How is tmux different from GNU screen? What else does it offer?
tmux and GNU screen have many similarities. Some of the main differences I am
aware of are (bearing in mind I haven't used screen for a few years now):
tmux offers several advantages over screen:
- tmux uses a client-server model. Each server has single Unix domain socket in
/tmp and within one server there are multiple sessions which may be attached
to multiple clients (terminals).
- a clearly-defined client-server model: windows are independent entities which
may be attached simultaneously to multiple sessions and viewed from multiple
clients (terminals), as well as moved freely between sessions within the same
tmux server;
- a consistent, well-documented command interface, with the same syntax
whether used interactively, as a key binding, or from the shell;
- easily scriptable from the shell;
- multiple paste buffers;
- choice of vi or emacs key layouts;
- an option to limit the window size;
- a more usable status line syntax, with the ability to display the first line
of output of a specific command;
- a cleaner, modern, easily extended, BSD-licensed codebase.
This has advantages, notably: windows may be linked simultaneously to
multiple sessions; windows may be moved freely between sessions; and a client
may be switched between sessions easily (C-b D). There is one major
disadvantage: if the server crashes, game over, all sessions die. In
practice, however, tmux is quite stable and gets more so as people report any
bugs they hit :-).
There are still a few features screen includes that tmux omits:
This model is different from screen, where typically each new screen instance
is independent. tmux supports the same behaviour by using multiple servers
with the -L option but it is not typically recommended.
- Different command interfaces. One of the goals of tmux is that the shell
should be easily usable as a scripting language - almost all tmux commands
can be used from the shell and behave identically whether used from the
shell, from a key binding or from the command prompt. Personally I also find
tmux's command interface much more consistent and clearer, but this is
subjective.
- tmux calls window names (what you see in the status line) "names", screen
calls them "titles".
- tmux has a multiple paste buffers. Not a major one but comes in handy quite a
lot.
- tmux supports automatically renaming windows to the running application
without gross hacks using escape sequences. Its even on by default.
- tmux has a choice of vi or emacs key layouts. Again, not major, but I use
emacs so if tmux did support only one key set it would be emacs and then all
the vi users would get humpy. Key bindings may be completely reconfigured in
any case.
- tmux has an option to limit the window size.
- tmux has search in windows (C-b f).
- The window split (pane) model is different. tmux has two objects, windows and
panes; screen has just windows. This difference has several implications:
* In screen you can have a window appear in several layouts, in tmux a pane
can only be in one window (fixing this is a big todo item but quite
invasive).
* tmux layouts are immutable and do not get changed unless you modify them.
* In tmux, all panes are closed when you kill a window.
* tmux panes do not have individual names, titles and so on.
I think tmux's model is much easier to manage and navigate within a window,
but breaking panes off from and joining them to windows is more clumsy.
tmux also has support for preset pane layouts.
- tmux's status line syntax is more readable and easier to use. I think it'd be
hard for anyone to argue with this. tmux doesn't support running a command
constantly and always using the last line of its output, commands must be run
again each time.
- tmux has modern, easily extended code. Again hard to argue screen is better
if you have looked at the code.
- tmux depends on libevent. I don't see this as a disadvantage: libevent is
small and portable, and on modern systems with current package management
systems dependencies are not an issue. libevent brings advantages in code
simplicity and performance.
- screen allows the window to be bigger than the terminal and can pan around
it. tmux limits the size to the largest attached client. This is a big todo
item for tmux but it is not trivial.
- screen has builtin serial and telnet support; this is bloat and is unlikely
to be added to tmux.
- screen has support for updating utmp. Nobody has really come up with a clean,
portable way to do this without making tmux setuid or setgid yet.
- Environment handling is different.
- tmux tends to be more demanding on the terminal so tends to show up terminal
and application bugs which screen does not.
- screen has wider platform support, for example IRIX and HP-UX, and for odd
terminals.
- builtin serial and telnet support; this is bloat and is unlikely to be added
to tmux;
- wider platform support, for example IRIX and HP-UX, and for odd terminals.
* I found a bug! What do I do?
@@ -237,8 +167,6 @@ the ctrl (bit 5 set, for example ^[[5~ to ^[[5^) modifier in non-xterm(1) mode;
it may be possible to configure vim to accept these, an example of how to do so
would be welcome.
vim users may also want to set the "ttyfast" option inside tmux.
* Why doesn't elinks set the window title inside tmux?
There isn't a way to detect if a terminal supports setting the window title, so
@@ -311,65 +239,4 @@ set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx
Note that this will only work in tmux 1.2 and above.
* How can I blank the tmux window?
GNU screen has a feature whereby it will blank the screen after a period of
inactivity. To do the same thing in tmux, use the lock-command setting, for
example (with GNU bash):
set -g lock-command 'tput civis && read -s -n1'
This will remove the cursor and tell the shell to quit once a key has been
pressed. For zsh, use "read -s -k1".
In addition, it's possible to have both blanking and locking (for instance via
lock(1) or vlock(1)) by using the following:
bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
* How can I open a new window in the same directory as the current window?
One option is to just run "TMUX= tmux" in the window. However, this only works if no
command is running, so that you can input the command.
A workaround is to let tmux know about the current path through an environment
variable. To do so, use the following command:
[ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD
Which sets TMUXPWD_i (where i is the number of the current window) to the path
of the current directory. This command can be added to PS1, for example:
PS1='$([ -n "$TMUX" ] && tmux setenv TMUXPWD_$(tmux display -p "#I") $PWD)\h$ '
When a new window is created, the shell should be asked to change
directory. You can define a new binding (for example, if using GNU bash):
bind-key C-c run-shell 'tmux neww "cd $(tmux display -p "\$TMUXPWD_#I"); exec bash"'
This solution will work even if a command is currently running in the terminal,
but it will not work from a window that has just been swapped with another
because TMUXPWD_i will not be updated after a swap. However, once a new prompt
is displayed, TMUXPWD_i is updated properly.
* tmux doesn't start with "daemon failed"
tmux shows something similar to this when started:
fatal: server_start: daemon failed: No such file or directory
fatal: main_dispatch: imsg_read failed
A possible reason is that /dev/null is not a character device or is otherwise
inaccessible.
Check with:
file /dev/null
ls -l /dev/null
If it is not a character device or has incorrect permissions, it can typically
be recreated with:
cd /dev && rm null && ./MAKEDEV null
$Id: FAQ,v 1.41 2010-12-15 23:31:30 nicm Exp $
$Id: FAQ,v 1.36 2010-02-04 21:01:59 nicm Exp $

View File

@@ -1,4 +1,4 @@
# $Id: GNUmakefile,v 1.130 2010-12-27 21:32:16 tcunha Exp $
# $Id: GNUmakefile,v 1.122 2010-03-10 15:15:33 tcunha Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
@@ -17,7 +17,7 @@
.PHONY: clean
VERSION= 1.4
VERSION= 1.2
#FDEBUG= 1
@@ -28,7 +28,7 @@ LIBS+=
# Sun CC
ifneq ($(shell ($(CC) -V 2>&1|awk '/Sun C/' || true)), )
CFLAGS+= -erroff=E_EMPTY_DECLARATION
CFLAGS+=-erroff=E_EMPTY_DECLARATION
FDEBUG=
endif
@@ -52,12 +52,11 @@ endif
endif
PREFIX?= /usr/local
INSTALL?= install
INSTALLDIR= $(INSTALL) -d
INSTALLBIN= $(INSTALL) -m 555
INSTALLMAN= $(INSTALL) -m 444
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
SRCS= $(shell echo *.c|LC_ALL=C sed 's|osdep-[a-z0-9]*.c||g')
SRCS= $(shell echo *.c|sed 's|osdep-[a-z0-9]*.c||g')
include config.mk
OBJS= $(patsubst %.c,%.o,$(SRCS))

View File

@@ -1,4 +1,4 @@
# $Id: Makefile,v 1.162 2010-12-27 21:32:16 tcunha Exp $
# $Id: Makefile,v 1.155 2010-03-10 15:15:33 tcunha Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
@@ -18,7 +18,7 @@
.SUFFIXES: .c .o
.PHONY: clean
VERSION= 1.4
VERSION= 1.2
#FDEBUG= 1
@@ -48,12 +48,11 @@ CFLAGS+= -Wno-pointer-sign
.endif
PREFIX?= /usr/local
INSTALL?= install
INSTALLDIR= ${INSTALL} -d
INSTALLBIN= ${INSTALL} -m 555
INSTALLMAN= ${INSTALL} -m 444
INSTALLDIR= install -d
INSTALLBIN= install -g bin -o root -m 555
INSTALLMAN= install -g bin -o root -m 444
SRCS!= echo *.c|LC_ALL=C sed 's|osdep-[a-z0-9]*.c||g'
SRCS!= echo *.c|sed 's|osdep-[a-z0-9]*.c||g'
.include "config.mk"
OBJS= ${SRCS:S/.c/.o/}

25
NOTES
View File

@@ -25,11 +25,34 @@ windows into several simultaneously displayed panes; and to bind and unbind
command keys (invoked preceded by a prefix key, by default ctrl-b). Please see
the tmux(1) man page for further information.
The following is a summary of major features implemented in this version:
- Basic multiplexing, window switching, attaching and detaching.
- Window listing and renaming.
- Key binding.
- Handling of client terminal resize.
- Terminal emulation sufficient to handle most curses applications.
- A optional status line (enabled by default).
- Window history and copy and paste.
- Support for VT100 line drawing characters.
- A large command set.
- Vertical window splitting and layout.
- Automatic server locking on inactivity by running an external command.
- A configuration file.
- UTF-8 support.
A more extensive, but rough, todo list is included in the TODO file.
tmux also depends on several features of the client terminal (TERM), if these
are missing it may refuse to run, or not behave correctly.
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
tmux(1) and the FAQ file. As of 0.9, tmux attempts to autodetect a
UTF-8 capable terminal by checking the LC_ALL, LC_CTYPE and LANG environment
variables. list-clients may be used to check if this is detected correctly; if
not, the -u command-line flag may be specified.
A Vim syntax file is available in the examples directory. To install it:
- Drop the file in the syntax directory in your runtimepath (such as
@@ -63,4 +86,4 @@ start. Please contact me with any queries.
-- Nicholas Marriott <nicm@users.sf.net>
$Id: NOTES,v 1.54 2010-12-27 21:36:37 tcunha Exp $
$Id: NOTES,v 1.53 2010-03-10 15:18:11 tcunha Exp $

91
TODO
View File

@@ -1,3 +1,4 @@
- window creation/idle time
- better errors when creating new windows/sessions (how?)
- implicitly add exec to the commands for new windows (switch to disable it)?
- it would be nice to have multichar commands eg C-b K K
@@ -6,18 +7,27 @@
bring back detach-session to detach all clients on a session?
- allow fnmatch for -c, so that you can, eg, detach all clients
- garbage collect window history (100 lines at a time?) if it hasn't been used
in $x time
in $x time (need window creation/use times)
- lift SHRT_MAX limits for history?
- flags to centre screen in window
- better terminal emulation
- activity/bell should be per-window not per-link? what if it is cur win in
session not being watched?
- next prev word etc in command prompt
- many more info() displays for various things
- input.c is too complicated. simplify?
- use a better termcap internally instead of screen, perhaps xterm
- fix rxvt cursor fg issue (text under cursor can have non-white fg)
- should be able to move to a hidden pane and it would be moved into view. pane
number in status line/top-right would be cool for this
- support other mouse modes (highlight etc) and use it in copy mode
- set-remain-on-exit is a bit of a hack, some way to do it generically?
- set-option should be set-session-option and should be overall global options
also quiet, utf8 and maybe other flags?
-g is a bit unexpected in conf file
- clear window title on exit
- the output code (tty.c) could do with optimisation depending on term
capabilities
- would be nice to be able to use "--" to mark start of command w/ neww etc
to avoid quoting
- make command sequences more usable: don't require space after ;, handle
@@ -28,7 +38,11 @@
"new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
$HOME/.tmux-session.conf
- get it passing all the vttest tests that don't require resizing the terminal
- esc seq to set window name and title should be documented, and name variant
should clear automatic-rename
- way to set socket path from config file
- XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up
when session is started
- what about utmp etc? can tmux update it like screen? setgid?
- warts on current naming:
- display-time but message-fg/bg/attr
@@ -36,30 +50,48 @@
- server-info
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
- split-window -> split-pane??
- tidy up and prioritise todo list ;-)
- neww and attach can create a session if none exists?
would work fine with config file since
- a way for force-width/height to apply to only one pane (how?)
- command to list what is actually running in each window with command line,
pid (need some adaption of the osdep code)
- support for bce
- it would be nice if the start/end line keys in copy mode were aware of
wrapped lines
- some way to force a screen to use the entire terminal even if it is forced
to be smaller by other clients. pan smaller terminal? (like screen F)
-- idea of a "view" onto a window, need base x/y offsets for redraw
-- idea of a "view" onto a window, need base x/y offsets
for redraw
- handle resize better in copy mode
- way to copy stuff that is off screen due to resize
- commands should be able to succeed or fail and have || or && for command
lists
- support the mouse wheel to scroll through history
- some way to KEEP a command running continually and just use its LAST line of
output
- bind commands to mouse buttons
- UTF-8 to a non-UTF-8 terminal should not be able to balls up
the terminal - www/ruby-addressable; make regress
- copy mode needs a tidy/cleanup
- 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
- UTF-8 should be a pointer into a combined string buffer
- check irssi (term_charset) works with UTF-8
- support esc-esc to quit in modes
- fix ctrl+F1-F4 output. to what?
- look into xterm clearing its selection when scrolling etc
- better utf8 support: window names, prompt input, message display
- better utf8 support:
window names
prompt input
message display
copy and paste cursor and wide characters
...?
- option so that when session is destroyed, attach client to another session
rather than exiting
- session history for client and last-session command
- option to change status line colour when current window is in a mode?
- option to move copy mode indicator into status line
@@ -67,10 +99,13 @@
- selection behaviour closer to vi in vi mode
- live update: server started with -U connects to server, requests sessions and
windows, receives fds
- convert status line history to be server global (anything else?)
- something for -t "last window in session" so a session can be used as a stack
- command to show a tree of sessions-windows-panes (active marked with *)
- sort out inheriting config from shell on new sessions/windows:
should pick up default-path/termios/etc from client if possible,
else leave empty/default
- define custom layouts
- link panes into multiple windows
- -h option to capture-pane to capture the history as well
- bells should be passed between sessions with visual-bell etc
@@ -80,51 +115,21 @@
- better session sharing: create-socket command to create socket somewhere (-r
flag for readonly)
- allow buffer to be specified when copying in copy mode
- multiline status line (no?)
- multiline status line
- flag for absolute pane size to resize-pane
- sanity check input to socket
- stdin fd should be passed up to parent so load-buffer and others could use it
for nonattaching clients
- environment should be set up for jobs
- select-buffer command
- fix jobs so they block in config file rather than executing at an arbitrary
future point -- need state stored in client so other clients can proceed
- rectangle copy:
when selecting leftward, cursor should be inside block per emacs
key to rotate corner at which cursor is
- double C-a should walk back over wrapped lines like C-e
- support title stack, both internally and externally
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=1149299+0+archive/2010/freebsd-questions/20100207.freebsd-questions
- copy buffers should be global, limit can be server option, nuke copy-buffer
command
- command to show status line information briefly when it is off
- some way to pad # stuff with spaces, #!2T maybe
- FreeBSD console problems
- a binding to "scroll down and exit at bottom" copy mode
- some way to pass keystrokes in copy mode through to underlying window
- last window update time and # replacement for it for display-message
- find-window across sessions - other ways to make session handling easier?
- ' and " should be parsed the same (eg "\e" vs '\e') in config and command
prompt?
- command to toggle selection not to move it in copy-mode
- why are alerts per-winlink? try per window?
- audit of escape sequence support vs xterm
- support binding keys to mouse (mouse-select-pane -> mouse-keys or something,
mouse click == select-pane -t %%, mouse scroll up == copy-mode)
- something for -t "last window in session" so a session can be used as a stack
- synchronous commands - client sends cmd and blocks, neww/splitw saves client
ptr then when program inside died, sends MSG_SOMETHING with wait status to
client
- documentation improvements - rlpowell's tutorial - build instructions
- better configure? with-libevent
- bind commands to key sequences?
- monitor, bell etc should monitor /all/ panes in the window not just one
- a history of commands that can be reversed (reverse member of each command,
and a buffer) info() when changing to same window
- don't pass UTF-8 through vis for titles
- clearing screen should push lines into history
- add a unique ever-increasing pane id to each pane, export it in $TMUX_PANE
(as %1, %2 etc) and allow it to be used as a target
- way to add dest for break-pane; maybe some easier way to unbreak-pane
- case insensitive searching
- dynamically generated jobs (eg "date ...") do not work well because
their entries are never collected, should either store status jobs in
a different tree or flush all unused persist jobs every update rather
than just updating them
- pane-index option like base-index
- option to move status line to top
- support "xterm2" mouse mode
- respawn-pane command
- configurable borders and empty space filler for when panes < window?

View File

@@ -1,4 +1,4 @@
/* $Id: array.h,v 1.11 2010-06-06 00:27:08 tcunha Exp $ */
/* $Id: array.h,v 1.10 2010-02-08 18:29:32 tcunha Exp $ */
/*
* Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -47,7 +47,7 @@
} \
} while (0)
#define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0)
#define ARRAY_EMPTY(a) ((a) == NULL || (a)->num == 0)
#define ARRAY_LENGTH(a) ((a)->num)
#define ARRAY_DATA(a) ((a)->list)

View File

@@ -1,4 +1,4 @@
/* $Id: attributes.c,v 1.4 2010-06-05 23:54:51 tcunha Exp $ */
/* $Id: attributes.c,v 1.3 2009-11-28 14:46:23 tcunha Exp $ */
/*
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
@@ -28,7 +28,7 @@ attributes_tostring(u_char attr)
static char buf[128];
if (attr == 0)
return ("none");
return ("default");
buf[0] = '\0';
if (attr & GRID_ATTR_BRIGHT)
@@ -63,7 +63,7 @@ attributes_fromstring(const char *str)
if (strchr(delimiters, str[strlen(str) - 1]) != NULL)
return (-1);
if (strcasecmp(str, "default") == 0 || strcasecmp(str, "none") == 0)
if (strcasecmp(str, "default") == 0)
return (0);
attr = 0;

4
cfg.c
View File

@@ -1,4 +1,4 @@
/* $Id: cfg.c,v 1.27 2010-06-06 00:04:18 tcunha Exp $ */
/* $Id: cfg.c,v 1.26 2010-02-08 18:29:32 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -69,7 +69,7 @@ cfg_add_cause(struct causelist *causes, const char *fmt, ...)
/*
* Load configuration file. Returns -1 for an error with a list of messages in
* causes. Note that causes must be initialised by the caller!
* causes. Note that causes and ncauses must be initialised by the caller!
*/
int
load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)

369
client.c
View File

@@ -1,4 +1,4 @@
/* $Id: client.c,v 1.100 2010-10-24 19:54:41 nicm Exp $ */
/* $Id: client.c,v 1.90 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -17,6 +17,7 @@
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
@@ -28,6 +29,7 @@
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "tmux.h"
@@ -36,180 +38,93 @@ struct imsgbuf client_ibuf;
struct event client_event;
const char *client_exitmsg;
int client_exitval;
int client_attached;
int client_connect(char *, int);
void client_send_identify(int);
void client_send_environ(void);
void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void);
void client_signal(int, short, void *);
void client_callback(int, short, void *);
int client_dispatch_attached(void);
int client_dispatch_wait(void *);
int client_dispatch(void);
/* Connect client to server. */
int
client_connect(char *path, int start_server)
struct imsgbuf *
client_init(char *path, int cmdflags, int flags)
{
struct sockaddr_un sa;
size_t size;
int fd, mode;
#ifdef HAVE_SETPROCTITLE
char rpathbuf[MAXPATHLEN];
#endif
#ifdef HAVE_SETPROCTITLE
if (realpath(path, rpathbuf) == NULL)
strlcpy(rpathbuf, path, sizeof rpathbuf);
setproctitle("client (%s)", rpathbuf);
#endif
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
return (-1);
goto not_found;
}
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed");
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
if (!start_server)
goto failed;
if (!(cmdflags & CMD_STARTSERVER))
goto not_found;
switch (errno) {
case ECONNREFUSED:
if (unlink(path) != 0)
goto failed;
goto not_found;
/* FALLTHROUGH */
case ENOENT:
if ((fd = server_start()) == -1)
goto failed;
break;
default:
goto failed;
if ((fd = server_start(path)) == -1)
goto start_failed;
goto server_started;
}
goto not_found;
}
server_started:
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
return (fd);
failed:
close(fd);
return (-1);
}
/* Client main loop. */
int
client_main(int argc, char **argv, int flags)
{
struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data cmddata;
int cmdflags, fd;
enum msgtype msg;
char *cause;
/* Set up the initial command. */
cmdflags = 0;
if (shell_cmd != NULL) {
msg = MSG_SHELL;
cmdflags = CMD_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
} else {
msg = MSG_COMMAND;
/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
log_warnx("%s", cause);
return (1);
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
if (cmd->entry->flags & CMD_SENDENVIRON)
cmdflags |= CMD_SENDENVIRON;
if (cmd->entry->flags & CMD_CANTNEST)
cmdflags |= CMD_CANTNEST;
}
cmd_list_free(cmdlist);
}
/*
* Check if this could be a nested session, if the command can't nest:
* if the socket path matches $TMUX, this is probably the same server.
*/
if (shell_cmd == NULL && environ_path != NULL &&
cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) {
log_warnx("sessions should be nested with care. "
"unset $TMUX to force.");
return (1);
}
/* Initialise the client socket and start the server. */
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) {
log_warn("failed to connect to server");
return (1);
}
/* Set process title, log and signals now this is the client. */
#ifdef HAVE_SETPROCTITLE
setproctitle("client (%s)", socket_path);
#endif
logfile("client");
/* Create imsg. */
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
imsg_init(&client_ibuf, fd);
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
/* Establish signal handlers. */
set_signals(client_signal);
/* Send initial environment. */
if (cmdflags & CMD_SENDENVIRON)
client_send_environ();
client_send_identify(flags);
if (isatty(STDIN_FILENO))
client_send_identify(flags);
/* Send first command. */
if (msg == MSG_COMMAND) {
/* Fill in command line arguments. */
cmddata.pid = environ_pid;
cmddata.idx = environ_idx;
return (&client_ibuf);
/* Prepare command for server. */
cmddata.argc = argc;
if (cmd_pack_argv(
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
log_warnx("command too long");
return (1);
}
start_failed:
log_warnx("server failed to start");
return (NULL);
client_write_server(msg, &cmddata, sizeof cmddata);
} else if (msg == MSG_SHELL)
client_write_server(msg, NULL, 0);
/* Set the event and dispatch. */
client_update_event();
event_dispatch();
/* Print the exit message, if any, and exit. */
if (client_attached && client_exitmsg != NULL && !login_shell)
printf("[%s]\n", client_exitmsg);
return (client_exitval);
not_found:
log_warn("server not found");
return (NULL);
}
/* Send identify message to server with the file descriptors. */
void
client_send_identify(int flags)
{
struct msg_identify_data data;
struct winsize ws;
char *term;
int fd;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
data.flags = flags;
if (getcwd(data.cwd, sizeof data.cwd) == NULL)
@@ -224,19 +139,8 @@ client_send_identify(int flags)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
if ((fd = dup(STDERR_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
}
/* Forward entire environment to server. */
void
client_send_environ(void)
{
@@ -250,14 +154,12 @@ client_send_environ(void)
}
}
/* Write a message to the server without a file descriptor. */
void
client_write_server(enum msgtype type, void *buf, size_t len)
{
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
}
/* Update client event based on whether it needs to read or read and write. */
void
client_update_event(void)
{
@@ -267,74 +169,102 @@ client_update_event(void)
events = EV_READ;
if (client_ibuf.w.queued > 0)
events |= EV_WRITE;
event_set(
&client_event, client_ibuf.fd, events, client_callback, shell_cmd);
event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
event_add(&client_event, NULL);
}
/* Callback to handle signals in the client. */
__dead void
client_main(void)
{
struct event ev_sigcont, ev_sigterm, ev_sigwinch;
struct sigaction sigact;
logfile("client");
/* Note: event_init() has already been called. */
/* Set up signals. */
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_set(&ev_sigcont, SIGCONT, client_signal, NULL);
signal_add(&ev_sigcont, NULL);
signal_set(&ev_sigterm, SIGTERM, client_signal, NULL);
signal_add(&ev_sigterm, NULL);
signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL);
signal_add(&ev_sigwinch, NULL);
/*
* imsg_read in the first client poll loop (before the terminal has
* been initialised) may have read messages into the buffer after the
* MSG_READY switched to here. Process anything outstanding now to
* avoid hanging waiting for messages that have already arrived.
*/
if (client_dispatch() != 0)
goto out;
/* Set the event and dispatch. */
client_update_event();
event_dispatch();
out:
/* Print the exit message, if any, and exit. */
if (client_exitmsg != NULL && !login_shell)
printf("[%s]\n", client_exitmsg);
exit(client_exitval);
}
/* ARGSUSED */
void
client_signal(int sig, unused short events, unused void *data)
{
struct sigaction sigact;
int status;
struct sigaction sigact;
if (!client_attached) {
switch (sig) {
case SIGCHLD:
waitpid(WAIT_ANY, &status, WNOHANG);
break;
case SIGTERM:
event_loopexit(NULL);
break;
}
} else {
switch (sig) {
case SIGHUP:
client_exitmsg = "lost tty";
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
case SIGTERM:
client_exitmsg = "terminated";
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
case SIGWINCH:
client_write_server(MSG_RESIZE, NULL, 0);
break;
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
client_write_server(MSG_WAKEUP, NULL, 0);
break;
}
switch (sig) {
case SIGTERM:
client_exitmsg = "terminated";
client_exitval = 1;
client_write_server(MSG_EXITING, NULL, 0);
break;
case SIGWINCH:
client_write_server(MSG_RESIZE, NULL, 0);
break;
case SIGCONT:
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
client_write_server(MSG_WAKEUP, NULL, 0);
break;
}
client_update_event();
}
/* Callback for client imsg read events. */
/* ARGSUSED */
void
client_callback(unused int fd, short events, void *data)
client_callback(unused int fd, short events, unused void *data)
{
ssize_t n;
int retval;
if (events & EV_READ) {
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
goto lost_server;
if (client_attached)
retval = client_dispatch_attached();
else
retval = client_dispatch_wait(data);
if (retval != 0) {
if (client_dispatch() != 0) {
event_loopexit(NULL);
return;
}
@@ -354,76 +284,8 @@ lost_server:
event_loopexit(NULL);
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
int
client_dispatch_wait(void *data)
{
struct imsg imsg;
ssize_t n, datalen;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata;
const char *shellcmd = data;
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof exitdata) {
if (datalen != 0)
fatalx("bad MSG_EXIT size");
} else {
memcpy(&exitdata, imsg.data, sizeof exitdata);
client_exitval = exitdata.retcode;
}
imsg_free(&imsg);
return (-1);
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
client_attached = 1;
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
log_warnx("protocol version mismatch (client %u, "
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
client_exitval = 1;
imsg_free(&imsg);
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';
clear_signals(0);
shell_exec(shelldata.shell, shellcmd);
/* NOTREACHED */
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
}
}
/* Dispatch imsgs in attached state (after MSG_READY). */
/* ARGSUSED */
int
client_dispatch_attached(void)
client_dispatch(void)
{
struct imsg imsg;
struct msg_lock_data lockdata;
@@ -447,8 +309,7 @@ client_dispatch_attached(void)
client_exitmsg = "detached";
break;
case MSG_EXIT:
if (datalen != 0 &&
datalen != sizeof (struct msg_exit_data))
if (datalen != 0)
fatalx("bad MSG_EXIT size");
client_write_server(MSG_EXITING, NULL, 0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-attach-session.c,v 1.37 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: cmd-attach-session.c,v 1.36 2010-02-08 18:27:34 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -47,7 +47,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
char *overrides, *cause;
u_int i;
if (RB_EMPTY(&sessions)) {
if (ARRAY_LENGTH(&sessions) == 0) {
ctx->error(ctx, "no sessions");
return (-1);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-bind-key.c,v 1.29 2010-07-02 02:43:01 tcunha Exp $ */
/* $Id: cmd-bind-key.c,v 1.28 2010-01-25 17:12:44 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -130,7 +130,7 @@ cmd_bind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
return (cmd_bind_key_table(self, ctx));
key_bindings_add(data->key, data->can_repeat, data->cmdlist);
data->cmdlist->references++;
data->cmdlist = NULL; /* avoid free */
return (0);
}
@@ -192,17 +192,8 @@ cmd_bind_key_print(struct cmd *self, char *buf, size_t len)
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->command_key)
off += xsnprintf(buf + off, len - off, " -c");
if (off < len && !(data->key & KEYC_PREFIX))
off += xsnprintf(buf + off, len - off, " -n");
if (off < len && data->can_repeat)
off += xsnprintf(buf + off, len - off, " -r");
if (off < len && data->tablename != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->tablename);
if (off < len) {
skey = key_string_lookup_key(data->key & ~KEYC_PREFIX);
skey = key_string_lookup_key(data->key);
off += xsnprintf(buf + off, len - off, " %s ", skey);
}
if (off < len)

View File

@@ -1,146 +0,0 @@
/* $Id: cmd-choose-buffer.c,v 1.1 2010-06-22 23:35:20 tcunha Exp $ */
/*
* Copyright (c) 2010 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 <ctype.h>
#include "tmux.h"
/*
* Enter choice mode to choose a buffer.
*/
int cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_buffer_callback(void *, int);
void cmd_choose_buffer_free(void *);
const struct cmd_entry cmd_choose_buffer_entry = {
"choose-buffer", NULL,
CMD_TARGET_WINDOW_USAGE " [template]",
CMD_ARG01, "",
cmd_target_init,
cmd_target_parse,
cmd_choose_buffer_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_choose_buffer_data {
struct client *client;
char *template;
};
int
cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct cmd_choose_buffer_data *cdata;
struct session *s;
struct winlink *wl;
struct paste_buffer *pb;
u_int idx;
char *tmp;
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
return (-1);
}
s = ctx->curclient->session;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
if (paste_get_top(&s->buffers) == NULL)
return (0);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
return (0);
idx = 0;
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
tmp = paste_print(pb, 50);
window_choose_add(wl->window->active, idx - 1,
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
}
cdata = xmalloc(sizeof *cdata);
if (data->arg != NULL)
cdata->template = xstrdup(data->arg);
else
cdata->template = xstrdup("paste-buffer -b '%%'");
cdata->client = ctx->curclient;
cdata->client->references++;
window_choose_ready(wl->window->active,
0, cmd_choose_buffer_callback, cmd_choose_buffer_free, cdata);
return (0);
}
void
cmd_choose_buffer_callback(void *data, int idx)
{
struct cmd_choose_buffer_data *cdata = data;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause, tmp[16];
if (idx == -1)
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
xsnprintf(tmp, sizeof tmp, "%u", idx);
template = cmd_template_replace(cdata->template, tmp, 1);
if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(cdata->client, "%s", cause);
xfree(cause);
}
xfree(template);
return;
}
xfree(template);
ctx.msgdata = NULL;
ctx.curclient = cdata->client;
ctx.error = key_bindings_error;
ctx.print = key_bindings_print;
ctx.info = key_bindings_info;
ctx.cmdclient = NULL;
cmd_list_exec(cmdlist, &ctx);
cmd_list_free(cmdlist);
}
void
cmd_choose_buffer_free(void *data)
{
struct cmd_choose_buffer_data *cdata = data;
cdata->client->references--;
xfree(cdata->template);
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-choose-session.c,v 1.17 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: cmd-choose-session.c,v 1.15 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -55,7 +55,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *wl;
struct session *s;
struct session_group *sg;
u_int idx, sgidx, cur;
u_int i, idx, cur;
char tmp[64];
if (ctx->curclient == NULL) {
@@ -70,7 +70,10 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
return (0);
cur = idx = 0;
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
if (s == ctx->curclient->session)
cur = idx;
idx++;
@@ -79,11 +82,11 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
if (sg == NULL)
*tmp = '\0';
else {
sgidx = session_group_index(sg);
xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx);
idx = session_group_index(sg);
xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
}
window_choose_add(wl->window->active, s->idx,
window_choose_add(wl->window->active, i,
"%s: %u windows [%ux%u]%s%s", s->name,
winlink_count(&s->windows), s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
@@ -117,7 +120,9 @@ cmd_choose_session_callback(void *data, int idx)
if (cdata->client->flags & CLIENT_DEAD)
return;
s = session_find_by_index(idx);
if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1)
return;
s = ARRAY_ITEM(&sessions, idx);
if (s == NULL)
return;
template = cmd_template_replace(cdata->template, s->name, 1);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-choose-window.c,v 1.24 2010-12-22 15:28:50 tcunha Exp $ */
/* $Id: cmd-choose-window.c,v 1.20 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -81,14 +81,12 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
idx++;
flag = ' ';
if (wm->flags & WINLINK_ACTIVITY)
if (session_alert_has(s, wm, WINDOW_ACTIVITY))
flag = '#';
else if (wm->flags & WINLINK_BELL)
else if (session_alert_has(s, wm, WINDOW_BELL))
flag = '!';
else if (wm->flags & WINLINK_CONTENT)
else if (session_alert_has(s, wm, WINDOW_CONTENT))
flag = '+';
else if (wm->flags & WINLINK_SILENCE)
flag = '~';
else if (wm == s->curw)
flag = '*';
else if (wm == TAILQ_FIRST(&s->lastw))
@@ -103,9 +101,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
left = right = "";
window_choose_add(wl->window->active,
wm->idx, "%3d: %s%c [%ux%u] (%u panes%s)%s%s%s",
wm->idx, "%3d: %s%c [%ux%u] (%u panes)%s%s%s",
wm->idx, w->name, flag, w->sx, w->sy, window_count_panes(w),
w->active->fd == -1 ? ", dead" : "",
left, title, right);
}
@@ -129,19 +126,20 @@ void
cmd_choose_window_callback(void *data, int idx)
{
struct cmd_choose_window_data *cdata = data;
struct session *s = cdata->session;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *target, *template, *cause;
if (idx == -1)
return;
if (!session_alive(s))
return;
if (cdata->client->flags & CLIENT_DEAD)
return;
if (cdata->session->flags & SESSION_DEAD)
return;
if (cdata->client->session != cdata->session)
return;
xasprintf(&target, "%s:%d", s->name, idx);
xasprintf(&target, "%s:%d", cdata->session->name, idx);
template = cmd_template_replace(cdata->template, target, 1);
xfree(target);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-command-prompt.c,v 1.28 2010-05-14 14:33:39 tcunha Exp $ */
/* $Id: cmd-command-prompt.c,v 1.27 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -81,10 +81,6 @@ cmd_command_prompt_init(struct cmd *self, int key)
case 'f':
data->template = xstrdup("find-window '%%'");
break;
case '\'':
data->template = xstrdup("select-window -t ':%%'");
data->prompts = xstrdup("index");
break;
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-copy-mode.c,v 1.28 2010-08-11 22:18:28 tcunha Exp $ */
/* $Id: cmd-copy-mode.c,v 1.26 2010-01-05 23:50:22 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -62,9 +62,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
return (0);
window_copy_init_from_pane(wp);
window_pane_set_mode(wp, &window_copy_mode);
if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u'))
window_copy_pageup(wp);

View File

@@ -1,7 +1,7 @@
/* $Id: cmd-last-pane.c,v 1.1 2010-10-24 01:34:30 tcunha Exp $ */
/* $Id: cmd-down-pane.c,v 1.14 2010-01-05 23:52:37 tcunha Exp $ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
* 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
@@ -21,24 +21,24 @@
#include "tmux.h"
/*
* Move to last pane.
* Move down a pane.
*/
int cmd_last_pane_exec(struct cmd *, struct cmd_ctx *);
int cmd_down_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_last_pane_entry = {
"last-pane", "lastp",
const struct cmd_entry cmd_down_pane_entry = {
"down-pane", "downp",
CMD_TARGET_WINDOW_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_last_pane_exec,
cmd_down_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_last_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
@@ -48,11 +48,13 @@ cmd_last_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
w = wl->window;
if (w->last == NULL) {
ctx->error(ctx, "no last pane");
return (-1);
}
window_set_active_pane(w, w->last);
do {
w->active = TAILQ_NEXT(w->active, entry);
if (w->active == NULL)
w->active = TAILQ_FIRST(&w->panes);
} while (!window_pane_visible(w->active));
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-find-window.c,v 1.15 2010-12-22 15:28:50 tcunha Exp $ */
/* $Id: cmd-find-window.c,v 1.14 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,7 +30,6 @@
int cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_find_window_callback(void *, int);
void cmd_find_window_free(void *);
const struct cmd_entry cmd_find_window_entry = {
"find-window", "findw",
@@ -44,7 +43,7 @@ const struct cmd_entry cmd_find_window_entry = {
};
struct cmd_find_window_data {
struct session *session;
u_int session;
};
int
@@ -135,11 +134,11 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
}
cdata = xmalloc(sizeof *cdata);
cdata->session = s;
cdata->session->references++;
if (session_index(s, &cdata->session) != 0)
fatalx("session not found");
window_choose_ready(wl->window->active,
0, cmd_find_window_callback, cmd_find_window_free, cdata);
window_choose_ready(
wl->window->active, 0, cmd_find_window_callback, xfree, cdata);
out:
ARRAY_FREE(&list_idx);
@@ -152,24 +151,12 @@ void
cmd_find_window_callback(void *data, int idx)
{
struct cmd_find_window_data *cdata = data;
struct session *s = cdata->session;
struct session *s;
if (idx == -1)
return;
if (!session_alive(s))
return;
if (session_select(s, idx) == 0) {
server_redraw_session(s);
if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
s = ARRAY_ITEM(&sessions, cdata->session);
if (s != NULL && session_select(s, idx) == 0)
server_redraw_session(s);
recalculate_sizes();
}
}
void
cmd_find_window_free(void *data)
{
struct cmd_find_window_data *cdata = data;
cdata->session->references--;
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-if-shell.c,v 1.10 2010-08-09 21:44:25 tcunha Exp $ */
/* $Id: cmd-if-shell.c,v 1.8 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -104,12 +104,10 @@ cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
struct msg_exit_data exitdata;
if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--;
exitdata.retcode = ctx->cmdclient->retcode;
ctx->cmdclient->flags |= CLIENT_EXIT;
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
}
if (ctx->curclient != NULL)
ctx->curclient->references--;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-join-pane.c,v 1.5 2010-08-11 22:17:32 tcunha Exp $ */
/* $Id: cmd-join-pane.c,v 1.2 2010-01-08 16:34:17 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,7 +44,7 @@ struct cmd_join_pane_data {
const struct cmd_entry cmd_join_pane_entry = {
"join-pane", "joinp",
"[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
"[-dhv] [-p percentage|-l size] [-t src-pane] [-t dst-pane] [command]",
0, "",
cmd_join_pane_init,
cmd_join_pane_parse,
@@ -150,14 +150,13 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp;
int size, dst_idx;
int size;
enum layout_type type;
struct layout_cell *lc;
if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL)
return (-1);
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL)
return (-1);
@@ -210,7 +209,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (!data->flag_detached) {
window_set_active_pane(dst_w, src_wp);
session_select(dst_s, dst_idx);
session_select(dst_s, dst_wl->idx);
server_redraw_session(dst_s);
} else
server_status_session(dst_s);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-kill-session.c,v 1.18 2010-07-02 02:43:50 tcunha Exp $ */
/* $Id: cmd-kill-session.c,v 1.17 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,11 +45,21 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
u_int i;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
server_destroy_session(s);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session == s) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
}
}
recalculate_sizes();
session_destroy(s);
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-buffers.c,v 1.16 2010-06-22 23:35:20 tcunha Exp $ */
/* $Id: cmd-list-buffers.c,v 1.15 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,17 +46,32 @@ cmd_list_buffers_exec(struct cmd *self, struct cmd_ctx *ctx)
struct session *s;
struct paste_buffer *pb;
u_int idx;
char *tmp;
char tmp[51 * 4 + 1];
size_t size, len;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
idx = 0;
while ((pb = paste_walk_stack(&s->buffers, &idx)) != NULL) {
tmp = paste_print(pb, 50);
ctx->print(ctx,
"%u: %zu bytes: \"%s\"", idx - 1, pb->size, tmp);
xfree(tmp);
size = pb->size;
/* Translate the first 50 characters. */
len = size;
if (len > 50)
len = 50;
strvisx(tmp, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
/*
* If the first 50 characters were encoded as a longer string,
* or there is definitely more data, add "...".
*/
if (size > 50 || strlen(tmp) > 50) {
tmp[50 - 3] = '\0';
strlcat(tmp, "...", sizeof tmp);
}
ctx->print(ctx, "%u: %zu bytes: \"%s\"", idx - 1, size, tmp);
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-keys.c,v 1.25 2010-10-24 01:31:57 tcunha Exp $ */
/* $Id: cmd-list-keys.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -80,11 +80,6 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
if (used >= sizeof tmp)
continue;
}
if (bd->can_repeat) {
used = strlcat(tmp, "(repeat) ", sizeof tmp);
if (used >= sizeof tmp)
continue;
}
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
ctx->print(ctx, "%s", tmp);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-panes.c,v 1.6 2010-12-06 21:56:32 nicm Exp $ */
/* $Id: cmd-list-panes.c,v 1.4 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -65,10 +65,8 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
}
size += gd->hsize * sizeof *gd->linedata;
ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s%s",
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
wp == wp->window->active ? " (active)" : "",
wp->fd == -1 ? " (dead)" : "");
ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]",
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
n++;
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-sessions.c,v 1.26 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: cmd-list-sessions.c,v 1.25 2009-11-28 14:50:36 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,10 +46,14 @@ cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
struct session *s;
struct session_group *sg;
char *tim, tmp[64];
u_int idx;
u_int i, idx;
time_t t;
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
sg = session_group_find(s);
if (sg == NULL)
*tmp = '\0';

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-windows.c,v 1.44 2010-12-06 21:56:32 nicm Exp $ */
/* $Id: cmd-list-windows.c,v 1.42 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,17 +45,13 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data;
struct session *s;
struct winlink *wl;
char *layout;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_FOREACH(wl, winlinks, &s->windows) {
layout = layout_dump(wl->window);
ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s",
wl->idx, wl->window->name, wl->window->sx, wl->window->sy,
layout, wl == s->curw ? " (active)" : "");
xfree(layout);
ctx->print(ctx, "%d: %s [%ux%u]",
wl->idx, wl->window->name, wl->window->sx, wl->window->sy);
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list.c,v 1.10 2010-12-06 21:48:56 nicm Exp $ */
/* $Id: cmd-list.c,v 1.7 2010-02-02 23:51:04 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,52 +29,47 @@ cmd_list_parse(int argc, char **argv, char **cause)
struct cmd *cmd;
int i, lastsplit;
size_t arglen, new_argc;
char **copy_argv, **new_argv;
copy_argv = cmd_copy_argv(argc, argv);
char **new_argv;
cmdlist = xmalloc(sizeof *cmdlist);
cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list);
TAILQ_INIT(cmdlist);
lastsplit = 0;
for (i = 0; i < argc; i++) {
arglen = strlen(copy_argv[i]);
if (arglen == 0 || copy_argv[i][arglen - 1] != ';')
arglen = strlen(argv[i]);
if (arglen == 0 || argv[i][arglen - 1] != ';')
continue;
copy_argv[i][arglen - 1] = '\0';
argv[i][arglen - 1] = '\0';
if (arglen > 1 && copy_argv[i][arglen - 2] == '\\') {
copy_argv[i][arglen - 2] = ';';
if (arglen > 1 && argv[i][arglen - 2] == '\\') {
argv[i][arglen - 2] = ';';
continue;
}
new_argc = i - lastsplit;
new_argv = copy_argv + lastsplit;
new_argv = argv + lastsplit;
if (arglen != 1)
new_argc++;
cmd = cmd_parse(new_argc, new_argv, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
lastsplit = i + 1;
}
if (lastsplit != argc) {
cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause);
cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
}
cmd_free_argv(argc, copy_argv);
return (cmdlist);
bad:
cmd_list_free(cmdlist);
cmd_free_argv(argc, copy_argv);
return (NULL);
}
@@ -85,7 +80,7 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
int n, retval;
retval = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if ((n = cmd_exec(cmd, ctx)) == -1)
return (-1);
@@ -104,10 +99,6 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
if (ctx->curclient == NULL) {
ctx->curclient = ctx->cmdclient;
ctx->cmdclient = NULL;
ctx->error = key_bindings_error;
ctx->print = key_bindings_print;
ctx->info = key_bindings_info;
}
}
}
@@ -119,12 +110,9 @@ cmd_list_free(struct cmd_list *cmdlist)
{
struct cmd *cmd;
if (--cmdlist->references != 0)
return;
while (!TAILQ_EMPTY(&cmdlist->list)) {
cmd = TAILQ_FIRST(&cmdlist->list);
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
while (!TAILQ_EMPTY(cmdlist)) {
cmd = TAILQ_FIRST(cmdlist);
TAILQ_REMOVE(cmdlist, cmd, qentry);
cmd_free(cmd);
}
xfree(cmdlist);
@@ -137,7 +125,7 @@ cmd_list_print(struct cmd_list *cmdlist, char *buf, size_t len)
size_t off;
off = 0;
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (off >= len)
break;
off += cmd_print(cmd, buf + off, len - off);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-load-buffer.c,v 1.18 2010-12-22 15:28:50 tcunha Exp $ */
/* $Id: cmd-load-buffer.c,v 1.15 2010-02-26 13:30:07 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -16,13 +16,10 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -31,7 +28,6 @@
*/
int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_load_buffer_callback(struct client *, void *);
const struct cmd_entry cmd_load_buffer_entry = {
"load-buffer", "loadb",
@@ -44,53 +40,20 @@ const struct cmd_entry cmd_load_buffer_entry = {
cmd_buffer_print
};
struct cmd_load_buffer_cdata {
struct session *session;
int buffer;
};
int
cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_buffer_data *data = self->data;
struct cmd_load_buffer_cdata *cdata;
struct session *s;
struct client *c = ctx->cmdclient;
FILE *f;
char *pdata, *new_pdata;
size_t psize;
u_int limit;
int ch;
struct cmd_buffer_data *data = self->data;
struct session *s;
FILE *f;
char *pdata, *new_pdata;
size_t psize;
u_int limit;
int ch;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (strcmp(data->arg, "-") == 0) {
if (c == NULL) {
ctx->error(ctx, "%s: can't read from stdin", data->arg);
return (-1);
}
if (c->flags & CLIENT_TERMINAL) {
ctx->error(ctx, "%s: stdin is a tty", data->arg);
return (-1);
}
if (c->stdin_fd == -1) {
ctx->error(ctx, "%s: can't read from stdin", data->arg);
return (-1);
}
cdata = xmalloc(sizeof *cdata);
cdata->session = s;
cdata->session->references++;
cdata->buffer = data->buffer;
c->stdin_data = cdata;
c->stdin_callback = cmd_load_buffer_callback;
c->references++;
bufferevent_enable(c->stdin_event, EV_READ);
return (1);
}
if ((f = fopen(data->arg, "rb")) == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
@@ -115,7 +78,6 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
pdata[psize] = '\0';
fclose(f);
f = NULL;
limit = options_get_number(&s->options, "buffer-limit");
if (data->buffer == -1) {
@@ -124,7 +86,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
}
if (paste_replace(&s->buffers, data->buffer, pdata, psize) != 0) {
ctx->error(ctx, "no buffer %d", data->buffer);
return (-1);
goto error;
}
return (0);
@@ -132,54 +94,6 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
error:
if (pdata != NULL)
xfree(pdata);
if (f != NULL)
fclose(f);
fclose(f);
return (-1);
}
void
cmd_load_buffer_callback(struct client *c, void *data)
{
struct cmd_load_buffer_cdata *cdata = data;
struct session *s = cdata->session;
char *pdata;
size_t psize;
u_int limit;
/*
* Event callback has already checked client is not dead and reduced
* its reference count. But tell it to exit.
*/
c->flags |= CLIENT_EXIT;
/* Does the target session still exist? */
if (!session_alive(s))
goto out;
psize = EVBUFFER_LENGTH(c->stdin_event->input);
if (psize == 0)
goto out;
pdata = malloc(psize + 1);
if (pdata == NULL)
goto out;
bufferevent_read(c->stdin_event, pdata, psize);
pdata[psize] = '\0';
limit = options_get_number(&s->options, "buffer-limit");
if (cdata->buffer == -1) {
paste_add(&s->buffers, pdata, psize, limit);
goto out;
}
if (paste_replace(&s->buffers, cdata->buffer, pdata, psize) != 0) {
/* No context so can't use server_client_msg_error. */
evbuffer_add_printf(
c->stderr_event->output, "no buffer %d\n", cdata->buffer);
bufferevent_enable(c->stderr_event, EV_WRITE);
goto out;
}
out:
cdata->session->references--;
xfree(cdata);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-new-session.c,v 1.80 2010-12-22 15:31:00 tcunha Exp $ */
/* $Id: cmd-new-session.c,v 1.76 2010-02-26 13:28:15 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,10 +18,8 @@
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "tmux.h"
@@ -122,14 +120,13 @@ int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_session_data *data = self->data;
struct session *s, *old_s, *groupwith;
struct session *s, *groupwith;
struct window *w;
struct window_pane *wp;
struct environ env;
struct termios tio, *tiop;
struct passwd *pw;
const char *update, *cwd;
char *overrides, *cmd, *cause;
const char *update;
char *overrides, *cmd, *cwd, *cause;
int detached, idx;
u_int sx, sy, i;
@@ -201,13 +198,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
/* Get the new session working directory. */
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else {
pw = getpwuid(getuid());
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
cwd = pw->pw_dir;
else
cwd = "/";
}
else
cwd = options_get_string(&global_s_options, "default-path");
/* Find new session size. */
if (detached) {
@@ -279,16 +271,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
if (!detached) {
if (ctx->cmdclient != NULL) {
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
old_s = ctx->cmdclient->session;
if (old_s != NULL)
ctx->cmdclient->last_session = old_s;
ctx->cmdclient->session = s;
server_redraw_client(ctx->cmdclient);
} else {
old_s = ctx->curclient->session;
if (old_s != NULL)
ctx->curclient->last_session = old_s;
ctx->curclient->session = s;
server_redraw_client(ctx->curclient);
}
@@ -302,11 +287,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
*/
if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) {
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
window_pane_set_mode(wp, &window_more_mode);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_copy_add(wp, "%s", cause);
window_more_add(wp, "%s", cause);
xfree(cause);
}
ARRAY_FREE(&cfg_causes);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-new-window.c,v 1.47 2010-07-02 02:49:19 tcunha Exp $ */
/* $Id: cmd-new-window.c,v 1.43 2010-01-22 17:28:34 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -36,14 +36,13 @@ struct cmd_new_window_data {
char *target;
char *name;
char *cmd;
int flag_insert_after;
int flag_detached;
int flag_kill;
};
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
"[-adk] [-n window-name] [-t target-window] [command]",
"[-dk] [-n window-name] [-t target-window] [command]",
0, "",
cmd_new_window_init,
cmd_new_window_parse,
@@ -62,7 +61,6 @@ cmd_new_window_init(struct cmd *self, unused int arg)
data->target = NULL;
data->name = NULL;
data->cmd = NULL;
data->flag_insert_after = 0;
data->flag_detached = 0;
data->flag_kill = 0;
}
@@ -76,11 +74,8 @@ cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
self->entry->init(self, KEYC_NONE);
data = self->data;
while ((opt = getopt(argc, argv, "adkt:n:")) != -1) {
while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
switch (opt) {
case 'a':
data->flag_insert_after = 1;
break;
case 'd':
data->flag_detached = 1;
break;
@@ -123,36 +118,13 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct session *s;
struct winlink *wl;
char *cmd, *cwd, *cause;
int idx, last;
int idx;
if (data == NULL)
return (0);
if (data->flag_insert_after) {
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
idx = wl->idx + 1;
/* Find the next free index. */
for (last = idx; last < INT_MAX; last++) {
if (winlink_find_by_index(&s->windows, last) == NULL)
break;
}
if (last == INT_MAX) {
ctx->error(ctx, "no free window indexes");
return (-1);
}
/* Move everything from last - 1 to idx up a bit. */
for (; last > idx; last--) {
wl = winlink_find_by_index(&s->windows, last - 1);
server_link_window(s, wl, s, last, 0, 0, NULL);
server_unlink_window(s, wl);
}
} else {
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
return (-1);
}
if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
return (-1);
wl = NULL;
if (idx != -1)
@@ -162,7 +134,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
* Can't use session_detach as it will destroy session if this
* makes it empty.
*/
wl->flags &= ~WINLINK_ALERTFLAGS;
session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
@@ -176,13 +148,10 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
cwd = options_get_string(&s->options, "default-path");
else
cwd = ctx->cmdclient->cwd;
if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index");

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-paste-buffer.c,v 1.29 2010-08-11 22:17:32 tcunha Exp $ */
/* $Id: cmd-paste-buffer.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,7 +18,6 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@@ -27,112 +26,32 @@
* Paste paste buffer if present.
*/
struct cmd_paste_buffer_data {
char *target;
int buffer;
int flag_delete;
char *sepstr;
};
void cmd_paste_buffer_init(struct cmd *, int);
int cmd_paste_buffer_parse(struct cmd *, int, char **, char **);
int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
void cmd_paste_buffer_filter(
struct window_pane *, const char *, size_t, char *);
void cmd_paste_buffer_free(struct cmd *);
size_t cmd_paste_buffer_print(struct cmd *, char *, size_t);
void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t);
const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb",
"[-dr] [-s separator] [-b buffer-index] [-t target-pane]",
0, "",
cmd_paste_buffer_init,
cmd_paste_buffer_parse,
"[-dr] " CMD_BUFFER_WINDOW_USAGE,
0, "dr",
cmd_buffer_init,
cmd_buffer_parse,
cmd_paste_buffer_exec,
cmd_paste_buffer_free,
cmd_paste_buffer_print
cmd_buffer_free,
cmd_buffer_print
};
/* ARGSUSED */
void
cmd_paste_buffer_init(struct cmd *self, unused int arg)
{
struct cmd_paste_buffer_data *data;
self->data = data = xmalloc(sizeof *data);
data->target = NULL;
data->buffer = -1;
data->flag_delete = 0;
data->sepstr = xstrdup("\r");
}
int
cmd_paste_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_paste_buffer_data *data;
int opt, n;
const char *errstr;
cmd_paste_buffer_init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "b:ds:t:r")) != -1) {
switch (opt) {
case 'b':
if (data->buffer == -1) {
n = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL) {
xasprintf(cause, "buffer %s", errstr);
goto error;
}
data->buffer = n;
}
break;
case 'd':
data->flag_delete = 1;
break;
case 's':
if (data->sepstr != NULL)
xfree(data->sepstr);
data->sepstr = xstrdup(optarg);
break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'r':
if (data->sepstr != NULL)
xfree(data->sepstr);
data->sepstr = xstrdup("\n");
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
error:
self->entry->free(self);
return (-1);
}
int
cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_paste_buffer_data *data = self->data;
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
struct cmd_buffer_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
wp = wl->window->active;
if (data->buffer == -1)
pb = paste_get_top(&s->buffers);
@@ -143,11 +62,16 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
if (pb != NULL)
cmd_paste_buffer_filter(wp, pb->data, pb->size, data->sepstr);
if (pb != NULL) {
/* -r means raw data without LF->CR conversion. */
if (cmd_check_flag(data->chflags, 'r'))
bufferevent_write(wp->event, pb->data, pb->size);
else
cmd_paste_buffer_lf2cr(wp, pb->data, pb->size);
}
/* Delete the buffer if -d. */
if (data->flag_delete) {
if (cmd_check_flag(data->chflags, 'd')) {
if (data->buffer == -1)
paste_free_top(&s->buffers);
else
@@ -157,66 +81,20 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
return (0);
}
/* Add bytes to a buffer and filter '\n' according to separator. */
/* Add bytes to a buffer but change every '\n' to '\r'. */
void
cmd_paste_buffer_filter(
struct window_pane *wp, const char *data, size_t size, char *sep)
cmd_paste_buffer_lf2cr(struct window_pane *wp, const char *data, size_t size)
{
const char *end = data + size;
const char *lf;
size_t seplen;
seplen = strlen(sep);
while ((lf = memchr(data, '\n', end - data)) != NULL) {
if (lf != data)
bufferevent_write(wp->event, data, lf - data);
bufferevent_write(wp->event, sep, seplen);
bufferevent_write(wp->event, "\r", 1);
data = lf + 1;
}
if (end != data)
bufferevent_write(wp->event, data, end - data);
}
void
cmd_paste_buffer_free(struct cmd *self)
{
struct cmd_paste_buffer_data *data = self->data;
if (data->target != NULL)
xfree(data->target);
if (data->sepstr != NULL)
xfree(data->sepstr);
xfree(data);
}
size_t
cmd_paste_buffer_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_paste_buffer_data *data = self->data;
size_t off = 0;
char tmp[BUFSIZ];
int r_flag;
r_flag = 0;
if (data->sepstr != NULL)
r_flag = (data->sepstr[0] == '\n' && data->sepstr[1] == '\0');
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_delete)
off += xsnprintf(buf + off, len - off, " -d");
if (off < len && r_flag)
off += xsnprintf(buf + off, len - off, " -r");
if (off < len && data->buffer != -1)
off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
if (off < len && data->sepstr != NULL && !r_flag) {
strnvis(
tmp, data->sepstr, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL);
off += cmd_prarg(buf + off, len - off, " -s ", tmp);
}
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
return (off);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-pipe-pane.c,v 1.15 2010-10-24 00:45:57 tcunha Exp $ */
/* $Id: cmd-pipe-pane.c,v 1.10 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -22,7 +22,6 @@
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
@@ -50,14 +49,9 @@ int
cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct client *c;
struct window_pane *wp;
char *command;
int old_fd, pipe_fd[2], null_fd, mode;
if ((c = cmd_find_client(ctx, NULL)) == NULL)
return (-1);
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
@@ -96,7 +90,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
case 0:
/* Child process. */
close(pipe_fd[0]);
clear_signals(1);
server_signal_clear();
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
@@ -111,10 +105,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
closefrom(STDERR_FILENO + 1);
command = status_replace(c, NULL, data->arg, time(NULL), 0);
execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL);
execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL);
_exit(1);
default:
/* Parent process. */
@@ -131,6 +122,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
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);
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-rename-session.c,v 1.21 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: cmd-rename-session.c,v 1.19 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,18 +45,11 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data;
struct session *s;
if (data->arg != NULL && session_find(data->arg) != NULL) {
ctx->error(ctx, "duplicate session: %s", data->arg);
return (-1);
}
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_REMOVE(sessions, &sessions, s);
xfree(s->name);
s->name = xstrdup(data->arg);
RB_INSERT(sessions, &sessions, s);
server_status_session(s);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-run-shell.c,v 1.9 2010-08-09 21:44:25 tcunha Exp $ */
/* $Id: cmd-run-shell.c,v 1.6 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -82,11 +82,6 @@ cmd_run_shell_callback(struct job *job)
int retcode;
u_int lines;
if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD)
return;
if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD)
return;
lines = 0;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
@@ -134,7 +129,7 @@ cmd_run_shell_free(void *data)
if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--;
ctx->cmdclient->flags |= CLIENT_EXIT;
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
}
if (ctx->curclient != NULL)
ctx->curclient->references--;

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-save-buffer.c,v 1.12 2010-08-09 21:44:25 tcunha Exp $ */
/* $Id: cmd-save-buffer.c,v 1.10 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -47,7 +47,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_buffer_data *data = self->data;
struct session *s;
struct paste_buffer *pb;
mode_t mask;
mode_t mask;
FILE *f;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
@@ -65,31 +65,24 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
if (strcmp(data->arg, "-") == 0) {
if (ctx->cmdclient == NULL) {
ctx->error(ctx, "%s: can't write to stdout", data->arg);
return (-1);
}
bufferevent_write(
ctx->cmdclient->stdout_event, pb->data, pb->size);
} else {
mask = umask(S_IRWXG | S_IRWXO);
if (cmd_check_flag(data->chflags, 'a'))
f = fopen(data->arg, "ab");
else
f = fopen(data->arg, "wb");
umask(mask);
if (f == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", data->arg);
fclose(f);
return (-1);
}
fclose(f);
mask = umask(S_IRWXG | S_IRWXO);
if (cmd_check_flag(data->chflags, 'a'))
f = fopen(data->arg, "ab");
else
f = fopen(data->arg, "wb");
umask(mask);
if (f == NULL) {
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
return (-1);
}
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
ctx->error(ctx, "%s: fwrite error", data->arg);
fclose(f);
return (-1);
}
fclose(f);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-select-layout.c,v 1.12 2010-07-02 02:54:52 tcunha Exp $ */
/* $Id: cmd-select-layout.c,v 1.10 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -59,9 +59,6 @@ cmd_select_layout_init(struct cmd *self, int key)
case ('4' | KEYC_ESCAPE):
data->arg = xstrdup("main-vertical");
break;
case ('5' | KEYC_ESCAPE):
data->arg = xstrdup("tiled");
break;
}
}
@@ -79,16 +76,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
layout = wl->window->lastlayout;
if (layout == -1)
return (0);
} else if ((layout = layout_set_lookup(data->arg)) != -1) {
layout = layout_set_select(wl->window, layout);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
} else {
if (layout_parse(wl->window, data->arg) == -1) {
ctx->error(ctx, "can't set layout: %s", data->arg);
return (-1);
}
ctx->info(ctx, "arranging in: %s", data->arg);
} else if ((layout = layout_set_lookup(data->arg)) == -1) {
ctx->error(ctx, "unknown layout or ambiguous: %s", data->arg);
return (-1);
}
layout = layout_set_select(wl->window, layout);
ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-select-pane.c,v 1.13 2010-03-15 22:03:38 nicm Exp $ */
/* $Id: cmd-select-pane.c,v 1.12 2010-01-05 23:52:37 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,40 +24,19 @@
* Select pane.
*/
void cmd_select_pane_init(struct cmd *, int);
int cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp",
"[-DLRU] " CMD_TARGET_PANE_USAGE,
0, "DLRU",
cmd_select_pane_init,
CMD_TARGET_PANE_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_select_pane_exec,
cmd_target_free,
cmd_target_print
};
void
cmd_select_pane_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
if (key == KEYC_UP)
cmd_set_flag(&data->chflags, 'U');
if (key == KEYC_DOWN)
cmd_set_flag(&data->chflags, 'D');
if (key == KEYC_LEFT)
cmd_set_flag(&data->chflags, 'L');
if (key == KEYC_RIGHT)
cmd_set_flag(&data->chflags, 'R');
if (key == 'o')
data->target = xstrdup(":.+");
}
int
cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
@@ -72,20 +51,6 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->error(ctx, "pane not visible: %s", data->target);
return (-1);
}
if (cmd_check_flag(data->chflags, 'L'))
wp = window_pane_find_left(wp);
else if (cmd_check_flag(data->chflags, 'R'))
wp = window_pane_find_right(wp);
else if (cmd_check_flag(data->chflags, 'U'))
wp = window_pane_find_up(wp);
else if (cmd_check_flag(data->chflags, 'D'))
wp = window_pane_find_down(wp);
if (wp == NULL) {
ctx->error(ctx, "pane not found");
return (-1);
}
window_set_active_pane(wl->window, wp);
server_status_window(wl->window);
server_redraw_window_borders(wl->window);

91
cmd-select-prompt.c Normal file
View File

@@ -0,0 +1,91 @@
/* $Id: cmd-select-prompt.c,v 1.13 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Prompt for window index and select it.
*/
int cmd_select_prompt_exec(struct cmd *, struct cmd_ctx *);
int cmd_select_prompt_callback(void *, const char *);
const struct cmd_entry cmd_select_prompt_entry = {
"select-prompt", NULL,
CMD_TARGET_CLIENT_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_select_prompt_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_select_prompt_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);
if (c->prompt_string != NULL)
return (0);
status_prompt_set(c, "index ", cmd_select_prompt_callback, NULL, c, 0);
return (0);
}
int
cmd_select_prompt_callback(void *data, const char *s)
{
struct client *c = data;
const char *errstr;
char msg[128];
u_int idx;
if (s == NULL || *s == '\0')
return (0);
idx = strtonum(s, 0, UINT_MAX, &errstr);
if (errstr != NULL) {
xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s);
status_message_set(c, "%s", msg);
return (0);
}
if (winlink_find_by_index(&c->session->windows, idx) == NULL) {
xsnprintf(msg, sizeof msg,
"Window not found: %s:%d", c->session->name, idx);
status_message_set(c, "%s", msg);
return (0);
}
if (session_select(c->session, idx) == 0)
server_redraw_session(c->session);
recalculate_sizes();
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-send-keys.c,v 1.25 2010-05-22 21:56:04 micahcowan Exp $ */
/* $Id: cmd-send-keys.c,v 1.24 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -105,17 +105,16 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_send_keys_data *data = self->data;
struct window_pane *wp;
struct session *s;
u_int i;
if (data == NULL)
return (-1);
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
for (i = 0; i < data->nkeys; i++)
window_pane_key(wp, s, data->keys[i]);
window_pane_key(wp, ctx->curclient, data->keys[i]);
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-send-prefix.c,v 1.29 2010-05-22 21:56:04 micahcowan Exp $ */
/* $Id: cmd-send-prefix.c,v 1.28 2009-11-14 17:56:39 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -49,7 +49,7 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
keylist = options_get_data(&s->options, "prefix");
window_pane_key(wp, s, ARRAY_FIRST(keylist));
window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist));
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-server-info.c,v 1.38 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: cmd-server-info.c,v 1.37 2009-12-10 16:59:02 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -81,6 +81,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
else
ctx->print(ctx, "configuration file not specified");
ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION);
ctx->print(ctx, "%u clients, %u sessions",
ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions));
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Clients:");
@@ -99,14 +101,19 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
ctx->print(ctx, "Sessions: [%zu/%zu]",
sizeof (struct grid_cell), sizeof (struct grid_utf8));
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
t = s->creation_time.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] "
"[flags=0x%x]", s->idx, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
"[flags=0x%x, references=%u]", i, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags,
s->references);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, "

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-set-option.c,v 1.102 2010-12-22 15:23:59 tcunha Exp $ */
/* $Id: cmd-set-option.c,v 1.96 2010-02-26 13:31:39 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -75,7 +75,6 @@ const char *set_option_bell_action_list[] = {
const struct set_option_entry set_option_table[] = {
{ "escape-time", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "exit-unattached", SET_OPTION_FLAG, 0, 0, NULL },
{ "quiet", SET_OPTION_FLAG, 0, 0, NULL },
{ NULL, 0, 0, 0, NULL }
};
@@ -88,8 +87,6 @@ const struct set_option_entry set_session_option_table[] = {
{ "default-path", SET_OPTION_STRING, 0, 0, NULL },
{ "default-shell", SET_OPTION_STRING, 0, 0, NULL },
{ "default-terminal", SET_OPTION_STRING, 0, 0, NULL },
{ "destroy-unattached", SET_OPTION_FLAG, 0, 0, NULL },
{ "detach-on-destroy", SET_OPTION_FLAG, 0, 0, NULL },
{ "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL },
{ "display-panes-active-colour", SET_OPTION_COLOUR, 0, 0, NULL },
{ "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL },
@@ -136,7 +133,6 @@ const struct set_option_entry set_session_option_table[] = {
{ "visual-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-bell", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-content", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-silence", SET_OPTION_FLAG, 0, 0, NULL },
{ NULL, 0, 0, 0, NULL }
};
@@ -158,15 +154,9 @@ const struct set_option_entry set_window_option_table[] = {
{ "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL },
{ "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "monitor-content", SET_OPTION_STRING, 0, 0, NULL },
{ "monitor-silence",SET_OPTION_NUMBER, 0, INT_MAX, NULL},
{ "other-pane-height", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "other-pane-width", SET_OPTION_NUMBER, 0, INT_MAX, NULL },
{ "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL },
{ "utf8", SET_OPTION_FLAG, 0, 0, NULL },
{ "window-status-alert-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "window-status-alert-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-alert-fg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "window-status-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "window-status-current-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
@@ -299,7 +289,6 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
*/
if (strcmp(entry->name, "status-left") == 0 ||
strcmp(entry->name, "status-right") == 0 ||
strcmp(entry->name, "status") == 0 ||
strcmp(entry->name, "set-titles-string") == 0 ||
strcmp(entry->name, "window-status-format") == 0) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-split-window.c,v 1.35 2010-07-02 02:49:19 tcunha Exp $ */
/* $Id: cmd-split-window.c,v 1.34 2010-01-08 16:31:35 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -169,13 +169,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd = data->cmd;
if (cmd == NULL)
cmd = options_get_string(&s->options, "default-command");
cwd = options_get_string(&s->options, "default-path");
if (*cwd == '\0') {
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
cwd = ctx->cmdclient->cwd;
else
cwd = s->cwd;
}
if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
cwd = options_get_string(&s->options, "default-path");
else
cwd = ctx->cmdclient->cwd;
type = LAYOUT_TOPBOTTOM;
if (data->flag_horizontal)

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-string.c,v 1.32 2010-12-13 22:53:56 nicm Exp $ */
/* $Id: cmd-string.c,v 1.31 2010-02-26 13:27:38 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -247,10 +247,9 @@ error:
char *
cmd_string_variable(const char *s, size_t *p)
{
int ch, fch;
char *buf, *t;
size_t len;
struct environ_entry *envent;
int ch, fch;
char *buf, *t;
size_t len;
#define cmd_string_first(ch) ((ch) == '_' || \
((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
@@ -302,11 +301,12 @@ cmd_string_variable(const char *s, size_t *p)
buf = xrealloc(buf, 1, len + 1);
buf[len] = '\0';
envent = environ_find(&global_environ, buf);
xfree(buf);
if (envent == NULL)
if ((t = getenv(buf)) == NULL) {
xfree(buf);
return (xstrdup(""));
return (xstrdup(envent->value));
}
xfree(buf);
return (xstrdup(t));
error:
if (buf != NULL)
@@ -317,17 +317,15 @@ error:
char *
cmd_string_expand_tilde(const char *s, size_t *p)
{
struct passwd *pw;
struct environ_entry *envent;
char *home, *path, *username;
struct passwd *pw;
char *home, *path, *username;
home = NULL;
if (cmd_string_getc(s, p) == '/') {
envent = environ_find(&global_environ, "HOME");
if (envent != NULL && *envent->value != '\0')
home = envent->value;
else if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir;
if ((home = getenv("HOME")) == NULL || *home == '\0') {
if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir;
}
} else {
cmd_string_ungetc(p);
if ((username = cmd_string_string(s, p, '/', 0)) == NULL)

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-switch-client.c,v 1.23 2010-12-22 15:31:00 tcunha Exp $ */
/* $Id: cmd-switch-client.c,v 1.19 2010-01-25 17:12:44 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,7 +27,6 @@
* Switch client to a different session.
*/
void cmd_switch_client_init(struct cmd *, int);
int cmd_switch_client_parse(struct cmd *, int, char **, char **);
int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
void cmd_switch_client_free(struct cmd *);
@@ -36,83 +35,36 @@ size_t cmd_switch_client_print(struct cmd *, char *, size_t);
struct cmd_switch_client_data {
char *name;
char *target;
int flag_last;
int flag_next;
int flag_previous;
};
const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc",
"[-lnp] [-c target-client] [-t target-session]",
"[-c target-client] [-t target-session]",
0, "",
cmd_switch_client_init,
NULL,
cmd_switch_client_parse,
cmd_switch_client_exec,
cmd_switch_client_free,
cmd_switch_client_print
};
void
cmd_switch_client_init(struct cmd *self, int key)
{
struct cmd_switch_client_data *data;
self->data = data = xmalloc(sizeof *data);
data->name = NULL;
data->target = NULL;
data->flag_last = 0;
data->flag_next = 0;
data->flag_previous = 0;
switch (key) {
case '(':
data->flag_previous = 1;
break;
case ')':
data->flag_next = 1;
break;
case 'L':
data->flag_last = 1;
break;
}
}
int
cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_switch_client_data *data;
int opt;
self->entry->init(self, KEYC_NONE);
data = self->data;
self->data = data = xmalloc(sizeof *data);
data->name = NULL;
data->target = NULL;
while ((opt = getopt(argc, argv, "c:lnpt:")) != -1) {
while ((opt = getopt(argc, argv, "c:t:")) != -1) {
switch (opt) {
case 'c':
if (data->name == NULL)
data->name = xstrdup(optarg);
break;
case 'l':
if (data->flag_next || data->flag_previous ||
data->target != NULL)
goto usage;
data->flag_last = 1;
break;
case 'n':
if (data->flag_previous || data->flag_last ||
data->target != NULL)
goto usage;
data->flag_next = 1;
break;
case 'p':
if (data->flag_next || data->flag_last ||
data->target != NULL)
goto usage;
data->flag_next = 1;
break;
case 't':
if (data->flag_next || data->flag_previous)
goto usage;
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
@@ -146,36 +98,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((c = cmd_find_client(ctx, data->name)) == NULL)
return (-1);
s = NULL;
if (data->flag_next) {
if ((s = session_next_session(c->session)) == NULL) {
ctx->error(ctx, "can't find next session");
return (-1);
}
} else if (data->flag_previous) {
if ((s = session_previous_session(c->session)) == NULL) {
ctx->error(ctx, "can't find previous session");
return (-1);
}
} else if (data->flag_last) {
if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session;
if (s == NULL) {
ctx->error(ctx, "can't find last session");
return (-1);
}
} else
s = cmd_find_session(ctx, data->target);
if (s == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
if (c->session != NULL)
c->last_session = c->session;
c->session = s;
recalculate_sizes();
server_check_unattached();
server_redraw_client(c);
return (0);
@@ -202,12 +130,6 @@ cmd_switch_client_print(struct cmd *self, char *buf, size_t len)
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_last)
off += xsnprintf(buf + off, len - off, "%s", " -l");
if (off < len && data->flag_next)
off += xsnprintf(buf + off, len - off, "%s", " -n");
if (off < len && data->flag_previous)
off += xsnprintf(buf + off, len - off, "%s", " -p");
if (off < len && data->name != NULL)
off += cmd_prarg(buf + off, len - off, " -c ", data->name);
if (off < len && data->target != NULL)

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-unbind-key.c,v 1.23 2010-12-06 21:51:02 nicm Exp $ */
/* $Id: cmd-unbind-key.c,v 1.22 2010-01-25 17:12:44 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -33,14 +33,13 @@ int cmd_unbind_key_table(struct cmd *, struct cmd_ctx *);
struct cmd_unbind_key_data {
int key;
int flag_all;
int command_key;
char *tablename;
};
const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind",
"[-acn] [-t key-table] key",
"[-cn] [-t key-table] key",
0, "",
NULL,
cmd_unbind_key_parse,
@@ -56,15 +55,11 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
int opt, no_prefix = 0;
self->data = data = xmalloc(sizeof *data);
data->flag_all = 0;
data->command_key = 0;
data->tablename = NULL;
while ((opt = getopt(argc, argv, "acnt:")) != -1) {
while ((opt = getopt(argc, argv, "cnt:")) != -1) {
switch (opt) {
case 'a':
data->flag_all = 1;
break;
case 'c':
data->command_key = 1;
break;
@@ -81,20 +76,15 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause)
}
argc -= optind;
argv += optind;
if (data->flag_all && (argc != 0 || data->tablename))
goto usage;
if (!data->flag_all && argc != 1)
if (argc != 1)
goto usage;
if (!data->flag_all) {
data->key = key_string_lookup_string(argv[0]);
if (data->key == KEYC_NONE) {
xasprintf(cause, "unknown key: %s", argv[0]);
goto error;
}
if (!no_prefix)
data->key |= KEYC_PREFIX;
if ((data->key = key_string_lookup_string(argv[0])) == KEYC_NONE) {
xasprintf(cause, "unknown key: %s", argv[0]);
goto error;
}
if (!no_prefix)
data->key |= KEYC_PREFIX;
return (0);
@@ -110,23 +100,13 @@ int
cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{
struct cmd_unbind_key_data *data = self->data;
struct key_binding *bd;
if (data == NULL)
return (0);
if (data->flag_all) {
while (!SPLAY_EMPTY(&key_bindings)) {
bd = SPLAY_ROOT(&key_bindings);
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
cmd_list_free(bd->cmdlist);
xfree(bd);
}
} else {
if (data->tablename != NULL)
return (cmd_unbind_key_table(self, ctx));
if (data->tablename != NULL)
return (cmd_unbind_key_table(self, ctx));
key_bindings_remove(data->key);
}
key_bindings_remove(data->key);
return (0);
}

60
cmd-up-pane.c Normal file
View File

@@ -0,0 +1,60 @@
/* $Id: cmd-up-pane.c,v 1.14 2010-01-05 23:52:37 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"
/*
* Move up a pane.
*/
int cmd_up_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_up_pane_entry = {
"up-pane", "upp",
CMD_TARGET_WINDOW_USAGE,
0, "",
cmd_target_init,
cmd_target_parse,
cmd_up_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window *w;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
w = wl->window;
do {
w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_LAST(&w->panes, window_panes);
} while (!window_pane_visible(w->active));
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
return (0);
}

252
cmd.c
View File

@@ -1,4 +1,4 @@
/* $Id: cmd.c,v 1.146 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: cmd.c,v 1.137 2010-01-22 17:28:34 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,7 +31,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_bind_key_entry,
&cmd_break_pane_entry,
&cmd_capture_pane_entry,
&cmd_choose_buffer_entry,
&cmd_choose_client_entry,
&cmd_choose_session_entry,
&cmd_choose_window_entry,
@@ -45,6 +44,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_detach_client_entry,
&cmd_display_message_entry,
&cmd_display_panes_entry,
&cmd_down_pane_entry,
&cmd_find_window_entry,
&cmd_has_session_entry,
&cmd_if_shell_entry,
@@ -53,7 +53,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_kill_server_entry,
&cmd_kill_session_entry,
&cmd_kill_window_entry,
&cmd_last_pane_entry,
&cmd_last_window_entry,
&cmd_link_window_entry,
&cmd_list_buffers_entry,
@@ -86,6 +85,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_save_buffer_entry,
&cmd_select_layout_entry,
&cmd_select_pane_entry,
&cmd_select_prompt_entry,
&cmd_select_window_entry,
&cmd_send_keys_entry,
&cmd_send_prefix_entry,
@@ -108,19 +108,16 @@ const struct cmd_entry *cmd_table[] = {
&cmd_switch_client_entry,
&cmd_unbind_key_entry,
&cmd_unlink_window_entry,
&cmd_up_pane_entry,
NULL
};
struct session *cmd_choose_session_list(struct sessionslist *);
struct session *cmd_choose_session(void);
struct session *cmd_choose_session(struct sessions *);
struct client *cmd_choose_client(struct clients *);
struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(const char *, int *);
struct winlink *cmd_lookup_window(struct session *, const char *, int *);
int cmd_lookup_index(struct session *, const char *, int *);
struct winlink *cmd_find_window_offset(const char *, struct session *, int *);
int cmd_find_index_offset(const char *, struct session *, int *);
struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
@@ -166,22 +163,6 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
return (0);
}
char **
cmd_copy_argv(int argc, char **argv)
{
char **new_argv;
int i;
if (argc == 0)
return (NULL);
new_argv = xcalloc(argc, sizeof *new_argv);
for (i = 0; i < argc; i++) {
if (argv[i] != NULL)
new_argv[i] = xstrdup(argv[i]);
}
return (new_argv);
}
void
cmd_free_argv(int argc, char **argv)
{
@@ -316,9 +297,10 @@ cmd_current_session(struct cmd_ctx *ctx)
struct msg_command_data *data = ctx->msgdata;
struct client *c = ctx->cmdclient;
struct session *s;
struct sessionslist ss;
struct sessions ss;
struct winlink *wl;
struct window_pane *wp;
u_int i;
int found;
if (ctx->curclient != NULL && ctx->curclient->session != NULL)
@@ -331,7 +313,9 @@ cmd_current_session(struct cmd_ctx *ctx)
*/
if (c != NULL && c->tty.path != NULL) {
ARRAY_INIT(&ss);
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
found = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
@@ -347,43 +331,29 @@ cmd_current_session(struct cmd_ctx *ctx)
ARRAY_ADD(&ss, s);
}
s = cmd_choose_session_list(&ss);
s = cmd_choose_session(&ss);
ARRAY_FREE(&ss);
if (s != NULL)
return (s);
}
/* Use the session from the TMUX environment variable. */
if (data != NULL && data->pid == getpid()) {
s = session_find_by_index(data->idx);
if (s != NULL)
return (s);
if (data != NULL && data->pid != -1) {
if (data->pid != getpid())
return (NULL);
if (data->idx > ARRAY_LENGTH(&sessions))
return (NULL);
if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL)
return (NULL);
return (s);
}
return (cmd_choose_session());
}
/* Find the most recently used session. */
struct session *
cmd_choose_session(void)
{
struct session *s, *sbest;
struct timeval *tv = NULL;
sbest = NULL;
RB_FOREACH(s, sessions, &sessions) {
if (tv == NULL || timercmp(&s->activity_time, tv, >)) {
sbest = s;
tv = &s->activity_time;
}
}
return (sbest);
return (cmd_choose_session(&sessions));
}
/* Find the most recently used session from a list. */
struct session *
cmd_choose_session_list(struct sessionslist *ss)
cmd_choose_session(struct sessions *ss)
{
struct session *s, *sbest;
struct timeval *tv = NULL;
@@ -531,6 +501,7 @@ struct session *
cmd_lookup_session(const char *name, int *ambiguous)
{
struct session *s, *sfound;
u_int i;
*ambiguous = 0;
@@ -539,15 +510,21 @@ cmd_lookup_session(const char *name, int *ambiguous)
* be unique so an exact match can't be ambigious and can just be
* returned.
*/
if ((s = session_find(name)) != NULL)
return (s);
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;
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (strncmp(name, s->name, strlen(name)) == 0 ||
fnmatch(name, s->name, 0) == 0) {
if (sfound != NULL) {
@@ -563,7 +540,7 @@ cmd_lookup_session(const char *name, int *ambiguous)
/*
* Lookup a window or return -1 if not found or ambigious. First try as an
* index and if invalid, use fnmatch or leading prefix. Return NULL but fill in
* idx if the window index is a valid number but there is no window with that
* idx if the window index is a valid number but there is now window with that
* index.
*/
struct winlink *
@@ -730,8 +707,10 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
wl = s->curw;
else if (winptr[0] == '!' && winptr[1] == '\0')
wl = TAILQ_FIRST(&s->lastw);
else if (winptr[0] == '+' || winptr[0] == '-')
wl = cmd_find_window_offset(winptr, s, &ambiguous);
else if (winptr[0] == '+' && winptr[1] == '\0')
wl = winlink_next(s->curw);
else if (winptr[0] == '-' && winptr[1] == '\0')
wl = winlink_previous(s->curw);
else
wl = cmd_lookup_window(s, winptr, &ambiguous);
if (wl == NULL)
@@ -749,28 +728,25 @@ no_colon:
if (arg[0] == '!' && arg[1] == '\0') {
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
goto not_found;
} else if (arg[0] == '+' || arg[0] == '-') {
if ((wl = cmd_find_window_offset(arg, s, &ambiguous)) == NULL)
goto lookup_session;
} else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL)
goto lookup_session;
} else if (arg[0] == '+' && arg[1] == '\0') {
if ((wl = winlink_next(s->curw)) == NULL)
goto not_found;
} else if (arg[0] == '-' && arg[1] == '\0') {
if ((wl = winlink_previous(s->curw)) == NULL)
goto not_found;
} else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL) {
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
wl = s->curw;
}
if (sp != NULL)
*sp = s;
return (wl);
lookup_session:
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
if (sp != NULL)
*sp = s;
return (s->curw);
no_session:
if (ambiguous)
ctx->error(ctx, "multiple sessions: %s", arg);
@@ -790,26 +766,6 @@ not_found:
return (NULL);
}
struct winlink *
cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous)
{
struct winlink *wl;
int offset = 1;
if (winptr[1] != '\0')
offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
if (offset == 0)
wl = cmd_lookup_window(s, winptr, ambiguous);
else {
if (winptr[0] == '+')
wl = winlink_next_by_number(s->curw, s, offset);
else
wl = winlink_previous_by_number(s->curw, s, offset);
}
return (wl);
}
/*
* Find the target session and window index, whether or not it exists in the
* session. Return -2 on error or -1 if no window index is specified. This is
@@ -871,11 +827,20 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
goto not_found;
idx = wl->idx;
} else if (winptr[0] == '+' || winptr[0] == '-') {
if ((idx = cmd_find_index_offset(winptr, s, &ambiguous)) < 0)
goto invalid_index;
} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1)
goto invalid_index;
} else if (winptr[0] == '+' && winptr[1] == '\0') {
if (s->curw->idx == INT_MAX)
goto not_found;
idx = s->curw->idx + 1;
} else if (winptr[0] == '-' && winptr[1] == '\0') {
if (s->curw->idx == 0)
goto not_found;
idx = s->curw->idx - 1;
} else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1) {
if (ambiguous)
goto not_found;
ctx->error(ctx, "invalid index: %s", arg);
idx = -2;
}
if (sessptr != NULL)
xfree(sessptr);
@@ -890,28 +855,27 @@ no_colon:
if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
goto not_found;
idx = wl->idx;
} else if (arg[0] == '+' || arg[0] == '-') {
if ((idx = cmd_find_index_offset(arg, s, &ambiguous)) < 0)
goto lookup_session;
} else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1)
goto lookup_session;
} else if (arg[0] == '+' && arg[1] == '\0') {
if (s->curw->idx == INT_MAX)
goto not_found;
idx = s->curw->idx + 1;
} else if (arg[0] == '-' && arg[1] == '\0') {
if (s->curw->idx == 0)
goto not_found;
idx = s->curw->idx - 1;
} else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1) {
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
idx = -1;
}
if (sp != NULL)
*sp = s;
return (idx);
lookup_session:
if (ambiguous)
goto not_found;
if ((s = cmd_lookup_session(arg, &ambiguous)) == NULL)
goto no_session;
if (sp != NULL)
*sp = s;
return (-1);
no_session:
if (ambiguous)
ctx->error(ctx, "multiple sessions: %s", arg);
@@ -921,15 +885,6 @@ no_session:
xfree(sessptr);
return (-2);
invalid_index:
if (ambiguous)
goto not_found;
ctx->error(ctx, "invalid index: %s", arg);
if (sessptr != NULL)
xfree(sessptr);
return (-2);
not_found:
if (ambiguous)
ctx->error(ctx, "multiple windows: %s", arg);
@@ -940,32 +895,6 @@ not_found:
return (-2);
}
int
cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous)
{
int idx, offset = 1;
if (winptr[1] != '\0')
offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
if (offset == 0)
idx = cmd_lookup_index(s, winptr, ambiguous);
else {
if (winptr[0] == '+') {
if (s->curw->idx == INT_MAX)
idx = cmd_lookup_index(s, winptr, ambiguous);
else
idx = s->curw->idx + offset;
} else {
if (s->curw->idx == 0)
idx = cmd_lookup_index(s, winptr, ambiguous);
else
idx = s->curw->idx - offset;
}
}
return (idx);
}
/*
* Find the target session, window and pane number or report an error and
* return NULL. The pane number is separated from the session:window by a .,
@@ -1012,8 +941,6 @@ cmd_find_pane(struct cmd_ctx *ctx,
paneptr = winptr + (period - arg) + 1;
if (*paneptr == '\0')
*wpp = wl->window->active;
else if (paneptr[0] == '+' || paneptr[0] == '-')
*wpp = cmd_find_pane_offset(paneptr, wl);
else {
idx = strtonum(paneptr, 0, INT_MAX, &errstr);
if (errstr != NULL)
@@ -1028,14 +955,14 @@ cmd_find_pane(struct cmd_ctx *ctx,
lookup_string:
/* Try pane string description. */
if ((lc = layout_find_string(wl->window, paneptr)) == NULL) {
if ((lc = layout_find_string(s->curw->window, paneptr)) == NULL) {
ctx->error(ctx, "can't find pane: %s", paneptr);
goto error;
}
*wpp = lc->wp;
xfree(winptr);
return (wl);
return (s->curw);
no_period:
/* Try as a pane number alone. */
@@ -1066,25 +993,6 @@ error:
return (NULL);
}
struct window_pane *
cmd_find_pane_offset(const char *paneptr, struct winlink *wl)
{
struct window *w = wl->window;
struct window_pane *wp = w->active;
u_int offset = 1;
if (paneptr[1] != '\0')
offset = strtonum(paneptr + 1, 1, INT_MAX, NULL);
if (offset > 0) {
if (paneptr[0] == '+')
wp = window_pane_next_by_number(w, wp, offset);
else
wp = window_pane_previous_by_number(w, wp, offset);
}
return (wp);
}
/* Replace the first %% or %idx in template by s. */
char *
cmd_template_replace(char *template, const char *s, int idx)

View File

@@ -1,4 +1,4 @@
/* $Id: compat.h,v 1.31 2010-11-11 20:45:49 nicm Exp $ */
/* $Id: compat.h,v 1.20 2009-11-08 22:51:34 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -16,20 +16,6 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef COMPAT_H
#define COMPAT_H
#ifndef __GNUC__
#define __attribute__(a)
#endif
#ifndef __dead
#define __dead __attribute__ ((__noreturn__))
#endif
#ifndef __packed
#define __packed __attribute__ ((__packed__))
#endif
#ifndef HAVE_U_INT
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
@@ -56,13 +42,21 @@ typedef uint64_t u_int64_t;
#else
#include "compat/tree.h"
#endif
#ifdef HAVE_BITSTRING_H
#include <bitstring.h>
#else
#include "compat/bitstring.h"
#endif
#ifdef HAVE_GETOPT
#include <getopt.h>
#endif
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
@@ -85,44 +79,19 @@ typedef uint64_t u_int64_t;
#include "compat/vis.h"
#endif
#ifdef HAVE_IMSG
#include <imsg.h>
#else
#ifndef HAVE_IMSG
#include "compat/imsg.h"
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#include <inttypes.h>
#endif
#ifdef HAVE_BROKEN_CMSG_FIRSTHDR
/* CMSG_FIRSTHDR broken on OS X. */
/* Broken on OS X. */
#undef CMSG_FIRSTHDR
#define CMSG_FIRSTHDR(mhdr) \
((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
(struct cmsghdr *)(mhdr)->msg_control : \
((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
(struct cmsghdr *)(mhdr)->msg_control : \
(struct cmsghdr *)NULL)
#endif
/* CMSG_ALIGN, CMSG_SPACE, CMSG_LEN missing from Solaris 9. */
#ifndef CMSG_ALIGN
#ifdef __sun
#define CMSG_ALIGN _CMSG_DATA_ALIGN
#else
#define CMSG_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
#endif
#endif
#ifndef CMSG_SPACE
#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
#endif
#ifndef CMSG_LEN
#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif
#ifndef INFTIM
#define INFTIM -1
#endif
@@ -135,6 +104,13 @@ typedef uint64_t u_int64_t;
#define SUN_LEN(sun) (sizeof (sun)->sun_path)
#endif
#ifndef __dead
#define __dead __attribute__ ((__noreturn__))
#endif
#ifndef __packed
#define __packed __attribute__ ((__packed__))
#endif
#ifndef timercmp
#define timercmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
@@ -159,16 +135,7 @@ typedef uint64_t u_int64_t;
#endif
#ifndef HAVE_BZERO
#undef bzero
#define bzero(buf, len) memset(buf, 0, len);
#endif
#ifndef HAVE_CLOSEFROM
/* closefrom.c */
#define HAVE_FCNTL_H
#define HAVE_DIRENT_H
#define HAVE_SYSCONF
void closefrom(int);
#define bzero(buf, len) memset((buf), 0, (len));
#endif
#ifndef HAVE_STRCASESTR
@@ -203,30 +170,21 @@ int daemon(int, int);
#ifndef HAVE_FORKPTY
/* forkpty.c */
#include <sys/ioctl.h>
pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#endif
#ifndef HAVE_ASPRINTF
/* asprintf.c */
int asprintf(char **, const char *, ...);
int vasprintf(char **, const char *, va_list);
int asprintf(char **, const char *, ...);
int vasprintf(char **, const char *, va_list);
#endif
#ifndef HAVE_FGETLN
/* fgetln.c */
char *fgetln(FILE *, size_t *);
char *fgetln(FILE *, size_t *);
#endif
#ifndef HAVE_SETENV
/* setenv.c */
int setenv(const char *, const char *, int);
int unsetenv(const char *);
#endif
#ifdef HAVE_GETOPT
#include <getopt.h>
#else
#ifndef HAVE_GETOPT
/* getopt.c */
extern int BSDopterr;
extern int BSDoptind;
@@ -241,5 +199,3 @@ int BSDgetopt(int, char *const *, const char *);
#define optreset BSDoptreset
#define optarg BSDoptarg
#endif
#endif /* COMPAT_H */

View File

@@ -1,111 +0,0 @@
/* $Id: closefrom.c,v 1.1 2010-10-27 20:21:01 nicm Exp $ */
/*
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 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 "tmux.h"
#ifndef HAVE_CLOSEFROM
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include <limits.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#ifndef OPEN_MAX
# define OPEN_MAX 256
#endif
#if 0
__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
#endif /* lint */
/*
* Close all file descriptors greater than or equal to lowfd.
*/
#ifdef HAVE_FCNTL_CLOSEM
void
closefrom(int lowfd)
{
(void) fcntl(lowfd, F_CLOSEM, 0);
}
#else
void
closefrom(int lowfd)
{
long fd, maxfd;
#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
char fdpath[PATH_MAX], *endp;
struct dirent *dent;
DIR *dirp;
int len;
/* Check for a /proc/$$/fd directory. */
len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
while ((dent = readdir(dirp)) != NULL) {
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
(void) close((int) fd);
}
(void) closedir(dirp);
} else
#endif
{
/*
* Fall back on sysconf() or getdtablesize(). We avoid checking
* resource limits since it is possible to open a file descriptor
* and then drop the rlimit such that it is below the open fd.
*/
#ifdef HAVE_SYSCONF
maxfd = sysconf(_SC_OPEN_MAX);
#else
maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */
if (maxfd < 0)
maxfd = OPEN_MAX;
for (fd = lowfd; fd < maxfd; fd++)
(void) close((int) fd);
}
}
#endif /* !HAVE_FCNTL_CLOSEM */
#endif /* HAVE_CLOSEFROM */

View File

@@ -32,6 +32,10 @@
#include <unistd.h>
#include <stdlib.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include "tmux.h"
int

View File

@@ -1,5 +1,5 @@
/* $Id: imsg-buffer.c,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
/* $Id: imsg-buffer.c,v 1.4 2009-09-15 23:59:40 tcunha Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.2 2009/09/15 18:12:51 jacekm Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -28,16 +28,16 @@
#include "tmux.h"
int ibuf_realloc(struct ibuf *, size_t);
void ibuf_enqueue(struct msgbuf *, struct ibuf *);
void ibuf_dequeue(struct msgbuf *, struct ibuf *);
int buf_realloc(struct buf *, size_t);
void buf_enqueue(struct msgbuf *, struct buf *);
void buf_dequeue(struct msgbuf *, struct buf *);
struct ibuf *
ibuf_open(size_t len)
struct buf *
buf_open(size_t len)
{
struct ibuf *buf;
struct buf *buf;
if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
if ((buf = calloc(1, sizeof(struct buf))) == NULL)
return (NULL);
if ((buf->buf = malloc(len)) == NULL) {
free(buf);
@@ -49,15 +49,15 @@ ibuf_open(size_t len)
return (buf);
}
struct ibuf *
ibuf_dynamic(size_t len, size_t max)
struct buf *
buf_dynamic(size_t len, size_t max)
{
struct ibuf *buf;
struct buf *buf;
if (max < len)
return (NULL);
if ((buf = ibuf_open(len)) == NULL)
if ((buf = buf_open(len)) == NULL)
return (NULL);
if (max > 0)
@@ -67,7 +67,7 @@ ibuf_dynamic(size_t len, size_t max)
}
int
ibuf_realloc(struct ibuf *buf, size_t len)
buf_realloc(struct buf *buf, size_t len)
{
u_char *b;
@@ -87,10 +87,10 @@ ibuf_realloc(struct ibuf *buf, size_t len)
}
int
ibuf_add(struct ibuf *buf, const void *data, size_t len)
buf_add(struct buf *buf, const void *data, size_t len)
{
if (buf->wpos + len > buf->size)
if (ibuf_realloc(buf, len) == -1)
if (buf_realloc(buf, len) == -1)
return (-1);
memcpy(buf->buf + buf->wpos, data, len);
@@ -99,12 +99,12 @@ ibuf_add(struct ibuf *buf, const void *data, size_t len)
}
void *
ibuf_reserve(struct ibuf *buf, size_t len)
buf_reserve(struct buf *buf, size_t len)
{
void *b;
if (buf->wpos + len > buf->size)
if (ibuf_realloc(buf, len) == -1)
if (buf_realloc(buf, len) == -1)
return (NULL);
b = buf->buf + buf->wpos;
@@ -113,7 +113,7 @@ ibuf_reserve(struct ibuf *buf, size_t len)
}
void *
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
buf_seek(struct buf *buf, size_t pos, size_t len)
{
/* only allowed to seek in already written parts */
if (pos + len > buf->wpos)
@@ -123,28 +123,28 @@ ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
}
size_t
ibuf_size(struct ibuf *buf)
buf_size(struct buf *buf)
{
return (buf->wpos);
}
size_t
ibuf_left(struct ibuf *buf)
buf_left(struct buf *buf)
{
return (buf->max - buf->wpos);
}
void
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
buf_close(struct msgbuf *msgbuf, struct buf *buf)
{
ibuf_enqueue(msgbuf, buf);
buf_enqueue(msgbuf, buf);
}
int
ibuf_write(struct msgbuf *msgbuf)
buf_write(struct msgbuf *msgbuf)
{
struct iovec iov[IOV_MAX];
struct ibuf *buf;
struct buf *buf;
unsigned int i = 0;
ssize_t n;
@@ -176,7 +176,7 @@ ibuf_write(struct msgbuf *msgbuf)
}
void
ibuf_free(struct ibuf *buf)
buf_free(struct buf *buf)
{
free(buf->buf);
free(buf);
@@ -193,14 +193,14 @@ msgbuf_init(struct msgbuf *msgbuf)
void
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
{
struct ibuf *buf, *next;
struct buf *buf, *next;
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
buf = next) {
next = TAILQ_NEXT(buf, entry);
if (buf->rpos + n >= buf->wpos) {
n -= buf->wpos - buf->rpos;
ibuf_dequeue(msgbuf, buf);
buf_dequeue(msgbuf, buf);
} else {
buf->rpos += n;
n = 0;
@@ -211,17 +211,17 @@ msgbuf_drain(struct msgbuf *msgbuf, size_t n)
void
msgbuf_clear(struct msgbuf *msgbuf)
{
struct ibuf *buf;
struct buf *buf;
while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
ibuf_dequeue(msgbuf, buf);
buf_dequeue(msgbuf, buf);
}
int
msgbuf_write(struct msgbuf *msgbuf)
{
struct iovec iov[IOV_MAX];
struct ibuf *buf;
struct buf *buf;
unsigned int i = 0;
ssize_t n;
struct msghdr msg;
@@ -284,14 +284,14 @@ msgbuf_write(struct msgbuf *msgbuf)
}
void
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
{
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
msgbuf->queued++;
}
void
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
{
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
@@ -299,5 +299,5 @@ ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
close(buf->fd);
msgbuf->queued--;
ibuf_free(buf);
buf_free(buf);
}

View File

@@ -1,5 +1,5 @@
/* $Id: imsg.c,v 1.7 2010-11-13 16:29:05 nicm Exp $ */
/* $OpenBSD: imsg.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
/* $Id: imsg.c,v 1.3 2009-08-20 12:54:08 nicm Exp $ */
/* $OpenBSD: imsg.c,v 1.1 2009/08/11 17:18:35 nicm Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -79,7 +79,7 @@ imsg_read(struct imsgbuf *ibuf)
cmsg->cmsg_type == SCM_RIGHTS) {
fd = (*(int *)CMSG_DATA(cmsg));
if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) {
close(fd);
/* XXX: this return can leak */
return (-1);
}
ifd->fd = fd;
@@ -111,7 +111,7 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
return (0);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
if ((imsg->data = malloc(datalen)) == NULL && datalen != 0)
if ((imsg->data = malloc(datalen)) == NULL)
return (-1);
if (imsg->hdr.flags & IMSGF_HASFD)
@@ -135,7 +135,7 @@ int
imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
pid_t pid, int fd, void *data, u_int16_t datalen)
{
struct ibuf *wbuf;
struct buf *wbuf;
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
return (-1);
@@ -154,7 +154,7 @@ int
imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
pid_t pid, int fd, const struct iovec *iov, int iovcnt)
{
struct ibuf *wbuf;
struct buf *wbuf;
int i, datalen = 0;
for (i = 0; i < iovcnt; i++)
@@ -175,11 +175,11 @@ imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
}
/* ARGSUSED */
struct ibuf *
struct buf *
imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
pid_t pid, u_int16_t datalen)
{
struct ibuf *wbuf;
struct buf *wbuf;
struct imsg_hdr hdr;
datalen += IMSG_HEADER_SIZE;
@@ -193,7 +193,7 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
hdr.peerid = peerid;
if ((hdr.pid = pid) == 0)
hdr.pid = ibuf->pid;
if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
return (NULL);
}
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
@@ -203,18 +203,18 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
}
int
imsg_add(struct ibuf *msg, void *data, u_int16_t datalen)
imsg_add(struct buf *msg, void *data, u_int16_t datalen)
{
if (datalen)
if (ibuf_add(msg, data, datalen) == -1) {
ibuf_free(msg);
if (buf_add(msg, data, datalen) == -1) {
buf_free(msg);
return (-1);
}
return (datalen);
}
void
imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
imsg_close(struct imsgbuf *ibuf, struct buf *msg)
{
struct imsg_hdr *hdr;
@@ -226,7 +226,7 @@ imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
hdr->len = (u_int16_t)msg->wpos;
ibuf_close(&ibuf->w, msg);
buf_close(&ibuf->w, msg);
}
void

View File

@@ -1,5 +1,5 @@
/* $Id: imsg.h,v 1.5 2010-06-06 00:08:28 tcunha Exp $ */
/* $OpenBSD: imsg.h,v 1.4 2010/05/26 13:56:07 nicm Exp $ */
/* $Id: imsg.h,v 1.4 2009-09-15 23:59:40 tcunha Exp $ */
/* $OpenBSD: imsg.h,v 1.2 2009/09/15 18:12:51 jacekm Exp $ */
/*
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -21,12 +21,12 @@
#include "tmux.h"
#define IBUF_READ_SIZE 65535
#define READ_BUF_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
#define MAX_IMSGSIZE 16384
struct ibuf {
TAILQ_ENTRY(ibuf) entry;
struct buf {
TAILQ_ENTRY(buf) entry;
u_char *buf;
size_t size;
size_t max;
@@ -36,13 +36,13 @@ struct ibuf {
};
struct msgbuf {
TAILQ_HEAD(, ibuf) bufs;
TAILQ_HEAD(, buf) bufs;
u_int32_t queued;
int fd;
};
struct ibuf_read {
u_char buf[IBUF_READ_SIZE];
struct buf_read {
u_char buf[READ_BUF_SIZE];
u_char *rptr;
size_t wpos;
};
@@ -54,7 +54,7 @@ struct imsg_fd {
struct imsgbuf {
TAILQ_HEAD(, imsg_fd) fds;
struct ibuf_read r;
struct buf_read r;
struct msgbuf w;
int fd;
pid_t pid;
@@ -78,16 +78,16 @@ struct imsg {
/* buffer.c */
struct ibuf *ibuf_open(size_t);
struct ibuf *ibuf_dynamic(size_t, size_t);
int ibuf_add(struct ibuf *, const void *, size_t);
void *ibuf_reserve(struct ibuf *, size_t);
void *ibuf_seek(struct ibuf *, size_t, size_t);
size_t ibuf_size(struct ibuf *);
size_t ibuf_left(struct ibuf *);
void ibuf_close(struct msgbuf *, struct ibuf *);
int ibuf_write(struct msgbuf *);
void ibuf_free(struct ibuf *);
struct buf *buf_open(size_t);
struct buf *buf_dynamic(size_t, size_t);
int buf_add(struct buf *, const void *, size_t);
void *buf_reserve(struct buf *, size_t);
void *buf_seek(struct buf *, size_t, size_t);
size_t buf_size(struct buf *);
size_t buf_left(struct buf *);
void buf_close(struct msgbuf *, struct buf *);
int buf_write(struct msgbuf *);
void buf_free(struct buf *);
void msgbuf_init(struct msgbuf *);
void msgbuf_clear(struct msgbuf *);
int msgbuf_write(struct msgbuf *);
@@ -101,10 +101,10 @@ int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
int, void *, u_int16_t);
int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
int, const struct iovec *, int);
struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
u_int16_t);
int imsg_add(struct ibuf *, void *, u_int16_t);
void imsg_close(struct imsgbuf *, struct ibuf *);
int imsg_add(struct buf *, void *, u_int16_t);
void imsg_close(struct imsgbuf *, struct buf *);
void imsg_free(struct imsg *);
int imsg_flush(struct imsgbuf *);
void imsg_clear(struct imsgbuf *);

View File

@@ -1,49 +0,0 @@
/* $Id: setenv.c,v 1.2 2010-06-05 18:20:48 nicm Exp $ */
/*
* Copyright (c) 2010 Dagobert Michelsen
* Copyright (c) 2010 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 <stdlib.h>
#include <string.h>
#include "tmux.h"
int
setenv(const char *name, const char *value, unused int overwrite)
{
char *newval;
xasprintf(&newval, "%s=%s", name, value);
return (putenv(newval));
}
int
unsetenv(const char *name)
{
char **envptr;
int namelen;
namelen = strlen(name);
for (envptr = environ; *envptr != NULL; envptr++) {
if (strncmp(name, *envptr, namelen) == 0 &&
((*envptr)[namelen] == '=' || (*envptr)[namelen] == '\0'))
break;
}
for (; *envptr != NULL; envptr++)
*envptr = *(envptr + 1);
return (0);
}

67
configure vendored
View File

@@ -1,5 +1,5 @@
#!/bin/sh
# $Id: configure,v 1.59 2010-12-08 19:55:31 nicm Exp $
# $Id: configure,v 1.47 2009-12-11 20:08:18 nicm Exp $
#
# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
#
@@ -33,22 +33,18 @@ cat <<EOF >>$CONFIG_H
#undef HAVE_BROKEN_KQUEUE
#undef HAVE_BROKEN_POLL
#undef HAVE_BZERO
#undef HAVE_CLOSEFROM
#undef HAVE_CRYPT_H
#undef HAVE_DAEMON
#undef HAVE_DIRFD
#undef HAVE_FCNTL_CLOSEM
#undef HAVE_FGETLN
#undef HAVE_FORKPTY
#undef HAVE_GETOPT
#undef HAVE_IMSG
#undef HAVE_LIBUTIL_H
#undef HAVE_PATHS_H
#undef HAVE_PROC_PID
#undef HAVE_PROGNAME
#undef HAVE_PTY_H
#undef HAVE_QUEUE_H
#undef HAVE_SETPROCTITLE
#undef HAVE_STDINT_H
#undef HAVE_STRCASESTR
#undef HAVE_STRLCAT
#undef HAVE_STRLCPY
@@ -67,18 +63,14 @@ case $TMUX_PLATFORM in
#define HAVE_ASPRINTF
#define HAVE_BITSTRING_H
#define HAVE_BZERO
#define HAVE_CLOSEFROM
#define HAVE_DAEMON
#define HAVE_FGETLN
#define HAVE_FORKPTY
#define HAVE_GETOPT
#define HAVE_IMSG
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_QUEUE_H
#define HAVE_SETENV
#define HAVE_SETPROCTITLE
#define HAVE_STDINT_H
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
#define HAVE_STRLCPY
@@ -91,7 +83,9 @@ case $TMUX_PLATFORM in
EOF
cat <<EOF >>$CONFIG_MK
LIBS+= -lcurses -lutil -levent
SRCS+= osdep-openbsd.c
SRCS+= osdep-openbsd.c \
compat/imsg-buffer.c \
compat/imsg.c
EOF
;;
# ------------------------------------------------------------------------------
@@ -100,28 +94,23 @@ EOF
#define HAVE_ASPRINTF
#define HAVE_BZERO
#define HAVE_DAEMON
#define HAVE_DIRFD
#define HAVE_FORKPTY
#define HAVE_PATHS_H
#define HAVE_PROC_PID
#define HAVE_PROGNAME
#define HAVE_PTY_H
#define HAVE_SETENV
#define HAVE_STDINT_H
#define HAVE_STRCASESTR
#define HAVE_STRSEP
#define HAVE_U_INT
EOF
cat <<EOF >>$CONFIG_MK
CFLAGS+= -std=c99 -D_GNU_SOURCE -D_POSIX_SOURCE
LIBS+= -lncurses -lutil -levent -lrt
LIBS+= -lncurses -lcrypt -lutil -levent
SRCS+= osdep-linux.c \
compat/closefrom.c \
compat/fgetln.c \
compat/strlcat.c \
compat/strlcpy.c \
compat/strtonum.c \
compat/getopt.c \
compat/getopt.c \
compat/vis.c \
compat/unvis.c \
compat/imsg-buffer.c \
@@ -131,14 +120,13 @@ EOF
# ------------------------------------------------------------------------------
AIX)
cat <<EOF >>$CONFIG_H
#define HAVE_SETENV
#define HAVE_STDINT_H
#define HAVE_BZERO
#define HAVE_DAEMON
EOF
cat <<EOF >>$CONFIG_MK
LIBS+= -lcurses -levent
SRCS+= osdep-unknown.c \
compat/asprintf.c \
compat/closefrom.c \
compat/daemon.c \
compat/forkpty-aix.c \
compat/strcasestr.c \
@@ -157,7 +145,7 @@ EOF
# ------------------------------------------------------------------------------
SunOS)
cat <<EOF >>$CONFIG_H
#define HAVE_CLOSEFROM
#define HAVE_CRYPT_H
#define HAVE_STRLCAT
#define HAVE_STRLCPY
EOF
@@ -170,7 +158,6 @@ SRCS+= osdep-sunos.c \
compat/fgetln.c \
compat/forkpty-sunos.c \
compat/getopt.c \
compat/setenv.c \
compat/strcasestr.c \
compat/strsep.c \
compat/strtonum.c \
@@ -189,15 +176,11 @@ EOF
#define HAVE_BROKEN_POLL
#define HAVE_BZERO
#define HAVE_DAEMON
#define HAVE_DIRFD
#define HAVE_FGETLN
#define HAVE_FORKPTY
#define HAVE_GETOPT
#define HAVE_PATHS_H
#define HAVE_PROC_PID
#define HAVE_PROGNAME
#define HAVE_SETENV
#define HAVE_STDINT_H
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
#define HAVE_STRLCPY
@@ -210,7 +193,6 @@ CPPFLAGS+= -I/opt/local/include
LDFLAGS+= -L/opt/local/lib
LIBS+= -lcurses -levent
SRCS+= osdep-darwin.c \
compat/closefrom.c \
compat/strtonum.c \
compat/vis.c \
compat/unvis.c \
@@ -222,9 +204,7 @@ EOF
FreeBSD|DragonFly)
cat <<EOF >>$CONFIG_H
#define HAVE_ASPRINTF
#define HAVE_BROKEN_KQUEUE
#define HAVE_BZERO
#define HAVE_CLOSEFROM
#define HAVE_DAEMON
#define HAVE_FGETLN
#define HAVE_FORKPTY
@@ -232,18 +212,16 @@ EOF
#define HAVE_LIBUTIL_H
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_SETENV
#define HAVE_SETPROCTITLE
#define HAVE_STDINT_H
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
#define HAVE_STRLCPY
#define HAVE_STRSEP
#define HAVE_STRTONUM
#define HAVE_STRSEP
#define HAVE_U_INT
EOF
cat <<EOF >>$CONFIG_MK
LIBS+= -lcurses -lutil -levent
LIBS+= -lcurses -lcrypt -lutil -levent
SRCS+= osdep-freebsd.c \
compat/vis.c \
compat/unvis.c \
@@ -255,17 +233,15 @@ EOF
NetBSD)
cat <<EOF >>$CONFIG_H
#define HAVE_ASPRINTF
#define HAVE_BROKEN_CURSES_H
#define HAVE_BZERO
#define HAVE_CLOSEFROM
#define HAVE_DAEMON
#define HAVE_FGETLN
#define HAVE_FORKPTY
#define HAVE_GETOPT
#define HAVE_PATHS_H
#define HAVE_PROGNAME
#define HAVE_SETENV
#define HAVE_SETPROCTITLE
#define HAVE_STDINT_H
#define HAVE_STRCASESTR
#define HAVE_STRLCAT
#define HAVE_STRLCPY
@@ -273,23 +249,10 @@ EOF
#define HAVE_UTIL_H
#define HAVE_U_INT
EOF
# NetBSD-6 has its own terminfo implementation
if test -f /lib/libterminfo.so; then
cat <<EOF >>$CONFIG_MK
LIBS+= -lterminfo
EOF
else
cat <<EOF >>$CONFIG_MK
cat <<EOF >>$CONFIG_MK
CPPFLAGS+= -I/usr/pkg/include
LDFLAGS+= -L/usr/pkg/lib
LIBS+= -lncurses
EOF
cat <<EOF >>$CONFIG_H
#define HAVE_BROKEN_CURSES_H
EOF
fi
cat <<EOF >>$CONFIG_MK
LIBS+= -lutil -levent
LIBS+= -lncurses -lcrypt -lutil -levent
SRCS+= osdep-netbsd.c \
compat/strtonum.c \
compat/vis.c \

View File

@@ -1,4 +1,4 @@
/* $Id: environ.c,v 1.4 2010-04-06 21:59:19 nicm Exp $ */
/* $Id: environ.c,v 1.3 2009-08-09 17:57:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -35,14 +35,12 @@ environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
return (strcmp(envent1->name, envent2->name));
}
/* Initialise the environment. */
void
environ_init(struct environ *env)
{
RB_INIT(env);
}
/* Free an environment. */
void
environ_free(struct environ *env)
{
@@ -58,7 +56,6 @@ environ_free(struct environ *env)
}
}
/* Copy one environment into another. */
void
environ_copy(struct environ *srcenv, struct environ *dstenv)
{
@@ -68,7 +65,6 @@ environ_copy(struct environ *srcenv, struct environ *dstenv)
environ_set(dstenv, envent->name, envent->value);
}
/* Find an environment variable. */
struct environ_entry *
environ_find(struct environ *env, const char *name)
{
@@ -78,7 +74,6 @@ environ_find(struct environ *env, const char *name)
return (RB_FIND(environ, env, &envent));
}
/* Set an environment variable. */
void
environ_set(struct environ *env, const char *name, const char *value)
{
@@ -102,11 +97,10 @@ environ_set(struct environ *env, const char *name, const char *value)
}
}
/* Set an environment variable from a NAME=VALUE string. */
void
environ_put(struct environ *env, const char *var)
{
char *name, *value;
char *name, *value;
value = strchr(var, '=');
if (value == NULL)
@@ -120,7 +114,6 @@ environ_put(struct environ *env, const char *var)
xfree(name);
}
/* Unset an environment variable. */
void
environ_unset(struct environ *env, const char *name)
{
@@ -135,10 +128,6 @@ environ_unset(struct environ *env, const char *name)
xfree(envent);
}
/*
* Copy a space-separated list of variables from a destination into a source
* environment.
*/
void
environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv)
{
@@ -154,28 +143,3 @@ environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv)
}
xfree(copyvars);
}
/* Push environment into the real environment - use after fork(). */
void
environ_push(struct environ *env)
{
ARRAY_DECL(, char *) varlist;
struct environ_entry *envent;
char **varp, *var;
u_int i;
ARRAY_INIT(&varlist);
for (varp = environ; *varp != NULL; varp++) {
var = xstrdup(*varp);
var[strcspn(var, "=")] = '\0';
ARRAY_ADD(&varlist, var);
}
for (i = 0; i < ARRAY_LENGTH(&varlist); i++)
unsetenv(ARRAY_ITEM(&varlist, i));
ARRAY_FREE(&varlist);
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
setenv(envent->name, envent->value, 1);
}
}

View File

@@ -1,105 +0,0 @@
# START tmux completion
# This file is in the public domain
# See: http://www.debian-administration.org/articles/317 for how to write more.
# Usage: Put "source bash_completion_tmux.sh" into your .bashrc
_tmux()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts=" \
attach-session \
bind-key \
break-pane \
capture-pane \
choose-client \
choose-session \
choose-window \
clear-history \
clock-mode \
command-prompt \
confirm-before \
copy-buffer \
copy-mode \
delete-buffer \
detach-client \
display-message \
display-panes \
down-pane \
find-window \
has-session \
if-shell \
join-pane \
kill-pane \
kill-server \
kill-session \
kill-window \
last-window \
link-window \
list-buffers \
list-clients \
list-commands \
list-keys \
list-panes \
list-sessions \
list-windows \
load-buffer \
lock-client \
lock-server \
lock-session \
move-window \
new-session \
new-window \
next-layout \
next-window \
paste-buffer \
pipe-pane \
previous-layout \
previous-window \
refresh-client \
rename-session \
rename-window \
resize-pane \
respawn-window \
rotate-window \
run-shell \
save-buffer \
select-layout \
select-pane \
select-prompt \
select-window \
send-keys \
send-prefix \
server-info \
set-buffer \
set-environment \
set-option \
set-window-option \
show-buffer \
show-environment \
show-messages \
show-options \
show-window-options \
source-file \
split-window \
start-server \
suspend-client \
swap-pane \
swap-window \
switch-client \
unbind-key \
unlink-window \
up-pane"
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
return 0
}
complete -F _tmux tmux
# END tmux completion

View File

@@ -1,4 +1,4 @@
# $Id: screen-keys.conf,v 1.7 2010-07-31 11:39:13 nicm Exp $
# $Id: screen-keys.conf,v 1.6 2010-02-02 21:34:16 nicm Exp $
#
# By Nicholas Marriott. Public domain.
#
@@ -93,9 +93,9 @@ bind | split-window
# :kB: focus up
unbind Tab
bind Tab select-pane -t:.+
bind Tab down-pane
unbind BTab
bind BTab select-pane -t:.-
bind BTab up-pane
# " windowlist -b
unbind '"'

View File

@@ -1,7 +1,7 @@
" Vim syntax file
" Language: tmux(1) configuration file
" Maintainer: Tiago Cunha <me@tiagocunha.org>
" Last Change: $Date: 2010-07-27 18:29:07 $
" Last Change: $Date: 2010-02-26 13:33:22 $
" License: This file is placed in the public domain.
if version < 600
@@ -29,11 +29,11 @@ syn keyword tmuxCmds new[-session] start[-server] kill-server setw
syn keyword tmuxCmds set-window-option show[-options] showw show-window-options
syn keyword tmuxCmds command-prompt setb set-buffer showb show-buffer lsb
syn keyword tmuxCmds list-buffers deleteb delete-buffer lscm list-commands
syn keyword tmuxCmds movew move-window 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 saveb save-buffer killp
syn keyword tmuxCmds saveb save-buffer downp down-pane killp
syn keyword tmuxCmds kill-pane resizep resize-pane selectp select-pane swapp
syn keyword tmuxCmds swap-pane splitw split-window 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 suspend-client findw find-window breakp break-pane nextl
syn keyword tmuxCmds next-layout rotatew rotate-window confirm[-before]
@@ -42,7 +42,7 @@ syn keyword tmuxCmds display[-message] setenv set-environment showenv
syn keyword tmuxCmds show-environment choose-client displayp display-panes
syn keyword tmuxCmds run[-shell] lockc lock-client locks lock-session lsp
syn keyword tmuxCmds list-panes pipep pipe-pane showmsgs show-messages capturep
syn keyword tmuxCmds capture-pane joinp join-pane choose-buffer
syn keyword tmuxCmds capture-pane joinp join-pane
syn keyword tmuxOptsSet prefix status status-fg status-bg bell-action
syn keyword tmuxOptsSet default-command history-limit status-left status-right
@@ -61,7 +61,6 @@ syn keyword tmuxOptsSet mouse-select-pane message-limit quiet escape-time
syn keyword tmuxOptsSet pane-active-border-bg pane-active-border-fg
syn keyword tmuxOptsSet pane-border-bg pane-border-fg
syn keyword tmuxOptsSet display-panes-active-colour alternate-screen
syn keyword tmuxOptsSet detach-on-destroy
syn keyword tmuxOptsSetw monitor-activity aggressive-resize force-width
syn keyword tmuxOptsSetw force-height remain-on-exit uft8 mode-fg mode-bg
@@ -72,8 +71,7 @@ syn keyword tmuxOptsSetw main-pane-width main-pane-height monitor-content
syn keyword tmuxOptsSetw window-status-current-attr window-status-current-bg
syn keyword tmuxOptsSetw window-status-current-fg mode-mouse synchronize-panes
syn keyword tmuxOptsSetw window-status-format window-status-current-format
syn keyword tmuxOptsSetw word-separators window-status-alert-alert
syn keyword tmuxOptsSetw window-status-alert-bg window-status-alert-fg
syn keyword tmuxOptsSetw word-separators
syn keyword tmuxTodo FIXME NOTE TODO XXX contained

View File

@@ -1,24 +1,23 @@
# $Id: vim-keys.conf,v 1.2 2010-09-18 09:36:15 nicm Exp $
# $Id: vim-keys.conf,v 1.1 2010-01-17 16:24:09 nicm Exp $
#
# vim-keys.conf, v1.2 2010/09/12
# vim-keys.conf, v1.0 2010/01/15
#
# By Daniel Thau. Public domain.
#
# This configuration file binds many vi- and vim-like bindings to the
# appropriate tmux key bindings. Note that for many key bindings there is no
# tmux analogue. This is intended for tmux 1.3, which handles pane selection
# differently from the previous versions
# tmux analogue.
# split windows like vim
# vim's definition of a horizontal/vertical split is reversed from tmux's
bind s split-window -v
bind v split-window -h
# move around panes with hjkl, as one would in vim after pressing ctrl-w
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# move around panes with j and k, a bit like vim
# as of tmux 1.1, there is no way to move based on pane position (ie, no way to
# move the pane to the right)
bind j down-pane
bind k up-pane
# resize panes like vim
# feel free to change the "1" to however many lines you want to resize by, only

43
grid.c
View File

@@ -1,4 +1,4 @@
/* $Id: grid.c,v 1.37 2010-04-05 05:11:43 micahcowan Exp $ */
/* $Id: grid.c,v 1.36 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,9 +46,18 @@ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' };
gc, sizeof gd->linedata[py].utf8data[px]); \
} while (0)
int grid_check_x(struct grid *, u_int);
int grid_check_y(struct grid *, u_int);
#ifdef DEBUG
int
grid_check_x(struct grid *gd, u_int px)
{
if ((px) >= (gd)->sx)
log_fatalx("x out of range: %u", px);
return (0);
}
int
grid_check_y(struct grid *gd, u_int py)
{
@@ -57,6 +66,16 @@ grid_check_y(struct grid *gd, u_int py)
return (0);
}
#else
int
grid_check_x(struct grid *gd, u_int px)
{
if ((px) >= (gd)->sx) {
log_debug("x out of range: %u", px);
return (-1);
}
return (0);
}
int
grid_check_y(struct grid *gd, u_int py)
{
@@ -251,6 +270,8 @@ grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx)
const struct grid_cell *
grid_peek_cell(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (&grid_default_cell);
if (grid_check_y(gd, py) != 0)
return (&grid_default_cell);
@@ -263,6 +284,8 @@ grid_peek_cell(struct grid *gd, u_int px, u_int py)
struct grid_cell *
grid_get_cell(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@@ -275,6 +298,8 @@ void
grid_set_cell(
struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
{
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
@@ -286,6 +311,8 @@ grid_set_cell(
const struct grid_utf8 *
grid_peek_utf8(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@@ -298,6 +325,8 @@ grid_peek_utf8(struct grid *gd, u_int px, u_int py)
struct grid_utf8 *
grid_get_utf8(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@@ -310,6 +339,8 @@ void
grid_set_utf8(
struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc)
{
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
@@ -333,6 +364,10 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
return;
}
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_x(gd, px + nx - 1) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
if (grid_check_y(gd, py + ny - 1) != 0)
@@ -430,6 +465,12 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
if (nx == 0 || px == dx)
return;
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_x(gd, px + nx - 1) != 0)
return;
if (grid_check_x(gd, dx + nx - 1) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
gl = &gd->linedata[py];

View File

@@ -1,4 +1,4 @@
/* $Id: input-keys.c,v 1.45 2010-09-07 19:32:58 nicm Exp $ */
/* $Id: input-keys.c,v 1.44 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

2427
input.c

File diff suppressed because it is too large Load Diff

11
job.c
View File

@@ -1,4 +1,4 @@
/* $Id: job.c,v 1.19 2010-10-24 00:45:57 tcunha Exp $ */
/* $Id: job.c,v 1.15 2010-02-26 13:35:04 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -148,9 +148,8 @@ job_run(struct job *job)
case -1:
return (-1);
case 0: /* child */
clear_signals(1);
environ_push(&global_environ);
server_signal_clear();
/* XXX environ? */
if (dup2(out[1], STDOUT_FILENO) == -1)
fatal("dup2 failed");
@@ -168,8 +167,6 @@ job_run(struct job *job)
if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
close(nullfd);
closefrom(STDERR_FILENO + 1);
execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
fatal("execl failed");
default: /* parent */
@@ -180,6 +177,8 @@ job_run(struct job *job)
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 (job->event != NULL)
bufferevent_free(job->event);

View File

@@ -1,4 +1,4 @@
/* $Id: key-bindings.c,v 1.97 2010-12-11 18:42:20 nicm Exp $ */
/* $Id: key-bindings.c,v 1.88 2010-02-08 18:27:34 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -108,8 +108,6 @@ key_bindings_init(void)
{ '#', 0, &cmd_list_buffers_entry },
{ '%', 0, &cmd_split_window_entry },
{ '&', 0, &cmd_confirm_before_entry },
{ '(', 0, &cmd_switch_client_entry },
{ ')', 0, &cmd_switch_client_entry },
{ ',', 0, &cmd_command_prompt_entry },
{ '-', 0, &cmd_delete_buffer_entry },
{ '.', 0, &cmd_command_prompt_entry },
@@ -124,13 +122,10 @@ key_bindings_init(void)
{ '8', 0, &cmd_select_window_entry },
{ '9', 0, &cmd_select_window_entry },
{ ':', 0, &cmd_command_prompt_entry },
{ ';', 0, &cmd_last_pane_entry },
{ '=', 0, &cmd_choose_buffer_entry },
{ '?', 0, &cmd_list_keys_entry },
{ 'D', 0, &cmd_choose_client_entry },
{ 'L', 0, &cmd_switch_client_entry },
{ '[', 0, &cmd_copy_mode_entry },
{ '\'', 0, &cmd_command_prompt_entry },
{ '\'', 0, &cmd_select_prompt_entry },
{ '\002', /* C-b */ 0, &cmd_send_prefix_entry },
{ '\017', /* C-o */ 0, &cmd_rotate_window_entry },
{ '\032', /* C-z */ 0, &cmd_suspend_client_entry },
@@ -141,7 +136,7 @@ key_bindings_init(void)
{ 'i', 0, &cmd_display_message_entry },
{ 'l', 0, &cmd_last_window_entry },
{ 'n', 0, &cmd_next_window_entry },
{ 'o', 0, &cmd_select_pane_entry },
{ 'o', 0, &cmd_down_pane_entry },
{ 'p', 0, &cmd_previous_window_entry },
{ 'q', 0, &cmd_display_panes_entry },
{ 'r', 0, &cmd_refresh_client_entry },
@@ -156,15 +151,12 @@ key_bindings_init(void)
{ '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '4' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '5' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ KEYC_PPAGE, 0, &cmd_copy_mode_entry },
{ 'n' | KEYC_ESCAPE, 0, &cmd_next_window_entry },
{ 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry },
{ 'p' | KEYC_ESCAPE, 0, &cmd_previous_window_entry },
{ KEYC_UP, 1, &cmd_select_pane_entry },
{ KEYC_DOWN, 1, &cmd_select_pane_entry },
{ KEYC_LEFT, 1, &cmd_select_pane_entry },
{ KEYC_RIGHT, 1, &cmd_select_pane_entry },
{ KEYC_UP, 0, &cmd_up_pane_entry },
{ KEYC_DOWN, 0, &cmd_down_pane_entry },
{ KEYC_UP | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
{ KEYC_DOWN | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
{ KEYC_LEFT | KEYC_ESCAPE, 1, &cmd_resize_pane_entry },
@@ -182,15 +174,14 @@ key_bindings_init(void)
for (i = 0; i < nitems(table); i++) {
cmdlist = xmalloc(sizeof *cmdlist);
TAILQ_INIT(&cmdlist->list);
cmdlist->references = 1;
TAILQ_INIT(cmdlist);
cmd = xmalloc(sizeof *cmd);
cmd->entry = table[i].entry;
cmd->data = NULL;
if (cmd->entry->init != NULL)
cmd->entry->init(cmd, table[i].key);
TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry);
TAILQ_INSERT_HEAD(cmdlist, cmd, qentry);
key_bindings_add(
table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist);
@@ -218,14 +209,12 @@ key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...)
struct winlink *wl = ctx->curclient->session->curw;
va_list ap;
if (wl->window->active->mode != &window_copy_mode) {
if (wl->window->active->mode != &window_more_mode)
window_pane_reset_mode(wl->window->active);
window_pane_set_mode(wl->window->active, &window_copy_mode);
window_copy_init_for_output(wl->window->active);
}
window_pane_set_mode(wl->window->active, &window_more_mode);
va_start(ap, fmt);
window_copy_vadd(wl->window->active, fmt, ap);
window_more_vadd(wl->window->active, fmt, ap);
va_end(ap);
}
@@ -264,7 +253,7 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c)
ctx.cmdclient = NULL;
readonly = 1;
TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) {
TAILQ_FOREACH(cmd, bd->cmdlist, qentry) {
if (!(cmd->entry->flags & CMD_READONLY))
readonly = 0;
}

View File

@@ -1,4 +1,4 @@
/* $Id: key-string.c,v 1.34 2010-06-05 20:29:11 micahcowan Exp $ */
/* $Id: key-string.c,v 1.29 2010-01-17 19:01:27 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -23,11 +23,10 @@
#include "tmux.h"
int key_string_search_table(const char *);
int key_string_get_modifiers(const char **);
struct {
const char *string;
int key;
const char *string;
int key;
} key_string_table[] = {
/* Function keys. */
{ "F1", KEYC_F1 },
@@ -101,131 +100,146 @@ key_string_search_table(const char *string)
return (KEYC_NONE);
}
/* Find modifiers. */
int
key_string_get_modifiers(const char **string)
{
int modifiers;
modifiers = 0;
while (((*string)[0] != '\0') && (*string)[1] == '-') {
switch ((*string)[0]) {
case 'C':
case 'c':
modifiers |= KEYC_CTRL;
break;
case 'M':
case 'm':
modifiers |= KEYC_ESCAPE;
break;
case 'S':
case 's':
modifiers |= KEYC_SHIFT;
break;
}
*string += 2;
}
return (modifiers);
}
/* Lookup a string and convert to a key value. */
/* Lookup a string and convert to a key value, handling C-/M-/S- prefix. */
int
key_string_lookup_string(const char *string)
{
int key, modifiers;
int key;
const char *ptr;
/* Check for modifiers. */
modifiers = 0;
if (string[0] == '^' && string[1] != '\0') {
modifiers |= KEYC_CTRL;
string++;
}
modifiers |= key_string_get_modifiers(&string);
if (string[0] == '\0')
return (KEYC_NONE);
if (string[1] == '\0')
return ((u_char) string[0]);
/* Is this a standard ASCII key? */
if (string[1] == '\0') {
key = (u_char) string[0];
if (key < 32 || key > 126)
ptr = NULL;
if ((string[0] == 'C' || string[0] == 'c') && string[1] == '-')
ptr = string + 2;
else if (string[0] == '^')
ptr = string + 1;
if (ptr != NULL) {
if (ptr[0] == '\0')
return (KEYC_NONE);
} else {
/* Otherwise look the key up in the table. */
key = key_string_search_table(string);
if (key == KEYC_NONE)
return (KEYC_NONE);
}
/*
* Lookup as a named key. If a function key (>= KEYC_BASE),
* return it with the ctrl modifier, otherwise fallthrough with
* the key value from the table (eg for C-Space). If not a
* named key, check for single character keys and try that.
*/
key = key_string_search_table(ptr);
if (key != KEYC_NONE) {
if (key >= KEYC_BASE)
return (key | KEYC_CTRL);
} else {
if (ptr[1] != '\0')
return (KEYC_NONE);
key = (u_char) ptr[0];
}
/* Convert the standard control keys. */
if (key < KEYC_BASE && (modifiers & KEYC_CTRL)) {
/*
* Figure out if the single character in key is a valid ctrl
* key.
*/
if (key == 32)
return (0);
if (key == 63)
return (KEYC_BSPACE);
if (key >= 64 && key <= 95)
return (key - 64);
if (key >= 97 && key <= 122)
key -= 96;
else if (key >= 64 && key <= 95)
key -= 64;
else if (key == 32)
key = 0;
else if (key == 63)
key = KEYC_BSPACE;
else
return (KEYC_NONE);
modifiers &= ~KEYC_CTRL;
return (key - 96);
return (KEYC_NONE);
}
return (key | modifiers);
if ((string[0] == 'M' || string[0] == 'm') && string[1] == '-') {
ptr = string + 2;
if (ptr[0] == '\0')
return (KEYC_NONE);
key = key_string_lookup_string(ptr);
if (key != KEYC_NONE) {
if (key >= KEYC_BASE)
return (key | KEYC_ESCAPE);
} else {
if (ptr[1] == '\0')
return (KEYC_NONE);
key = (u_char) ptr[0];
}
if (key >= 32 && key <= 127)
return (key | KEYC_ESCAPE);
return (KEYC_NONE);
}
if ((string[0] == 'S' || string[0] == 's') && string[1] == '-') {
ptr = string + 2;
if (ptr[0] == '\0')
return (KEYC_NONE);
key = key_string_lookup_string(ptr);
if (key != KEYC_NONE) {
if (key >= KEYC_BASE)
return (key | KEYC_SHIFT);
} else {
if (ptr[1] == '\0')
return (KEYC_NONE);
key = (u_char) ptr[0];
}
if (key >= 32 && key <= 127)
return (key | KEYC_SHIFT);
return (KEYC_NONE);
}
return (key_string_search_table(string));
}
/* Convert a key code into string format, with prefix if necessary. */
const char *
key_string_lookup_key(int key)
{
static char out[24];
char tmp[8];
u_int i;
static char tmp[24], tmp2[24];
const char *s;
u_int i;
*out = '\0';
/*
* Special case: display C-@ as C-Space. Could do this below in
* the (key >= 0 && key <= 32), but this way we let it be found
* in key_string_table, for the unlikely chance that we might
* change its name.
*/
if ((key & KEYC_MASK_KEY) == 0)
key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD);
/* Fill in the modifiers. */
if (key & KEYC_CTRL)
strlcat(out, "C-", sizeof out);
if (key & KEYC_ESCAPE)
strlcat(out, "M-", sizeof out);
if (key & KEYC_SHIFT)
strlcat(out, "S-", sizeof out);
key &= KEYC_MASK_KEY;
/* Try the key against the string table. */
for (i = 0; i < nitems(key_string_table); i++) {
if (key == key_string_table[i].key)
break;
}
if (i != nitems(key_string_table)) {
strlcat(out, key_string_table[i].string, sizeof out);
return (out);
}
/* Invalid keys are errors. */
if (key >= 127)
if (key == 127)
return (NULL);
/* Check for standard or control key. */
if (key & KEYC_ESCAPE) {
if ((s = key_string_lookup_key(key & ~KEYC_ESCAPE)) == NULL)
return (NULL);
xsnprintf(tmp2, sizeof tmp2, "M-%s", s);
return (tmp2);
}
if (key & KEYC_CTRL) {
if ((s = key_string_lookup_key(key & ~KEYC_CTRL)) == NULL)
return (NULL);
xsnprintf(tmp2, sizeof tmp2, "C-%s", s);
return (tmp2);
}
if (key & KEYC_SHIFT) {
if ((s = key_string_lookup_key(key & ~KEYC_SHIFT)) == NULL)
return (NULL);
xsnprintf(tmp2, sizeof tmp2, "S-%s", s);
return (tmp2);
}
for (i = 0; i < nitems(key_string_table); i++) {
if (key == key_string_table[i].key)
return (key_string_table[i].string);
}
if (key >= 32 && key <= 255) {
tmp[0] = (char) key;
tmp[1] = '\0';
return (tmp);
}
if (key >= 0 && key <= 32) {
if (key == 0 || key > 26)
xsnprintf(tmp, sizeof tmp, "C-%c", 64 + key);
else
xsnprintf(tmp, sizeof tmp, "C-%c", 96 + key);
} else if (key >= 32 && key <= 126) {
tmp[0] = key;
tmp[1] = '\0';
return (tmp);
}
strlcat(out, tmp, sizeof out);
return (out);
return (NULL);
}

View File

@@ -1,264 +0,0 @@
/* $Id: layout-custom.c,v 1.1 2010-07-02 02:54:52 tcunha Exp $ */
/*
* Copyright (c) 2010 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 <ctype.h>
#include <string.h>
#include "tmux.h"
u_short layout_checksum(const char *);
int layout_append(struct layout_cell *, char *, size_t);
struct layout_cell *layout_construct(struct layout_cell *, const char **);
void layout_assign(struct window_pane **, struct layout_cell *);
/* Calculate layout checksum. */
u_short
layout_checksum(const char *layout)
{
u_short csum;
csum = 0;
for (; *layout != '\0'; layout++) {
csum = (csum >> 1) + ((csum & 1) << 15);
csum += *layout;
}
return (csum);
}
/* Dump layout as a string. */
char *
layout_dump(struct window *w)
{
char layout[BUFSIZ], *out;
*layout = '\0';
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
return (NULL);
xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
return (out);
}
/* Append information for a single cell. */
int
layout_append(struct layout_cell *lc, char *buf, size_t len)
{
struct layout_cell *lcchild;
char tmp[64];
size_t tmplen;
const char *brackets = "][";
if (len == 0)
return (-1);
tmplen = xsnprintf(tmp, sizeof tmp,
"%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff);
if (tmplen > (sizeof tmp) - 1)
return (-1);
if (strlcat(buf, tmp, len) >= len)
return (-1);
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
brackets = "}{";
/* FALLTHROUGH */
case LAYOUT_TOPBOTTOM:
if (strlcat(buf, &brackets[1], len) >= len)
return (-1);
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (layout_append(lcchild, buf, len) != 0)
return (-1);
if (strlcat(buf, ",", len) >= len)
return (-1);
}
buf[strlen(buf) - 1] = brackets[0];
break;
case LAYOUT_WINDOWPANE:
break;
}
return (0);
}
/* Parse a layout string and arrange window as layout. */
int
layout_parse(struct window *w, const char *layout)
{
struct layout_cell *lc, *lcchild;
struct window_pane *wp;
u_int npanes, ncells, sx, sy;
u_short csum;
/* Check validity. */
if (sscanf(layout, "%hx,", &csum) != 1)
return (-1);
layout += 5;
if (csum != layout_checksum(layout))
return (-1);
/* Build the layout. */
lc = layout_construct(NULL, &layout);
if (lc == NULL)
return (-1);
if (*layout != '\0')
goto fail;
/* Check this window will fit into the layout. */
for (;;) {
npanes = window_count_panes(w);
ncells = layout_count_cells(lc);
if (npanes > ncells)
goto fail;
if (npanes == ncells)
break;
/* Fewer panes than cells - close the bottom right. */
lcchild = layout_find_bottomright(lc);
layout_destroy_cell(lcchild, &lc);
}
/* Save the old window size and resize to the layout size. */
sx = w->sx; sy = w->sy;
window_resize(w, lc->sx, lc->sy);
/* Destroy the old layout and swap to the new. */
layout_free_cell(w->layout_root);
w->layout_root = lc;
/* Assign the panes into the cells. */
wp = TAILQ_FIRST(&w->panes);
layout_assign(&wp, lc);
/* Update pane offsets and sizes. */
layout_fix_offsets(lc);
layout_fix_panes(w, lc->sx, lc->sy);
/* Then resize the layout back to the original window size. */
layout_resize(w, sx, sy);
window_resize(w, sx, sy);
layout_print_cell(lc, __func__, 0);
return (0);
fail:
layout_free_cell(lc);
return (-1);
}
/* Assign panes into cells. */
void
layout_assign(struct window_pane **wp, struct layout_cell *lc)
{
struct layout_cell *lcchild;
switch (lc->type) {
case LAYOUT_WINDOWPANE:
layout_make_leaf(lc, *wp);
*wp = TAILQ_NEXT(*wp, entry);
return;
case LAYOUT_LEFTRIGHT:
case LAYOUT_TOPBOTTOM:
TAILQ_FOREACH(lcchild, &lc->cells, entry)
layout_assign(wp, lcchild);
return;
}
}
/* Construct a cell from all or part of a layout tree. */
struct layout_cell *
layout_construct(struct layout_cell *lcparent, const char **layout)
{
struct layout_cell *lc, *lcchild;
u_int sx, sy, xoff, yoff;
if (!isdigit((u_char) **layout))
return (NULL);
if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
return (NULL);
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout != 'x')
return (NULL);
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout != ',')
return (NULL);
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout != ',')
return (NULL);
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
lc = layout_create_cell(lcparent);
lc->sx = sx;
lc->sy = sy;
lc->xoff = xoff;
lc->yoff = yoff;
switch (**layout) {
case ',':
case '}':
case ']':
case '\0':
return (lc);
case '{':
lc->type = LAYOUT_LEFTRIGHT;
break;
case '[':
lc->type = LAYOUT_TOPBOTTOM;
break;
default:
goto fail;
}
do {
(*layout)++;
lcchild = layout_construct(lc, layout);
if (lcchild == NULL)
goto fail;
TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
} while (**layout == ',');
switch (lc->type) {
case LAYOUT_LEFTRIGHT:
if (**layout != '}')
goto fail;
break;
case LAYOUT_TOPBOTTOM:
if (**layout != ']')
goto fail;
break;
default:
goto fail;
}
(*layout)++;
return (lc);
fail:
layout_free_cell(lc);
return (NULL);
}

View File

@@ -1,4 +1,4 @@
/* $Id: layout-set.c,v 1.8 2010-12-22 15:23:59 tcunha Exp $ */
/* $Id: layout-set.c,v 1.5 2010-02-05 01:29:04 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,7 +31,6 @@ void layout_set_even_h(struct window *);
void layout_set_even_v(struct window *);
void layout_set_main_h(struct window *);
void layout_set_main_v(struct window *);
void layout_set_tiled(struct window *);
const struct {
const char *name;
@@ -41,7 +40,6 @@ const struct {
{ "even-vertical", layout_set_even_v },
{ "main-horizontal", layout_set_main_h },
{ "main-vertical", layout_set_main_v },
{ "tiled", layout_set_tiled },
};
const char *
@@ -135,9 +133,10 @@ layout_set_even_h(struct window *w)
return;
/* How many can we fit? */
width = (w->sx - (n - 1)) / n;
if (width < PANE_MINIMUM)
width = PANE_MINIMUM;
if (w->sx / n < PANE_MINIMUM + 1)
width = PANE_MINIMUM + 1;
else
width = w->sx / n;
/* Free the old root and construct a new. */
layout_free(w);
@@ -150,12 +149,12 @@ layout_set_even_h(struct window *w)
TAILQ_FOREACH(wp, &w->panes, entry) {
/* Create child cell. */
lcnew = layout_create_cell(lc);
layout_set_size(lcnew, width, w->sy, xoff, 0);
layout_set_size(lcnew, width - 1, w->sy, xoff, 0);
layout_make_leaf(lcnew, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
i++;
xoff += width + 1;
xoff += width;
}
/* Allocate any remaining space. */
@@ -188,9 +187,10 @@ layout_set_even_v(struct window *w)
return;
/* How many can we fit? */
height = (w->sy - (n - 1)) / n;
if (height < PANE_MINIMUM)
height = PANE_MINIMUM;
if (w->sy / n < PANE_MINIMUM + 1)
height = PANE_MINIMUM + 1;
else
height = w->sy / n;
/* Free the old root and construct a new. */
layout_free(w);
@@ -203,12 +203,12 @@ layout_set_even_v(struct window *w)
TAILQ_FOREACH(wp, &w->panes, entry) {
/* Create child cell. */
lcnew = layout_create_cell(lc);
layout_set_size(lcnew, w->sx, height, 0, yoff);
layout_set_size(lcnew, w->sx, height - 1, 0, yoff);
layout_make_leaf(lcnew, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
i++;
yoff += height + 1;
yoff += height;
}
/* Allocate any remaining space. */
@@ -231,8 +231,8 @@ layout_set_main_h(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcrow, *lcchild;
u_int n, mainheight, otherheight, width, height;
u_int used, i, j, columns, rows, totalrows;
u_int n, mainheight, width, height, used;
u_int i, j, columns, rows, totalrows;
layout_print_cell(w->layout_root, __func__, 1);
@@ -242,26 +242,16 @@ layout_set_main_h(struct window *w)
return;
n--; /* take off main pane */
/* How many rows and columns will be needed, not counting main? */
columns = (w->sx + 1) / (PANE_MINIMUM + 1); /* maximum columns */
/* How many rows and columns will be needed? */
columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */
if (columns == 0)
columns = 1;
rows = 1 + (n - 1) / columns;
columns = 1 + (n - 1) / rows;
width = (w->sx - (n - 1)) / columns;
width = w->sx / columns;
/* Get the main pane height and add one for separator line. */
mainheight = options_get_number(&w->options, "main-pane-height") + 1;
/* Get the optional other pane height and add one for separator line. */
otherheight = options_get_number(&w->options, "other-pane-height") + 1;
/*
* If an other pane height was specified, honour it so long as it
* doesn't shrink the main height to less than the main-pane-height
*/
if (otherheight > 1 && w->sx - otherheight > mainheight)
mainheight = w->sx - otherheight;
if (mainheight < PANE_MINIMUM + 1)
mainheight = PANE_MINIMUM + 1;
@@ -272,14 +262,14 @@ layout_set_main_h(struct window *w)
mainheight = PANE_MINIMUM + 2;
else
mainheight = w->sy - totalrows;
height = PANE_MINIMUM;
height = PANE_MINIMUM + 1;
} else
height = (w->sy - mainheight - (rows - 1)) / rows;
height = (w->sy - mainheight) / rows;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0);
layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create the main pane. */
@@ -297,7 +287,7 @@ layout_set_main_h(struct window *w)
/* Create the new row. */
lcrow = layout_create_cell(lc);
layout_set_size(lcrow, w->sx, height, 0, 0);
layout_set_size(lcrow, w->sx, height - 1, 0, 0);
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
/* If only one column, just use the row directly. */
@@ -312,7 +302,7 @@ layout_set_main_h(struct window *w)
for (i = 0; i < columns; i++) {
/* Create and add a pane cell. */
lcchild = layout_create_cell(lcrow);
layout_set_size(lcchild, width, height, 0, 0);
layout_set_size(lcchild, width - 1, height - 1, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
@@ -324,7 +314,7 @@ layout_set_main_h(struct window *w)
/* Adjust the row to fit the full width if necessary. */
if (i == columns)
i--;
used = ((i + 1) * (width + 1)) - 1;
used = ((i + 1) * width) - 1;
if (w->sx <= used)
continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
@@ -332,7 +322,7 @@ layout_set_main_h(struct window *w)
}
/* Adjust the last row height to fit if necessary. */
used = mainheight + (rows * height) + rows - 1;
used = mainheight + (rows * height) - 1;
if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
@@ -352,8 +342,8 @@ layout_set_main_v(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lccolumn, *lcchild;
u_int n, mainwidth, otherwidth, width, height;
u_int used, i, j, columns, rows, totalcolumns;
u_int n, mainwidth, width, height, used;
u_int i, j, columns, rows, totalcolumns;
layout_print_cell(w->layout_root, __func__, 1);
@@ -363,26 +353,16 @@ layout_set_main_v(struct window *w)
return;
n--; /* take off main pane */
/* How many rows and columns will be needed, not counting main? */
rows = (w->sy + 1) / (PANE_MINIMUM + 1); /* maximum rows */
/* How many rows and columns will be needed? */
rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */
if (rows == 0)
rows = 1;
columns = 1 + (n - 1) / rows;
rows = 1 + (n - 1) / columns;
height = (w->sy - (n - 1)) / rows;
height = w->sy / rows;
/* Get the main pane width and add one for separator line. */
mainwidth = options_get_number(&w->options, "main-pane-width") + 1;
/* Get the optional other pane width and add one for separator line. */
otherwidth = options_get_number(&w->options, "other-pane-width") + 1;
/*
* If an other pane width was specified, honour it so long as it
* doesn't shrink the main width to less than the main-pane-width
*/
if (otherwidth > 1 && w->sx - otherwidth > mainwidth)
mainwidth = w->sx - otherwidth;
if (mainwidth < PANE_MINIMUM + 1)
mainwidth = PANE_MINIMUM + 1;
@@ -393,14 +373,14 @@ layout_set_main_v(struct window *w)
mainwidth = PANE_MINIMUM + 2;
else
mainwidth = w->sx - totalcolumns;
width = PANE_MINIMUM;
width = PANE_MINIMUM + 1;
} else
width = (w->sx - mainwidth - (columns - 1)) / columns;
width = (w->sx - mainwidth) / columns;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0);
layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0);
layout_make_node(lc, LAYOUT_LEFTRIGHT);
/* Create the main pane. */
@@ -418,7 +398,7 @@ layout_set_main_v(struct window *w)
/* Create the new column. */
lccolumn = layout_create_cell(lc);
layout_set_size(lccolumn, width, w->sy, 0, 0);
layout_set_size(lccolumn, width - 1, w->sy, 0, 0);
TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
/* If only one row, just use the row directly. */
@@ -433,7 +413,7 @@ layout_set_main_v(struct window *w)
for (i = 0; i < rows; i++) {
/* Create and add a pane cell. */
lcchild = layout_create_cell(lccolumn);
layout_set_size(lcchild, width, height, 0, 0);
layout_set_size(lcchild, width - 1, height - 1, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
@@ -445,7 +425,7 @@ layout_set_main_v(struct window *w)
/* Adjust the column to fit the full height if necessary. */
if (i == rows)
i--;
used = ((i + 1) * (height + 1)) - 1;
used = ((i + 1) * height) - 1;
if (w->sy <= used)
continue;
lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
@@ -453,7 +433,7 @@ layout_set_main_v(struct window *w)
}
/* Adjust the last column width to fit if necessary. */
used = mainwidth + (columns * width) + columns - 1;
used = mainwidth + (columns * width) - 1;
if (w->sx > used) {
lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used);
@@ -467,103 +447,3 @@ layout_set_main_v(struct window *w)
server_redraw_window(w);
}
void
layout_set_tiled(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcrow, *lcchild;
u_int n, width, height, used;
u_int i, j, columns, rows;
layout_print_cell(w->layout_root, __func__, 1);
/* Get number of panes. */
n = window_count_panes(w);
if (n <= 1)
return;
/* How many rows and columns are wanted? */
rows = columns = 1;
while (rows * columns < n) {
rows++;
if (rows * columns < n)
columns++;
}
/* What width and height should they be? */
width = (w->sx - (columns - 1)) / columns;
if (width < PANE_MINIMUM)
width = PANE_MINIMUM;
height = (w->sy - (rows - 1)) / rows;
if (height < PANE_MINIMUM)
height = PANE_MINIMUM;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, (width + 1) * columns - 1,
(height + 1) * rows - 1, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create a grid of the cells. */
wp = TAILQ_FIRST(&w->panes);
for (j = 0; j < rows; j++) {
/* If this is the last cell, all done. */
if (wp == NULL)
break;
/* Create the new row. */
lcrow = layout_create_cell(lc);
layout_set_size(lcrow, w->sx, height, 0, 0);
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
/* If only one column, just use the row directly. */
if (n - (j * columns) == 1) {
layout_make_leaf(lcrow, wp);
wp = TAILQ_NEXT(wp, entry);
continue;
}
/* Add in the columns. */
layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
for (i = 0; i < columns; i++) {
/* Create and add a pane cell. */
lcchild = layout_create_cell(lcrow);
layout_set_size(lcchild, width, height, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
/* Move to the next cell. */
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
break;
}
/*
* Adjust the row and columns to fit the full width if
* necessary.
*/
if (i == columns)
i--;
used = ((i + 1) * (width + 1)) - 1;
if (w->sx <= used)
continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
}
/* Adjust the last row height to fit if necessary. */
used = (rows * height) + rows - 1;
if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
}
/* Fix cell offsets. */
layout_fix_offsets(lc);
layout_fix_panes(w, w->sx, w->sy);
layout_print_cell(w->layout_root, __func__, 1);
server_redraw_window(w);
}

View File

@@ -1,4 +1,4 @@
/* $Id: layout-string.c,v 1.4 2010-07-02 02:54:52 tcunha Exp $ */
/* $Id: layout-string.c,v 1.3 2010-01-08 16:28:04 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -36,6 +36,7 @@ struct layout_cell *layout_find_right(struct layout_cell *);
struct layout_cell *layout_find_topleft(struct layout_cell *);
struct layout_cell *layout_find_topright(struct layout_cell *);
struct layout_cell *layout_find_bottomleft(struct layout_cell *);
struct layout_cell *layout_find_bottomright(struct layout_cell *);
/* Find the cell; returns NULL if string not understood. */
struct layout_cell *

130
layout.c
View File

@@ -1,4 +1,4 @@
/* $Id: layout.c,v 1.19 2010-07-02 02:54:52 tcunha Exp $ */
/* $Id: layout.c,v 1.18 2010-01-08 16:31:35 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -218,27 +218,6 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
}
}
/* Count the number of available cells in a layout. */
u_int
layout_count_cells(struct layout_cell *lc)
{
struct layout_cell *lcchild;
u_int n;
switch (lc->type) {
case LAYOUT_WINDOWPANE:
return (1);
case LAYOUT_LEFTRIGHT:
case LAYOUT_TOPBOTTOM:
n = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry)
n += layout_count_cells(lcchild);
return (n);
default:
fatalx("bad layout type");
}
}
/* Calculate how much size is available to be removed from a cell. */
u_int
layout_resize_check(struct layout_cell *lc, enum layout_type type)
@@ -323,56 +302,6 @@ layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
}
}
/* Destroy a cell and redistribute the space. */
void
layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot)
{
struct layout_cell *lcother, *lcparent;
/*
* If no parent, this is the last pane so window close is imminent and
* there is no need to resize anything.
*/
lcparent = lc->parent;
if (lcparent == NULL) {
layout_free_cell(lc);
*lcroot = NULL;
return;
}
/* Merge the space into the previous or next cell. */
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
else
layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
/* Remove this from the parent's list. */
TAILQ_REMOVE(&lcparent->cells, lc, entry);
layout_free_cell(lc);
/*
* If the parent now has one cell, remove the parent from the tree and
* replace it by that cell.
*/
lc = TAILQ_FIRST(&lcparent->cells);
if (TAILQ_NEXT(lc, entry) == NULL) {
TAILQ_REMOVE(&lcparent->cells, lc, entry);
lc->parent = lcparent->parent;
if (lc->parent == NULL) {
lc->xoff = 0; lc->yoff = 0;
*lcroot = lc;
} else
TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
layout_free_cell(lcparent);
}
}
void
layout_init(struct window *w)
{
@@ -668,16 +597,59 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size)
return (lcnew);
}
/* Destroy the cell associated with a pane. */
/* Destroy the layout associated with a pane and redistribute the space. */
void
layout_close_pane(struct window_pane *wp)
{
/* Remove the cell. */
layout_destroy_cell(wp->layout_cell, &wp->window->layout_root);
struct layout_cell *lc, *lcother, *lcparent;
lc = wp->layout_cell;
lcparent = lc->parent;
/*
* If no parent, this is the last pane so window close is imminent and
* there is no need to resize anything.
*/
if (lcparent == NULL) {
layout_free_cell(lc);
wp->window->layout_root = NULL;
return;
}
/* Merge the space into the previous or next cell. */
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
else
layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
/* Remove this from the parent's list. */
TAILQ_REMOVE(&lcparent->cells, lc, entry);
layout_free_cell(lc);
/*
* If the parent now has one cell, remove the parent from the tree and
* replace it by that cell.
*/
lc = TAILQ_FIRST(&lcparent->cells);
if (TAILQ_NEXT(lc, entry) == NULL) {
TAILQ_REMOVE(&lcparent->cells, lc, entry);
lc->parent = lcparent->parent;
if (lc->parent == NULL) {
lc->xoff = 0; lc->yoff = 0;
wp->window->layout_root = lc;
} else
TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
layout_free_cell(lcparent);
}
/* Fix pane offsets and sizes. */
if (wp->window->layout_root != NULL) {
layout_fix_offsets(wp->window->layout_root);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
}
layout_fix_offsets(wp->window->layout_root);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
}

View File

@@ -1,4 +1,4 @@
/* $Id: mode-key.c,v 1.46 2010-03-16 17:30:58 micahcowan Exp $ */
/* $Id: mode-key.c,v 1.45 2010-03-08 15:02:07 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -88,10 +88,6 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_GOTOLINE, "goto-line" },
{ MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" },
{ MODEKEYCOPY_HISTORYTOP, "history-top" },
{ MODEKEYCOPY_JUMP, "jump-forward" },
{ MODEKEYCOPY_JUMPAGAIN, "jump-again" },
{ MODEKEYCOPY_JUMPREVERSE, "jump-reverse" },
{ MODEKEYCOPY_JUMPBACK, "jump-backward" },
{ MODEKEYCOPY_LEFT, "cursor-left" },
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
@@ -181,8 +177,6 @@ struct mode_key_tree mode_key_tree_vi_choice;
const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION },
{ '$', 0, MODEKEYCOPY_ENDOFLINE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
{ '/', 0, MODEKEYCOPY_SEARCHDOWN },
{ '0', 0, MODEKEYCOPY_STARTOFLINE },
{ '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
@@ -198,7 +192,6 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '?', 0, MODEKEYCOPY_SEARCHUP },
{ 'B', 0, MODEKEYCOPY_PREVIOUSSPACE },
{ 'E', 0, MODEKEYCOPY_NEXTSPACEEND },
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
{ 'G', 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'H', 0, MODEKEYCOPY_TOPLINE },
{ 'J', 0, MODEKEYCOPY_SCROLLDOWN },
@@ -220,7 +213,6 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '^', 0, MODEKEYCOPY_BACKTOINDENTATION },
{ 'b', 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'e', 0, MODEKEYCOPY_NEXTWORDEND },
{ 'f', 0, MODEKEYCOPY_JUMP },
{ 'g', 0, MODEKEYCOPY_HISTORYTOP },
{ 'h', 0, MODEKEYCOPY_LEFT },
{ 'j', 0, MODEKEYCOPY_DOWN },
@@ -298,8 +290,6 @@ struct mode_key_tree mode_key_tree_emacs_choice;
/* emacs copy mode keys. */
const struct mode_key_entry mode_key_emacs_copy[] = {
{ ' ', 0, MODEKEYCOPY_NEXTPAGE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
@@ -311,8 +301,6 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP },
{ '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
{ 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
@@ -331,7 +319,6 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'f', 0, MODEKEYCOPY_JUMP },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND },
{ 'g', 0, MODEKEYCOPY_GOTOLINE },
{ 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION },

26
paste.c
View File

@@ -1,4 +1,4 @@
/* $Id: paste.c,v 1.15 2010-06-22 23:36:54 tcunha Exp $ */
/* $Id: paste.c,v 1.13 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -156,27 +156,3 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size)
return (0);
}
/* Convert a buffer into a visible string. */
char *
paste_print(struct paste_buffer *pb, size_t width)
{
char *buf;
size_t len, used;
if (width < 3)
width = 3;
buf = xmalloc(width * 4 + 1);
len = pb->size;
if (len > width)
len = width;
used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
if (pb->size > width || used > width) {
buf[width - 3] = '\0';
strlcat(buf, "...", width);
}
return (buf);
}

View File

@@ -1,4 +1,4 @@
/* $Id: resize.c,v 1.27 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: resize.c,v 1.24 2009-09-25 17:47:42 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -52,7 +52,11 @@ recalculate_sizes(void)
u_int i, j, ssx, ssy, has, limit;
int flag;
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
ssx = ssy = UINT_MAX;
for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j);
@@ -94,13 +98,14 @@ recalculate_sizes(void)
flag = options_get_number(&w->options, "aggressive-resize");
ssx = ssy = UINT_MAX;
RB_FOREACH(s, sessions, &sessions) {
if (s->flags & SESSION_UNATTACHED)
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
s = ARRAY_ITEM(&sessions, j);
if (s == NULL || s->flags & SESSION_UNATTACHED)
continue;
if (flag)
has = s->curw->window == w;
else
has = session_has(s, w) != NULL;
has = session_has(s, w);
if (has) {
if (s->sx < ssx)
ssx = s->sx;
@@ -108,8 +113,11 @@ recalculate_sizes(void)
ssy = s->sy;
}
}
if (ssx == UINT_MAX || ssy == UINT_MAX)
if (ssx == UINT_MAX || ssy == UINT_MAX) {
w->flags |= WINDOW_HIDDEN;
continue;
}
w->flags &= ~WINDOW_HIDDEN;
limit = options_get_number(&w->options, "force-width");
if (limit != 0 && ssx > limit)

View File

@@ -1,4 +1,4 @@
/* $Id: screen-redraw.c,v 1.53 2010-09-18 15:43:53 tcunha Exp $ */
/* $Id: screen-redraw.c,v 1.52 2010-02-05 01:31:06 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -41,8 +41,6 @@ void screen_redraw_draw_number(struct client *, struct window_pane *);
#define CELL_JOIN 11
#define CELL_OUTSIDE 12
#define CELL_BORDERS " xqlkmjwvtun~"
/* Check if cell is on the border of a particular pane. */
int
screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
@@ -175,6 +173,8 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
struct grid_cell active_gc, other_gc;
u_int i, j, type;
int status, fg, bg;
const u_char *base, *ptr;
u_char ch, border[20];
/* Get status line, er, status. */
if (c->message_string != NULL || c->prompt_string != NULL)
@@ -193,7 +193,6 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
memcpy(&other_gc, &grid_default_cell, sizeof other_gc);
memcpy(&active_gc, &grid_default_cell, sizeof active_gc);
active_gc.data = other_gc.data = 'x'; /* not space */
active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET;
fg = options_get_number(&c->session->options, "pane-border-fg");
colour_set_fg(&other_gc, fg);
bg = options_get_number(&c->session->options, "pane-border-bg");
@@ -204,6 +203,16 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
colour_set_bg(&active_gc, bg);
/* Draw background and borders. */
strlcpy(border, " |-....--||+.", sizeof border);
if (tty_term_has(tty->term, TTYC_ACSC)) {
base = " xqlkmjwvtun~";
for (ptr = base; *ptr != '\0'; ptr++) {
if ((ch = tty_get_acs(tty, *ptr)) != '\0')
border[ptr - base] = ch;
}
other_gc.attr |= GRID_ATTR_CHARSET;
active_gc.attr |= GRID_ATTR_CHARSET;
}
for (j = 0; j < tty->sy - status; j++) {
if (status_only && j != tty->sy - 1)
continue;
@@ -216,7 +225,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
else
tty_attributes(tty, &other_gc);
tty_cursor(tty, i, j);
tty_putc(tty, CELL_BORDERS[type]);
tty_putc(tty, border[type]);
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: screen-write.c,v 1.90 2010-06-16 18:09:23 micahcowan Exp $ */
/* $Id: screen-write.c,v 1.88 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -23,7 +23,7 @@
#include "tmux.h"
void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int);
void screen_write_overwrite(struct screen_write_ctx *, u_int);
void screen_write_overwrite(struct screen_write_ctx *);
int screen_write_combine(
struct screen_write_ctx *, const struct utf8_data *);
@@ -1009,18 +1009,17 @@ screen_write_cell(struct screen_write_ctx *ctx,
}
/* Check this will fit on the current line and wrap if not. */
if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
if (s->cx > screen_size_x(s) - width) {
screen_write_linefeed(ctx, 1);
s->cx = 0; /* carriage return */
}
/* Sanity checks. */
if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - 1)
|| s->cy > screen_size_y(s) - 1)
if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
return;
/* Handle overwriting of UTF-8 characters. */
screen_write_overwrite(ctx, width);
screen_write_overwrite(ctx);
/*
* If the new character is UTF-8 wide, fill in padding cells. Have
@@ -1123,11 +1122,12 @@ screen_write_combine(
* by the same character.
*/
void
screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
screen_write_overwrite(struct screen_write_ctx *ctx)
{
struct screen *s = ctx->s;
struct grid *gd = s->grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
u_int xx;
gc = grid_view_peek_cell(gd, s->cx, s->cy);
@@ -1147,17 +1147,30 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
/* Overwrite the character at the start of this padding. */
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
}
/*
* Overwrite any padding cells that belong to a UTF-8 character
* we'll be overwriting with the current character.
*/
xx = s->cx + width - 1;
while (++xx < screen_size_x(s)) {
gc = grid_view_peek_cell(gd, xx, s->cy);
if (!(gc->flags & GRID_FLAG_PADDING))
break;
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
/* Overwrite following padding cells. */
xx = s->cx;
while (++xx < screen_size_x(s)) {
gc = grid_view_peek_cell(gd, xx, s->cy);
if (!(gc->flags & GRID_FLAG_PADDING))
break;
grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
}
} else if (gc->flags & GRID_FLAG_UTF8) {
gu = grid_view_peek_utf8(gd, s->cx, s->cy);
if (gu->width > 1) {
/*
* An UTF-8 wide cell; overwrite following padding
* cells only.
*/
xx = s->cx;
while (++xx < screen_size_x(s)) {
gc = grid_view_peek_cell(gd, xx, s->cy);
if (!(gc->flags & GRID_FLAG_PADDING))
break;
grid_view_set_cell(
gd, xx, s->cy, &grid_default_cell);
}
}
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: screen.c,v 1.103 2010-12-11 17:57:28 nicm Exp $ */
/* $Id: screen.c,v 1.99 2010-02-08 18:13:17 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,10 +18,8 @@
#include <sys/types.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -32,14 +30,9 @@ void screen_resize_y(struct screen *, u_int);
void
screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
{
char hn[MAXHOSTNAMELEN];
s->grid = grid_create(sx, sy, hlimit);
if (gethostname(hn, MAXHOSTNAMELEN) == 0)
s->title = xstrdup(hn);
else
s->title = xstrdup("");
s->title = xstrdup("");
s->tabs = NULL;
@@ -56,7 +49,7 @@ screen_reinit(struct screen *s)
s->rupper = 0;
s->rlower = screen_size_y(s) - 1;
s->mode = MODE_CURSOR | MODE_WRAP;
s->mode = MODE_CURSOR;
screen_reset_tabs(s);
@@ -287,7 +280,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
*/
if (sel->ex < sel->sx) {
/* Cursor (ex) is on the left. */
if (px < sel->ex)
if (px <= sel->ex)
return (0);
if (px > sel->sx)
@@ -297,7 +290,7 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
if (px < sel->sx)
return (0);
if (px > sel->ex)
if (px >= sel->ex)
return (0);
}
} else {

View File

@@ -1,4 +1,4 @@
/* $Id: server-client.c,v 1.48 2010-12-22 15:31:00 tcunha Exp $ */
/* $Id: server-client.c,v 1.31 2010-02-08 18:27:34 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -28,14 +28,9 @@
void server_client_handle_key(int, struct mouse_event *, void *);
void server_client_repeat_timer(int, short, void *);
void server_client_check_exit(struct client *);
void server_client_check_backoff(struct client *);
void server_client_check_redraw(struct client *);
void server_client_set_title(struct client *);
void server_client_reset_state(struct client *);
void server_client_in_callback(struct bufferevent *, short, void *);
void server_client_out_callback(struct bufferevent *, short, void *);
void server_client_err_callback(struct bufferevent *, short, void *);
int server_client_msg_dispatch(struct client *);
void server_client_msg_command(struct client *, struct msg_command_data *);
@@ -59,6 +54,8 @@ server_client_create(int fd)
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;
@@ -69,15 +66,12 @@ server_client_create(int fd)
fatal("gettimeofday failed");
memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
c->stdin_event = NULL;
c->stdout_event = NULL;
c->stderr_event = NULL;
ARRAY_INIT(&c->prompt_hdata);
c->tty.fd = -1;
c->title = NULL;
c->session = NULL;
c->last_session = NULL;
c->tty.sx = 80;
c->tty.sy = 24;
@@ -123,19 +117,6 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty);
if (c->stdin_fd != -1)
close(c->stdin_fd);
if (c->stdin_event != NULL)
bufferevent_free(c->stdin_event);
if (c->stdout_fd != -1)
close(c->stdout_fd);
if (c->stdout_event != NULL)
bufferevent_free(c->stdout_event);
if (c->stderr_fd != -1)
close(c->stderr_fd);
if (c->stderr_event != NULL)
bufferevent_free(c->stderr_event);
screen_free(&c->status);
job_tree_free(&c->status_jobs);
@@ -159,6 +140,9 @@ server_client_lost(struct client *c)
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);
@@ -178,7 +162,6 @@ server_client_lost(struct client *c)
c->flags |= CLIENT_DEAD;
recalculate_sizes();
server_check_unattached();
server_update_socket();
}
@@ -316,7 +299,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
server_redraw_window_borders(w);
wp = w->active;
}
window_pane_mouse(wp, c->session, mouse);
window_pane_mouse(wp, c, mouse);
return;
}
@@ -338,7 +321,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
/* Try as a non-prefix key binding. */
if ((bd = key_bindings_lookup(key)) == NULL) {
if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c->session, key);
window_pane_key(wp, c, key);
} else
key_bindings_dispatch(bd, c);
}
@@ -354,7 +337,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c->session, key);
window_pane_key(wp, c, key);
}
return;
}
@@ -365,7 +348,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c->session, key);
window_pane_key(wp, c, key);
return;
}
@@ -395,14 +378,11 @@ server_client_loop(void)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL)
if (c == NULL || c->session == NULL)
continue;
server_client_check_exit(c);
if (c->session != NULL) {
server_client_check_redraw(c);
server_client_reset_state(c);
}
server_client_check_redraw(c);
server_client_reset_state(c);
}
/*
@@ -465,72 +445,6 @@ server_client_repeat_timer(unused int fd, unused short events, void *data)
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
}
/* Check if client should be exited. */
void
server_client_check_exit(struct client *c)
{
struct msg_exit_data exitdata;
if (!(c->flags & CLIENT_EXIT))
return;
if (c->stdout_fd != -1 && c->stdout_event != NULL &&
EVBUFFER_LENGTH(c->stdout_event->output) != 0)
return;
if (c->stderr_fd != -1 && c->stderr_event != NULL &&
EVBUFFER_LENGTH(c->stderr_event->output) != 0)
return;
exitdata.retcode = c->retcode;
server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
c->flags &= ~CLIENT_EXIT;
}
/*
* Check if the client should backoff. During backoff, data from external
* programs is not written to the terminal. When the existing data drains, the
* client is redrawn.
*
* There are two backoff phases - both the tty and client have backoff flags -
* the first to allow existing data to drain and the latter to ensure backoff
* is disabled until the redraw has finished and prevent the redraw triggering
* another backoff.
*/
void
server_client_check_backoff(struct client *c)
{
struct tty *tty = &c->tty;
size_t used;
used = EVBUFFER_LENGTH(tty->event->output);
/*
* If in the second backoff phase (redrawing), don't check backoff
* until the redraw has completed (or enough of it to drop below the
* backoff threshold).
*/
if (c->flags & CLIENT_BACKOFF) {
if (used > BACKOFF_THRESHOLD)
return;
c->flags &= ~CLIENT_BACKOFF;
return;
}
/* Once drained, allow data through again and schedule redraw. */
if (tty->flags & TTY_BACKOFF) {
if (used != 0)
return;
tty->flags &= ~TTY_BACKOFF;
c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS);
return;
}
/* If too much data, start backoff. */
if (used > BACKOFF_THRESHOLD)
tty->flags |= TTY_BACKOFF;
}
/* Check for client redraws. */
void
server_client_check_redraw(struct client *c)
@@ -559,10 +473,6 @@ server_client_check_redraw(struct client *c)
if (c->flags & CLIENT_REDRAW) {
screen_redraw_screen(c, 0, 0);
c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
} else if (c->flags & CLIENT_REDRAWWINDOW) {
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
screen_redraw_pane(c, wp);
c->flags &= ~CLIENT_REDRAWWINDOW;
} else {
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
if (wp->flags & PANE_REDRAW)
@@ -601,52 +511,6 @@ server_client_set_title(struct client *c)
xfree(title);
}
/*
* Error callback for client stdin. Caller must increase reference count when
* enabling event!
*/
void
server_client_in_callback(
unused struct bufferevent *bufev, unused short what, void *data)
{
struct client *c = data;
c->references--;
if (c->flags & CLIENT_DEAD)
return;
bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE);
close(c->stdin_fd);
c->stdin_fd = -1;
if (c->stdin_callback != NULL)
c->stdin_callback(c, c->stdin_data);
}
/* Error callback for client stdout. */
void
server_client_out_callback(
unused struct bufferevent *bufev, unused short what, unused void *data)
{
struct client *c = data;
bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE);
close(c->stdout_fd);
c->stdout_fd = -1;
}
/* Error callback for client stderr. */
void
server_client_err_callback(
unused struct bufferevent *bufev, unused short what, unused void *data)
{
struct client *c = data;
bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE);
close(c->stderr_fd);
c->stderr_fd = -1;
}
/* Dispatch message from client. */
int
server_client_msg_dispatch(struct client *c)
@@ -656,7 +520,6 @@ server_client_msg_dispatch(struct client *c)
struct msg_identify_data identifydata;
struct msg_environ_data environdata;
ssize_t n, datalen;
int mode;
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
return (-1);
@@ -691,55 +554,15 @@ server_client_msg_dispatch(struct client *c)
fatalx("MSG_IDENTIFY missing fd");
memcpy(&identifydata, imsg.data, sizeof identifydata);
c->stdin_fd = imsg.fd;
c->stdin_event = bufferevent_new(c->stdin_fd,
NULL, NULL, server_client_in_callback, c);
if (c->stdin_event == NULL)
fatalx("failed to create stdin event");
if ((mode = fcntl(c->stdin_fd, F_GETFL)) != -1)
fcntl(c->stdin_fd, F_SETFL, mode|O_NONBLOCK);
server_client_msg_identify(c, &identifydata, imsg.fd);
break;
case MSG_STDOUT:
if (datalen != 0)
fatalx("bad MSG_STDOUT size");
if (imsg.fd == -1)
fatalx("MSG_STDOUT missing fd");
c->stdout_fd = imsg.fd;
c->stdout_event = bufferevent_new(c->stdout_fd,
NULL, NULL, server_client_out_callback, c);
if (c->stdout_event == NULL)
fatalx("failed to create stdout event");
if ((mode = fcntl(c->stdout_fd, F_GETFL)) != -1)
fcntl(c->stdout_fd, F_SETFL, mode|O_NONBLOCK);
break;
case MSG_STDERR:
if (datalen != 0)
fatalx("bad MSG_STDERR size");
if (imsg.fd == -1)
fatalx("MSG_STDERR missing fd");
c->stderr_fd = imsg.fd;
c->stderr_event = bufferevent_new(c->stderr_fd,
NULL, NULL, server_client_err_callback, c);
if (c->stderr_event == NULL)
fatalx("failed to create stderr event");
if ((mode = fcntl(c->stderr_fd, F_GETFL)) != -1)
fcntl(c->stderr_fd, F_SETFL, mode|O_NONBLOCK);
break;
case MSG_RESIZE:
if (datalen != 0)
fatalx("bad MSG_RESIZE size");
if (tty_resize(&c->tty)) {
recalculate_sizes();
server_redraw_client(c);
}
tty_resize(&c->tty);
recalculate_sizes();
server_redraw_client(c);
break;
case MSG_EXITING:
if (datalen != 0)
@@ -797,43 +620,45 @@ server_client_msg_dispatch(struct client *c)
void printflike2
server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
{
va_list ap;
struct msg_print_data data;
va_list ap;
va_start(ap, fmt);
evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1);
ctx->cmdclient->retcode = 1;
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, ...)
{
va_list ap;
struct msg_print_data data;
va_list ap;
va_start(ap, fmt);
evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
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, ...)
{
va_list ap;
struct msg_print_data data;
va_list ap;
if (options_get_number(&global_options, "quiet"))
return;
va_start(ap, fmt);
evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
}
/* Handle command message. */
@@ -875,14 +700,14 @@ server_client_msg_command(struct client *c, struct msg_command_data *data)
cmd_free_argv(argc, argv);
if (cmd_list_exec(cmdlist, &ctx) != 1)
c->flags |= CLIENT_EXIT;
server_write_client(c, MSG_EXIT, NULL, 0);
cmd_list_free(cmdlist);
return;
error:
if (cmdlist != NULL)
cmd_list_free(cmdlist);
c->flags |= CLIENT_EXIT;
server_write_client(c, MSG_EXIT, NULL, 0);
}
/* Handle identify message. */
@@ -890,19 +715,13 @@ void
server_client_msg_identify(
struct client *c, struct msg_identify_data *data, int fd)
{
int tty_fd;
c->cwd = NULL;
data->cwd[(sizeof data->cwd) - 1] = '\0';
if (*data->cwd != '\0')
c->cwd = xstrdup(data->cwd);
if (!isatty(fd))
return;
if ((tty_fd = dup(fd)) == -1)
fatal("dup failed");
data->term[(sizeof data->term) - 1] = '\0';
tty_init(&c->tty, tty_fd, data->term);
tty_init(&c->tty, fd, data->term);
if (data->flags & IDENTIFY_UTF8)
c->tty.flags |= TTY_UTF8;
if (data->flags & IDENTIFY_256COLOURS)

View File

@@ -1,4 +1,4 @@
/* $Id: server-fn.c,v 1.117 2010-12-25 23:44:37 tcunha Exp $ */
/* $Id: server-fn.c,v 1.102 2010-01-25 17:13:43 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,22 +24,33 @@
#include "tmux.h"
struct session *server_next_session(struct session *);
void server_callback_identify(int, short, void *);
void server_callback_identify(int, short, void *);
void
server_fill_environ(struct session *s, struct environ *env)
{
char tmuxvar[MAXPATHLEN], *term;
char tmuxvar[MAXPATHLEN], *term;
u_int idx;
if (session_index(s, &idx) != 0)
fatalx("session not found");
xsnprintf(tmuxvar, sizeof tmuxvar,
"%s,%ld,%u", socket_path, (long) getpid(), s->idx);
"%s,%ld,%u", socket_path, (long) getpid(), idx);
environ_set(env, "TMUX", tmuxvar);
term = options_get_string(&s->options, "default-terminal");
environ_set(env, "TERM", term);
}
void
server_write_error(struct client *c, const char *msg)
{
struct msg_print_data printdata;
strlcpy(printdata.msg, msg, sizeof printdata.msg);
server_write_client(c, MSG_ERROR, &printdata, sizeof printdata);
}
void
server_write_client(
struct client *c, enum msgtype type, const void *buf, size_t len)
@@ -172,6 +183,7 @@ void
server_status_window(struct window *w)
{
struct session *s;
u_int i;
/*
* This is slightly different. We want to redraw the status line of any
@@ -179,8 +191,9 @@ server_status_window(struct window *w)
* current window.
*/
RB_FOREACH(s, sessions, &sessions) {
if (session_has(s, w) != NULL)
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s != NULL && session_has(s, w))
server_status_session(s);
}
}
@@ -239,15 +252,13 @@ server_lock_client(struct client *c)
void
server_kill_window(struct window *w)
{
struct session *s, *next_s;
struct session *s;
struct winlink *wl;
u_int i;
next_s = RB_MIN(sessions, &sessions);
while (next_s != NULL) {
s = next_s;
next_s = RB_NEXT(sessions, &sessions, s);
if (session_has(s, w) == NULL)
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL || !session_has(s, w))
continue;
while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
if (session_detach(s, wl)) {
@@ -277,16 +288,14 @@ server_link_window(struct session *src, struct winlink *srcwl,
if (dstidx != -1)
dstwl = winlink_find_by_index(&dst->windows, dstidx);
if (dstwl != NULL) {
if (dstwl->window == srcwl->window) {
xasprintf(cause, "same index: %d", dstidx);
return (-1);
}
if (dstwl->window == srcwl->window)
return (0);
if (killflag) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
dstwl->flags &= ~WINLINK_ALERTFLAGS;
session_alert_cancel(dst, dstwl);
winlink_stack_remove(&dst->lastw, dstwl);
winlink_remove(&dst->windows, dstwl);
@@ -325,11 +334,9 @@ server_destroy_pane(struct window_pane *wp)
{
struct window *w = wp->window;
if (wp->fd != -1) {
close(wp->fd);
bufferevent_free(wp->event);
wp->fd = -1;
}
close(wp->fd);
bufferevent_free(wp->event);
wp->fd = -1;
if (options_get_number(&w->options, "remain-on-exit"))
return;
@@ -358,64 +365,18 @@ server_destroy_session_group(struct session *s)
}
}
struct session *
server_next_session(struct session *s)
{
struct session *s_loop, *s_out;
s_out = NULL;
RB_FOREACH(s_loop, sessions, &sessions) {
if (s_loop == s)
continue;
if (s_out == NULL ||
timercmp(&s_loop->activity_time, &s_out->activity_time, <))
s_out = s_loop;
}
return (s_out);
}
void
server_destroy_session(struct session *s)
{
struct client *c;
struct session *s_new;
u_int i;
if (!options_get_number(&s->options, "detach-on-destroy"))
s_new = server_next_session(s);
else
s_new = NULL;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
if (s_new == NULL) {
c->session = NULL;
c->flags |= CLIENT_EXIT;
} else {
c->last_session = NULL;
c->session = s_new;
server_redraw_client(c);
}
}
recalculate_sizes();
}
void
server_check_unattached (void)
{
struct session *s;
/*
* If any sessions are no longer attached and have destroy-unattached
* set, collect them.
*/
RB_FOREACH(s, sessions, &sessions) {
if (!(s->flags & SESSION_UNATTACHED))
continue;
if (options_get_number (&s->options, "destroy-unattached"))
session_destroy(s);
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
}
}

View File

@@ -1,4 +1,4 @@
/* $Id: server-window.c,v 1.19 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: server-window.c,v 1.14 2010-02-26 13:26:44 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,56 +24,90 @@
#include "tmux.h"
int server_window_backoff(struct window_pane *);
int server_window_check_bell(struct session *, struct winlink *);
int server_window_check_activity(struct session *, struct winlink *);
int server_window_check_silence(struct session *, struct winlink *);
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 winlink *, struct window_pane *);
struct session *, struct window *, struct window_pane *);
/* 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 (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD)
return (1);
}
return (0);
}
/* Window functions that need to happen every loop. */
void
server_window_loop(void)
{
struct window *w;
struct winlink *wl;
struct window_pane *wp;
struct session *s;
u_int i;
u_int i, j;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
w = ARRAY_ITEM(&windows, i);
if (w == NULL)
continue;
RB_FOREACH(s, sessions, &sessions) {
wl = session_has(s, w);
if (wl == NULL)
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
if (!(wp->flags & PANE_FREEZE)) {
if (server_window_backoff(wp))
bufferevent_disable(wp->event, EV_READ);
else
bufferevent_enable(wp->event, EV_READ);
}
}
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, wl) ||
server_window_check_activity(s, wl) ||
server_window_check_silence(s, wl))
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, wl, wp);
server_window_check_content(s, w, wp);
}
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY);
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
}
}
/* Check for bell in window. */
int
server_window_check_bell(struct session *s, struct winlink *wl)
server_window_check_bell(struct session *s, struct window *w)
{
struct client *c;
struct window *w = wl->window;
u_int i;
int action, visual;
if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
if (!(w->flags & WINDOW_BELL))
return (0);
if (s->curw != wl)
wl->flags |= WINLINK_BELL;
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) {
@@ -121,22 +155,25 @@ server_window_check_bell(struct session *s, struct winlink *wl)
/* Check for activity in window. */
int
server_window_check_activity(struct session *s, struct winlink *wl)
server_window_check_activity(struct session *s, struct window *w)
{
struct client *c;
struct window *w = wl->window;
u_int i;
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
if (!(w->flags & WINDOW_ACTIVITY))
return (0);
if (s->curw == wl)
if (s->curw->window == w)
return (0);
if (!options_get_number(&w->options, "monitor-activity"))
return (0);
wl->flags |= WINLINK_ACTIVITY;
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);
@@ -150,80 +187,34 @@ server_window_check_activity(struct session *s, struct winlink *wl)
return (1);
}
/* Check for silence in window. */
int
server_window_check_silence(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
struct timeval timer;
u_int i;
int silence_interval, timer_difference;
if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
return (0);
if (s->curw == wl) {
/*
* Reset the timer for this window if we've focused it. We
* don't want the timer tripping as soon as we've switched away
* from this window.
*/
if (gettimeofday(&w->silence_timer, NULL) != 0)
fatal("gettimeofday failed.");
return (0);
}
silence_interval = options_get_number(&w->options, "monitor-silence");
if (silence_interval == 0)
return (0);
if (gettimeofday(&timer, NULL) != 0)
fatal("gettimeofday");
timer_difference = timer.tv_sec - w->silence_timer.tv_sec;
if (timer_difference <= silence_interval)
return (0);
wl->flags |= WINLINK_SILENCE;
if (options_get_number(&s->options, "visual-silence")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
status_message_set(c, "Silence 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 winlink *wl, struct window_pane *wp)
struct session *s, struct window *w, struct window_pane *wp)
{
struct client *c;
struct window *w = wl->window;
u_int i;
char *found, *ptr;
/* Activity flag must be set for new content. */
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT)
if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */
return (0);
if (s->curw == wl)
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);
wl->flags |= WINLINK_CONTENT;
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);

188
server.c
View File

@@ -1,4 +1,4 @@
/* $Id: server.c,v 1.249 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: server.c,v 1.235 2010-02-08 18:29:32 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -48,6 +48,9 @@ struct clients dead_clients;
int server_fd;
int server_shutdown;
struct event server_ev_accept;
struct event server_ev_sigterm;
struct event server_ev_sigusr1;
struct event server_ev_sigchld;
struct event server_ev_second;
int server_create_socket(void);
@@ -85,7 +88,7 @@ server_create_socket(void)
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed");
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
fatal("bind failed");
umask(mask);
@@ -97,6 +100,8 @@ server_create_socket(void)
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");
server_update_socket();
@@ -105,13 +110,16 @@ server_create_socket(void)
/* Fork new server. */
int
server_start(void)
server_start(char *path)
{
struct window_pane *wp;
int pair[2];
int pair[2], retval;
char *cause;
struct timeval tv;
u_int i;
#ifdef HAVE_SETPROCTITLE
char rpathbuf[MAXPATHLEN];
#endif
/* The first client is special and gets a socketpair; create it. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
@@ -135,33 +143,49 @@ server_start(void)
if (daemon(1, 0) != 0)
fatal("daemon failed");
/* event_init() was called in our parent, need to reinit. */
if (event_reinit(ev_base) != 0)
fatal("event_reinit failed");
clear_signals(0);
logfile("server");
log_debug("server started, pid %ld", (long) getpid());
ARRAY_INIT(&windows);
ARRAY_INIT(&clients);
ARRAY_INIT(&dead_clients);
RB_INIT(&sessions);
RB_INIT(&dead_sessions);
ARRAY_INIT(&sessions);
ARRAY_INIT(&dead_sessions);
TAILQ_INIT(&session_groups);
mode_key_init_trees();
key_bindings_init();
utf8_build();
start_time = time(NULL);
log_debug("socket path %s", socket_path);
socket_path = path;
#ifdef HAVE_SETPROCTITLE
setproctitle("server (%s)", socket_path);
if (realpath(socket_path, rpathbuf) == NULL)
strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
log_debug("socket path %s", socket_path);
setproctitle("server (%s)", rpathbuf);
#endif
#ifdef HAVE_BROKEN_KQUEUE
if (setenv("EVENT_NOKQUEUE", "1", 1) != 0)
fatal("setenv failed");
#endif
#ifdef HAVE_BROKEN_POLL
if (setenv("EVENT_NOPOLL", "1", 1) != 0)
fatal("setenv failed");
#endif
event_init();
#ifdef HAVE_BROKEN_KQUEUE
unsetenv("EVENT_NOKQUEUE");
#endif
#ifdef HAVE_BROKEN_POLL
unsetenv("EVENT_NOPOLL");
#endif
server_fd = server_create_socket();
server_client_create(pair[1]);
retval = 0;
if (access(SYSTEM_CFG, R_OK) == 0)
load_cfg(SYSTEM_CFG, NULL, &cfg_causes);
else if (errno != ENOENT) {
@@ -175,13 +199,12 @@ server_start(void)
* If there is a session already, put the current window and pane into
* more mode.
*/
if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
wp = RB_MIN(sessions, &sessions)->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
wp = ARRAY_FIRST(&sessions)->curw->window->active;
window_pane_set_mode(wp, &window_more_mode);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_copy_add(wp, "%s", cause);
window_more_add(wp, "%s", cause);
xfree(cause);
}
ARRAY_FREE(&cfg_causes);
@@ -197,7 +220,7 @@ server_start(void)
evtimer_set(&server_ev_second, server_second_callback, NULL);
evtimer_add(&server_ev_second, &tv);
set_signals(server_signal_callback);
server_signal_set();
server_loop();
exit(0);
}
@@ -217,14 +240,14 @@ server_loop(void)
}
}
/* Check if the server should be shutting down (no more clients or sessions). */
/* Check if the server should be shutting down (no more clients or windows). */
int
server_should_shutdown(void)
{
u_int i;
if (!options_get_number(&global_options, "exit-unattached")) {
if (!RB_EMPTY(&sessions))
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (ARRAY_ITEM(&sessions, i) != NULL)
return (0);
}
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -239,7 +262,7 @@ void
server_send_shutdown(void)
{
struct client *c;
struct session *s, *next_s;
struct session *s;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -253,11 +276,9 @@ server_send_shutdown(void)
}
}
s = RB_MIN(sessions, &sessions);
while (s != NULL) {
next_s = RB_NEXT(sessions, &sessions, s);
session_destroy(s);
s = next_s;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) != NULL)
session_destroy(s);
}
}
@@ -265,19 +286,16 @@ server_send_shutdown(void)
void
server_clean_dead(void)
{
struct session *s, *next_s;
struct session *s;
struct client *c;
u_int i;
s = RB_MIN(sessions, &dead_sessions);
while (s != NULL) {
next_s = RB_NEXT(sessions, &dead_sessions, s);
if (s->references == 0) {
RB_REMOVE(sessions, &dead_sessions, s);
xfree(s->name);
xfree(s);
}
s = next_s;
for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
s = ARRAY_ITEM(&dead_sessions, i);
if (s == NULL || s->references != 0)
continue;
ARRAY_SET(&dead_sessions, i, NULL);
xfree(s);
}
for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
@@ -294,13 +312,14 @@ void
server_update_socket(void)
{
struct session *s;
u_int i;
static int last = -1;
int n, mode;
struct stat sb;
int n;
n = 0;
RB_FOREACH(s, sessions, &sessions) {
if (!(s->flags & SESSION_UNATTACHED)) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
n++;
break;
}
@@ -308,20 +327,10 @@ server_update_socket(void)
if (n != last) {
last = n;
if (stat(socket_path, &sb) != 0)
return;
mode = sb.st_mode;
if (n != 0) {
if (mode & S_IRUSR)
mode |= S_IXUSR;
if (mode & S_IRGRP)
mode |= S_IXGRP;
if (mode & S_IROTH)
mode |= S_IXOTH;
} else
mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
chmod(socket_path, mode);
if (n != 0)
chmod(socket_path, S_IRWXU);
else
chmod(socket_path, S_IRUSR|S_IWUSR);
}
}
@@ -350,6 +359,61 @@ server_accept_callback(int fd, short events, unused void *data)
server_client_create(newfd);
}
/* Set up server signal handling. */
void
server_signal_set(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGHUP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL);
signal_add(&server_ev_sigchld, NULL);
signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL);
signal_add(&server_ev_sigterm, NULL);
signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL);
signal_add(&server_ev_sigusr1, NULL);
}
/* Destroy server signal events. */
void
server_signal_clear(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGHUP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_del(&server_ev_sigchld);
signal_del(&server_ev_sigterm);
signal_del(&server_ev_sigusr1);
}
/* Signal handler. */
/* ARGSUSED */
void
@@ -487,11 +551,15 @@ void
server_lock_server(void)
{
struct session *s;
u_int i;
int timeout;
time_t t;
t = time(NULL);
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (s->flags & SESSION_UNATTACHED) {
if (gettimeofday(&s->activity_time, NULL) != 0)
fatal("gettimeofday failed");
@@ -512,11 +580,15 @@ void
server_lock_sessions(void)
{
struct session *s;
u_int i;
int timeout;
time_t t;
t = time(NULL);
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (s->flags & SESSION_UNATTACHED) {
if (gettimeofday(&s->activity_time, NULL) != 0)
fatal("gettimeofday failed");

238
session.c
View File

@@ -1,4 +1,4 @@
/* $Id: session.c,v 1.83 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: session.c,v 1.74 2009-12-26 23:45:21 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,56 +29,87 @@
/* Global session list. */
struct sessions sessions;
struct sessions dead_sessions;
u_int next_session;
struct session_groups session_groups;
struct winlink *session_next_alert(struct winlink *);
struct winlink *session_previous_alert(struct winlink *);
struct winlink *session_next_activity(struct session *, struct winlink *);
struct winlink *session_previous_activity(struct session *, struct winlink *);
RB_GENERATE(sessions, session, entry, session_cmp);
int
session_cmp(struct session *s1, struct session *s2)
void
session_alert_cancel(struct session *s, struct winlink *wl)
{
return (strcmp(s1->name, s2->name));
struct session_alert *sa, *sb;
sa = SLIST_FIRST(&s->alerts);
while (sa != NULL) {
sb = sa;
sa = SLIST_NEXT(sa, entry);
if (wl == NULL || sb->wl == wl) {
SLIST_REMOVE(&s->alerts, sb, session_alert, entry);
xfree(sb);
}
}
}
/*
* Find if session is still alive. This is true if it is still on the global
* sessions list.
*/
int
session_alive(struct session *s)
void
session_alert_add(struct session *s, struct window *w, int type)
{
struct session *s_loop;
struct session_alert *sa;
struct winlink *wl;
RB_FOREACH(s_loop, sessions, &sessions) {
if (s_loop == s)
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl == s->curw)
continue;
if (wl->window == w &&
!session_alert_has(s, wl, type)) {
sa = xmalloc(sizeof *sa);
sa->wl = wl;
sa->type = type;
SLIST_INSERT_HEAD(&s->alerts, sa, entry);
}
}
}
int
session_alert_has(struct session *s, struct winlink *wl, int type)
{
struct session_alert *sa;
SLIST_FOREACH(sa, &s->alerts, entry) {
if (sa->wl == wl && sa->type == type)
return (1);
}
return (0);
}
int
session_alert_has_window(struct session *s, struct window *w, int type)
{
struct session_alert *sa;
SLIST_FOREACH(sa, &s->alerts, entry) {
if (sa->wl->window == w && sa->type == type)
return (1);
}
return (0);
}
/* Find session by name. */
struct session *
session_find(const char *name)
{
struct session s;
s.name = (char *) name;
return (RB_FIND(sessions, &sessions, &s));
}
/* Find session by index. */
struct session *
session_find_by_index(u_int idx)
{
struct session *s;
u_int i;
RB_FOREACH(s, sessions, &sessions) {
if (s->idx == idx)
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s != NULL && strcmp(s->name, name) == 0)
return (s);
}
return (NULL);
}
@@ -89,6 +120,7 @@ session_create(const char *name, const char *cmd, const char *cwd,
char **cause)
{
struct session *s;
u_int i;
s = xmalloc(sizeof *s);
s->references = 0;
@@ -98,11 +130,10 @@ session_create(const char *name, const char *cmd, const char *cwd,
fatal("gettimeofday failed");
memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time);
s->cwd = xstrdup(cwd);
s->curw = NULL;
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
SLIST_INIT(&s->alerts);
paste_init_stack(&s->buffers);
@@ -120,12 +151,19 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->sx = sx;
s->sy = sy;
s->idx = next_session++;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (ARRAY_ITEM(&sessions, i) == NULL) {
ARRAY_SET(&sessions, i, s);
break;
}
}
if (i == ARRAY_LENGTH(&sessions))
ARRAY_ADD(&sessions, s);
if (name != NULL)
s->name = xstrdup(name);
else
xasprintf(&s->name, "%u", s->idx);
RB_INSERT(sessions, &sessions, s);
xasprintf(&s->name, "%u", i);
if (cmd != NULL) {
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
@@ -144,14 +182,21 @@ session_create(const char *name, const char *cmd, const char *cwd,
void
session_destroy(struct session *s)
{
u_int i;
log_debug("session %s destroyed", s->name);
RB_REMOVE(sessions, &sessions, s);
if (session_index(s, &i) != 0)
fatalx("session not found");
ARRAY_SET(&sessions, i, NULL);
while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL)
ARRAY_TRUNC(&sessions, 1);
if (s->tio != NULL)
xfree(s->tio);
session_group_remove(s);
session_alert_cancel(s, NULL);
environ_free(&s->environ);
options_free(&s->options);
paste_free_stack(&s->buffers);
@@ -161,49 +206,28 @@ session_destroy(struct session *s)
while (!RB_EMPTY(&s->windows))
winlink_remove(&s->windows, RB_ROOT(&s->windows));
xfree(s->cwd);
xfree(s->name);
RB_INSERT(sessions, &dead_sessions, s);
for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
if (ARRAY_ITEM(&dead_sessions, i) == NULL) {
ARRAY_SET(&dead_sessions, i, s);
break;
}
}
if (i == ARRAY_LENGTH(&dead_sessions))
ARRAY_ADD(&dead_sessions, s);
s->flags |= SESSION_DEAD;
}
/* Find the next usable session. */
struct session *
session_next_session(struct session *s)
/* Find session index. */
int
session_index(struct session *s, u_int *i)
{
struct session *s2;
if (RB_EMPTY(&sessions) || !session_alive(s))
return (NULL);
s2 = s;
do {
s2 = RB_NEXT(sessions, &sessions, s2);
if (s2 == NULL)
s2 = RB_MIN(sessions, &sessions);
} while (s2 != s);
if (s2 == s)
return (NULL);
return (s2);
}
/* Find the previous usable session. */
struct session *
session_previous_session(struct session *s)
{
struct session *s2;
if (RB_EMPTY(&sessions) || !session_alive(s))
return (NULL);
s2 = s;
do {
s2 = RB_PREV(sessions, &sessions, s2);
if (s2 == NULL)
s2 = RB_MAX(sessions, &sessions);
} while (s2 != s);
if (s2 == s)
return (NULL);
return (s2);
for (*i = 0; *i < ARRAY_LENGTH(&sessions); (*i)++) {
if (s == ARRAY_ITEM(&sessions, *i))
return (0);
}
return (-1);
}
/* Create a new window on a session. */
@@ -260,7 +284,7 @@ session_detach(struct session *s, struct winlink *wl)
session_last(s) != 0 && session_previous(s, 0) != 0)
session_next(s, 0);
wl->flags &= ~WINLINK_ALERTFLAGS;
session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
session_group_synchronize_from(s);
@@ -272,23 +296,27 @@ session_detach(struct session *s, struct winlink *wl)
}
/* Return if session has window. */
struct winlink *
int
session_has(struct session *s, struct window *w)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window == w)
return (wl);
return (1);
}
return (NULL);
return (0);
}
struct winlink *
session_next_alert(struct winlink *wl)
session_next_activity(struct session *s, struct winlink *wl)
{
while (wl != NULL) {
if (wl->flags & WINLINK_ALERTFLAGS)
if (session_alert_has(s, wl, WINDOW_BELL))
break;
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
break;
if (session_alert_has(s, wl, WINDOW_CONTENT))
break;
wl = winlink_next(wl);
}
@@ -297,7 +325,7 @@ session_next_alert(struct winlink *wl)
/* Move session to next window. */
int
session_next(struct session *s, int alert)
session_next(struct session *s, int activity)
{
struct winlink *wl;
@@ -305,11 +333,11 @@ session_next(struct session *s, int alert)
return (-1);
wl = winlink_next(s->curw);
if (alert)
wl = session_next_alert(wl);
if (activity)
wl = session_next_activity(s, wl);
if (wl == NULL) {
wl = RB_MIN(winlinks, &s->windows);
if (alert && ((wl = session_next_alert(wl)) == NULL))
if (activity && ((wl = session_next_activity(s, wl)) == NULL))
return (-1);
}
if (wl == s->curw)
@@ -317,15 +345,19 @@ session_next(struct session *s, int alert)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
wl->flags &= ~WINLINK_ALERTFLAGS;
session_alert_cancel(s, wl);
return (0);
}
struct winlink *
session_previous_alert(struct winlink *wl)
session_previous_activity(struct session *s, struct winlink *wl)
{
while (wl != NULL) {
if (wl->flags & WINLINK_ALERTFLAGS)
if (session_alert_has(s, wl, WINDOW_BELL))
break;
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
break;
if (session_alert_has(s, wl, WINDOW_CONTENT))
break;
wl = winlink_previous(wl);
}
@@ -334,7 +366,7 @@ session_previous_alert(struct winlink *wl)
/* Move session to previous window. */
int
session_previous(struct session *s, int alert)
session_previous(struct session *s, int activity)
{
struct winlink *wl;
@@ -342,11 +374,11 @@ session_previous(struct session *s, int alert)
return (-1);
wl = winlink_previous(s->curw);
if (alert)
wl = session_previous_alert(wl);
if (activity)
wl = session_previous_activity(s, wl);
if (wl == NULL) {
wl = RB_MAX(winlinks, &s->windows);
if (alert && (wl = session_previous_alert(wl)) == NULL)
if (activity && (wl = session_previous_activity(s, wl)) == NULL)
return (-1);
}
if (wl == s->curw)
@@ -354,7 +386,7 @@ session_previous(struct session *s, int alert)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
wl->flags &= ~WINLINK_ALERTFLAGS;
session_alert_cancel(s, wl);
return (0);
}
@@ -372,7 +404,7 @@ session_select(struct session *s, int idx)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
wl->flags &= ~WINLINK_ALERTFLAGS;
session_alert_cancel(s, wl);
return (0);
}
@@ -391,7 +423,7 @@ session_last(struct session *s)
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
wl->flags &= ~WINLINK_ALERTFLAGS;
session_alert_cancel(s, wl);
return (0);
}
@@ -508,6 +540,7 @@ 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;
@@ -525,10 +558,8 @@ session_group_synchronize1(struct session *target, struct session *s)
RB_INIT(&s->windows);
/* Link all the windows from the target. */
RB_FOREACH(wl, winlinks, ww) {
wl2 = winlink_add(&s->windows, wl->window, wl->idx);
wl2->flags |= wl->flags & WINLINK_ALERTFLAGS;
}
RB_FOREACH(wl, winlinks, ww)
winlink_add(&s->windows, wl->window, wl->idx);
/* Fix up the current window. */
if (s->curw != NULL)
@@ -545,6 +576,15 @@ session_group_synchronize1(struct session *target, struct session *s)
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);

103
signal.c
View File

@@ -1,103 +0,0 @@
/* $Id: signal.c,v 1.3 2010-08-29 14:42:11 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
* Copyright (c) 2010 Romain Francoise <rfrancoise@debian.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 <string.h>
#include <signal.h>
#include "tmux.h"
struct event ev_sighup;
struct event ev_sigchld;
struct event ev_sigcont;
struct event ev_sigterm;
struct event ev_sigusr1;
struct event ev_sigwinch;
void
set_signals(void(*handler)(int, short, unused void *))
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_set(&ev_sighup, SIGHUP, handler, NULL);
signal_add(&ev_sighup, NULL);
signal_set(&ev_sigchld, SIGCHLD, handler, NULL);
signal_add(&ev_sigchld, NULL);
signal_set(&ev_sigcont, SIGCONT, handler, NULL);
signal_add(&ev_sigcont, NULL);
signal_set(&ev_sigterm, SIGTERM, handler, NULL);
signal_add(&ev_sigterm, NULL);
signal_set(&ev_sigusr1, SIGUSR1, handler, NULL);
signal_add(&ev_sigusr1, NULL);
signal_set(&ev_sigwinch, SIGWINCH, handler, NULL);
signal_add(&ev_sigwinch, NULL);
}
void
clear_signals(int after_fork)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
if (after_fork) {
if (sigaction(SIGHUP, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGCHLD, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGCONT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTERM, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGWINCH, &sigact, NULL) != 0)
fatal("sigaction failed");
} else {
event_del(&ev_sighup);
event_del(&ev_sigchld);
event_del(&ev_sigcont);
event_del(&ev_sigterm);
event_del(&ev_sigusr1);
event_del(&ev_sigwinch);
}
}

157
status.c
View File

@@ -1,4 +1,4 @@
/* $Id: status.c,v 1.151 2010-12-11 16:15:02 nicm Exp $ */
/* $Id: status.c,v 1.144 2010-03-10 13:41:13 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -35,20 +35,16 @@ char *status_redraw_get_right(
struct client *, time_t, int, struct grid_cell *, size_t *);
char *status_job(struct client *, char **);
void status_job_callback(struct job *);
size_t status_width(struct client *, struct winlink *, time_t);
char *status_print(
struct client *, struct winlink *, time_t, struct grid_cell *);
void status_replace1(struct client *,
struct winlink *, char **, char **, char *, size_t, int);
void status_message_callback(int, short, void *);
const char *status_prompt_up_history(u_int *);
const char *status_prompt_down_history(u_int *);
void status_prompt_add_history(const char *);
void status_prompt_add_history(struct client *);
char *status_prompt_complete(const char *);
/* Status prompt history. */
ARRAY_DECL(, char *) status_prompt_history = ARRAY_INITIALIZER;
/* Retrieve options for left string. */
char *
status_redraw_get_left(struct client *c,
@@ -253,15 +249,25 @@ status_redraw(struct client *c)
*/
offset = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->flags & WINLINK_ALERTFLAGS &&
larrow == 1 && offset < wlstart)
larrow = -1;
if (larrow == 1 && offset < wlstart) {
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
larrow = -1;
else if (session_alert_has(s, wl, WINDOW_BELL))
larrow = -1;
else if (session_alert_has(s, wl, WINDOW_CONTENT))
larrow = -1;
}
offset += wl->status_width;
if (wl->flags & WINLINK_ALERTFLAGS &&
rarrow == 1 && offset > wlstart + wlwidth)
rarrow = -1;
if (rarrow == 1 && offset > wlstart + wlwidth) {
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
rarrow = -1;
else if (session_alert_has(s, wl, WINDOW_BELL))
rarrow = -1;
else if (session_alert_has(s, wl, WINDOW_CONTENT))
rarrow = -1;
}
}
draw:
@@ -394,14 +400,12 @@ status_replace1(struct client *c,struct winlink *wl,
goto do_replace;
case 'F':
tmp[0] = ' ';
if (wl->flags & WINLINK_CONTENT)
if (session_alert_has(s, wl, WINDOW_CONTENT))
tmp[0] = '+';
else if (wl->flags & WINLINK_BELL)
else if (session_alert_has(s, wl, WINDOW_BELL))
tmp[0] = '!';
else if (wl->flags & WINLINK_ACTIVITY)
else if (session_alert_has(s, wl, WINDOW_ACTIVITY))
tmp[0] = '#';
else if (wl->flags & WINLINK_SILENCE)
tmp[0] = '~';
else if (wl == s->curw)
tmp[0] = '*';
else if (wl == TAILQ_FIRST(&s->lastw))
@@ -556,6 +560,30 @@ status_job_callback(struct job *job)
job->data = xstrdup(line);
}
/* Calculate winlink status line entry width. */
size_t
status_width(struct client *c, struct winlink *wl, time_t t)
{
struct options *oo = &wl->window->options;
struct session *s = c->session;
const char *fmt;
char *text;
size_t size;
int utf8flag;
utf8flag = options_get_number(&s->options, "status-utf8");
fmt = options_get_string(&wl->window->options, "window-status-format");
if (wl == s->curw)
fmt = options_get_string(oo, "window-status-current-format");
text = status_replace(c, wl, fmt, t, 1);
size = screen_write_cstrlen(utf8flag, "%s", text);
xfree(text);
return (size);
}
/* Return winlink status line entry and adjust gc as necessary. */
char *
status_print(
@@ -590,17 +618,10 @@ status_print(
fmt = options_get_string(oo, "window-status-current-format");
}
if (wl->flags & WINLINK_ALERTFLAGS) {
fg = options_get_number(oo, "window-status-alert-fg");
if (fg != 8)
colour_set_fg(gc, fg);
bg = options_get_number(oo, "window-status-alert-bg");
if (bg != 8)
colour_set_bg(gc, bg);
attr = options_get_number(oo, "window-status-alert-attr");
if (attr != 0)
gc->attr = attr;
}
if (session_alert_has(s, wl, WINDOW_ACTIVITY) ||
session_alert_has(s, wl, WINDOW_BELL) ||
session_alert_has(s, wl, WINDOW_CONTENT))
gc->attr ^= GRID_ATTR_REVERSE;
text = status_replace(c, wl, fmt, t, 1);
return (text);
@@ -865,7 +886,6 @@ status_prompt_key(struct client *c, int key)
{
struct paste_buffer *pb;
char *s, *first, *last, word[64], swapc;
const char *histstr;
u_char ch;
size_t size, n, off, idx;
@@ -978,20 +998,29 @@ status_prompt_key(struct client *c, int key)
}
break;
case MODEKEYEDIT_HISTORYUP:
histstr = status_prompt_up_history(&c->prompt_hindex);
if (histstr == NULL)
if (ARRAY_LENGTH(&c->prompt_hdata) == 0)
break;
xfree(c->prompt_buffer);
c->prompt_buffer = xstrdup(histstr);
c->prompt_buffer = xstrdup(ARRAY_ITEM(&c->prompt_hdata,
ARRAY_LENGTH(&c->prompt_hdata) - 1 - c->prompt_hindex));
if (c->prompt_hindex != ARRAY_LENGTH(&c->prompt_hdata) - 1)
c->prompt_hindex++;
c->prompt_index = strlen(c->prompt_buffer);
c->flags |= CLIENT_STATUS;
break;
case MODEKEYEDIT_HISTORYDOWN:
histstr = status_prompt_down_history(&c->prompt_hindex);
if (histstr == NULL)
break;
xfree(c->prompt_buffer);
c->prompt_buffer = xstrdup(histstr);
if (c->prompt_hindex != 0) {
c->prompt_hindex--;
c->prompt_buffer = xstrdup(ARRAY_ITEM(
&c->prompt_hdata, ARRAY_LENGTH(
&c->prompt_hdata) - 1 - c->prompt_hindex));
} else
c->prompt_buffer = xstrdup("");
c->prompt_index = strlen(c->prompt_buffer);
c->flags |= CLIENT_STATUS;
break;
@@ -1033,7 +1062,7 @@ status_prompt_key(struct client *c, int key)
break;
case MODEKEYEDIT_ENTER:
if (*c->prompt_buffer != '\0')
status_prompt_add_history(c->prompt_buffer);
status_prompt_add_history(c);
if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0)
status_prompt_clear(c);
break;
@@ -1042,7 +1071,7 @@ status_prompt_key(struct client *c, int key)
status_prompt_clear(c);
break;
case MODEKEY_OTHER:
if ((key & 0xff00) != 0 || key < 32 || key == 127)
if (key < 32 || key == 127)
break;
c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 2);
@@ -1069,56 +1098,20 @@ status_prompt_key(struct client *c, int key)
}
}
/* Get previous line from the history. */
const char *
status_prompt_up_history(u_int *idx)
{
u_int size;
/*
* History runs from 0 to size - 1.
*
* Index is from 0 to size. Zero is empty.
*/
size = ARRAY_LENGTH(&status_prompt_history);
if (size == 0 || *idx == size)
return (NULL);
(*idx)++;
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
}
/* Get next line from the history. */
const char *
status_prompt_down_history(u_int *idx)
{
u_int size;
size = ARRAY_LENGTH(&status_prompt_history);
if (size == 0 || *idx == 0)
return ("");
(*idx)--;
if (*idx == 0)
return ("");
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
}
/* Add line to the history. */
void
status_prompt_add_history(const char *line)
status_prompt_add_history(struct client *c)
{
u_int size;
size = ARRAY_LENGTH(&status_prompt_history);
if (size > 0 && strcmp(ARRAY_LAST(&status_prompt_history), line) == 0)
if (ARRAY_LENGTH(&c->prompt_hdata) > 0 &&
strcmp(ARRAY_LAST(&c->prompt_hdata), c->prompt_buffer) == 0)
return;
if (size == PROMPT_HISTORY) {
xfree(ARRAY_FIRST(&status_prompt_history));
ARRAY_REMOVE(&status_prompt_history, 0);
if (ARRAY_LENGTH(&c->prompt_hdata) == PROMPT_HISTORY) {
xfree(ARRAY_FIRST(&c->prompt_hdata));
ARRAY_REMOVE(&c->prompt_hdata, 0);
}
ARRAY_ADD(&status_prompt_history, xstrdup(line));
ARRAY_ADD(&c->prompt_hdata, xstrdup(c->prompt_buffer));
}
/* Complete word. */

498
tmux.1
View File

@@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.280 2010-12-27 21:17:25 tcunha Exp $
.\" $Id: tmux.1,v 1.237 2010-03-08 15:02:07 tcunha Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: December 10 2010 $
.Dd $Mdocdate: March 2 2010 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -23,7 +23,7 @@
.Sh SYNOPSIS
.Nm tmux
.Bk -words
.Op Fl 28lquvV
.Op Fl 28lquv
.Op Fl c Ar shell-command
.Op Fl f Ar file
.Op Fl L Ar socket-name
@@ -131,6 +131,10 @@ commands which are executed in sequence when the server is first started.
If a command in the configuration file fails,
.Nm
will report an error and exit without executing further commands.
.It Fl l
Behave as a login shell.
This flag currently has no effect and is for compatibility with other shells
when using tmux as a login shell.
.It Fl L Ar socket-name
.Nm
stores the server socket in a directory under
@@ -151,10 +155,6 @@ If the socket is accidentally removed, the
signal may be sent to the
.Nm
server process to recreate it.
.It Fl l
Behave as a login shell.
This flag currently has no effect and is for compatibility with other shells
when using tmux as a login shell.
.It Fl q
Set the
.Ic quiet
@@ -198,10 +198,6 @@ and
files in the current directory, where
.Em PID
is the PID of the server or client process.
.It Fl V
Report the
.Nm
version.
.It Ar command Op Ar flags
This specifies one of a set of commands used to control
.Nm ,
@@ -217,114 +213,32 @@ prefix key,
.Ql C-b
(Ctrl-b) by default, followed by a command key.
.Pp
The default command key bindings are:
Some of the default key bindings are:
.Pp
.Bl -tag -width "XXXXXXXXXX" -offset indent -compact
.It C-b
Send the prefix key (C-b) through to the application.
.It C-o
Rotate the panes in the current window forwards.
.It C-z
Suspend the
.Nm
client.
.It !
Break the current pane out of the window.
.It \&"
Split the current pane into two, top and bottom.
.It #
List all paste buffers.
.It %
Split the current pane into two, left and right.
.It &
Kill the current window.
.It '
Prompt for a window index to select.
.It ,
Rename the current window.
.It -
Delete the most recently copied buffer of text.
.It .
Prompt for an index to move the current window.
.It 0 to 9
Select windows 0 to 9.
.It :
Enter the
.Nm
command prompt.
.It ;
Move to the previously active pane.
.It =
Choose which buffer to paste interactively from a list.
.It \&?
List all key bindings.
.It D
Choose a client to detach.
.It \&[
Enter copy mode to copy text or view the history.
.It \&]
Paste the most recently copied buffer of text.
.Bl -tag -width Ds -offset indent -compact
.It c
Create a new window.
.It d
Detach the current client.
.It f
Prompt to search for text in open windows.
.It i
Display some information about the current window.
.It l
Move to the previously selected window.
.It n
Change to the next window.
.It o
Select the next pane in the current window.
.It p
Change to the previous window.
.It q
Briefly display pane indexes.
.It r
Force redraw of the attached client.
.It s
Select a new session for the attached client interactively.
.It L
Switch the attached client back to the last session.
.It t
Show the time.
.It w
Choose the current window interactively.
.It x
Kill the current pane.
.It {
Swap the current pane with the previous pane.
.It }
Swap the current pane with the next pane.
.It ~
Show previous messages from
.Nm ,
if any.
.It Page Up
Enter copy mode and scroll one page up.
.It Up, Down
.It Left, Right
Change to the pane above, below, to the left, or to the right of the current
pane.
.It M-1 to M-5
Arrange panes in one of the five preset layouts: even-horizontal,
even-vertical, main-horizontal, main-vertical, or tiled.
.It M-n
Move to the next window with a bell or activity marker.
.It M-o
Rotate the panes in the current window backwards.
.It M-p
Move to the previous window with a bell or activity marker.
.It C-Up, C-Down
.It C-Left, C-Right
Resize the current pane in steps of one cell.
.It M-Up, M-Down
.It M-Left, M-Right
Resize the current pane in steps of five cells.
.It &
Kill the current window.
.It ,
Rename the current window.
.It \&?
List all key bindings.
.El
.Pp
A complete list may be obtained with the
.Ic list-keys
command (bound to
.Ql \&?
by default).
Key bindings may be changed with the
.Ic bind-key
and
@@ -422,11 +336,6 @@ If neither a colon nor period appears,
first attempts to use the argument as a pane index; if that fails, it is looked
up as for
.Ar target-window .
A
.Ql +
or
.Ql -
indicate the next or previous pane index, respectively.
One of the strings
.Em top ,
.Em bottom ,
@@ -438,18 +347,6 @@ One of the strings
.Em bottom-right
may be used instead of a pane index.
.Pp
The special characters
.Ql +
and
.Ql -
may be followed by an offset, for example:
.Bd -literal -offset indent
select-window -t:+2
.Ed
.Pp
When dealing with a session that doesn't contain sequential window indexes,
they will be correctly skipped.
.Pp
.Ar shell-command
arguments are
.Xr sh 1
@@ -471,6 +368,7 @@ bind-key F1 set-window-option force-width 81
.Pp
Or if using
.Xr sh 1 :
.Pp
.Bd -literal -offset indent
$ tmux bind-key F1 set-window-option force-width 81
.Ed
@@ -498,12 +396,13 @@ new-window ; split-window -d
.Pp
Or from
.Xr sh 1 :
.Pp
.Bd -literal -offset indent
$ tmux kill-window -t :1
$ tmux new-window \e; split-window -d
$ tmux new-window \\; split-window -d
$ tmux new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach
$ tmux new-session -d 'vi /etc/passwd' \\; split-window -d \\; attach
.Ed
.Sh CLIENTS AND SESSIONS
The
@@ -515,7 +414,7 @@ when they are created with the
command, or later with the
.Ic attach-session
command.
Each session has one or more windows
Each session has one of more windows
.Em linked
into it.
Windows may be linked to multiple sessions and are made up of one or
@@ -576,15 +475,17 @@ List the syntax of all commands supported by
.It Ic list-sessions
.D1 (alias: Ic ls )
List all sessions managed by the server.
.It Ic lock-client Op Fl t Ar target-client
.D1 (alias: Ic lockc )
.It Xo Ic lock-client
.Op Fl t Ar target-client
.Xc
Lock
.Ar target-client ,
see the
.Ic lock-server
command.
.It Ic lock-session Op Fl t Ar target-session
.D1 (alias: Ic locks )
.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
@@ -668,7 +569,6 @@ Suspend a client by sending
.Dv SIGTSTP
(tty stop).
.It Xo Ic switch-client
.Op Fl lnp
.Op Fl c Ar target-client
.Op Fl t Ar target-session
.Xc
@@ -677,21 +577,20 @@ Switch the current session for client
.Ar target-client
to
.Ar target-session .
If
.Fl l ,
.Fl n
or
.Fl p
is used, the client is moved to the last, next or previous session
respectively.
.El
.Sh WINDOWS AND PANES
A
.Nm
window may be in one of several modes.
The default permits direct access to the terminal attached to the window.
The other is copy mode, which permits a section of a window or its
history to be copied to a
The others are:
.Bl -tag -width Ds
.It Em output mode
This is entered when a command which produces output, such as
.Ic list-keys ,
is executed from a key binding.
.It Em copy mode
This permits a section of a window or its history to be copied to a
.Em paste buffer
for later insertion into another window.
This mode is entered with the
@@ -699,16 +598,14 @@ This mode is entered with the
command, bound to
.Ql \&[
by default.
It is also entered when a command that produces output, such as
.Ic list-keys ,
is executed from a key binding.
.El
.Pp
The keys available depend on whether emacs or vi mode is selected
(see the
.Ic mode-keys
option).
The following keys are supported as appropriate for the mode:
.Bl -column "FunctionXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
.It Li "Back to indentation" Ta "^" Ta "M-m"
.It Li "Bottom of history" Ta "G" Ta "M-<"
@@ -727,10 +624,6 @@ The following keys are supported as appropriate for the mode:
.It Li "Go to line" Ta ":" Ta "g"
.It Li "Half page down" Ta "C-d" Ta "M-Down"
.It Li "Half page up" Ta "C-u" Ta "M-Up"
.It Li "Jump forward" Ta "f" Ta "f"
.It Li "Jump backward" Ta "F" Ta "F"
.It Li "Jump again" Ta ";" Ta ";"
.It Li "Jump again in reverse" Ta "," Ta ","
.It Li "Next page" Ta "C-f" Ta "Page down"
.It Li "Next space" Ta "W" Ta ""
.It Li "Next space, end of word" Ta "E" Ta ""
@@ -768,18 +661,6 @@ next word and previous word to the start of the previous word.
The three next and previous space keys work similarly but use a space alone as
the word separator.
.Pp
The jump commands enable quick movement within a line.
For instance, typing
.Ql f
followed by
.Ql /
will move the cursor to the next
.Ql /
character on the current line.
A
.Ql \&;
will then jump to the next occurrence.
.Pp
Commands in copy mode may be prefaced by an optional repeat count.
With vi key bindings, a prefix is entered using the number keys; with
emacs, the Alt (meta) key and a number begins prefix entry.
@@ -799,7 +680,7 @@ and
.Em emacs-choice
for keys used when choosing from lists (such as produced by the
.Ic choose-window
command); and
command) or in output mode; and
.Em vi-copy
and
.Em emacs-copy
@@ -814,9 +695,7 @@ and
The paste buffer key pastes the first line from the top paste buffer on the
stack.
.Pp
The synopsis for the
.Ic copy-mode
command is:
The mode commands are as follows:
.Bl -tag -width Ds
.It Xo Ic copy-mode
.Op Fl u
@@ -848,8 +727,10 @@ command (bound to
and
.Ql C-right
by default), the current pane may be changed with the
.Ic select-pane
command and the
.Ic up-pane
and
.Ic down-pane
commands and the
.Ic rotate-window
and
.Ic swap-pane
@@ -888,30 +769,8 @@ bottom along the right.
See the
.Em main-pane-width
window option.
.It Ic tiled
Panes are spread out as evenly as possible over the window in both rows and
columns.
.El
.Pp
In addition,
.Ic select-layout
may be used to apply a previously used layout - the
.Ic list-windows
command displays the layout of each window in a form suitable for use with
.Ic select-layout .
For example:
.Bd -literal -offset indent
$ tmux list-windows
0: ksh [159x48]
layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}
$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0}
.Ed
.Pp
.Nm
automatically adjusts the size of the layout for the current window size.
Note that a layout cannot be applied to a window with more panes than that
from which the layout was originally defined.
.Pp
Commands related to windows and panes are as follows:
.Bl -tag -width Ds
.It Xo Ic break-pane
@@ -1000,6 +859,9 @@ While the indicator is on screen, a pane may be selected with the
to
.Ql 9
keys.
.It Ic down-pane Op Fl t Ar target-pane
.D1 (alias: Ic downp )
Change the active pane to the next pane (higher index).
.It Xo Ic find-window
.Op Fl t Ar target-window
.Ar match-string
@@ -1048,9 +910,6 @@ option kills all but the pane given with
Kill the current window or the window at
.Ar target-window ,
removing it from any sessions to which it is linked.
.It Ic last-pane Op Fl t Ar target-window
.D1 (alias: Ic lastp )
Select the last (previously selected) pane.
.It Ic last-window Op Fl t Ar target-session
.D1 (alias: Ic last )
Select the last (previously selected) window.
@@ -1089,7 +948,7 @@ List the panes in the current window or in
List windows in the current session or in
.Ar target-session .
.It Xo Ic move-window
.Op Fl dk
.Op Fl d
.Op Fl s Ar src-window
.Op Fl t Ar dst-window
.Xc
@@ -1101,22 +960,13 @@ except the window at
is moved to
.Ar dst-window .
.It Xo Ic new-window
.Op Fl adk
.Op Fl dk
.Op Fl n Ar window-name
.Op Fl t Ar target-window
.Op Ar shell-command
.Xc
.D1 (alias: Ic neww )
Create a new window.
With
.Fl a ,
the new window is inserted at the next index up from the specified
.Ar target-window ,
moving windows up if necessary,
otherwise
.Ar target-window
is the new window location.
.Pp
If
.Fl d
is given, the session does not make the new window the current window.
@@ -1174,11 +1024,6 @@ A pane may only be piped to one command at a time, any existing pipe is
closed before
.Ar shell-command
is executed.
The
.Ar shell-command
string may contain the special character sequences supported by the
.Ic status-left
command.
If no
.Ar shell-command
is given, the current pipe (if any) is closed.
@@ -1188,13 +1033,8 @@ The
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.#I-#P'
bind-key C-p pipe-pane -o 'cat >>~/output'
.Ed
.It Xo Ic previous-layout
.Op Fl t Ar target-window
.Xc
.D1 (alias: Ic prevl )
Move to the previous layout in the session.
.It Xo Ic previous-window
.Op Fl a
.Op Fl t Ar target-session
@@ -1258,28 +1098,17 @@ or downward (numerically higher).
.Op Fl t Ar target-window
.Op Ar layout-name
.Xc
.D1 (alias: Ic selectl )
.D1 (alias: selectl )
Choose a specific layout for a window.
If
.Ar layout-name
is not given, the last preset layout used (if any) is reapplied.
.It Xo Ic select-pane
.Op Fl DLRU
.Op Fl t Ar target-pane
.Xc
is not given, the last layout used (if any) is reapplied.
.It Ic select-pane Op Fl t Ar target-pane
.D1 (alias: Ic selectp )
Make pane
.Ar target-pane
the active pane in window
.Ar target-window .
If one of
.Fl D ,
.Fl L ,
.Fl R ,
or
.Fl U
is used, respectively the pane below, to the left, to the right, or above the
target pane is used.
.It Ic select-window Op Fl t Ar target-window
.D1 (alias: Ic selectw )
Select the window at
@@ -1292,7 +1121,7 @@ Select the window at
.Op Fl t Ar target-pane
.Op Ar shell-command
.Xc
.D1 (alias: Ic splitw )
.D1 (alias: splitw )
Create a new pane by splitting
.Ar target-pane :
.Fl h
@@ -1355,6 +1184,9 @@ if
.Fl k
is specified and the window is linked to only one session, it is unlinked and
destroyed.
.It Ic up-pane Op Fl t Ar target-pane
.D1 (alias: Ic upp )
Change the active pane to the previous pane (lower index).
.El
.Sh KEY BINDINGS
.Nm
@@ -1401,7 +1233,7 @@ or
keys, quotation marks are necessary, for example:
.Bd -literal -offset indent
bind-key '"' split-window
bind-key "'" new-window
bind-key "'" select-prompt
.Ed
.Pp
Commands related to key bindings are as follows:
@@ -1488,7 +1320,7 @@ All arguments are sent sequentially from first to last.
Send the prefix key to a window as if it was pressed.
If multiple prefix keys are configured, only the first is sent.
.It Xo Ic unbind-key
.Op Fl acn
.Op Fl cn
.Op Fl t Ar key-table
.Ar key
.Xc
@@ -1502,9 +1334,6 @@ the primary key bindings are modified; in this case, if
is specified, the command bound to
.Ar key
without a prefix (if any) is removed.
If
.Fl a
is present, all key bindings are removed.
.Pp
If
.Fl t
@@ -1604,9 +1433,6 @@ Set the time in milliseconds for which
waits after an escape is input to determine if it is part of a function or meta
key sequences.
The default is 500 milliseconds.
.It Ic exit-unattached
If enabled, the server will exit when there are no attached clients, rather
than when there are no attached sessions.
.It Ic quiet
Enable or disable the display of various informational messages (see also the
.Fl q
@@ -1646,11 +1472,6 @@ The default is an empty string, which instructs
to create a login shell using the value of the
.Ic default-shell
option.
.It Ic default-path Ar path
Set the default working directory for processes created from keys, or
interactively from the prompt.
The default is empty, which means to use the working directory of the shell
from which the server was started if it is available or the user's home if not.
.It Ic default-shell Ar path
Specify the default shell.
This is used as the login shell for new windows when the
@@ -1667,6 +1488,10 @@ or
This option should be configured when
.Nm
is used as a login shell.
.It Ic default-path Ar path
Set the default working directory for processes created from keys, or
interactively from the prompt.
The default is the current working directory when the server is started.
.It Ic default-terminal Ar terminal
Set the default terminal for new windows created in this session - the
default value of the
@@ -1679,14 +1504,6 @@ to work correctly, this
be set to
.Ql screen
or a derivative of it.
.It Ic destroy-unattached
If enabled and the session is no longer attached to any clients, it is
destroyed.
.It Ic detach-on-destroy
If on (the default), the client is detached when the session it is attached to
is destroyed.
If off, the client is switched to the most recently active of the remaining
sessions.
.It Ic display-panes-active-colour Ar colour
Set the colour used by the
.Ic display-panes
@@ -1740,7 +1557,7 @@ This has no effect as a session option; it must be set as a global option.
Set status line message attributes, where
.Ar attributes
is either
.Ic none
.Ic default
or a comma-delimited list of one or more of:
.Ic bright
(or
@@ -1783,12 +1600,12 @@ If on,
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 pane-active-border-bg Ar colour
.It Ic pane-active-border-fg Ar colour
Set the pane border colour for the currently active pane.
.It Ic pane-border-bg Ar colour
.It Ic pane-border-fg Ar colour
.It Ic pane-border-bg Ar colour
Set the pane border colour for panes aside from the active pane.
.It Ic pane-active-border-fg Ar colour
.It Ic pane-active-border-bg Ar colour
Set the pane border colour for the currently active pane.
.It Ic prefix Ar keys
Set the keys accepted as a prefix key.
.Ar keys
@@ -1861,12 +1678,7 @@ or right justified.
.Xc
Use vi or emacs-style
key bindings in the status line, for example at the command prompt.
The default is emacs, unless the
.Ev VISUAL
or
.Ev EDITOR
environment variables are set and contain the string
.Ql vi .
Defaults to emacs.
.It Ic status-left Ar string
Display
.Ar string
@@ -1900,19 +1712,6 @@ the
.Ic status-interval
option: if the status line is redrawn in the meantime, the previous result is
used.
Shell commands are executed with the
.Nm
global environment set (see the
.Sx ENVIRONMENT
section).
.Pp
The window title (#T) is the title set by the program running within the window
using the OSC title setting sequence, for example:
.Bd -literal -offset indent
$ printf '\e033]2;My Title\e033\e\e'
.Ed
.Pp
When a window is first created, its title is the hostname.
.Pp
#[attributes] allows a comma-separated list of attributes to be specified,
these may be
@@ -1943,10 +1742,10 @@ is not interpreted, to enable UTF-8, use the
option.
.It Ic status-left-attr Ar attributes
Set the attribute of the left part of the status line.
.It Ic status-left-bg Ar colour
Set the background colour of the left part of the status line.
.It Ic status-left-fg Ar colour
Set the foreground colour of the left part of the status line.
.It Ic status-left-bg Ar colour
Set the background colour of the left part of the status line.
.It Ic status-left-length Ar length
Set the maximum
.Ar length
@@ -1968,15 +1767,16 @@ character pairs are replaced, and UTF-8 is dependent on the
option.
.It Ic status-right-attr Ar attributes
Set the attribute of the right part of the status line.
.It Ic status-right-bg Ar colour
Set the background colour of the right part of the status line.
.It Ic status-right-fg Ar colour
Set the foreground colour of the right part of the status line.
.It Ic status-right-bg Ar colour
Set the background colour of the right part of the status line.
.It Ic status-right-length Ar length
Set the maximum
.Ar length
of the right component of the status bar.
The default is 40.
.Pp
.It Xo Ic status-utf8
.Op Ic on | off
.Xc
@@ -2035,8 +1835,7 @@ was given to the
.Ic set-environment
command).
The default is
"DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID
XAUTHORITY".
"DISPLAY WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION".
.It Xo Ic visual-activity
.Op Ic on | off
.Xc
@@ -2061,12 +1860,6 @@ display a message when content is present in a window
for which the
.Ic monitor-content
window option is enabled.
.It Xo Ic visual-silence
.Op Ic on | off
.Xc
If
.Ic monitor-silence
is enabled, prints a message after the interval has expired on a given window.
.El
.It Xo Ic set-window-option
.Op Fl agu
@@ -2100,19 +1893,6 @@ this option is good for full-screen programs which support
.Dv SIGWINCH
and poor for interactive programs such as shells.
.Pp
.It Xo Ic alternate-screen
.Op Ic on | off
.Xc
This option configures whether programs running inside
.Nm
may use the terminal alternate screen feature, which allows the
.Em smcup
and
.Em rmcup
.Xr terminfo 5
capabilities to be issued to preserve the existing window content on start and
restore it on exit.
.Pp
.It Xo Ic automatic-rename
.Op Ic on | off
.Xc
@@ -2123,8 +1903,7 @@ will attempt - on supported platforms - to rename the window to reflect the
command currently running in it.
This flag is automatically disabled for an individual window when a name
is specified at creation with
.Ic new-window
or
.Ic new-window or
.Ic new-session ,
or later with
.Ic rename-window .
@@ -2151,8 +1930,8 @@ or
.Ar height .
A value of zero restores the default unlimited setting.
.Pp
.It Ic main-pane-height Ar height
.It Ic main-pane-width Ar width
.It Ic main-pane-height Ar height
Set the width or height of the main (left or top) pane in the
.Ic main-horizontal
or
@@ -2172,21 +1951,16 @@ Set window modes foreground colour.
.Op Ic vi | emacs
.Xc
Use vi or emacs-style key bindings in copy and choice modes.
As with the
.Ic status-keys
option, the default is emacs, unless
.Ev VISUAL
or
.Ev EDITOR
contains
.Ql vi .
Key bindings default to emacs.
.Pp
.It Xo Ic mode-mouse
.Op Ic on | off
.Xc
Mouse state in modes.
If on, the mouse may be used to copy a selection by dragging in copy mode, or
to select an option in choice mode.
If on,
.Nm
will respond to mouse clicks by moving the cursor in copy mode or selecting an
option in choice mode.
.Pp
.It Xo Ic monitor-activity
.Op Ic on | off
@@ -2202,35 +1976,6 @@ pattern
.Ar match-string
appears in the window, it is highlighted in the status line.
.Pp
.It Xo Ic monitor-silence
.Op Ic interval
.Xc
Monitor for silence (no activity) in the window within
.Ic interval
seconds.
Windows that have been silent for the interval are highlighted in the
status line.
An interval of zero disables the monitoring.
.Pp
.It Ic other-pane-height Ar height
Set the height of the other panes (not the main pane) in the
.Ic main-horizontal
layout.
If this option is set to 0 (the default), it will have no effect.
If both the
.Ic main-pane-height
and
.Ic other-pane-height
options are set, the main pane will grow taller to make the other panes the
specified height, but will never shrink to do so.
.Pp
.It Ic other-pane-width Ar width
Like
.Ic other-pane-height ,
but set the width of other panes in the
.Ic main-vertical
layout.
.Pp
.It Xo Ic remain-on-exit
.Op Ic on | off
.Xc
@@ -2243,8 +1988,21 @@ command.
.It Xo Ic synchronize-panes
.Op Ic on | off
.Xc
Duplicate input to any pane to all other panes in the same window (only
for panes that are not in any special mode).
Duplicate input to any pane to all other panes in the same window, except
for panes that are not in output mode.
.Pp
.It Xo Ic alternate-screen
.Op Ic on | off
.Xc
This option configures whether programs running inside
.Nm
may use the terminal alternate screen feature, which allows the
.Em smcup
and
.Em rmcup
.Xr terminfo 5
capabilities to be issued to preserve the existing window content on start and
restore it on exit.
.Pp
.It Xo Ic utf8
.Op Ic on | off
@@ -2270,16 +2028,6 @@ option for details of special character sequences available.
The default is
.Ql #I:#W#F .
.Pp
.It Ic window-status-alert-attr Ar attributes
Set status line attributes for windows which have an alert (bell, activity
or content).
.Pp
.It Ic window-status-alert-bg Ar colour
Set status line background colour for windows with an alert.
.Pp
.It Ic window-status-alert-fg Ar colour
Set status line foreground colour for windows with an alert.
.Pp
.It Ic window-status-current-attr Ar attributes
Set status line attributes for the currently active window.
.Pp
@@ -2346,9 +2094,9 @@ copies the environment into the
.Em global environment ;
in addition, each session has a
.Em session environment .
When a window is created, the session and global environments are merged.
If a variable exists in both, the value from the session environment is used.
The result is the initial environment passed to the new process.
When a window is created, the session and global environments are merged with
the session environment overriding any variable present in both.
This is the initial environment passed to the new process.
.Pp
The
.Ic update-environment
@@ -2429,7 +2177,6 @@ The flag is one of the following symbols appended to the window name:
.It Li "#" Ta "Window is monitored and activity has been detected."
.It Li "!" Ta "A bell has occurred in the window."
.It Li "+" Ta "Window is monitored for content and it has appeared."
.It Li "~" Ta "The window has been silent for the monitor-silence interval."
.El
.Pp
The # symbol relates to the
@@ -2524,6 +2271,10 @@ The format of
is as for
.Ic status-left ,
with the exception that #() are not handled.
.It Ic select-prompt Op Fl t Ar target-client
Open a prompt inside
.Ar target-client
allowing a window index to be entered interactively.
.El
.Sh BUFFERS
.Nm
@@ -2551,23 +2302,6 @@ command above).
.Pp
The buffer commands are as follows:
.Bl -tag -width Ds
.It Xo
.Ic choose-buffer
.Op Fl t Ar target-window
.Op Ar template
.Xc
Put a window into buffer choice mode, where a buffer may be chosen
interactively from a list.
After a buffer is selected,
.Ql %%
is replaced by the buffer index in
.Ar template
and the result executed as a command.
If
.Ar template
is not given, "paste-buffer -b '%%'" is used.
This command works only from inside
.Nm .
.It Ic clear-history Op Fl t Ar target-pane
.D1 (alias: Ic clearhist )
Remove and free the history for the specified pane.
@@ -2602,23 +2336,18 @@ Load the contents of the specified paste buffer from
.It Xo Ic paste-buffer
.Op Fl dr
.Op Fl b Ar buffer-index
.Op Fl s Ar separator
.Op Fl t Ar target-pane
.Op Fl t Ar target-window
.Xc
.D1 (alias: Ic pasteb )
Insert the contents of a paste buffer into the specified pane.
If not specified, paste into the current one.
Insert the contents of a paste buffer into the current window.
With
.Fl d ,
also delete the paste buffer from the stack.
When output, any linefeed (LF) characters in the paste buffer are replaced with
a separator, by default carriage return (CR).
A custom separator may be specified using the
.Fl s
flag.
The
carriage returns (CR).
This translation may be disabled with the
.Fl r
flag means to do no replacement (equivalent to a separator of LF).
flag.
.It Xo Ic save-buffer
.Op Fl a
.Op Fl b Ar buffer-index
@@ -2647,6 +2376,7 @@ Set the contents of the specified buffer to
Display the contents of the specified buffer.
.El
.Sh MISCELLANEOUS
.Pp
Miscellaneous commands are as follows:
.Bl -tag -width Ds
.It Ic clock-mode Op Fl t Ar target-pane
@@ -2668,7 +2398,7 @@ option.
Execute
.Ar shell-command
in the background without creating a window.
After it finishes, any output to stdout is displayed in copy mode.
After it finishes, any output to stdout is displayed in output mode.
If the command doesn't return success, the exit status is also displayed.
.It Ic server-info
.D1 (alias: Ic info )

393
tmux.c
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.228 2010-12-27 21:22:24 tcunha Exp $ */
/* $Id: tmux.c,v 1.204 2010-02-26 13:31:39 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -21,10 +21,11 @@
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "tmux.h"
@@ -33,26 +34,37 @@
extern char *malloc_options;
#endif
char *cfg_file;
struct options global_options; /* server options */
struct options global_s_options; /* session options */
struct options global_w_options; /* window options */
struct environ global_environ;
struct event_base *ev_base;
char *cfg_file;
char *shell_cmd;
int debug_level;
time_t start_time;
char socket_path[MAXPATHLEN];
char *socket_path;
int login_shell;
char *environ_path;
pid_t environ_pid;
u_int environ_idx;
struct env_data {
char *path;
pid_t pid;
u_int idx;
};
__dead void usage(void);
void parseenvironment(void);
char *makesocketpath(const char *);
void parse_env(struct env_data *);
char *makesockpath(const char *);
__dead void shell_exec(const char *, const char *);
struct imsgbuf *main_ibuf;
struct event main_ev_sigterm;
int main_exitval;
void main_set_signals(void);
void main_clear_signals(void);
void main_signal(int, short, unused void *);
void main_callback(int, short, void *);
void main_dispatch(const char *);
#ifndef HAVE_PROGNAME
char *__progname = (char *) "tmux";
@@ -62,7 +74,7 @@ __dead void
usage(void)
{
fprintf(stderr,
"usage: %s [-28lquvV] [-c shell-command] [-f file] [-L socket-name]\n"
"usage: %s [-28lquv] [-c shell-command] [-f file] [-L socket-name]\n"
" [-S socket-path] [command [flags]]\n",
__progname);
exit(1);
@@ -126,14 +138,14 @@ areshell(const char *shell)
}
void
parseenvironment(void)
parse_env(struct env_data *data)
{
char *env, *path_pid, *pid_idx, buf[256];
size_t len;
const char *errstr;
long long ll;
environ_pid = -1;
data->pid = -1;
if ((env = getenv("TMUX")) == NULL)
return;
@@ -146,9 +158,9 @@ parseenvironment(void)
/* path */
len = path_pid - env;
environ_path = xmalloc(len + 1);
memcpy(environ_path, env, len);
environ_path[len] = '\0';
data->path = xmalloc (len + 1);
memcpy(data->path, env, len);
data->path[len] = '\0';
/* pid */
len = pid_idx - path_pid - 1;
@@ -160,17 +172,17 @@ parseenvironment(void)
ll = strtonum(buf, 0, LONG_MAX, &errstr);
if (errstr != NULL)
return;
environ_pid = ll;
data->pid = ll;
/* idx */
ll = strtonum(pid_idx + 1, 0, UINT_MAX, &errstr);
ll = strtonum(pid_idx+1, 0, UINT_MAX, &errstr);
if (errstr != NULL)
return;
environ_idx = ll;
data->idx = ll;
}
char *
makesocketpath(const char *label)
makesockpath(const char *label)
{
char base[MAXPATHLEN], *path;
struct stat sb;
@@ -202,7 +214,6 @@ shell_exec(const char *shell, const char *shellcmd)
{
const char *shellname, *ptr;
char *argv0;
int mode;
ptr = strrchr(shell, '/');
if (ptr != NULL && *(ptr + 1) != '\0')
@@ -215,14 +226,6 @@ shell_exec(const char *shell, const char *shellcmd)
xasprintf(&argv0, "%s", shellname);
setenv("SHELL", shell, 1);
if ((mode = fcntl(STDIN_FILENO, F_GETFL)) != -1)
fcntl(STDIN_FILENO, F_SETFL, mode & ~O_NONBLOCK);
if ((mode = fcntl(STDOUT_FILENO, F_GETFL)) != -1)
fcntl(STDOUT_FILENO, F_SETFL, mode & ~O_NONBLOCK);
if ((mode = fcntl(STDERR_FILENO, F_GETFL)) != -1)
fcntl(STDERR_FILENO, F_SETFL, mode & ~O_NONBLOCK);
closefrom(STDERR_FILENO + 1);
execl(shell, argv0, "-c", shellcmd, (char *) NULL);
fatal("execl failed");
}
@@ -230,20 +233,30 @@ shell_exec(const char *shell, const char *shellcmd)
int
main(int argc, char **argv)
{
struct passwd *pw;
struct options *oo, *so, *wo;
struct keylist *keylist;
char *s, *path, *label, *home, **var;
int opt, flags, quiet, keys;
struct cmd_list *cmdlist;
struct cmd *cmd;
enum msgtype msg;
struct passwd *pw;
struct options *oo, *so, *wo;
struct keylist *keylist;
struct env_data envdata;
struct msg_command_data cmddata;
char *s, *shellcmd, *path, *label, *home, *cause;
char cwd[MAXPATHLEN], **var;
void *buf;
size_t len;
int opt, flags, quiet = 0, cmdflags = 0;
short events;
#if defined(DEBUG) && defined(__OpenBSD__)
malloc_options = (char *) "AFGJPX";
#endif
quiet = flags = 0;
label = path = NULL;
flags = 0;
shellcmd = label = path = NULL;
envdata.path = NULL;
login_shell = (**argv == '-');
while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUvV")) != -1) {
while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) {
switch (opt) {
case '2':
flags |= IDENTIFY_256COLOURS;
@@ -254,13 +267,10 @@ main(int argc, char **argv)
flags &= ~IDENTIFY_256COLOURS;
break;
case 'c':
if (shell_cmd != NULL)
xfree(shell_cmd);
shell_cmd = xstrdup(optarg);
if (shellcmd != NULL)
xfree(shellcmd);
shellcmd = xstrdup(optarg);
break;
case 'V':
printf("%s %s\n", __progname, BUILD);
exit(0);
case 'f':
if (cfg_file != NULL)
xfree(cfg_file);
@@ -295,7 +305,7 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
if (shell_cmd != NULL && argc != 0)
if (shellcmd != NULL && argc != 0)
usage();
log_open_tty(debug_level);
@@ -325,7 +335,6 @@ main(int argc, char **argv)
oo = &global_options;
options_set_number(oo, "quiet", quiet);
options_set_number(oo, "escape-time", 500);
options_set_number(oo, "exit-unattached", 0);
options_init(&global_s_options, NULL);
so = &global_s_options;
@@ -333,13 +342,10 @@ main(int argc, char **argv)
options_set_number(so, "bell-action", BELL_ANY);
options_set_number(so, "buffer-limit", 9);
options_set_string(so, "default-command", "%s", "");
options_set_string(so, "default-path", "%s", "");
options_set_string(so, "default-shell", "%s", getshell());
options_set_string(so, "default-terminal", "screen");
options_set_number(so, "destroy-unattached", 0);
options_set_number(so, "detach-on-destroy", 1);
options_set_number(so, "display-panes-active-colour", 1);
options_set_number(so, "display-panes-colour", 4);
options_set_number(so, "display-panes-active-colour", 1);
options_set_number(so, "display-panes-time", 1000);
options_set_number(so, "display-time", 750);
options_set_number(so, "history-limit", 2000);
@@ -351,8 +357,8 @@ main(int argc, char **argv)
options_set_number(so, "message-fg", 0);
options_set_number(so, "message-limit", 20);
options_set_number(so, "mouse-select-pane", 0);
options_set_number(so, "pane-active-border-bg", 8);
options_set_number(so, "pane-active-border-fg", 2);
options_set_number(so, "pane-active-border-bg", 2);
options_set_number(so, "pane-active-border-fg", 8);
options_set_number(so, "pane-border-bg", 8);
options_set_number(so, "pane-border-fg", 8);
options_set_number(so, "repeat-time", 500);
@@ -365,6 +371,7 @@ main(int argc, char **argv)
options_set_number(so, "status-fg", 0);
options_set_number(so, "status-interval", 15);
options_set_number(so, "status-justify", 0);
options_set_number(so, "status-keys", MODEKEY_EMACS);
options_set_string(so, "status-left", "[#S]");
options_set_number(so, "status-left-attr", 0);
options_set_number(so, "status-left-bg", 8);
@@ -377,15 +384,11 @@ main(int argc, char **argv)
options_set_number(so, "status-right-length", 40);
options_set_string(so, "terminal-overrides",
"*88col*:colors=88,*256col*:colors=256");
options_set_string(so, "update-environment",
"DISPLAY "
"SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION "
"WINDOWID "
"XAUTHORITY");
options_set_string(so, "update-environment", "DISPLAY "
"WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION");
options_set_number(so, "visual-activity", 0);
options_set_number(so, "visual-bell", 0);
options_set_number(so, "visual-content", 0);
options_set_number(so, "visual-silence", 0);
keylist = xmalloc(sizeof *keylist);
ARRAY_INIT(keylist);
@@ -402,25 +405,20 @@ main(int argc, char **argv)
options_set_number(wo, "force-height", 0);
options_set_number(wo, "force-width", 0);
options_set_number(wo, "main-pane-height", 24);
options_set_number(wo, "main-pane-width", 80);
options_set_number(wo, "main-pane-width", 81);
options_set_number(wo, "mode-attr", 0);
options_set_number(wo, "mode-bg", 3);
options_set_number(wo, "mode-fg", 0);
options_set_number(wo, "mode-keys", MODEKEY_EMACS);
options_set_number(wo, "mode-mouse", 0);
options_set_number(wo, "monitor-activity", 0);
options_set_string(wo, "monitor-content", "%s", "");
options_set_number(wo, "monitor-silence", 0);
options_set_number(wo, "other-pane-height", 0);
options_set_number(wo, "other-pane-width", 0);
options_set_number(wo, "window-status-attr", 0);
options_set_number(wo, "window-status-bg", 8);
options_set_number(wo, "window-status-current-attr", 0);
options_set_number(wo, "window-status-current-bg", 8);
options_set_number(wo, "window-status-current-fg", 8);
options_set_number(wo, "window-status-fg", 8);
options_set_number(wo, "window-status-alert-attr", GRID_ATTR_REVERSE);
options_set_number(wo, "window-status-alert-bg", 8);
options_set_number(wo, "window-status-alert-fg", 8);
options_set_string(wo, "window-status-format", "#I:#W#F");
options_set_string(wo, "window-status-current-format", "#I:#W#F");
options_set_string(wo, "word-separators", " -_@");
@@ -436,17 +434,15 @@ main(int argc, char **argv)
options_set_number(wo, "utf8", 0);
}
keys = MODEKEY_EMACS;
if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
if (strrchr(s, '/') != NULL)
s = strrchr(s, '/') + 1;
if (strstr(s, "vi") != NULL)
keys = MODEKEY_VI;
if (getcwd(cwd, sizeof cwd) == NULL) {
pw = getpwuid(getuid());
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
strlcpy(cwd, pw->pw_dir, sizeof cwd);
else
strlcpy(cwd, "/", sizeof cwd);
}
options_set_number(so, "status-keys", keys);
options_set_number(wo, "mode-keys", keys);
options_set_string(so, "default-path", "%s", cwd);
/* Locate the configuration file. */
if (cfg_file == NULL) {
home = getenv("HOME");
if (home == NULL || *home == '\0') {
@@ -462,22 +458,21 @@ main(int argc, char **argv)
}
/*
* Figure out the socket path. If specified on the command-line with -S
* or -L, use it, otherwise try $TMUX or assume -L default.
* Figure out the socket path. If specified on the command-line with
* -S or -L, use it, otherwise try $TMUX or assume -L default.
*/
parseenvironment();
parse_env(&envdata);
if (path == NULL) {
/* If no -L, use the environment. */
/* No -L. Try $TMUX, or default. */
if (label == NULL) {
if (environ_path != NULL)
path = xstrdup(environ_path);
else
path = envdata.path;
if (path == NULL)
label = xstrdup("default");
}
/* -L or default set. */
if (label != NULL) {
if ((path = makesocketpath(label)) == NULL) {
if ((path = makesockpath(label)) == NULL) {
log_warn("can't create socket");
exit(1);
}
@@ -485,16 +480,70 @@ main(int argc, char **argv)
}
if (label != NULL)
xfree(label);
if (realpath(path, socket_path) == NULL)
strlcpy(socket_path, path, sizeof socket_path);
if (shellcmd != NULL) {
msg = MSG_SHELL;
buf = NULL;
len = 0;
} else {
cmddata.pid = envdata.pid;
cmddata.idx = envdata.idx;
/* Prepare command for server. */
cmddata.argc = argc;
if (cmd_pack_argv(
argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
log_warnx("command too long");
exit(1);
}
msg = MSG_COMMAND;
buf = &cmddata;
len = sizeof cmddata;
}
if (shellcmd != NULL)
cmdflags |= CMD_STARTSERVER;
else if (argc == 0) /* new-session is the default */
cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
else {
/*
* It sucks parsing the command string twice (in client and
* later in server) but it is necessary to get the start server
* flag.
*/
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
log_warnx("%s", cause);
exit(1);
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
if (cmd->entry->flags & CMD_SENDENVIRON)
cmdflags |= CMD_SENDENVIRON;
if (cmd->entry->flags & CMD_CANTNEST)
cmdflags |= CMD_CANTNEST;
}
cmd_list_free(cmdlist);
}
/*
* Check if this could be a nested session, if the command can't nest:
* if the socket path matches $TMUX, this is probably the same server.
*/
if (shellcmd == NULL && envdata.path != NULL &&
cmdflags & CMD_CANTNEST &&
(path == envdata.path || strcmp(path, envdata.path) == 0)) {
log_warnx("sessions should be nested with care. "
"unset $TMUX to force.");
exit(1);
}
if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
exit(1);
xfree(path);
#ifdef HAVE_SETPROCTITLE
/* Set process title. */
setproctitle("%s (%s)", __progname, socket_path);
#endif
/* Pass control to the client. */
#ifdef HAVE_BROKEN_KQUEUE
if (setenv("EVENT_NOKQUEUE", "1", 1) != 0)
fatal("setenv failed");
@@ -503,12 +552,170 @@ main(int argc, char **argv)
if (setenv("EVENT_NOPOLL", "1", 1) != 0)
fatal("setenv failed");
#endif
ev_base = event_init();
event_init();
#ifdef HAVE_BROKEN_KQUEUE
unsetenv("EVENT_NOKQUEUE");
#endif
#ifdef HAVE_BROKEN_POLL
unsetenv("EVENT_NOPOLL");
#endif
exit(client_main(argc, argv, flags));
imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
main_set_signals();
events = EV_READ;
if (main_ibuf->w.queued > 0)
events |= EV_WRITE;
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
main_exitval = 0;
event_dispatch();
main_clear_signals();
client_main(); /* doesn't return */
}
void
main_set_signals(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL);
signal_add(&main_ev_sigterm, NULL);
}
void
main_clear_signals(void)
{
struct sigaction sigact;
memset(&sigact, 0, sizeof sigact);
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
sigact.sa_handler = SIG_DFL;
if (sigaction(SIGINT, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
fatal("sigaction failed");
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed");
event_del(&main_ev_sigterm);
}
/* ARGSUSED */
void
main_signal(int sig, unused short events, unused void *data)
{
switch (sig) {
case SIGTERM:
exit(1);
}
}
/* ARGSUSED */
void
main_callback(unused int fd, short events, void *data)
{
char *shellcmd = data;
if (events & EV_READ)
main_dispatch(shellcmd);
if (events & EV_WRITE) {
if (msgbuf_write(&main_ibuf->w) < 0)
fatalx("msgbuf_write failed");
}
events = EV_READ;
if (main_ibuf->w.queued > 0)
events |= EV_WRITE;
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
}
void
main_dispatch(const char *shellcmd)
{
struct imsg imsg;
ssize_t n, datalen;
struct msg_print_data printdata;
struct msg_shell_data shelldata;
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
fatalx("imsg_read failed");
for (;;) {
if ((n = imsg_get(main_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
if (n == 0)
return;
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != 0)
fatalx("bad MSG_EXIT size");
exit(main_exitval);
case MSG_ERROR:
case MSG_PRINT:
if (datalen != sizeof printdata)
fatalx("bad MSG_PRINT size");
memcpy(&printdata, imsg.data, sizeof printdata);
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
log_info("%s", printdata.msg);
if (imsg.hdr.type == MSG_ERROR)
main_exitval = 1;
break;
case MSG_READY:
if (datalen != 0)
fatalx("bad MSG_READY size");
event_loopexit(NULL); /* move to client_main() */
break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
log_warnx("protocol version mismatch (client %u, "
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
exit(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';
main_clear_signals();
shell_exec(shelldata.shell, shellcmd);
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
}
}

253
tmux.h
View File

@@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.591 2010-12-22 15:36:44 tcunha Exp $ */
/* $Id: tmux.h,v 1.547 2010-03-08 15:02:07 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -21,7 +21,7 @@
#include "config.h"
#define PROTOCOL_VERSION 6
#define PROTOCOL_VERSION 5
#include <sys/param.h>
#include <sys/time.h>
@@ -31,6 +31,7 @@
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <termios.h>
@@ -57,8 +58,8 @@ extern char **environ;
/* Automatic name refresh interval, in milliseconds. */
#define NAME_INTERVAL 500
/* Maximum data to buffer for output before suspending writing to a tty. */
#define BACKOFF_THRESHOLD 16384
/* 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
@@ -66,6 +67,7 @@ extern char **environ;
*/
#define COMMAND_LENGTH 2048 /* packed argv size */
#define TERMINAL_LENGTH 128 /* length of TERM environment variable */
#define PRINT_LENGTH 512 /* printed error/message size */
#define ENVIRON_LENGTH 1024 /* environment variable length */
/*
@@ -108,10 +110,6 @@ extern char **environ;
#define KEYC_SHIFT 0x8000
#define KEYC_PREFIX 0x10000
/* Mask to obtain key w/o modifiers */
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
/* Other key codes. */
enum key_code {
/* Mouse key. */
@@ -370,9 +368,7 @@ enum msgtype {
MSG_ENVIRON,
MSG_UNLOCK,
MSG_LOCK,
MSG_SHELL,
MSG_STDERR,
MSG_STDOUT,
MSG_SHELL
};
/*
@@ -380,6 +376,10 @@ enum msgtype {
*
* Don't forget to bump PROTOCOL_VERSION if any of these change!
*/
struct msg_print_data {
char msg[PRINT_LENGTH];
};
struct msg_command_data {
pid_t pid; /* pid from $TMUX or -1 */
u_int idx; /* index from $TMUX */
@@ -411,10 +411,6 @@ struct msg_shell_data {
char shell[MAXPATHLEN];
};
struct msg_exit_data {
int retcode;
};
/* Mode key commands. */
enum mode_key_cmd {
MODEKEY_NONE,
@@ -462,10 +458,6 @@ enum mode_key_cmd {
MODEKEYCOPY_HALFPAGEUP,
MODEKEYCOPY_HISTORYBOTTOM,
MODEKEYCOPY_HISTORYTOP,
MODEKEYCOPY_JUMP,
MODEKEYCOPY_JUMPAGAIN,
MODEKEYCOPY_JUMPREVERSE,
MODEKEYCOPY_JUMPBACK,
MODEKEYCOPY_LEFT,
MODEKEYCOPY_MIDDLELINE,
MODEKEYCOPY_NEXTPAGE,
@@ -544,8 +536,6 @@ struct mode_key_table {
#define MODE_KCURSOR 0x4
#define MODE_KKEYPAD 0x8 /* set = application, clear = number */
#define MODE_MOUSE 0x10
#define MODE_MOUSEMOTION 0x20
#define MODE_WRAP 0x40 /* whether lines wrap */
/*
* A single UTF-8 character.
@@ -728,52 +718,59 @@ struct screen_write_ctx {
#define screen_hsize(s) ((s)->grid->hsize)
#define screen_hlimit(s) ((s)->grid->hlimit)
/* Input parser sequence argument. */
struct input_arg {
u_char data[64];
size_t used;
};
/* Input parser context. */
struct input_ctx {
struct window_pane *wp;
struct window_pane *wp;
struct screen_write_ctx ctx;
struct grid_cell cell;
u_char *buf;
size_t len;
size_t off;
size_t was;
struct grid_cell old_cell;
u_int old_cx;
u_int old_cy;
struct grid_cell cell;
u_char interm_buf[4];
size_t interm_len;
struct grid_cell saved_cell;
u_int saved_cx;
u_int saved_cy;
u_char param_buf[64];
size_t param_len;
#define MAXSTRINGLEN 1024
u_char *string_buf;
size_t string_len;
int string_type;
#define STRING_SYSTEM 0
#define STRING_APPLICATION 1
#define STRING_NAME 2
u_char input_buf[256];
size_t input_len;
struct utf8_data utf8data;
int param_list[24]; /* -1 not present */
u_int param_list_len;
u_char intermediate;
void *(*state)(u_char, struct input_ctx *);
struct utf8_data utf8data;
int ch;
int flags;
#define INPUT_DISCARD 0x1
const struct input_state *state;
u_char private;
ARRAY_DECL(, struct input_arg) args;
};
/*
* Window mode. Windows can be in several modes and this is used to call the
* right function to handle input and output.
*/
struct session;
struct client;
struct window;
struct mouse_event;
struct window_mode {
struct screen *(*init)(struct window_pane *);
void (*free)(struct window_pane *);
void (*resize)(struct window_pane *, u_int, u_int);
void (*key)(struct window_pane *, struct session *, int);
void (*key)(struct window_pane *, struct client *, int);
void (*mouse)(struct window_pane *,
struct session *, struct mouse_event *);
struct client *, struct mouse_event *);
void (*timer)(struct window_pane *);
};
@@ -828,10 +825,8 @@ TAILQ_HEAD(window_panes, window_pane);
struct window {
char *name;
struct event name_timer;
struct timeval silence_timer;
struct window_pane *active;
struct window_pane *last;
struct window_panes panes;
int lastlayout;
@@ -842,9 +837,10 @@ struct window {
int flags;
#define WINDOW_BELL 0x1
#define WINDOW_ACTIVITY 0x2
#define WINDOW_REDRAW 0x4
#define WINDOW_SILENCE 0x8
#define WINDOW_HIDDEN 0x2
#define WINDOW_ACTIVITY 0x4
#define WINDOW_CONTENT 0x8
#define WINDOW_REDRAW 0x10
struct options options;
@@ -861,14 +857,6 @@ struct winlink {
struct grid_cell status_cell;
char *status_text;
int flags;
#define WINLINK_BELL 0x1
#define WINLINK_ACTIVITY 0x2
#define WINLINK_CONTENT 0x4
#define WINLINK_SILENCE 0x8
#define WINLINK_ALERTFLAGS \
(WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT|WINLINK_SILENCE)
RB_ENTRY(winlink) entry;
TAILQ_ENTRY(winlink) sentry;
};
@@ -920,6 +908,13 @@ struct environ_entry {
RB_HEAD(environ, environ_entry);
/* Client session. */
struct session_alert {
struct winlink *wl;
int type;
SLIST_ENTRY(session_alert) entry;
};
struct session_group {
TAILQ_HEAD(, session) sessions;
@@ -928,10 +923,7 @@ struct session_group {
TAILQ_HEAD(session_groups, session_group);
struct session {
u_int idx;
char *name;
char *cwd;
struct timeval creation_time;
struct timeval activity_time;
@@ -947,7 +939,10 @@ struct session {
struct paste_stack buffers;
SLIST_HEAD(, session_alert) alerts;
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
#define SESSION_DEAD 0x2
int flags;
struct termios *tio;
@@ -957,10 +952,8 @@ struct session {
int references;
TAILQ_ENTRY(session) gentry;
RB_ENTRY(session) entry;
};
RB_HEAD(sessions, session);
ARRAY_DECL(sessionslist, struct session *);
ARRAY_DECL(sessions, struct session *);
/* TTY information. */
struct tty_key {
@@ -977,8 +970,6 @@ struct tty_term {
char *name;
u_int references;
char acs[UCHAR_MAX + 1][2];
struct tty_code codes[NTTYCODE];
#define TERM_256COLOURS 0x1
@@ -1016,13 +1007,14 @@ struct tty {
struct grid_cell cell;
u_char acs[UCHAR_MAX + 1];
#define TTY_NOCURSOR 0x1
#define TTY_FREEZE 0x2
#define TTY_ESCAPE 0x4
#define TTY_UTF8 0x8
#define TTY_STARTED 0x10
#define TTY_OPENED 0x20
#define TTY_BACKOFF 0x40
int flags;
int term_flags;
@@ -1060,23 +1052,9 @@ struct tty_ctx {
u_int last_width;
};
/*
* xterm mouse mode is fairly silly. Buttons are in the bottom two
* bits: 0 button 1; 1 button 2; 2 button 3; 3 buttons released.
*
* Bit 3 is shift; bit 4 is meta; bit 5 control.
*
* Bit 6 is added for mouse buttons 4 and 5.
*/
/* Mouse input. */
struct mouse_event {
u_char b;
#define MOUSE_1 0
#define MOUSE_2 1
#define MOUSE_3 2
#define MOUSE_UP 3
#define MOUSE_BUTTON 3
#define MOUSE_45 64
u_char x;
u_char y;
};
@@ -1091,7 +1069,6 @@ struct message_entry {
struct client {
struct imsgbuf ibuf;
struct event event;
int retcode;
struct timeval creation_time;
struct timeval activity_time;
@@ -1102,18 +1079,6 @@ struct client {
char *cwd;
struct tty tty;
int stdin_fd;
void *stdin_data;
void (*stdin_callback)(struct client *, void *);
struct bufferevent *stdin_event;
int stdout_fd;
struct bufferevent *stdout_event;
int stderr_fd;
struct bufferevent *stderr_event;
struct event repeat_timer;
struct timeval status_timer;
@@ -1122,7 +1087,7 @@ struct client {
#define CLIENT_TERMINAL 0x1
#define CLIENT_PREFIX 0x2
#define CLIENT_EXIT 0x4
#define CLIENT_MOUSE 0x4
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */
@@ -1132,8 +1097,6 @@ struct client {
#define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800
#define CLIENT_BACKOFF 0x1000
#define CLIENT_REDRAWWINDOW 0x2000
int flags;
struct event identify_timer;
@@ -1148,15 +1111,16 @@ struct client {
int (*prompt_callbackfn)(void *, const char *);
void (*prompt_freefn)(void *);
void *prompt_data;
u_int prompt_hindex;
#define PROMPT_SINGLE 0x1
int prompt_flags;
u_int prompt_hindex;
ARRAY_DECL(, char *) prompt_hdata;
struct mode_key_data prompt_mdata;
struct session *session;
struct session *last_session;
int references;
};
@@ -1197,10 +1161,7 @@ struct cmd {
TAILQ_ENTRY(cmd) qentry;
};
struct cmd_list {
int references;
TAILQ_HEAD(, cmd) list;
};
TAILQ_HEAD(cmd_list, cmd);
struct cmd_entry {
const char *name;
@@ -1293,25 +1254,20 @@ extern struct options global_options;
extern struct options global_s_options;
extern struct options global_w_options;
extern struct environ global_environ;
extern struct event_base *ev_base;
extern char *cfg_file;
extern char *shell_cmd;
extern int debug_level;
extern int be_quiet;
extern time_t start_time;
extern char socket_path[MAXPATHLEN];
extern char *socket_path;
extern int login_shell;
extern char *environ_path;
extern pid_t environ_pid;
extern u_int environ_idx;
void logfile(const char *);
const char *getshell(void);
int checkshell(const char *);
int areshell(const char *);
__dead void shell_exec(const char *, const char *);
/* cfg.c */
extern int cfg_finished;
extern struct causelist cfg_causes;
struct causelist cfg_causes;
void printflike2 cfg_add_cause(struct causelist *, const char *, ...);
int load_cfg(const char *, struct cmd_ctx *, struct causelist *);
@@ -1376,10 +1332,10 @@ void environ_set(struct environ *, const char *, const char *);
void environ_put(struct environ *, const char *);
void environ_unset(struct environ *, const char *);
void environ_update(const char *, struct environ *, struct environ *);
void environ_push(struct environ *);
/* tty.c */
void tty_raw(struct tty *, const char *);
u_char tty_get_acs(struct tty *, u_char);
void tty_attributes(struct tty *, const struct grid_cell *);
void tty_reset(struct tty *);
void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int);
@@ -1393,7 +1349,7 @@ void tty_puts(struct tty *, const char *);
void tty_putc(struct tty *, u_char);
void tty_pututf8(struct tty *, const struct grid_utf8 *);
void tty_init(struct tty *, int, char *);
int tty_resize(struct tty *);
void tty_resize(struct tty *);
void tty_start_tty(struct tty *);
void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *);
@@ -1433,9 +1389,6 @@ const char *tty_term_string2(
int tty_term_number(struct tty_term *, enum tty_code_code);
int tty_term_flag(struct tty_term *, enum tty_code_code);
/* tty-acs.c */
const char *tty_acs_get(struct tty *, u_char);
/* tty-keys.c */
void tty_keys_init(struct tty *);
void tty_keys_free(struct tty *);
@@ -1451,7 +1404,6 @@ int paste_free_top(struct paste_stack *);
int paste_free_index(struct paste_stack *, u_int);
void paste_add(struct paste_stack *, char *, size_t, u_int);
int paste_replace(struct paste_stack *, u_int, char *, size_t);
char *paste_print(struct paste_buffer *, size_t);
/* clock.c */
extern const char clock_table[14][5][5];
@@ -1467,7 +1419,6 @@ const char *cmd_set_option_print(
/* cmd.c */
int cmd_pack_argv(int, char **, char *, size_t);
int cmd_unpack_argv(char *, size_t, int, char ***);
char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **);
struct cmd *cmd_parse(int, char **, char **);
int cmd_exec(struct cmd *, struct cmd_ctx *);
@@ -1489,7 +1440,6 @@ extern const struct cmd_entry cmd_attach_session_entry;
extern const struct cmd_entry cmd_bind_key_entry;
extern const struct cmd_entry cmd_break_pane_entry;
extern const struct cmd_entry cmd_capture_pane_entry;
extern const struct cmd_entry cmd_choose_buffer_entry;
extern const struct cmd_entry cmd_choose_client_entry;
extern const struct cmd_entry cmd_choose_session_entry;
extern const struct cmd_entry cmd_choose_window_entry;
@@ -1512,7 +1462,6 @@ extern const struct cmd_entry cmd_kill_pane_entry;
extern const struct cmd_entry cmd_kill_server_entry;
extern const struct cmd_entry cmd_kill_session_entry;
extern const struct cmd_entry cmd_kill_window_entry;
extern const struct cmd_entry cmd_last_pane_entry;
extern const struct cmd_entry cmd_last_window_entry;
extern const struct cmd_entry cmd_link_window_entry;
extern const struct cmd_entry cmd_list_buffers_entry;
@@ -1545,6 +1494,7 @@ extern const struct cmd_entry cmd_run_shell_entry;
extern const struct cmd_entry cmd_save_buffer_entry;
extern const struct cmd_entry cmd_select_layout_entry;
extern const struct cmd_entry cmd_select_pane_entry;
extern const struct cmd_entry cmd_select_prompt_entry;
extern const struct cmd_entry cmd_select_window_entry;
extern const struct cmd_entry cmd_send_keys_entry;
extern const struct cmd_entry cmd_send_prefix_entry;
@@ -1608,7 +1558,8 @@ void cmd_buffer_free(struct cmd *);
size_t cmd_buffer_print(struct cmd *, char *, size_t);
/* client.c */
int client_main(int, char **, int);
struct imsgbuf *client_init(char *, int, int);
__dead void client_main(void);
/* key-bindings.c */
extern struct key_bindings key_bindings;
@@ -1631,7 +1582,9 @@ const char *key_string_lookup_key(int);
/* server.c */
extern struct clients clients;
extern struct clients dead_clients;
int server_start(void);
int server_start(char *);
void server_signal_set(void);
void server_signal_clear(void);
void server_update_socket(void);
/* server-client.c */
@@ -1646,6 +1599,7 @@ void server_window_loop(void);
/* server-fn.c */
void server_fill_environ(struct session *, struct environ *);
void server_write_error(struct client *, const char *);
void server_write_client(
struct client *, enum msgtype, const void *, size_t);
void server_write_session(
@@ -1670,7 +1624,6 @@ void server_unlink_window(struct session *, struct winlink *);
void server_destroy_pane(struct window_pane *);
void server_destroy_session_group(struct session *);
void server_destroy_session(struct session *);
void server_check_unattached (void);
void server_set_identify(struct client *);
void server_clear_identify(struct client *);
void server_update_event(struct client *);
@@ -1836,7 +1789,9 @@ int screen_check_selection(struct screen *, u_int, u_int);
/* window.c */
extern struct windows windows;
int window_cmp(struct window *, struct window *);
int winlink_cmp(struct winlink *, struct winlink *);
RB_PROTOTYPE(windows, window, entry, window_cmp);
RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp);
struct winlink *winlink_find_by_index(struct winlinks *, int);
struct winlink *winlink_find_by_window(struct winlinks *, struct window *);
@@ -1846,10 +1801,6 @@ struct winlink *winlink_add(struct winlinks *, struct window *, int);
void winlink_remove(struct winlinks *, struct winlink *);
struct winlink *winlink_next(struct winlink *);
struct winlink *winlink_previous(struct winlink *);
struct winlink *winlink_next_by_number(struct winlink *, struct session *,
int);
struct winlink *winlink_previous_by_number(struct winlink *, struct session *,
int);
void winlink_stack_push(struct winlink_stack *, struct winlink *);
void winlink_stack_remove(struct winlink_stack *, struct winlink *);
int window_index(struct window *, u_int *);
@@ -1864,10 +1815,6 @@ struct window_pane *window_add_pane(struct window *, u_int);
void window_resize(struct window *, u_int, u_int);
void window_remove_pane(struct window *, struct window_pane *);
struct window_pane *window_pane_at_index(struct window *, u_int);
struct window_pane *window_pane_next_by_number(struct window *,
struct window_pane *, u_int);
struct window_pane *window_pane_previous_by_number(struct window *,
struct window_pane *, u_int);
u_int window_pane_index(struct window *, struct window_pane *);
u_int window_count_panes(struct window *);
void window_destroy_panes(struct window *);
@@ -1877,30 +1824,21 @@ int window_pane_spawn(struct window_pane *, const char *,
const char *, const char *, struct environ *,
struct termios *, char **);
void window_pane_resize(struct window_pane *, u_int, u_int);
void window_pane_alternate_on(
struct window_pane *, struct grid_cell *);
void window_pane_alternate_off(
struct window_pane *, struct grid_cell *);
int window_pane_set_mode(
struct window_pane *, const struct window_mode *);
void window_pane_reset_mode(struct window_pane *);
void window_pane_key(struct window_pane *, struct session *, int);
void window_pane_parse(struct window_pane *);
void window_pane_key(struct window_pane *, struct client *, int);
void window_pane_mouse(struct window_pane *,
struct session *, struct mouse_event *);
struct client *, struct mouse_event *);
int window_pane_visible(struct window_pane *);
char *window_pane_search(
struct window_pane *, const char *, u_int *);
struct window_pane *window_pane_find_up(struct window_pane *);
struct window_pane *window_pane_find_down(struct window_pane *);
struct window_pane *window_pane_find_left(struct window_pane *);
struct window_pane *window_pane_find_right(struct window_pane *);
/* layout.c */
u_int layout_count_cells(struct layout_cell *);
struct layout_cell *layout_create_cell(struct layout_cell *);
void layout_free_cell(struct layout_cell *);
void layout_print_cell(struct layout_cell *, const char *, u_int);
void layout_destroy_cell(struct layout_cell *, struct layout_cell **);
void layout_set_size(
struct layout_cell *, u_int, u_int, u_int, u_int);
void layout_make_leaf(
@@ -1921,10 +1859,6 @@ struct layout_cell *layout_split_pane(
struct window_pane *, enum layout_type, int);
void layout_close_pane(struct window_pane *);
/* layout-custom.c */
char *layout_dump(struct window *);
int layout_parse(struct window *, const char *);
/* layout-set.c */
const char *layout_set_name(u_int);
int layout_set_lookup(const char *);
@@ -1935,19 +1869,19 @@ void layout_set_active_changed(struct window *);
/* layout-string.c */
struct layout_cell *layout_find_string(struct window *, const char *);
struct layout_cell *layout_find_bottomright(struct layout_cell *);
/* window-clock.c */
extern const struct window_mode window_clock_mode;
/* window-copy.c */
extern const struct window_mode window_copy_mode;
void window_copy_init_from_pane(struct window_pane *);
void window_copy_init_for_output(struct window_pane *);
void window_copy_add(struct window_pane *, const char *, ...);
void window_copy_vadd(struct window_pane *, const char *, va_list);
void window_copy_pageup(struct window_pane *);
/* window-more.c */
extern const struct window_mode window_more_mode;
void window_more_add(struct window_pane *, const char *, ...);
void window_more_vadd(struct window_pane *, const char *, va_list);
/* window-choose.c */
extern const struct window_mode window_choose_mode;
void window_choose_vadd(
@@ -1961,31 +1895,26 @@ void window_choose_ready(struct window_pane *,
void queue_window_name(struct window *);
char *default_window_name(struct window *);
/* signal.c */
void set_signals(void(*)(int, short, void *));
void clear_signals(int);
/* session.c */
extern struct sessions sessions;
extern struct sessions dead_sessions;
extern struct session_groups session_groups;
int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *);
void session_alert_add(struct session *, struct window *, int);
void session_alert_cancel(struct session *, struct winlink *);
int session_alert_has(struct session *, struct winlink *, int);
int session_alert_has_window(struct session *, struct window *, int);
struct session *session_find(const char *);
struct session *session_find_by_index(u_int);
struct session *session_create(const char *, const char *, const char *,
struct environ *, struct termios *, int, u_int, u_int,
char **);
void session_destroy(struct session *);
struct session *session_next_session(struct session *);
struct session *session_previous_session(struct session *);
int session_index(struct session *, u_int *);
struct winlink *session_new(struct session *,
const char *, const char *, const char *, int, char **);
struct winlink *session_attach(
struct session *, struct window *, int, char **);
int session_detach(struct session *, struct winlink *);
struct winlink* session_has(struct session *, struct window *);
int session_has(struct session *, struct window *);
int session_next(struct session *, int);
int session_previous(struct session *, int);
int session_select(struct session *, int);

View File

@@ -1,5 +0,0 @@
# $Id: check-compat.sh,v 1.1 2010-10-24 00:42:04 tcunha Exp $
grep "#include" compat.h|while read line; do
grep "$line" *.[ch] compat/*.[ch]
done

View File

@@ -1,6 +1,6 @@
# $Id: dist.mk,v 1.11 2010-12-27 21:32:16 tcunha Exp $
# $Id: dist.mk,v 1.8 2010-03-10 15:16:19 tcunha Exp $
VERSION= 1.4
VERSION= 1.2
DISTDIR= tmux-${VERSION}
DISTFILES= *.[ch] Makefile GNUmakefile configure tmux.1 \
@@ -20,7 +20,7 @@ dist:
upload-index.html: update-index.html
scp www/index.html www/main.css www/images/*.png \
${USER},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-*
update-index.html:

View File

@@ -1,31 +0,0 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int
main(void)
{
time_t t;
int i;
setvbuf(stdout, NULL, _IONBF, 0);
t = time(NULL);
srandom((u_int) t);
for (;;) {
putchar('\033');
for (i = 0; i < random() % 25; i++) {
if (i > 22)
putchar(';');
else
putchar(random() % 256);
}
/* usleep(100); */
}
}

View File

@@ -1,97 +0,0 @@
/* $Id: tty-acs.c,v 1.1 2010-09-18 15:43:53 tcunha Exp $ */
/*
* Copyright (c) 2010 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 "tmux.h"
int tty_acs_cmp(const void *, const void *);
/* Table mapping ACS entries to UTF-8. */
struct tty_acs_entry {
u_char key;
const char *string;
};
const struct tty_acs_entry tty_acs_table[] = {
{ '+', "\342\206\222" },
{ ',', "\342\206\220" },
{ '-', "\342\206\221" },
{ '.', "\342\206\223" },
{ '0', "\342\226\256" },
{ '`', "\342\227\206" },
{ 'a', "\342\226\222" },
{ 'f', "\302\260" },
{ 'g', "\302\261" },
{ 'h', "\342\226\222" },
{ 'i', "\342\230\203" },
{ 'j', "\342\224\230" },
{ 'k', "\342\224\220" },
{ 'l', "\342\224\214" },
{ 'm', "\342\224\224" },
{ 'n', "\342\224\274" },
{ 'o', "\342\216\272" },
{ 'p', "\342\216\273" },
{ 'q', "\342\224\200" },
{ 'r', "\342\216\274" },
{ 's', "\342\216\275" },
{ 't', "\342\224\234" },
{ 'u', "\342\224\244" },
{ 'v', "\342\224\264" },
{ 'w', "\342\224\254" },
{ 'x', "\342\224\202" },
{ 'y', "\342\211\244" },
{ 'z', "\342\211\245" },
{ '{', "\317\200" },
{ '|', "\342\211\240" },
{ '}', "\302\243" },
{ '~', "\302\267" }
};
int
tty_acs_cmp(const void *key, const void *value)
{
const struct tty_acs_entry *entry = value;
u_char ch;
ch = *(u_char *) key;
return (ch - entry->key);
}
/* Retrieve ACS to output as a string. */
const char *
tty_acs_get(struct tty *tty, u_char ch)
{
struct tty_acs_entry *entry;
/* If not a UTF-8 terminal, use the ACS set. */
if (!(tty->flags & TTY_UTF8)) {
if (tty->term->acs[ch][0] == '\0')
return (NULL);
return (&tty->term->acs[ch][0]);
}
/* Otherwise look up the UTF-8 translation. */
entry = bsearch(&ch,
tty_acs_table, nitems(tty_acs_table), sizeof tty_acs_table[0],
tty_acs_cmp);
if (entry == NULL)
return (NULL);
return (entry->string);
}

View File

@@ -1,4 +1,4 @@
/* $Id: tty-keys.c,v 1.57 2010-06-06 00:23:44 tcunha Exp $ */
/* $Id: tty-keys.c,v 1.55 2009-12-18 18:57:00 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -408,7 +408,7 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
(*size)++;
/* At the end of the string, return the current node. */
if (len == 0 || (tk->next == NULL && tk->key != KEYC_NONE))
if (len == 0)
return (tk);
/* Move into the next tree for the following character. */
@@ -612,8 +612,7 @@ tty_keys_mouse(const char *buf, size_t len, size_t *size, struct mouse_event *m)
return (1);
*size = 6;
log_debug(
"mouse input: %.6s (%hhu,%hhu/%hhu)", buf, buf[4], buf[5], buf[3]);
log_debug("mouse input is: %.6s", buf);
m->b = buf[3];
m->x = buf[4];

View File

@@ -1,4 +1,4 @@
/* $Id: tty-term.c,v 1.43 2010-09-18 15:43:53 tcunha Exp $ */
/* $Id: tty-term.c,v 1.41 2009-12-18 07:42:30 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -252,8 +252,7 @@ tty_term_override(struct tty_term *term, const char *overrides)
} else if (entstr[strlen(entstr) - 1] == '@') {
entstr[strlen(entstr) - 1] = '\0';
removeflag = 1;
} else
continue;
}
for (i = 0; i < NTTYCODE; i++) {
ent = &tty_term_codes[i];
@@ -305,7 +304,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
u_int i;
int n, error;
char *s;
const char *acs;
SLIST_FOREACH(term, &tty_terms, entry) {
if (strcmp(term->name, name) == 0) {
@@ -319,7 +317,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
term->name = xstrdup(name);
term->references = 1;
term->flags = 0;
memset(term->codes, 0, sizeof term->codes);
memset(&term->codes, 0, sizeof term->codes);
SLIST_INSERT_HEAD(&tty_terms, term, entry);
/* Set up curses terminal. */
@@ -417,15 +415,6 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
if (!tty_term_flag(term, TTYC_XENL))
term->flags |= TERM_EARLYWRAP;
/* Generate ACS table. If none is present, use nearest ASCII. */
memset(term->acs, 0, sizeof term->acs);
if (tty_term_has(term, TTYC_ACSC))
acs = tty_term_string(term, TTYC_ACSC);
else
acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~.";
for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2)
term->acs[(u_char) acs[0]][0] = acs[1];
return (term);
error:

124
tty.c
View File

@@ -1,4 +1,4 @@
/* $Id: tty.c,v 1.197 2010-12-06 21:57:56 nicm Exp $ */
/* $Id: tty.c,v 1.189 2010-03-08 14:53:49 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,6 +31,8 @@
void tty_read_callback(struct bufferevent *, void *);
void tty_error_callback(struct bufferevent *, short, void *);
void tty_fill_acs(struct tty *);
int tty_try_256(struct tty *, u_char, const char *);
int tty_try_88(struct tty *, u_char, const char *);
@@ -46,9 +48,6 @@ void tty_emulate_repeat(
void tty_cell(struct tty *,
const struct grid_cell *, const struct grid_utf8 *);
#define tty_use_acs(tty) \
(tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
void
tty_init(struct tty *tty, int fd, char *term)
{
@@ -61,6 +60,9 @@ tty_init(struct tty *tty, int fd, char *term)
tty->termname = xstrdup("unknown");
else
tty->termname = xstrdup(term);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
tty->fd = fd;
if ((path = ttyname(fd)) == NULL)
@@ -71,55 +73,34 @@ tty_init(struct tty *tty, int fd, char *term)
tty->term_flags = 0;
}
int
void
tty_resize(struct tty *tty)
{
struct winsize ws;
u_int sx, sy;
if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) {
sx = ws.ws_col;
if (sx == 0)
sx = 80;
sy = ws.ws_row;
if (sy == 0)
sy = 24;
} else {
sx = 80;
sy = 24;
tty->sx = ws.ws_col;
tty->sy = ws.ws_row;
}
if (sx == tty->sx && sy == tty->sy)
return (0);
tty->sx = sx;
tty->sy = sy;
if (tty->sx == 0)
tty->sx = 80;
if (tty->sy == 0)
tty->sy = 24;
tty->cx = UINT_MAX;
tty->cy = UINT_MAX;
tty->rupper = UINT_MAX;
tty->rlower = UINT_MAX;
/*
* If the terminal has been started, reset the actual scroll region and
* cursor position, as this may not have happened.
*/
if (tty->flags & TTY_STARTED) {
tty_cursor(tty, 0, 0);
tty_region(tty, 0, tty->sy - 1);
}
return (1);
}
int
tty_open(struct tty *tty, const char *overrides, char **cause)
{
char out[64];
int fd;
if (debug_level > 3) {
xsnprintf(out, sizeof out, "tmux-out-%ld.log", (long) getpid());
fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644);
fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
tty->log_fd = fd;
@@ -141,6 +122,8 @@ tty_open(struct tty *tty, const char *overrides, char **cause)
tty_keys_init(tty);
tty_fill_acs(tty);
return (0);
}
@@ -197,8 +180,7 @@ tty_start_tty(struct tty *tty)
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
tty_putcode(tty, TTYC_RMKX);
if (tty_use_acs(tty))
tty_putcode(tty, TTYC_ENACS);
tty_putcode(tty, TTYC_ENACS);
tty_putcode(tty, TTYC_CLEAR);
tty_putcode(tty, TTYC_CNORM);
@@ -239,8 +221,7 @@ tty_stop_tty(struct tty *tty)
return;
tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1));
if (tty_use_acs(tty))
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
@@ -255,6 +236,30 @@ tty_stop_tty(struct tty *tty)
fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK);
}
void
tty_fill_acs(struct tty *tty)
{
const char *ptr;
memset(tty->acs, 0, sizeof tty->acs);
if (!tty_term_has(tty->term, TTYC_ACSC))
return;
ptr = tty_term_string(tty->term, TTYC_ACSC);
if (strlen(ptr) % 2 != 0)
return;
for (; *ptr != '\0'; ptr += 2)
tty->acs[(u_char) ptr[0]] = ptr[1];
}
u_char
tty_get_acs(struct tty *tty, u_char ch)
{
if (tty->acs[ch] != '\0')
return (tty->acs[ch]);
return (ch);
}
void
tty_close(struct tty *tty)
{
@@ -334,17 +339,11 @@ tty_puts(struct tty *tty, const char *s)
void
tty_putc(struct tty *tty, u_char ch)
{
const char *acs;
u_int sx;
u_int sx;
if (tty->cell.attr & GRID_ATTR_CHARSET) {
acs = tty_acs_get(tty, ch);
if (acs != NULL)
bufferevent_write(tty->event, acs, strlen(acs));
else
bufferevent_write(tty->event, &ch, 1);
} else
bufferevent_write(tty->event, &ch, 1);
if (tty->cell.attr & GRID_ATTR_CHARSET)
ch = tty_get_acs(tty, ch);
bufferevent_write(tty->event, &ch, 1);
if (ch >= 0x20 && ch != 0x7f) {
sx = tty->sx;
@@ -403,18 +402,11 @@ tty_update_mode(struct tty *tty, int mode)
else
tty_putcode(tty, TTYC_CIVIS);
}
if (changed & (MODE_MOUSE|MODE_MOUSEMOTION)) {
if (mode & MODE_MOUSE) {
if (mode & MODE_MOUSEMOTION)
tty_puts(tty, "\033[?1003h");
else
tty_puts(tty, "\033[?1000h");
} else {
if (mode & MODE_MOUSEMOTION)
tty_puts(tty, "\033[?1003l");
else
tty_puts(tty, "\033[?1000l");
}
if (changed & MODE_MOUSE) {
if (mode & MODE_MOUSE)
tty_puts(tty, "\033[?1000h");
else
tty_puts(tty, "\033[?1000l");
}
if (changed & MODE_KKEYPAD) {
if (mode & MODE_KKEYPAD)
@@ -547,7 +539,7 @@ tty_write(void (*cmdfn)(
if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW)
return;
if (!window_pane_visible(wp))
if (wp->window->flags & WINDOW_HIDDEN || !window_pane_visible(wp))
return;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -558,9 +550,7 @@ tty_write(void (*cmdfn)(
continue;
if (c->session->curw->window == wp->window) {
if (c->tty.term == NULL)
continue;
if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF))
if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL)
continue;
cmdfn(&c->tty, ctx);
}
@@ -977,7 +967,7 @@ tty_reset(struct tty *tty)
if (memcmp(gc, &grid_default_cell, sizeof *gc) == 0)
return;
if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty))
if (tty_term_has(tty->term, TTYC_RMACS) && gc->attr & GRID_ATTR_CHARSET)
tty_putcode(tty, TTYC_RMACS);
tty_putcode(tty, TTYC_SGR0);
memcpy(gc, &grid_default_cell, sizeof *gc);
@@ -1093,7 +1083,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
* Use HPA if change is larger than absolute, otherwise move
* the cursor with CUB/CUF.
*/
if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
if (abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
tty_putcode1(tty, TTYC_HPA, cx);
goto out;
} else if (change > 0 && tty_term_has(term, TTYC_CUB)) {
@@ -1129,7 +1119,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
* Try to use VPA if change is larger than absolute or if this
* change would cross the scroll region, otherwise use CUU/CUD.
*/
if ((u_int) abs(change) > cy ||
if (abs(change) > cy ||
(change < 0 && cy - change > tty->rlower) ||
(change > 0 && cy - change < tty->rupper)) {
if (tty_term_has(term, TTYC_VPA)) {
@@ -1214,7 +1204,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc)
}
if (changed & GRID_ATTR_HIDDEN)
tty_putcode(tty, TTYC_INVIS);
if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty))
if (changed & GRID_ATTR_CHARSET)
tty_putcode(tty, TTYC_SMACS);
}

View File

@@ -1,4 +1,4 @@
/* $Id: window-choose.c,v 1.30 2010-05-22 21:56:04 micahcowan Exp $ */
/* $Id: window-choose.c,v 1.29 2010-02-02 23:55:21 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -25,9 +25,9 @@
struct screen *window_choose_init(struct window_pane *);
void window_choose_free(struct window_pane *);
void window_choose_resize(struct window_pane *, u_int, u_int);
void window_choose_key(struct window_pane *, struct session *, int);
void window_choose_key(struct window_pane *, struct client *, int);
void window_choose_mouse(
struct window_pane *, struct session *, struct mouse_event *);
struct window_pane *, struct client *, struct mouse_event *);
void window_choose_redraw_screen(struct window_pane *);
void window_choose_write_line(
@@ -171,7 +171,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
/* ARGSUSED */
void
window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
window_choose_key(struct window_pane *wp, unused struct client *c, int key)
{
struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -304,7 +304,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
/* ARGSUSED */
void
window_choose_mouse(
struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
struct window_pane *wp, unused struct client *c, struct mouse_event *m)
{
struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen;

View File

@@ -1,4 +1,4 @@
/* $Id: window-clock.c,v 1.12 2010-05-22 21:56:04 micahcowan Exp $ */
/* $Id: window-clock.c,v 1.11 2009-12-04 22:14:47 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,7 +26,7 @@
struct screen *window_clock_init(struct window_pane *);
void window_clock_free(struct window_pane *);
void window_clock_resize(struct window_pane *, u_int, u_int);
void window_clock_key(struct window_pane *, struct session *, int);
void window_clock_key(struct window_pane *, struct client *, int);
void window_clock_timer(struct window_pane *);
void window_clock_draw_screen(struct window_pane *);
@@ -85,7 +85,7 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy)
/* ARGSUSED */
void
window_clock_key(
struct window_pane *wp, unused struct session *sess, unused int key)
struct window_pane *wp, unused struct client *c, unused int key)
{
window_pane_reset_mode(wp);
}

View File

@@ -1,4 +1,4 @@
/* $Id: window-copy.c,v 1.125 2010-12-11 17:57:28 nicm Exp $ */
/* $Id: window-copy.c,v 1.109 2010-03-08 15:02:07 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,11 +26,11 @@
struct screen *window_copy_init(struct window_pane *);
void window_copy_free(struct window_pane *);
void window_copy_resize(struct window_pane *, u_int, u_int);
void window_copy_key(struct window_pane *, struct session *, int);
void window_copy_key(struct window_pane *, struct client *, int);
int window_copy_key_input(struct window_pane *, int);
int window_copy_key_numeric_prefix(struct window_pane *, int);
void window_copy_mouse(
struct window_pane *, struct session *, struct mouse_event *);
struct window_pane *, struct client *, struct mouse_event *);
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
void window_copy_redraw_screen(struct window_pane *);
@@ -52,7 +52,7 @@ void window_copy_goto_line(struct window_pane *, const char *);
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
void window_copy_start_selection(struct window_pane *);
int window_copy_update_selection(struct window_pane *);
void window_copy_copy_selection(struct window_pane *, struct session *);
void window_copy_copy_selection(struct window_pane *, struct client *);
void window_copy_clear_selection(struct window_pane *);
void window_copy_copy_line(
struct window_pane *, char **, size_t *, u_int, u_int, u_int);
@@ -65,8 +65,6 @@ void window_copy_cursor_left(struct window_pane *);
void window_copy_cursor_right(struct window_pane *);
void window_copy_cursor_up(struct window_pane *, int);
void window_copy_cursor_down(struct window_pane *, int);
void window_copy_cursor_jump(struct window_pane *);
void window_copy_cursor_jump_back(struct window_pane *);
void window_copy_cursor_next_word(struct window_pane *, const char *);
void window_copy_cursor_next_word_end(struct window_pane *, const char *);
void window_copy_cursor_previous_word(struct window_pane *, const char *);
@@ -88,33 +86,12 @@ enum window_copy_input_type {
WINDOW_COPY_NUMERICPREFIX,
WINDOW_COPY_SEARCHUP,
WINDOW_COPY_SEARCHDOWN,
WINDOW_COPY_JUMPFORWARD,
WINDOW_COPY_JUMPBACK,
WINDOW_COPY_GOTOLINE,
};
/*
* Copy-mode's visible screen (the "screen" field) is filled from one of
* two sources: the original contents of the pane (used when we
* actually enter via the "copy-mode" command, to copy the contents of
* the current pane), or else a series of lines containing the output
* from an output-writing tmux command (such as any of the "show-*" or
* "list-*" commands).
*
* In either case, the full content of the copy-mode grid is pointed at
* by the "backing" field, and is copied into "screen" as needed (that
* is, when scrolling occurs). When copy-mode is backed by a pane,
* backing points directly at that pane's screen structure (&wp->base);
* when backed by a list of output-lines from a command, it points at
* a newly-allocated screen structure (which is deallocated when the
* mode ends).
*/
struct window_copy_mode_data {
struct screen screen;
struct screen *backing;
int backing_written; /* backing display has started */
struct mode_key_data mdata;
u_int oy;
@@ -138,9 +115,6 @@ struct window_copy_mode_data {
enum window_copy_input_type searchtype;
char *searchstr;
enum window_copy_input_type jumptype;
char jumpchar;
};
struct screen *
@@ -148,18 +122,18 @@ window_copy_init(struct window_pane *wp)
{
struct window_copy_mode_data *data;
struct screen *s;
struct screen_write_ctx ctx;
u_int i;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
data->oy = 0;
data->cx = 0;
data->cy = 0;
data->cx = wp->base.cx;
data->cy = wp->base.cy;
data->lastcx = 0;
data->lastsx = 0;
data->backing_written = 0;
data->rectflag = 0;
data->inputtype = WINDOW_COPY_OFF;
@@ -171,11 +145,7 @@ window_copy_init(struct window_pane *wp)
data->searchstr = NULL;
wp->flags |= PANE_FREEZE;
if (wp->fd != -1)
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
data->jumptype = WINDOW_COPY_OFF;
data->jumpchar = '\0';
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
@@ -188,26 +158,6 @@ window_copy_init(struct window_pane *wp)
else
mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
data->backing = NULL;
return (s);
}
void
window_copy_init_from_pane(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
if (wp->mode != &window_copy_mode)
fatalx("not in copy mode");
data->backing = &wp->base;
data->cx = data->backing->cx;
data->cy = data->backing->cy;
s->cx = data->cx;
s->cy = data->cy;
@@ -216,17 +166,8 @@ window_copy_init_from_pane(struct window_pane *wp)
window_copy_write_line(wp, &ctx, i);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
void
window_copy_init_for_output(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
data->backing = xmalloc(sizeof *data->backing);
screen_init(data->backing, screen_size_x(&wp->base),
screen_size_y(&wp->base), UINT_MAX);
data->backing->mode &= ~MODE_WRAP;
return (s);
}
void
@@ -235,80 +176,17 @@ window_copy_free(struct window_pane *wp)
struct window_copy_mode_data *data = wp->modedata;
wp->flags &= ~PANE_FREEZE;
if (wp->fd != -1)
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
if (data->searchstr != NULL)
xfree(data->searchstr);
xfree(data->inputstr);
if (data->backing != &wp->base) {
screen_free(data->backing);
xfree(data->backing);
}
screen_free(&data->screen);
xfree(data);
}
void
window_copy_add(struct window_pane *wp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
window_copy_vadd(wp, fmt, ap);
va_end(ap);
}
void
window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *backing = data->backing;
struct screen_write_ctx back_ctx, ctx;
struct grid_cell gc;
int utf8flag;
u_int old_hsize;
if (backing == &wp->base)
return;
utf8flag = options_get_number(&wp->window->options, "utf8");
memcpy(&gc, &grid_default_cell, sizeof gc);
old_hsize = screen_hsize(data->backing);
screen_write_start(&back_ctx, NULL, backing);
if (data->backing_written) {
/*
* On the second or later line, do a CRLF before writing
* (so it's on a new line).
*/
screen_write_carriagereturn(&back_ctx);
screen_write_linefeed(&back_ctx, 0);
} else
data->backing_written = 1;
screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap);
screen_write_stop(&back_ctx);
data->oy += screen_hsize(data->backing) - old_hsize;
screen_write_start(&ctx, wp, &data->screen);
/*
* If the history has changed, draw the top line.
* (If there's any history at all, it has changed.)
*/
if (screen_hsize(data->backing))
window_copy_redraw_lines(wp, 0, 1);
/* Write the line, if it's visible. */
if (backing->cy + data->oy < screen_size_y(backing))
window_copy_redraw_lines(wp, backing->cy, 1);
screen_write_stop(&ctx);
}
void
window_copy_pageup(struct window_pane *wp)
{
@@ -319,8 +197,8 @@ window_copy_pageup(struct window_pane *wp)
n = 1;
if (screen_size_y(s) > 2)
n = screen_size_y(s) - 2;
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
else
data->oy += n;
window_copy_update_selection(wp);
@@ -335,15 +213,11 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
struct screen_write_ctx ctx;
screen_resize(s, sx, sy);
if (data->backing != &wp->base)
screen_resize(data->backing, sx, sy);
if (data->cy > sy - 1)
data->cy = sy - 1;
if (data->cx > sx)
data->cx = sx;
if (data->oy > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
window_copy_clear_selection(wp);
@@ -355,7 +229,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
}
void
window_copy_key(struct window_pane *wp, struct session *sess, int key)
window_copy_key(struct window_pane *wp, struct client *c, int key)
{
const char *word_separators;
struct window_copy_mode_data *data = wp->modedata;
@@ -368,24 +242,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
if (np == 0)
np = 1;
if (data->inputtype == WINDOW_COPY_JUMPFORWARD
|| data->inputtype == WINDOW_COPY_JUMPBACK) {
/* Ignore keys with modifiers. */
if ((key & KEYC_MASK_MOD) == 0) {
data->jumpchar = key;
if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
for (; np != 0; np--)
window_copy_cursor_jump(wp);
} else {
for (; np != 0; np--)
window_copy_cursor_jump_back(wp);
}
}
data->jumptype = data->inputtype;
data->inputtype = WINDOW_COPY_OFF;
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return;
} if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
if (window_copy_key_numeric_prefix(wp, key) == 0)
return;
data->inputtype = WINDOW_COPY_OFF;
@@ -399,8 +256,9 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
cmd = mode_key_lookup(&data->mdata, key);
switch (cmd) {
case MODEKEYCOPY_CANCEL:
window_pane_reset_mode(wp);
return;
for (; np != 0; np--)
window_pane_reset_mode(wp);
break;
case MODEKEYCOPY_LEFT:
for (; np != 0; np--)
window_copy_cursor_left(wp);
@@ -445,8 +303,8 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
case MODEKEYCOPY_HALFPAGEUP:
n = screen_size_y(s) / 2;
for (; np != 0; np--) {
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
else
data->oy += n;
}
@@ -485,7 +343,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
case MODEKEYCOPY_HISTORYTOP:
data->cx = 0;
data->cy = 0;
data->oy = screen_hsize(data->backing);
data->oy = screen_hsize(&wp->base);
window_copy_update_selection(wp);
window_copy_redraw_screen(wp);
break;
@@ -505,10 +363,9 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
window_copy_redraw_screen(wp);
break;
case MODEKEYCOPY_COPYSELECTION:
if (sess != NULL) {
window_copy_copy_selection(wp, sess);
if (c != NULL && c->session != NULL) {
window_copy_copy_selection(wp, c);
window_pane_reset_mode(wp);
return;
}
break;
case MODEKEYCOPY_STARTOFLINE:
@@ -550,36 +407,6 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
for (; np != 0; np--)
window_copy_cursor_previous_word(wp, word_separators);
break;
case MODEKEYCOPY_JUMP:
data->inputtype = WINDOW_COPY_JUMPFORWARD;
data->inputprompt = "Jump Forward";
*data->inputstr = '\0';
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return; /* skip numprefix reset */
case MODEKEYCOPY_JUMPAGAIN:
if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
for (; np != 0; np--)
window_copy_cursor_jump(wp);
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
for (; np != 0; np--)
window_copy_cursor_jump_back(wp);
}
break;
case MODEKEYCOPY_JUMPREVERSE:
if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
for (; np != 0; np--)
window_copy_cursor_jump_back(wp);
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
for (; np != 0; np--)
window_copy_cursor_jump(wp);
}
break;
case MODEKEYCOPY_JUMPBACK:
data->inputtype = WINDOW_COPY_JUMPBACK;
data->inputprompt = "Jump Back";
*data->inputstr = '\0';
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return; /* skip numprefix reset */
case MODEKEYCOPY_SEARCHUP:
data->inputtype = WINDOW_COPY_SEARCHUP;
data->inputprompt = "Search Up";
@@ -593,8 +420,6 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
switch (data->searchtype) {
case WINDOW_COPY_OFF:
case WINDOW_COPY_GOTOLINE:
case WINDOW_COPY_JUMPFORWARD:
case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
@@ -631,7 +456,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
*data->inputstr = '\0';
goto input_on;
case MODEKEYCOPY_STARTNUMBERPREFIX:
key &= KEYC_MASK_KEY;
key &= 0xff;
if (key >= '0' && key <= '9') {
data->inputtype = WINDOW_COPY_NUMERICPREFIX;
data->numprefix = 0;
@@ -699,8 +524,6 @@ window_copy_key_input(struct window_pane *wp, int key)
switch (data->inputtype) {
case WINDOW_COPY_OFF:
case WINDOW_COPY_JUMPFORWARD:
case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
@@ -745,7 +568,7 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
key &= KEYC_MASK_KEY;
key &= 0xff;
if (key < '0' || key > '9')
return 1;
@@ -760,63 +583,29 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
/* ARGSUSED */
void
window_copy_mouse(
struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
struct window_pane *wp, unused struct client *c, struct mouse_event *m)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int i;
if ((m->b & 3) == 3)
return;
if (m->x >= screen_size_x(s))
return;
if (m->y >= screen_size_y(s))
return;
/* If mouse wheel (buttons 4 and 5), scroll. */
if ((m->b & MOUSE_45)) {
if ((m->b & MOUSE_BUTTON) == MOUSE_1) {
for (i = 0; i < 5; i++)
window_copy_cursor_up(wp, 0);
} else if ((m->b & MOUSE_BUTTON) == MOUSE_2) {
for (i = 0; i < 5; i++)
window_copy_cursor_down(wp, 0);
}
return;
}
/*
* If already reading motion, move the cursor while buttons are still
* pressed, or stop the selection on their release.
*/
if (s->mode & MODE_MOUSEMOTION) {
if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
window_copy_update_cursor(wp, m->x, m->y);
if (window_copy_update_selection(wp))
window_copy_redraw_screen(wp);
} else {
s->mode &= ~MODE_MOUSEMOTION;
if (sess != NULL) {
window_copy_copy_selection(wp, sess);
window_pane_reset_mode(wp);
}
}
return;
}
/* Otherwise i other buttons pressed, start selection and motion. */
if ((m->b & MOUSE_BUTTON) != MOUSE_UP) {
s->mode |= MODE_MOUSEMOTION;
window_copy_update_cursor(wp, m->x, m->y);
window_copy_start_selection(wp);
window_copy_update_cursor(wp, m->x, m->y);
if (window_copy_update_selection(wp))
window_copy_redraw_screen(wp);
}
}
void
window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
{
struct window_copy_mode_data *data = wp->modedata;
struct grid *gd = data->backing->grid;
struct screen *s = &wp->base;
struct grid *gd = s->grid;
u_int offset, gap;
data->cx = px;
@@ -911,7 +700,7 @@ void
window_copy_search_up(struct window_pane *wp, const char *searchstr)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing, ss;
struct screen *s = &wp->base, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
@@ -968,7 +757,7 @@ void
window_copy_search_down(struct window_pane *wp, const char *searchstr)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing, ss;
struct screen *s = &wp->base, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
@@ -1028,7 +817,7 @@ window_copy_goto_line(struct window_pane *wp, const char *linestr)
const char *errstr;
u_int lineno;
lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr);
if (errstr != NULL)
return;
@@ -1056,9 +845,7 @@ window_copy_write_line(
last = screen_size_y(s) - 1;
if (py == 0) {
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->oy, screen_hsize(data->backing));
if (size > screen_size_x(s))
size = screen_size_x(s);
"[%u/%u]", data->oy, screen_hsize(&wp->base));
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
screen_write_puts(ctx, &gc, "%s", hdr);
} else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
@@ -1075,9 +862,8 @@ window_copy_write_line(
size = 0;
screen_write_cursormove(ctx, xoff, py);
screen_write_copy(ctx, data->backing, xoff,
(screen_hsize(data->backing) - data->oy) + py,
screen_size_x(s) - size, 1);
screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) -
data->oy) + py, screen_size_x(s) - size, 1);
if (py == data->cy && data->cx == screen_size_x(s)) {
memcpy(&gc, &grid_default_cell, sizeof gc);
@@ -1146,7 +932,7 @@ window_copy_start_selection(struct window_pane *wp)
struct screen *s = &data->screen;
data->selx = data->cx;
data->sely = screen_hsize(data->backing) + data->cy - data->oy;
data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
s->sel.flag = 1;
window_copy_update_selection(wp);
@@ -1171,7 +957,7 @@ window_copy_update_selection(struct window_pane *wp)
gc.attr |= options_get_number(oo, "mode-attr");
/* Find top of screen. */
ty = screen_hsize(data->backing) - data->oy;
ty = screen_hsize(&wp->base) - data->oy;
/* Adjust the selection. */
sx = data->selx;
@@ -1208,7 +994,7 @@ window_copy_update_selection(struct window_pane *wp)
}
void
window_copy_copy_selection(struct window_pane *wp, struct session *sess)
window_copy_copy_selection(struct window_pane *wp, struct client *c)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -1232,7 +1018,7 @@ window_copy_copy_selection(struct window_pane *wp, struct session *sess)
/* Find start and end. */
xx = data->cx;
yy = screen_hsize(data->backing) + data->cy - data->oy;
yy = screen_hsize(&wp->base) + data->cy - data->oy;
if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
sx = xx; sy = yy;
ex = data->selx; ey = data->sely;
@@ -1267,8 +1053,8 @@ window_copy_copy_selection(struct window_pane *wp, struct session *sess)
/* Cursor is on the left. */
lastex = data->selx + 1;
restex = data->selx + 1;
firstsx = data->cx;
restsx = data->cx;
firstsx = data->cx + 1;
restsx = data->cx + 1;
}
} else {
/*
@@ -1303,21 +1089,20 @@ window_copy_copy_selection(struct window_pane *wp, struct session *sess)
off--; /* remove final \n */
/* Add the buffer to the stack. */
limit = options_get_number(&sess->options, "buffer-limit");
paste_add(&sess->buffers, buf, off, limit);
limit = options_get_number(&c->session->options, "buffer-limit");
paste_add(&c->session->buffers, buf, off, limit);
}
void
window_copy_copy_line(struct window_pane *wp,
char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
{
struct window_copy_mode_data *data = wp->modedata;
struct grid *gd = data->backing->grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
struct grid_line *gl;
u_int i, xx, wrapped = 0;
size_t size;
struct grid *gd = wp->base.grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
struct grid_line *gl;
u_int i, xx, wrapped = 0;
size_t size;
if (sx > ex)
return;
@@ -1372,7 +1157,7 @@ window_copy_clear_selection(struct window_pane *wp)
screen_clear_selection(&data->screen);
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx > px)
window_copy_update_cursor(wp, px, data->cy);
@@ -1381,10 +1166,9 @@ window_copy_clear_selection(struct window_pane *wp)
int
window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
{
struct window_copy_mode_data *data = wp->modedata;
const struct grid_cell *gc;
const struct grid_cell *gc;
gc = grid_peek_cell(data->backing->grid, px, py);
gc = grid_peek_cell(wp->base.grid, px, py);
if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
return (0);
if (gc->data == 0x00 || gc->data == 0x7f)
@@ -1395,10 +1179,8 @@ window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
u_int
window_copy_find_length(struct window_pane *wp, u_int py)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing;
const struct grid_cell *gc;
u_int px;
const struct grid_cell *gc;
u_int px;
/*
* If the pane has been resized, its grid can contain old overlong
@@ -1406,11 +1188,11 @@ window_copy_find_length(struct window_pane *wp, u_int py)
* width of the grid, and screen_write_copy treats them as spaces, so
* ignore them here too.
*/
px = s->grid->linedata[py].cellsize;
if (px > screen_size_x(s))
px = screen_size_x(s);
px = wp->base.grid->linedata[py].cellsize;
if (px > screen_size_x(&wp->base))
px = screen_size_x(&wp->base);
while (px > 0) {
gc = grid_peek_cell(s->grid, px - 1, py);
gc = grid_peek_cell(wp->base.grid, px - 1, py);
if (gc->flags & GRID_FLAG_UTF8)
break;
if (gc->data != ' ')
@@ -1424,17 +1206,7 @@ void
window_copy_cursor_start_of_line(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct grid *gd = back_s->grid;
u_int py;
if (data->cx == 0) {
py = screen_hsize(back_s) + data->cy - data->oy;
while (py > 0 && gd->linedata[py-1].flags & GRID_LINE_WRAPPED) {
window_copy_cursor_up(wp, 0);
py = screen_hsize(back_s) + data->cy - data->oy;
}
}
window_copy_update_cursor(wp, 0, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
@@ -1448,11 +1220,11 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp)
const struct grid_cell *gc;
px = 0;
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
while (px < xx) {
gc = grid_peek_cell(data->backing->grid, px, py);
gc = grid_peek_cell(wp->base.grid, px, py);
if (gc->flags & GRID_FLAG_UTF8)
break;
if (gc->data != ' ')
@@ -1469,22 +1241,21 @@ void
window_copy_cursor_end_of_line(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct grid *gd = back_s->grid;
struct screen *base_s = &wp->base;
struct grid *gd = base_s->grid;
u_int px, py;
py = screen_hsize(back_s) + data->cy - data->oy;
py = screen_hsize(base_s) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx == px) {
if (data->screen.sel.flag && data->rectflag)
px = screen_size_x(back_s);
px = screen_size_x(&wp->base);
if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
while (py < gd->sy + gd->hsize &&
gd->linedata[py].flags & GRID_LINE_WRAPPED) {
window_copy_cursor_down(wp, 0);
py = screen_hsize(back_s)
+ data->cy - data->oy;
py = screen_hsize(base_s) + data->cy - data->oy;
}
px = window_copy_find_length(wp, py);
}
@@ -1519,7 +1290,7 @@ window_copy_cursor_right(struct window_pane *wp)
if (data->screen.sel.flag && data->rectflag)
px = screen_size_x(&data->screen);
else {
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
}
@@ -1540,7 +1311,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
struct screen *s = &data->screen;
u_int ox, oy, px, py;
oy = screen_hsize(data->backing) + data->cy - data->oy;
oy = screen_hsize(&wp->base) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (ox != 0) {
data->lastcx = data->cx;
@@ -1567,7 +1338,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
}
if (!data->screen.sel.flag || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
data->cx > px)
@@ -1582,7 +1353,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
struct screen *s = &data->screen;
u_int ox, oy, px, py;
oy = screen_hsize(data->backing) + data->cy - data->oy;
oy = screen_hsize(&wp->base) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (ox != 0) {
data->lastcx = data->cx;
@@ -1601,7 +1372,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
}
if (!data->screen.sel.flag || !data->rectflag) {
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
data->cx > px)
@@ -1609,74 +1380,18 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
}
}
void
window_copy_cursor_jump(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
const struct grid_cell *gc;
uint px, py, xx;
px = data->cx + 1;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
while (px < xx) {
gc = grid_peek_cell(back_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
window_copy_update_cursor(wp, px, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
return;
}
px++;
}
}
void
window_copy_cursor_jump_back(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
const struct grid_cell *gc;
uint px, py;
px = data->cx;
py = screen_hsize(back_s) + data->cy - data->oy;
if (px > 0)
px--;
for (;;) {
gc = grid_peek_cell(back_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
window_copy_update_cursor(wp, px, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
return;
}
if (px == 0)
break;
px--;
}
}
void
window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct screen *base_s = &wp->base;
u_int px, py, xx, yy;
int expected = 0;
px = data->cx;
py = screen_hsize(back_s) + data->cy - data->oy;
py = screen_hsize(base_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
/*
* First skip past any nonword characters and then any word characters.
@@ -1694,7 +1409,7 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
window_copy_cursor_down(wp, 0);
px = 0;
py = screen_hsize(back_s) + data->cy - data->oy;
py = screen_hsize(base_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
} else
px++;
@@ -1711,14 +1426,14 @@ void
window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *back_s = data->backing;
struct screen *base_s = &wp->base;
u_int px, py, xx, yy;
int expected = 1;
px = data->cx;
py = screen_hsize(back_s) + data->cy - data->oy;
py = screen_hsize(base_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
/*
* First skip past any word characters, then any nonword characters.
@@ -1736,7 +1451,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
window_copy_cursor_down(wp, 0);
px = 0;
py = screen_hsize(back_s) + data->cy - data->oy;
py = screen_hsize(base_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
} else
px++;
@@ -1757,7 +1472,7 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
u_int px, py;
px = data->cx;
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
/* Move back to the previous word character. */
for (;;) {
@@ -1767,12 +1482,12 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
break;
} else {
if (data->cy == 0 &&
(screen_hsize(data->backing) == 0 ||
data->oy >= screen_hsize(data->backing) - 1))
(screen_hsize(&wp->base) == 0 ||
data->oy >= screen_hsize(&wp->base) - 1))
goto out;
window_copy_cursor_up(wp, 0);
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
}
}
@@ -1825,11 +1540,11 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (ny > screen_hsize(data->backing))
if (ny > screen_hsize(&wp->base))
return;
if (data->oy > screen_hsize(data->backing) - ny)
ny = screen_hsize(data->backing) - data->oy;
if (data->oy > screen_hsize(&wp->base) - ny)
ny = screen_hsize(&wp->base) - data->oy;
if (ny == 0)
return;
data->oy += ny;
@@ -1856,7 +1571,7 @@ window_copy_rectangle_toggle(struct window_pane *wp)
data->rectflag = !data->rectflag;
py = screen_hsize(data->backing) + data->cy - data->oy;
py = screen_hsize(&wp->base) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx > px)
window_copy_update_cursor(wp, px, data->cy);

260
window-more.c Normal file
View File

@@ -0,0 +1,260 @@
/* $Id: window-more.c,v 1.42 2010-02-08 18:10:07 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_more_init(struct window_pane *);
void window_more_free(struct window_pane *);
void window_more_resize(struct window_pane *, u_int, u_int);
void window_more_key(struct window_pane *, struct client *, int);
void window_more_redraw_screen(struct window_pane *);
void window_more_write_line(
struct window_pane *, struct screen_write_ctx *, u_int);
void window_more_scroll_up(struct window_pane *);
void window_more_scroll_down(struct window_pane *);
const struct window_mode window_more_mode = {
window_more_init,
window_more_free,
window_more_resize,
window_more_key,
NULL,
NULL,
};
struct window_more_mode_data {
struct screen screen;
struct mode_key_data mdata;
ARRAY_DECL(, char *) list;
u_int top;
};
void
window_more_add(struct window_pane *wp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
window_more_vadd(wp, fmt, ap);
va_end(ap);
}
void
window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
char *msg;
u_int size;
xvasprintf(&msg, fmt, ap);
ARRAY_ADD(&data->list, msg);
screen_write_start(&ctx, wp, NULL);
size = ARRAY_LENGTH(&data->list) - 1;
if (size >= data->top && size <= data->top + screen_size_y(s) - 1) {
window_more_write_line(wp, &ctx, size - data->top);
if (size != data->top)
window_more_write_line(wp, &ctx, 0);
} else
window_more_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}
struct screen *
window_more_init(struct window_pane *wp)
{
struct window_more_mode_data *data;
struct screen *s;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
ARRAY_INIT(&data->list);
data->top = 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_choice);
else
mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
return (s);
}
void
window_more_free(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
xfree(ARRAY_ITEM(&data->list, i));
ARRAY_FREE(&data->list);
screen_free(&data->screen);
xfree(data);
}
void
window_more_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
screen_resize(s, sx, sy);
window_more_redraw_screen(wp);
}
/* ARGSUSED */
void
window_more_key(struct window_pane *wp, unused struct client *c, int key)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
switch (mode_key_lookup(&data->mdata, key)) {
case MODEKEYCHOICE_CANCEL:
window_pane_reset_mode(wp);
break;
case MODEKEYCHOICE_UP:
case MODEKEYCHOICE_SCROLLUP:
window_more_scroll_up(wp);
break;
case MODEKEYCHOICE_DOWN:
case MODEKEYCHOICE_SCROLLDOWN:
window_more_scroll_down(wp);
break;
case MODEKEYCHOICE_PAGEUP:
if (data->top < screen_size_y(s))
data->top = 0;
else
data->top -= screen_size_y(s);
window_more_redraw_screen(wp);
break;
case MODEKEYCHOICE_PAGEDOWN:
if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list))
data->top = ARRAY_LENGTH(&data->list);
else
data->top += screen_size_y(s);
window_more_redraw_screen(wp);
break;
default:
break;
}
}
void
window_more_write_line(
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct options *oo = &wp->window->options;
struct grid_cell gc;
char *msg, hdr[32];
size_t size;
int utf8flag;
utf8flag = options_get_number(&wp->window->options, "utf8");
memcpy(&gc, &grid_default_cell, sizeof gc);
if (py == 0) {
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->top, ARRAY_LENGTH(&data->list));
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
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_puts(ctx, &gc, "%s", hdr);
memcpy(&gc, &grid_default_cell, sizeof gc);
} else
size = 0;
screen_write_cursormove(ctx, 0, py);
if (data->top + py < ARRAY_LENGTH(&data->list)) {
msg = ARRAY_ITEM(&data->list, data->top + py);
screen_write_nputs(
ctx, screen_size_x(s) - size, &gc, utf8flag, "%s", msg);
}
while (s->cx < screen_size_x(s) - size)
screen_write_putc(ctx, &gc, ' ');
}
void
window_more_redraw_screen(struct window_pane *wp)
{
struct window_more_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_more_write_line(wp, &ctx, i);
screen_write_stop(&ctx);
}
void
window_more_scroll_up(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen_write_ctx ctx;
if (data->top == 0)
return;
data->top--;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, 1);
window_more_write_line(wp, &ctx, 0);
window_more_write_line(wp, &ctx, 1);
screen_write_stop(&ctx);
}
void
window_more_scroll_down(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (data->top >= ARRAY_LENGTH(&data->list))
return;
data->top++;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_deleteline(&ctx, 1);
window_more_write_line(wp, &ctx, screen_size_y(s) - 1);
window_more_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}

335
window.c
View File

@@ -1,4 +1,4 @@
/* $Id: window.c,v 1.142 2010-12-06 22:52:21 nicm Exp $ */
/* $Id: window.c,v 1.126 2010-02-08 18:10:07 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,6 +24,7 @@
#include <fnmatch.h>
#include <pwd.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
@@ -169,28 +170,6 @@ winlink_previous(struct winlink *wl)
return (RB_PREV(winlinks, wwl, wl));
}
struct winlink *
winlink_next_by_number(struct winlink *wl, struct session *s, int n)
{
for (; n > 0; n--) {
if ((wl = RB_NEXT(winlinks, wwl, wl)) == NULL)
wl = RB_MIN(winlinks, &s->windows);
}
return (wl);
}
struct winlink *
winlink_previous_by_number(struct winlink *wl, struct session *s, int n)
{
for (; n > 0; n--) {
if ((wl = RB_PREV(winlinks, wwl, wl)) == NULL)
wl = RB_MAX(winlinks, &s->windows);
}
return (wl);
}
void
winlink_stack_push(struct winlink_stack *stack, struct winlink *wl)
{
@@ -322,9 +301,6 @@ window_resize(struct window *w, u_int sx, u_int sy)
void
window_set_active_pane(struct window *w, struct window_pane *wp)
{
if (wp == w->active)
return;
w->last = w->active;
w->active = wp;
while (!window_pane_visible(w->active)) {
w->active = TAILQ_PREV(w->active, window_panes, entry);
@@ -341,7 +317,7 @@ window_set_active_at(struct window *w, u_int x, u_int y)
struct window_pane *wp;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp == w->active || !window_pane_visible(wp))
if (!window_pane_visible(wp))
continue;
if (x < wp->xoff || x >= wp->xoff + wp->sx)
continue;
@@ -368,16 +344,9 @@ window_add_pane(struct window *w, u_int hlimit)
void
window_remove_pane(struct window *w, struct window_pane *wp)
{
if (wp == w->active) {
w->active = w->last;
w->last = NULL;
if (w->active == NULL) {
w->active = TAILQ_PREV(wp, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_NEXT(wp, entry);
}
} else if (wp == w->last)
w->last = NULL;
w->active = TAILQ_PREV(wp, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_NEXT(wp, entry);
TAILQ_REMOVE(&w->panes, wp, entry);
window_pane_destroy(wp);
@@ -398,29 +367,6 @@ window_pane_at_index(struct window *w, u_int idx)
return (NULL);
}
struct window_pane *
window_pane_next_by_number(struct window *w, struct window_pane *wp, u_int n)
{
for (; n > 0; n--) {
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
}
return (wp);
}
struct window_pane *
window_pane_previous_by_number(struct window *w, struct window_pane *wp,
u_int n)
{
for (; n > 0; n--) {
if ((wp = TAILQ_PREV(wp, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
}
return (wp);
}
u_int
window_pane_index(struct window *w, struct window_pane *wp)
{
@@ -502,8 +448,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
void
window_pane_destroy(struct window_pane *wp)
{
window_pane_reset_mode(wp);
if (wp->fd != -1) {
close(wp->fd);
bufferevent_free(wp->event);
@@ -511,6 +455,7 @@ window_pane_destroy(struct window_pane *wp)
input_free(wp);
window_pane_reset_mode(wp);
screen_free(&wp->base);
if (wp->saved_grid != NULL)
grid_destroy(wp->saved_grid);
@@ -533,11 +478,14 @@ int
window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
const char *cwd, struct environ *env, struct termios *tio, char **cause)
{
struct winsize ws;
int mode;
char *argv0;
const char *ptr;
struct termios tio2;
struct winsize ws;
int mode;
char *argv0, **varp, *var;
ARRAY_DECL(, char *) varlist;
struct environ_entry *envent;
const char *ptr;
struct termios tio2;
u_int i;
if (wp->fd != -1) {
close(wp->fd);
@@ -580,11 +528,22 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
fatal("tcgetattr failed");
closefrom(STDERR_FILENO + 1);
ARRAY_INIT(&varlist);
for (varp = environ; *varp != NULL; varp++) {
var = xstrdup(*varp);
var[strcspn(var, "=")] = '\0';
ARRAY_ADD(&varlist, var);
}
for (i = 0; i < ARRAY_LENGTH(&varlist); i++) {
var = ARRAY_ITEM(&varlist, i);
unsetenv(var);
}
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
setenv(envent->name, envent->value, 1);
}
environ_push(env);
clear_signals(1);
server_signal_clear();
log_close();
if (*wp->cmd != '\0') {
@@ -612,6 +571,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
fatal("fcntl failed");
if (fcntl(wp->fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if (fcntl(wp->fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
wp->event = bufferevent_new(wp->fd,
window_pane_read_callback, NULL, window_pane_error_callback, wp);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
@@ -623,27 +584,9 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
void
window_pane_read_callback(unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
char *new_data;
size_t new_size;
struct window_pane *wp = data;
new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
if (wp->pipe_fd != -1 && new_size > 0) {
new_data = EVBUFFER_DATA(wp->event->input);
bufferevent_write(wp->pipe_event, new_data, new_size);
}
input_parse(wp);
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
/*
* If we get here, we're not outputting anymore, so set the silence
* flag on the window.
*/
wp->window->flags |= WINDOW_SILENCE;
if (gettimeofday(&wp->window->silence_timer, NULL) != 0)
fatal("gettimeofday failed.");
window_pane_parse(wp);
}
/* ARGSUSED */
@@ -687,81 +630,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
fatal("ioctl failed");
}
/*
* Enter alternative screen mode. A copy of the visible screen is saved and the
* history is not updated
*/
void
window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc)
{
struct screen *s = &wp->base;
u_int sx, sy;
if (wp->saved_grid != NULL)
return;
if (!options_get_number(&wp->window->options, "alternate-screen"))
return;
sx = screen_size_x(s);
sy = screen_size_y(s);
wp->saved_grid = grid_create(sx, sy, 0);
grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
wp->saved_cx = s->cx;
wp->saved_cy = s->cy;
memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell);
grid_view_clear(s->grid, 0, 0, sx, sy);
wp->base.grid->flags &= ~GRID_HISTORY;
wp->flags |= PANE_REDRAW;
}
/* Exit alternate screen mode and restore the copied grid. */
void
window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc)
{
struct screen *s = &wp->base;
u_int sx, sy;
if (wp->saved_grid == NULL)
return;
if (!options_get_number(&wp->window->options, "alternate-screen"))
return;
sx = screen_size_x(s);
sy = screen_size_y(s);
/*
* If the current size is bigger, temporarily resize to the old size
* before copying back.
*/
if (sy > wp->saved_grid->sy)
screen_resize(s, sx, wp->saved_grid->sy);
/* Restore the grid, cursor position and cell. */
grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
s->cx = wp->saved_cx;
if (s->cx > screen_size_x(s) - 1)
s->cx = screen_size_x(s) - 1;
s->cy = wp->saved_cy;
if (s->cy > screen_size_y(s) - 1)
s->cy = screen_size_y(s) - 1;
memcpy(gc, &wp->saved_cell, sizeof *gc);
/*
* Turn history back on (so resize can use it) and then resize back to
* the current size.
*/
wp->base.grid->flags |= GRID_HISTORY;
if (sy > wp->saved_grid->sy)
screen_resize(s, sx, sy);
grid_destroy(wp->saved_grid);
wp->saved_grid = NULL;
wp->flags |= PANE_REDRAW;
}
int
window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode)
{
@@ -791,7 +659,24 @@ window_pane_reset_mode(struct window_pane *wp)
}
void
window_pane_key(struct window_pane *wp, struct session *sess, int key)
window_pane_parse(struct window_pane *wp)
{
char *data;
size_t new_size;
new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
if (wp->pipe_fd != -1 && new_size > 0) {
data = EVBUFFER_DATA(wp->event->input);
bufferevent_write(wp->pipe_event, data, new_size);
}
input_parse(wp);
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
}
void
window_pane_key(struct window_pane *wp, struct client *c, int key)
{
struct window_pane *wp2;
@@ -800,7 +685,7 @@ window_pane_key(struct window_pane *wp, struct session *sess, int key)
if (wp->mode != NULL) {
if (wp->mode->key != NULL)
wp->mode->key(wp, sess, key);
wp->mode->key(wp, c, key);
return;
}
@@ -819,7 +704,7 @@ window_pane_key(struct window_pane *wp, struct session *sess, int key)
void
window_pane_mouse(
struct window_pane *wp, struct session *sess, struct mouse_event *m)
struct window_pane *wp, struct client *c, struct mouse_event *m)
{
if (!window_pane_visible(wp))
return;
@@ -833,7 +718,7 @@ window_pane_mouse(
if (wp->mode != NULL) {
if (wp->mode->mouse != NULL)
wp->mode->mouse(wp, sess, m);
wp->mode->mouse(wp, c, m);
} else if (wp->fd != -1)
input_mouse(wp, m);
}
@@ -874,113 +759,3 @@ window_pane_search(struct window_pane *wp, const char *searchstr, u_int *lineno)
xfree(newsearchstr);
return (msg);
}
/* Find the pane directly above another. */
struct window_pane *
window_pane_find_up(struct window_pane *wp)
{
struct window_pane *wp2;
u_int left, top;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
top = wp->yoff;
if (top == 0)
top = wp->window->sy + 1;
left = wp->xoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->yoff + wp2->sy + 1 != top)
continue;
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
return (wp2);
}
return (NULL);
}
/* Find the pane directly below another. */
struct window_pane *
window_pane_find_down(struct window_pane *wp)
{
struct window_pane *wp2;
u_int left, bottom;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
bottom = wp->yoff + wp->sy + 1;
if (bottom >= wp->window->sy)
bottom = 0;
left = wp->xoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->yoff != bottom)
continue;
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
return (wp2);
}
return (NULL);
}
/*
* Find the pane directly to the left of another, adjacent to the left side and
* containing the top edge.
*/
struct window_pane *
window_pane_find_left(struct window_pane *wp)
{
struct window_pane *wp2;
u_int left, top;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
left = wp->xoff;
if (left == 0)
left = wp->window->sx + 1;
top = wp->yoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->xoff + wp2->sx + 1 != left)
continue;
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
return (wp2);
}
return (NULL);
}
/*
* Find the pane directly to the right of another, that is adjacent to the
* right edge and including the top edge.
*/
struct window_pane *
window_pane_find_right(struct window_pane *wp)
{
struct window_pane *wp2;
u_int right, top;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
right = wp->xoff + wp->sx + 1;
if (right >= wp->window->sx)
right = 0;
top = wp->yoff;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (!window_pane_visible(wp2))
continue;
if (wp2->xoff != right)
continue;
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
return (wp2);
}
return (NULL);
}

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