221 Commits
1.0 ... 1.1

Author SHA1 Message Date
no_author
09c558685a This commit was manufactured by cvs2svn to create tag 'TMUX_1_1'. 2009-11-05 12:35:48 +00:00
Tiago Cunha
e4b743cced Update CHANGES, and NOTES for the 1.1 release. 2009-11-05 12:35:47 +00:00
Tiago Cunha
9128b7df7f Bump VERSION. 2009-11-05 12:32:46 +00:00
Tiago Cunha
90d4cbe67e Prepare the tree for the 1.1 release. 2009-11-05 12:30:55 +00:00
Tiago Cunha
625348122c Sync OpenBSD patchset 490:
Unused (but assigned to) variable, found by lint.
2009-11-04 23:12:32 +00:00
Tiago Cunha
27c2b98f5f Sync OpenBSD patchset 489:
Ignore the colour on space, /not/ the attributes.
2009-11-04 23:10:43 +00:00
Tiago Cunha
344a241c28 Sync OpenBSD patchset 488:
Fix the reverse emulation when a terminal doesn't have setab to use the correct
fg/bg (adjusted if spaces) and happen before attribute setting.
2009-11-04 23:09:48 +00:00
Tiago Cunha
fdda6ef8bd Adjust OpenBSD patchset 487 to the portable version, and while there drop
malloc_options on DragonFlyBSD, and FreeBSD.
2009-11-04 23:09:09 +00:00
Tiago Cunha
c78426f033 Sync OpenBSD patchset 487:
Change declaration and use of malloc_options to be more standard, from Tim van
der Molen.
2009-11-04 22:49:27 +00:00
Tiago Cunha
9e208584ed Sync OpenBSD patchset 486:
Don't backoff based on suspended or deda clients as they are always likely to
have data backed up.
2009-11-04 22:47:29 +00:00
Tiago Cunha
5be38f2b3a Sync OpenBSD patchset 485:
Add an activity time for clients, like for sessions, and change session and
client lookup to pick the most recently used rather than the most recently
created - this is much more useful when used interactively and (because the
activity time is set at creation) should have no effect on source-file.

Based on a problem reported by Jan Johansson.
2009-11-04 22:46:25 +00:00
Tiago Cunha
b7fc4f3760 Sync OpenBSD patchset 484:
If it isn't available explicitly, work out the current client in a similar way
to the current session - build a list of the possibilities then pick the
newest.
2009-11-04 22:44:01 +00:00
Tiago Cunha
bbad75fb6c Sync OpenBSD patchset 483:
Change session and client activity and creation time members to have more
meaningful names.

Also, remove the code to try and update the session activity time for the
command client when a command message is received as is pointless because it
des not have a session.
2009-11-04 22:42:31 +00:00
Tiago Cunha
a090b78e8d Sync OpenBSD patchset 482:
tv member of struct paste_buffer is updated but not otherwise used, so remove
it.
2009-11-04 22:39:20 +00:00
Tiago Cunha
0a4d830ee1 Sync OpenBSD patchset 481:
Fix vi page up mode key (from naddy), add missing half page keys, and sort.
2009-11-04 22:38:16 +00:00
Tiago Cunha
f3b4b60aa8 Sync OpenBSD patchset 480:
Double the escape timer (the time after a \033 is received before tmux gives up
waiting to see if it is part of a key sequence and passes it through) to 500
ms, the previous setting was too fast. Suggested by naddy.
2009-11-04 22:37:18 +00:00
Tiago Cunha
012e7106de Sync OpenBSD patchset 479:
When matching the session names with -t, look for exact matches first before
trying partial matches.

Avoids problems where two ambiguous matches are present before an exact match
(eg foo1, foo2, foo would give an error on trying -tfoo), reported by Natacha
Port? natbsd at instinctive dot eu.
2009-11-02 21:42:27 +00:00
Tiago Cunha
bbdf78cd97 Sync OpenBSD patchset 478:
Leftover unused variable :-/.
2009-11-02 21:41:16 +00:00
Tiago Cunha
6b4b4c78cf Sync OpenBSD patchset 477:
There isn't much point in doing lstat before connect so instead just do connect
and handle ENOENT from it which is a little tidier.
2009-11-02 21:40:44 +00:00
Tiago Cunha
ee1cc9f415 Sync OpenBSD patchset 476:
Reorder slightly to tidy code.
2009-11-02 21:39:34 +00:00
Tiago Cunha
053e40572c Sync OpenBSD patchset 475:
Add a flag for jobs that shouldn't be freed after they've died and use it for
status jobs, then only kill those jobs when status-left, status-right or
set-titles-string is changed.

Fixes problems with changing options from inside #().
2009-11-02 21:38:27 +00:00
Tiago Cunha
47f69075a0 Sync OpenBSD patchset 474:
Missing setenv/showenv aliases.
2009-11-02 21:35:40 +00:00
Tiago Cunha
b4beb1a5cb Sync OpenBSD patchset 473:
Missing ;. From eric@ ages ago.
2009-11-02 21:34:32 +00:00
Tiago Cunha
738489f2bb Sync OpenBSD patchset 472:
If any client currently displaying a window pane has more than 1 KB of output
buffered, don't accept any further data from the process running in the pane.

This makes tmux much more responsive when flooded with output, although other
buffers can still have an impact when running remotely.

Prompted by a query from Ranganathan Sankaralingam.
2009-11-02 21:32:52 +00:00
Nicholas Marriott
d57ba5e30b +. 2009-11-02 20:24:07 +00:00
Nicholas Marriott
ca24e00d75 Example from Thayer Williams. 2009-11-02 18:59:28 +00:00
Nicholas Marriott
513c1cf0c7 +-. 2009-11-01 18:48:20 +00:00
Tiago Cunha
d13d3a9902 Sync OpenBSD patchset 471:
Add a minor optimisatin: if the character being printed is space, don't worry
about setting the background colour or attributes (except reverse).
2009-10-28 23:17:28 +00:00
Tiago Cunha
c529c02ac0 Sync OpenBSD patchset 470:
Twaek this slightly to avoid confusing use of flags variable.
2009-10-28 23:16:30 +00:00
Tiago Cunha
745fd16452 Sync OpenBSD patchset 469:
Setting SGR0 when setting the fg and bg has problems if only one of the two is
meant to be default, so rewrite the code to move this outside, move setting
colours before attributes and generally clean up.

Tested by sthen@, fixes problems he was seeing with mutt and should fix some
existing problems with (rarely) lost attributes.
2009-10-28 23:15:32 +00:00
Tiago Cunha
f4514f5c60 Sync OpenBSD patchset 468:
Move the poll registration functions into the server-*.c files.
2009-10-28 23:14:15 +00:00
Tiago Cunha
a5acabd923 Sync OpenBSD patchset 467:
tabs are better; ok nicm
2009-10-28 23:12:38 +00:00
Tiago Cunha
e65aa04ad7 Sync OpenBSD patchset 466:
Clear signal flags /before/ taking action and continue afterwards to reduce
chance of dropping signals. Pointed out by deraadt@.
2009-10-28 23:11:07 +00:00
Tiago Cunha
d0afc47bfb Sync OpenBSD patchset 465:
Call fstat() after fopen() rather than stat() before.
2009-10-28 23:10:05 +00:00
Tiago Cunha
ce743b2058 Sync OpenBSD patchset 464:
Reset the umask right after fopen to avoid leaving it changed on error, noticed
by deraadt@.
2009-10-28 23:08:52 +00:00
Tiago Cunha
88bb9381b2 Sync OpenBSD patchset 463:
Use strlcpy instead of strncpy, pointed out by deraadt.
2009-10-28 23:08:04 +00:00
Tiago Cunha
876ded6dfe Sync OpenBSD patchset 462:
Don't do anything in the client callback if the client has already died to
avoid a use-after-free (the callback is used twice, once for the client itself
and once for the tty). Fixes crashes seen by Han Boetes.
2009-10-28 23:06:41 +00:00
Tiago Cunha
5a4ba76293 Sync OpenBSD patchset 461:
Nuke accidentally-committed debugging statement.
2009-10-28 23:05:43 +00:00
Tiago Cunha
31bb577075 Sync OpenBSD patchset 460:
Not all terminals swap CSI and SS3 on ctrl, so remove that.

Also mark the rxvt special-cases as such until terminfo is updated to have
kLFT5, kRIT5 etc.
2009-10-28 23:05:01 +00:00
Tiago Cunha
10aab82539 Sync OpenBSD patchset 459:
Rewrite xterm-keys code (both input and output) so that works (doesn't always
output the same modifiers, accepts all the possible input keys) and is more
understandable.
2009-10-28 23:03:51 +00:00
Tiago Cunha
1c4b7d33b1 Sync OpenBSD patchset 458:
Support the (mostly new) function key+modifier caps (kIC-kIC7). Most of these
will be caught (soon) by the xterm keys code in xterm itself but some other
descriptions such as rxvt define them as well.
2009-10-28 23:01:44 +00:00
Tiago Cunha
8ff0d06d34 Sync OpenBSD patchset 457:
On second thoughts, drop the rxvt output entirely.
2009-10-28 23:00:21 +00:00
Tiago Cunha
6cf9965e42 Sync OpenBSD patchset 456:
Set the output code for ctrl+cursor keys correctly, and disable (comment)
rxvt-style output.
2009-10-28 22:59:01 +00:00
Tiago Cunha
c45a56d66b Sync OpenBSD patchset 455:
As we always put the cursor keys into application mode, assume keys sent
with CSI have ctrl.

Also add a couple of comments.
2009-10-28 22:57:55 +00:00
Tiago Cunha
a8300b7a44 Sync OpenBSD patchset 454:
Tidy up table.
2009-10-28 22:56:50 +00:00
Tiago Cunha
98122860cc Sync OpenBSD patchset 453:
Drop INPUTKEY_CTRL and just handle it as part of the table.
2009-10-28 22:56:05 +00:00
Tiago Cunha
dd8174f545 Sync OpenBSD patchset 452:
Add or fix some comments.
2009-10-28 22:54:54 +00:00
Tiago Cunha
5350212e53 Sync OpenBSD patchset 451:
Tidy up table.
2009-10-28 22:54:00 +00:00
Tiago Cunha
4f7e669271 Sync OpenBSD patchset 450:
Rename keypad keys to something more useful.
2009-10-28 22:53:03 +00:00
Tiago Cunha
165538b4bd Sync OpenBSD patchset 449:
Remove the xterm-keys code which is broken (a replacement is coming but some
more cleanup is needed first).
2009-10-28 22:51:55 +00:00
Tiago Cunha
6338fd78f7 Sync OpenBSD patchset 448:
Don't try to continue processing a client if the session has been destroyed.
2009-10-28 22:50:24 +00:00
Tiago Cunha
181f7722b3 Sync OpenBSD patchset 447:
Remove -d from tmux.1 as well.
2009-10-28 22:49:22 +00:00
Tiago Cunha
41863470ba Sync OpenBSD patchset 446:
Remove the -d flag to tmux and just use op/AX to detect default colours.

Irritatingly, although op can be used to tell if a terminal supports default
colours, it can't be used to set them because in some terminfo descriptions it
resets attributes as a side-effect (acts as sgr0) and in others it doesn't, so
it is not possible to determine reliably what the terminal state will be
afterwards. So if AX is missing and op is present, tmux just sends sgr0.

Anyone using -d for a terminal who finds they actually needed it can replace it
using terminal-overrides, but please let me know as it is probably an omission
from terminfo.
2009-10-28 22:48:35 +00:00
Tiago Cunha
c4637da860 Sync OpenBSD patchset 445:
+time.h.
2009-10-28 22:46:15 +00:00
Nicholas Marriott
382aa8f6de RHS spacing. 2009-10-26 15:07:52 +00:00
Nicholas Marriott
a460e1ada3 Fix in IE6. 2009-10-26 15:04:45 +00:00
Nicholas Marriott
aaef0d316f Spacing tweaks. 2009-10-26 14:53:30 +00:00
Tiago Cunha
76bb6d6138 Add missing license. 2009-10-25 22:16:55 +00:00
Nicholas Marriott
2536ea12cb +confirm-before. 2009-10-25 21:58:05 +00:00
Nicholas Marriott
cb3b0e661d Add or clarify licenses where appropriate. 2009-10-25 21:45:26 +00:00
Nicholas Marriott
2cee0139e4 +. 2009-10-25 18:23:14 +00:00
Tiago Cunha
132485a660 Sync OpenBSD patchset 444:
[ is a punctuation character and should be escaped with Ql. Although the
current groff version we have seems to handle it fine, other versions are not
so tolerant.
2009-10-25 10:42:56 +00:00
Tiago Cunha
d55ee38c7f Sync OpenBSD patchset 443:
Bring a comment into line with reality.
2009-10-25 10:42:08 +00:00
Tiago Cunha
e214ea1c59 Update. 2009-10-25 10:41:25 +00:00
Tiago Cunha
85ae64b981 Sync OpenBSD patchset 442:
-a option to kill all except current pane. From Tiago Cunha, thanks!
2009-10-25 10:41:03 +00:00
Tiago Cunha
4a87cef46f Sync OpenBSD patchset 441:
Support the bright fg/bg colour SGR 90-97 and 100-107.

Reported by Tim Allen.
2009-10-25 10:39:48 +00:00
Nicholas Marriott
8c00dc2b6b Mustn't forget this. 2009-10-25 08:14:56 +00:00
Nicholas Marriott
38aa9a447a Much improved web page from Mike Putnam. 2009-10-25 08:14:34 +00:00
Nicholas Marriott
6dc796bb29 Update. 2009-10-25 08:13:13 +00:00
Nicholas Marriott
d8e566d0e9 cc -> $(CC) 2009-10-24 22:02:18 +00:00
Tiago Cunha
5820efa513 Sync OpenBSD patchset 440:
Redraw checks have to after handling input or pane redraw flags set by key
presses will not be acted on.
2009-10-23 17:53:16 +00:00
Tiago Cunha
e05fe0ba05 Sync OpenBSD patchset 439:
The client buffers have to be checked after every event in order to catch the
escape timers and properly reset the cursor.
2009-10-23 17:51:57 +00:00
Tiago Cunha
134a33f6e0 Adjust OpenBSD patchset 438 to the portable version. 2009-10-23 17:51:02 +00:00
Tiago Cunha
cc9ef11985 Sync OpenBSD patchset 438:
Split the server code handling clients, jobs and windows off into separate
files from server.c (merging server-msg.c into the client file) and rather than
iterating over each set after poll(), allow a callback to be specified when the
fd is added and just walk once over the returned pollfds calling each callback
where needed.

More to come, getting this in so it is tested.
2009-10-23 17:49:47 +00:00
Tiago Cunha
9ad2347258 Sync OpenBSD patchset 437:
Only redraw the pane when changing mode, not the entire window.
2009-10-23 17:41:20 +00:00
Tiago Cunha
dbefea339f Sync OpenBSD patchset 436:
Merge prepare_cmd into main as it is short and only called once.
2009-10-23 17:40:23 +00:00
Tiago Cunha
9260888d1c Fix CVS keyword. 2009-10-23 17:38:42 +00:00
Tiago Cunha
eaa188bb63 Sync OpenBSD patchset 435:
Tidy identify message send into a separate function.
2009-10-23 17:37:41 +00:00
Tiago Cunha
dc8b7d6b03 Sync OpenBSD patchset 434:
Don't try to unsuspend a client if it isn't suspended.
2009-10-23 17:33:26 +00:00
Tiago Cunha
84392ffc0d Sync OpenBSD patchset 433:
Client tidying: get rid of client_ctx struct in favour of two variables in
client.c, and move the functions in client-fn.c into other files.
2009-10-23 17:32:26 +00:00
Tiago Cunha
c6828bf32b Sync OpenBSD patchset 432:
Unused variable.
2009-10-23 17:28:29 +00:00
Tiago Cunha
31552722a8 Sync OpenBSD patchset 431:
Remove unused function.
2009-10-23 17:27:40 +00:00
Tiago Cunha
d7d4d7830b Sync OpenBSD patchset 430:
Nuke dead store.
2009-10-23 17:26:40 +00:00
Tiago Cunha
dbf2351d3a Sync OpenBSD patchset 429:
Now we are correctly not redrawing the whole pane on linefeed, redo the
last-cursor-position code to move to the right position when panes reach EOL.
2009-10-23 17:25:51 +00:00
Tiago Cunha
9731625230 Sync OpenBSD patchset 428:
Tweak descriptions for up/down pane to be clearer.
2009-10-23 17:24:57 +00:00
Tiago Cunha
a572533c89 Sync OpenBSD patchset 427:
Don't redraw the scroll region on linefeed/reverse index unless it is necessary
(the cursor is at the bottom/top). Should fix slow cursor movement when using
vi in a pane spotted by pirofti@.
2009-10-23 17:23:52 +00:00
Tiago Cunha
8ec8d1f32a Sync OpenBSD patchset 426:
Some terminals don't correctly clear their let's-wrap flag after changing the
scroll region (which moves the cursor to 0,0). This means that if the cursor
was at the edge of the screen, any further output after scroll region change
incorrectly causes a line wrap. Add a workaround to move the cursor to position
0 if it is at the screen edge before changing scroll region.
2009-10-23 17:22:39 +00:00
Tiago Cunha
21b23f8e54 Sync OpenBSD patchset 424:
%zu not %u, doh.
2009-10-23 17:21:34 +00:00
Tiago Cunha
fce889235c Sync OpenBSD patchset 422:
Correctly nuke the EOL $ marker when scrolling, reported by martynas@, thanks.
2009-10-23 17:17:20 +00:00
Tiago Cunha
f41a3914a5 Sync OpenBSD patchset 421:
Try to reduce the UTF-8 mess.

Get rid of passing around u_char[4]s and define a struct utf8_data which has
character data, size (sequence length) and width. Move UTF-8 character
collection into two functions utf8_open/utf8_append in utf8.c which fill in
this struct and use these functions from input.c and the various functions in
screen-write.c.

Space for rather more data than is necessary for one UTF-8 sequence is in the
utf8_data struct because screen_write_copy is still nasty and needs to reinject
the character (after combining) into screen_write_cell.
2009-10-23 17:16:25 +00:00
Tiago Cunha
c643ac4827 Sync OpenBSD patchset 420:
UTF-8 combined character fixes.

Thai can have treble combinations (1 x width=1 then 2 x width=0) so bump the
UTF-8 cell data size to 9 and alter the code to allow this.

Also break off the combining code into a separate function, handle any further
combining beyond the buffer size by replacing the character with _s, and when
redrawing the UTF-8 character don't assume the first part has just been
printed, redraw the entire line.
2009-10-23 17:13:10 +00:00
Tiago Cunha
97e02eae7d Sync OpenBSD patchset 419:
Move the check for whether to force a line wrapper lower down into the tty code
where it has access to the tty width, which is what should have been checked.
2009-10-23 17:11:26 +00:00
Tiago Cunha
516bfe7ba3 Sync OpenBSD patchset 418:
Nuke stray blank line.
2009-10-23 17:10:00 +00:00
Tiago Cunha
9463492ac1 Sync OpenBSD patchset 417:
Stop updating the screen when not in output mode, stops copy mode getting
confused.
2009-10-23 17:09:21 +00:00
Tiago Cunha
2f14ef61ff Sync OpenBSD patchset 416:
Always move the cursor position on !xenl terminals, since there is no invisible
last cursor position.

Also nuke an unused variable.
2009-10-23 17:08:30 +00:00
Tiago Cunha
2e39ab59d7 Sync OpenBSD patchset 415:
Don't print wide characters at screen width - 1. Matches uterm behaviour and
is probably a better idea anyway.
2009-10-23 17:07:18 +00:00
Tiago Cunha
ac4e4a2b6c Sync OpenBSD patchset 414:
Instead of having a complicated check to see if the cursor is in the last
position to avoid an explicit wrap, actually move it there.

Some UTF-8 fixes to come.
2009-10-23 17:06:23 +00:00
Tiago Cunha
13d1df659f Sync OpenBSD patchset 413:
When checking whether the region will scroll and the cursor position is thus
unsuitable for using CUD/CUU, check the current cursor position not the target
position.
2009-10-23 17:03:48 +00:00
Nicholas Marriott
4afecbe400 Getting the read and write ends of the pipe the right way round is usually
recommended. DOH.
2009-10-21 07:37:11 +00:00
Nicholas Marriott
bb625a76d9 +. 2009-10-21 07:19:59 +00:00
Nicholas Marriott
b027aa103c +. 2009-10-20 14:22:17 +00:00
Nicholas Marriott
59269a431b +. 2009-10-17 15:58:52 +00:00
Nicholas Marriott
c8f2584d87 +. 2009-10-15 20:48:51 +00:00
Tiago Cunha
24d7cf6618 Sync OpenBSD patchset 412:
The pane pty name isn't useful for anything so show the pane number instead.
2009-10-15 20:10:28 +00:00
Nicholas Marriott
1fdf489cae Turn off stupid warnings when using Sun CC. 2009-10-15 08:15:06 +00:00
Nicholas Marriott
0614ca434a Fill in the tty name in SunOS's forkpty compat, and use it in osdep_getname.
From Todd Carson.

Tweaked by me to nuke (void) casts. Say no to lint appeasement! ;-)
2009-10-15 07:11:25 +00:00
Tiago Cunha
8085adb8a2 Sync OpenBSD patchset 411:
cmd_find_client shouldn't die when there is an empty slot in the clients
array. DOH.
2009-10-15 01:56:45 +00:00
Tiago Cunha
3d88da7b2a Sync OpenBSD patchset 409:
Move lines into the history when scrolling even if the scroll region is not
the entire screen.

Allows ircII users to see history, prompted by naddy.
2009-10-15 01:55:12 +00:00
Tiago Cunha
ee46dba585 Sync OpenBSD patchset 408:
Handle DECCOLM by just emulating its side-effect of clearing the screen.
2009-10-15 01:53:48 +00:00
Tiago Cunha
a505ca69d9 Sync OpenBSD patchset 407:
Add mode keys to move the cursor to the top, middle and bottom of the screen.
H/M/L in vi mode and M-R/M-r in emacs (bottom of screen not bound in emacs).
2009-10-15 01:52:47 +00:00
Tiago Cunha
428f76db80 Fix CVS keyword. 2009-10-15 01:51:09 +00:00
Tiago Cunha
b6ebf7cb60 Update. 2009-10-15 01:49:39 +00:00
Tiago Cunha
6257be6371 Sync OpenBSD patchset 406:
Do this in a better way - print messages when exiting with nonzero.

Also remove the login shell information from server-info, only the client
should care about it.
2009-10-15 01:48:24 +00:00
Tiago Cunha
9800dc4697 Sync OpenBSD patchset 405:
Don't print exit messages when used as a login shell, requested by martynas@ a
while back.
2009-10-15 01:45:13 +00:00
Tiago Cunha
b8e4bd2029 Sync OpenBSD patchset 404:
Don't try to use \n across scroll region when doing \r\n either.
2009-10-15 01:44:15 +00:00
Tiago Cunha
941032b707 Sync OpenBSD patchset 403:
When a session is unattached, reset its activity timer to prevent it locking
instantly when reattached.
2009-10-15 01:43:16 +00:00
Tiago Cunha
fe99f6fa11 Sync OpenBSD patchset 402:
Instead of using something sort of similar for both newline checks, use
something the same. Doesn't fix the bug I'm looking for though :-/.
2009-10-15 01:42:07 +00:00
Tiago Cunha
6103628129 Sync OpenBSD patchset 401:
When drawing lines that have wrapped naturally, don't force a newline but
permit them to wrap naturally again. This allows terminals that use this to
guess where lines start and end for eg mouse selecting (like xterm) to work
correctly.

This was another long-standing issue raised by several people over the last
while.

Thanks to martynas@ for much testing. This was not trivial to get right so
bringing it in for wider testing and adn to fix any further glitches in-tree.
2009-10-15 01:41:14 +00:00
Tiago Cunha
cbd3b1bc9b Sync OpenBSD patchset 400:
When backspace is received at the beginning of a line and the previous line was
wrapped, move the cursor back up to the end of the previous line.

Another one of the forgotten persons requested this quite a while ago (I need
to start noting names on todo items...) when it was quite hard to
implement. Now it is easy and I don't see it can do any harm, so hey presto...
2009-10-15 01:39:30 +00:00
Tiago Cunha
04db3c6211 Sync OpenBSD patchset 399:
Don't run through the column unchanged case if the row was unchanged but there
were no suitable optimisations, instead make it an else to fall through to
absolute addressing.
2009-10-15 01:38:09 +00:00
Tiago Cunha
858b8b190b Sync OpenBSD patchset 398:
If the vertical cursor movement crosses the scroll region, CUU and CUD
shouldn't be used even if VPA isn't present - in that case CUP should be used.
2009-10-15 01:36:53 +00:00
Tiago Cunha
7af01a4afb Sync OpenBSD patchset 397:
Wrap a couple of long lines.
2009-10-15 01:35:35 +00:00
Tiago Cunha
9e4a3d50f0 Sync OpenBSD patchset 396:
Use absolute movement if right at the end of the line as it isn't a reliable
place to move from relatively.
2009-10-15 01:34:28 +00:00
Tiago Cunha
44fd6f4381 Sync OpenBSD patchset 395:
Use relative cursor movement instead of absolute when possible and when
supported by the terminal to reduce the size of the output data (generally
about 10-20%).
2009-10-15 01:33:21 +00:00
Tiago Cunha
8ab3a3d9aa Sync OpenBSD patchset 394:
Permit attributes to be turned off in #[] by prefixing with "no", for example
"noblink".
2009-10-15 01:31:38 +00:00
Tiago Cunha
8bdcc10c8f Sync OpenBSD patchset 393:
Similarly add a tty_cursor_pane function to tidy up most of the calls.
2009-10-15 01:30:00 +00:00
Tiago Cunha
6369fca253 Sync OpenBSD patchset 392:
_absolute is redundant, just use tty_region.
2009-10-15 01:28:14 +00:00
Tiago Cunha
9b771a96f0 Sync OpenBSD patchset 391:
Cleanup: use two functions for region setting, one for absolute and one inside
pane.
2009-10-15 01:26:50 +00:00
Nicholas Marriott
f8f2421ac3 Don't let cmd_lookup_client find clients w/o a session. 2009-10-14 13:22:24 +00:00
Nicholas Marriott
9e6d1b24c8 Support for automatic-rename for Solaris thanks to Todd Carson. 2009-10-14 10:14:21 +00:00
Nicholas Marriott
587e7127eb +. 2009-10-13 14:35:06 +00:00
Nicholas Marriott
6b522bd770 +. 2009-10-13 14:27:57 +00:00
Nicholas Marriott
edc901d107 Lots of stuff is done done done. 2009-10-13 13:48:47 +00:00
Nicholas Marriott
e88a2ba7d4 +. 2009-10-12 23:13:06 +00:00
Tiago Cunha
629afba526 Reduce diff with OpenBSD. 2009-10-12 00:49:06 +00:00
Tiago Cunha
f92cc84631 Sync OpenBSD patchset 390:
Like linefeed, don't set the scroll region for reverse index unless it will be
needed.

While here, also tidy up a couple of long lines and remove an extraneous blank.
2009-10-12 00:41:00 +00:00
Tiago Cunha
6ea6d1b29f Sync OpenBSD patchset 389:
punctuation fix;
2009-10-12 00:38:31 +00:00
Tiago Cunha
39afe3fc2a Sync OpenBSD patchset 388:
Set the current window pointer to NULL when killing a winlink that is to be
replaced with link-window -k. This prevents it being pushed onto the last
window stack and causing a use-after-free.

Only took me an hour to find this :-/...
2009-10-12 00:37:41 +00:00
Tiago Cunha
3584fa15ec No paths.h in here, as well. 2009-10-12 00:36:31 +00:00
Tiago Cunha
6091b051fb Sync OpenBSD patchset 387:
Add a pipe-pane command to allow a pane to be piped to a shell command, for
example:

        pipe-pane 'cat >~/out'

No arguments stops outputing and closes the pipe; the -o flag toggles a pipe
and on and off (useful for key bindings).

Suggested by espie@.
2009-10-12 00:35:08 +00:00
Tiago Cunha
a053aeddf8 Sync OpenBSD patchset 386:
Convert if-shell over to the background job framework as well.
2009-10-12 00:29:03 +00:00
Tiago Cunha
50ece89ab9 Sync OpenBSD patchset 385:
Remove a debugging leftover and add copyright.
2009-10-12 00:26:06 +00:00
Tiago Cunha
197f8b88bf Sync OpenBSD patchset 384:
Switch run-shell over to queue the command in the background like #().
2009-10-12 00:25:25 +00:00
Tiago Cunha
c8d0608369 Sync OpenBSD patchset 383:
There isn't much point in having a free function if it isn't used.

Also allow a NULL tree.
2009-10-12 00:22:17 +00:00
Tiago Cunha
1b03bc2404 Sync OpenBSD patchset 382:
Collect status from dead jobs and don't invoke the callback until both
all input (the socket is closed) and status is available.
2009-10-12 00:21:08 +00:00
Tiago Cunha
b26ea8462e Sync OpenBSD patchset 381:
Clean up by introducing a wrapper struct for mouse clicks rather than passing
three u_chars around.

As a side-effect this fixes incorrectly rejecting high cursor positions
(because it was comparing them as signed char), reported by Tom Doherty.
2009-10-12 00:18:19 +00:00
Tiago Cunha
323469723b Sync OpenBSD patchset 380:
Braek some bits out of server_fill_client() that aren't really related to
polling into their own function.
2009-10-12 00:14:44 +00:00
Tiago Cunha
d7fa9bc056 Sync OpenBSD patchset 379:
Put all jobs on a global all_jobs list and use that in server.c instead of
running through all the clients.
2009-10-12 00:12:33 +00:00
Tiago Cunha
256a55b33b Sync OpenBSD patchset 378:
-scroll mode which is dead.
2009-10-12 00:09:48 +00:00
Tiago Cunha
53f1e6eed2 Update. 2009-10-12 00:08:48 +00:00
Tiago Cunha
0b8a7dc4a2 Sync OpenBSD patchset 377:
Split list-panes off from list-windows.
2009-10-12 00:08:12 +00:00
Tiago Cunha
cf9804f2a0 Sync OpenBSD patchset 376:
Accept key and mouse input for keys in zombified windows if they are in a mode..
2009-10-12 00:04:56 +00:00
Tiago Cunha
bc90c7c199 Sync OpenBSD patchset 375:
When a window is zombified and automatic-rename is on, append [dead] to the
name.
2009-10-12 00:03:04 +00:00
Tiago Cunha
3e93bdf31b Do not include paths.h, since it's OS-dependent, due to OpenBSD patchset 374. 2009-10-11 23:59:34 +00:00
Tiago Cunha
bc236109fd Sync OpenBSD patchset 374:
Rather than running status-left, status-right and window title #() with popen
immediately every redraw, queue them up and run them in the background,
starting each once every status-interval. The actual status line uses the
output from the last run.

This brings several advantages:

- tmux itself may be called from inside #() without causing the server to hang;
- likewise, sleep or similar doesn't cause the server to block;
- commands aren't run excessively often when redrawing;
- commands shared by status-left and status-right, or used multiple times, will
  only be run once.

run-shell and if-shell still use system()/popen() but will be changed over to
use this too later.
2009-10-11 23:55:26 +00:00
Tiago Cunha
07ad6da7e8 Update. 2009-10-11 23:47:02 +00:00
Tiago Cunha
ea1721bcb0 Sync OpenBSD patchset 373:
New option, mouse-select-pane. If on, the mouse may be used to select the
current pane.

Suggested by sthen@ and also by someone else ages ago who I have forgotten.
2009-10-11 23:46:02 +00:00
Tiago Cunha
2486a36af3 Sync OpenBSD patchset 372:
There is no point setting the scroll region up for line feeds unless scrolling
is actually going to happen, so don't.
2009-10-11 23:39:37 +00:00
Tiago Cunha
6a1ebb11df Sync OpenBSD patchset 371:
Add "grouped sessions" which have independent name, options, current window and
so on but where the linked windows are synchronized (ie creating, killing
windows and so on are mirrored between the sessions). A grouped session may be
created by passing -t to new-session.

Had this around for a while, tested by a couple of people.
2009-10-11 23:38:16 +00:00
Tiago Cunha
1fd3a405e6 Update. 2009-10-11 23:31:02 +00:00
Tiago Cunha
91e4dc83fc Sync OpenBSD patchset 370:
Support for individual session idle time locking. May be enabled by turning off
the lock-server option (it is on by default). When this is off, each session
locks when it has been idle for the lock-after-time setting. When on, the
entire server locks when ALL sessions have been idle for their individual
lock-after-time settings.

This replaces one global-only option (lock-after-time) with another
(lock-server), but the default behaviour is usually preferable so there don't
seem to be many alternatives.

Diff/idea largely from Thomas Adam, tweaked by me.
2009-10-11 23:30:28 +00:00
Tiago Cunha
a4ea6a9d19 Sync OpenBSD patchset 369:
Instead of passing a struct pollfd ** around through various functions, build
them into a tree and then convert into a flat poll array before and after poll.

This adds a little code but should reduce annoying problems with ordering when
adding new things that also need to be polled.
2009-10-11 23:25:44 +00:00
Nicholas Marriott
0e5f20a97d +. 2009-10-11 22:06:25 +00:00
Nicholas Marriott
bc67e01e52 Done or not doing. 2009-10-11 12:46:40 +00:00
Nicholas Marriott
eba57d84a6 pcvt25 has AX but in fact the console doesn't support it. 2009-10-10 17:08:57 +00:00
Nicholas Marriott
3d1936e9c7 Update. 2009-10-10 15:17:50 +00:00
Tiago Cunha
932f0a757f Sync with reality. 2009-10-09 22:55:43 +00:00
Tiago Cunha
cddb781127 Sync OpenBSD patchset 368:
The UTF-8 detection idea doesn't work and I am reasonably happy with the
current methods, so remove the (already #ifdef 0'd) code.
2009-10-09 13:11:42 +00:00
Tiago Cunha
220f3f2384 Update. 2009-10-09 13:07:29 +00:00
Tiago Cunha
9ac062acef Sync OpenBSD patchset 367:
Add a simple synchronize-panes window option: when set, all input to any pane
that is part of the window is also sent to all other panes in the same
window. Suggested by several, most recently Tomasz Pajor.
2009-10-09 13:07:04 +00:00
Tiago Cunha
765a38e534 Sync OpenBSD patchset 366:
Be less aggressive about turning the cursor off, only explicitly turn it off
when tmux is redrawing, otherwise leave in the state set by the application.
2009-10-09 13:03:28 +00:00
Nicholas Marriott
c2e78a3104 Add a little. 2009-10-09 07:30:27 +00:00
Tiago Cunha
1eb665832a Sync OpenBSD patchset 365:
Support J and K for scroll up and scroll down in copy mode with vi keys,
suggested by martynas.
2009-10-07 17:13:59 +00:00
Tiago Cunha
64e9d07b1b Sync OpenBSD patchset 364:
Fix comment.
2009-10-07 17:10:44 +00:00
Tiago Cunha
d23635f66d Remove unneeded defines that were used with the internal locking mechanism. 2009-10-06 15:32:21 +00:00
Tiago Cunha
4640627f6e Sync OpenBSD patchset 363:
Accept ^? for backspace as well as BSpace.
2009-10-06 14:15:45 +00:00
Tiago Cunha
83bf166a1f Update. 2009-10-06 14:14:40 +00:00
Tiago Cunha
f881502f84 Sync OpenBSD patchset 362:
Remove scroll mode which is now redundant, copy mode should be used instead.

The = key binding now does nothing.
2009-10-06 14:14:07 +00:00
Tiago Cunha
32291172bf Sync OpenBSD patchset 361:
Make C-Up and C-Down in copy mode scroll the screen up and down one line
without moving the cursor, like Up and Down in scroll mode (which will shortly
disappear).
2009-10-06 14:10:10 +00:00
Tiago Cunha
eb7f8b6d33 Sync OpenBSD patchset 360:
If no target client is specified to commands which accept one, try to guess the
current client, in a similar manner to how sessions already work: if the
current session can be established and has only one client, use that; otherwise
use the most recently created client.
2009-10-06 14:00:50 +00:00
Tiago Cunha
d8c0634524 Sync OpenBSD patchset 359:
tweak previous;
2009-10-05 18:26:00 +00:00
Tiago Cunha
11e97f4eb0 Sync OpenBSD patchset 358:
Get / and ? the right way round in vi mode, and use : for goto line rather than
g.
2009-10-05 18:25:05 +00:00
Tiago Cunha
813d78e46a Sync OpenBSD patchset 357:
Check for already locked/suspended clients in server_lock_client rather than
its callers.
2009-10-05 18:23:31 +00:00
Tiago Cunha
2931277608 Sync OpenBSD patchset 356:
Add a key string for space ("Space") and document the names, suggested by
guenther@. Also document how to bind " and ', suggested by miod@.
2009-10-05 18:21:58 +00:00
Tiago Cunha
6b3ec44ee9 Sync OpenBSD patchset 355:
C-v and M-v too.
2009-10-05 18:19:52 +00:00
Tiago Cunha
19e502c64e Sync OpenBSD patchset 354:
Support C-n/C-p with emacs keys in choice mode, also fix a comment.
2009-10-05 18:18:50 +00:00
Tiago Cunha
a9a0cd8297 Update. 2009-09-25 17:52:26 +00:00
Tiago Cunha
88c3b9c989 Sync OpenBSD patchset 353:
New lock-client and lock-session commands to lock an individual client or all
clients attached to a session respectively.
2009-09-25 17:51:39 +00:00
Tiago Cunha
804b8696a4 Sync OpenBSD patchset 352:
Don't allow locked or suspended clients to limit the size of active clients.
2009-09-25 17:47:42 +00:00
Tiago Cunha
b5d23ef38b Sync OpenBSD patchset 351:
Remove PROMPT_HIDDEN code which is now unused.
2009-09-25 17:45:46 +00:00
Nicholas Marriott
c190a65c69 Should be bestp now. 2009-09-24 12:30:22 +00:00
Nicholas Marriott
bf4b27e679 Earlier versions of FreeBSD are missing RB_PREV. 2009-09-24 07:15:22 +00:00
Nicholas Marriott
d73516c0a9 Use __sun not __sun__ as Sun's CC doesn't define the latter. 2009-09-23 16:09:12 +00:00
Tiago Cunha
ac95da3afc Adjust OpenBSD patchset 350 to the portable version. 2009-09-23 15:20:16 +00:00
Tiago Cunha
5be3fb86b9 Sync OpenBSD patchset 350:
Support -c like sh(1) to execute a command, useful when tmux is a login
shell. Suggested by halex@.

This includes another protocol version increase (the last for now) so again
restart the tmux server before upgrading.
2009-09-23 15:18:56 +00:00
Tiago Cunha
4dd332c95e Sync OpenBSD patchset 349:
On SIGTERM, just abandon any suspended/locked clients and leave them to it,
otherwise the server will hang around (refusing new connections) until they
exit properly.
2009-09-23 15:10:37 +00:00
Tiago Cunha
fea7bda58f Sync OpenBSD patchset 348:
Don't die if the client is detaching (the tty has been closed) after waking up
from locking.
2009-09-23 15:08:21 +00:00
Tiago Cunha
88f689e167 Remove HAVE_LOGIN_CAP now that the internal locking mechanism was removed, due
to OpenBSD patchset 347.
2009-09-23 15:05:03 +00:00
Tiago Cunha
5743da5588 Update. 2009-09-23 15:01:10 +00:00
Tiago Cunha
1310ea2729 Sync OpenBSD patchset 347:
Remove the internal tmux locking and instead detach each client and run the
command specified by a new option "lock-command" (by default "lock -np") in
each client.

This means each terminal has to be unlocked individually but simplifies the
code and allows the system password to be used to unlock.

Note that the set-password command is gone, so it will need to be removed from
configuration files, and the -U command line flag has been removed.

This is the third protocol version change so again it is best to stop the tmux
server before upgrading.
2009-09-23 15:00:09 +00:00
Tiago Cunha
2acf349d4e Sync OpenBSD patchset 346:
Trim some code by moving the ioctl(TIOCGWINSZ) after SIGWINCH from the client
into the server.

This is another (the second of four) protocol version changes coming this
morning, so again the server should be killed before upgrading.
2009-09-23 14:44:02 +00:00
Tiago Cunha
acedc2dcf2 Sync OpenBSD patchset 345:
Don't attempt to open() the tty path, rely on the client sending its stdin fd
with imsg and fatal if it doesn't, then set the FD_CLOEXEC flag in tty_init
instead of tty_open to prevent them leaking into child processes if any are
created between the two calls.

This bumps the protocol version, so the tmux server should be killed before
upgrading.
2009-09-23 14:39:30 +00:00
Tiago Cunha
c40d8cbda4 Sync OpenBSD patchset 344:
Be more careful about what flags are cleared when opening the terminal,
otherwise the opened/started flags are cleared and the terminal never released.
2009-09-23 14:33:13 +00:00
Nicholas Marriott
07bd160861 +. 2009-09-23 12:07:08 +00:00
Nicholas Marriott
2c9d4dfdd4 Tweak tparm() to make Solaris' backward userland happy and remove the -I mess
in configure which tried to deal with the fallout from their horrible package
management.
2009-09-22 19:20:08 +00:00
Tiago Cunha
df7b68480c Sync OpenBSD patchset 343:
Permit multiple prefix keys to be defined, separated by commas, for example:

set -g prefix ^a,^b

Any key in the list acts as the prefix. The send-prefix command always sends
the first key in the list.
2009-09-22 14:22:21 +00:00
Tiago Cunha
31ccf2f813 Sync OpenBSD patchset 342:
Use KEYC_NONE constant instead of 0 on init.
2009-09-22 14:06:40 +00:00
Tiago Cunha
480211f0ee Sync OpenBSD patchset 341:
Nuke -i option which isn't used anymore.
2009-09-22 14:03:11 +00:00
Tiago Cunha
59e65cbda2 Sync OpenBSD patchset 340:
Use option print function for info messages as well.
2009-09-22 13:59:46 +00:00
Tiago Cunha
649b7c132d Sync OpenBSD patchset 339:
Move common code from show-options and show-window-options into a function.
2009-09-22 13:56:02 +00:00
Tiago Cunha
b6bc8a6828 Sync OpenBSD patchset 338:
zap trailing whitespace;
2009-09-22 13:51:24 +00:00
Tiago Cunha
f2d249fdc7 Sync OpenBSD patchset 337:
Drop tiny union from option struct.
2009-09-22 13:49:13 +00:00
Tiago Cunha
c28d4e41cf Sync OpenBSD patchset 336:
Key options were implemented as a number so these struct members are unused.
2009-09-22 13:45:06 +00:00
Nicholas Marriott
1572e483c2 Done. 2009-09-22 11:40:11 +00:00
Tiago Cunha
f8ea4f44e8 Update. 2009-09-20 22:20:51 +00:00
Tiago Cunha
e3dcc5327a Sync OpenBSD patchset 335:
run-shell command to run a shell command without opening a window, sending
stdout to output mode.
2009-09-20 22:20:10 +00:00
Tiago Cunha
bd24bdd411 Sync OpenBSD patchset 334:
Nuke unused variables and fix stupid error message.
2009-09-20 22:17:03 +00:00
Tiago Cunha
7335ef5792 Sync OpenBSD patchset 333:
Move some common and untidy code for window link/unlink into generic functions
instead of duplicating it in move/link window..
2009-09-20 22:15:32 +00:00
Tiago Cunha
3266fb5441 Sync OpenBSD patchset 332:
Regularise some fatal messages.
2009-09-20 22:11:27 +00:00
Tiago Cunha
ab96772436 Delete backup files in the compat directory, as well. 2009-09-20 22:06:34 +00:00
Nicholas Marriott
c7ace08193 Now working on 1.1. 2009-09-20 19:01:01 +00:00
103 changed files with 6057 additions and 4050 deletions

54
CHANGES
View File

@@ -1,3 +1,55 @@
CHANGES FROM 1.0 TO 1.1, 05 November 2009
* New run-shell (alias run) command to run an external command without a
window, capture it's stdout, and send it to output mode.
* Ability to define multiple prefix keys.
* Internal locking mechanism removed. Instead, detach each client and run the
external command specified in the new session option lock-command (by default
lock -np), thus allowing the system password to be used.
* set-password command, and -U command line flag removed per the above change.
* Add support for -c command line flag to execute a shell command.
* New lock-client (alias lockc), and lock-session (alias locks) commands to
lock a particular client, or all clients attached to a session.
* Support C-n/C-p/C-v/M-v with emacs keys in choice mode.
* Use : for goto line rather than g in vi mode.
* Try to guess which client to use when no target client was specified. Finds
the current session, and if only one client is present, use it. Otherwise,
return the most recently used client.
* Make C-Down/C-Up in copy mode scroll the screen down/up one line without
moving the cursor.
* Scroll mode superseded by copy mode.
* New synchronize-panes window option to send all input to all other panes in
the same window.
* New lock-server session option to lock, when off (on by default), each
session when it has been idle for the lock-after-time setting. When on, the
entire server locks when all sessions have been idle for their individual
lock-after-time setting.
* Add support for grouped sessions which have independent name, options,
current window, but where the linked windows are synchronized (ie creating,
killing windows are mirrored between the sessions). A grouped session may be
created by passing -t to new-session.
* New mouse-select-pane session option to select the current pane with the
mouse.
* Queue, and run commands in the background for if-shell, status-left,
status-right, and #() by starting each once every status-interval. Adds the
capability to call some programs which would previously cause the server to
hang (eg sleep/tmux). It also avoids running commands excessively (ie if used
multiple times, it will be run only once).
* When a window is zombified and automatic-rename is on, append [dead] to the
name.
* Split list-panes (alias lsp) off from list-windows.
* New pipe-pane (alias pipep) to redirect a pane output to an external command.
* Support for automatic-renames for Solaris.
* Permit attributes to be turned off in #[] by prefixing with no (eg nobright).
* Add H/M/L in vi mode, and M-R/M-r in emacs to move the cursor to the top,
middle, and bottom of the screen.
* -a option added to kill-pane to kill all except current pane.
* The -d command line flag is now gone (can be replaced by terminal-overrides).
Just use op/AX to detect default colours.
* input/tty/utf8 improvements.
* xterm-keys rewrite.
* Additional code reduction, and bug fixes.
CHANGES FROM 0.9 TO 1.0, 20 Sept 2009
* Option to alter the format of the window title set by tmux.
@@ -1358,7 +1410,7 @@ 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.300 2009-09-20 18:54:21 nicm Exp $
$Id: CHANGES,v 1.301 2009-11-05 12:35:47 tcunha Exp $
LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr
LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms

View File

@@ -1,16 +1,37 @@
# $Id: GNUmakefile,v 1.114 2009-09-20 18:54:21 nicm Exp $
# $Id: GNUmakefile,v 1.120 2009-11-05 12:30:55 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.
#
.PHONY: clean
VERSION= 1.0
VERSION= 1.1
#FDEBUG= 1
CC?= gcc
CC?= cc
CFLAGS+= -DBUILD="\"$(VERSION)\""
LDFLAGS+= -L/usr/local/lib
LIBS+=
# Sun CC
ifneq ($(shell ($(CC) -V 2>&1|awk '/Sun C/' || true)), )
CFLAGS+=-erroff=E_EMPTY_DECLARATION
FDEBUG=
endif
ifdef FDEBUG
CFLAGS+= -g -ggdb -DDEBUG
CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
@@ -48,7 +69,7 @@ depend: $(SRCS)
$(CC) $(CPPFLAGS) $(CFLAGS) -MM $(SRCS) > .depend
clean:
rm -f tmux *.o *~ *.core *.log compat/*.o
rm -f tmux *.o *~ *.core *.log compat/*.o compat/*~
clean-depend:
rm -f .depend

View File

@@ -1,9 +1,24 @@
# $Id: Makefile,v 1.149 2009-09-20 18:54:21 nicm Exp $
# $Id: Makefile,v 1.153 2009-11-05 12:30:55 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.
#
.SUFFIXES: .c .o
.PHONY: clean
VERSION= 1.0
VERSION= 1.1
#FDEBUG= 1
@@ -53,7 +68,7 @@ depend:
mkdep ${CPPFLAGS} ${CFLAGS} ${SRCS:M*.c}
clean:
rm -f tmux *.o *~ *.core *.log compat/*.o
rm -f tmux *.o *~ *.core *.log compat/*.o compat/*~
clean-depend:
rm -f .depend

29
NOTES
View File

@@ -4,15 +4,17 @@ tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.
This 0.9 release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still
run on Solaris and AIX (although they hasn't been tested in a while). It is
This release runs on OpenBSD, FreeBSD, NetBSD, Linux and OS X and may still
run on Solaris and AIX (although they haven't been tested in a while). It is
usable, although there remain a number of missing features and some remaining
bugs are expected.
If upgrading from 0.5, PLEASE NOTE the following configuration file changes: it
is now required to pass the -g flag to set-option or set-window-option to set
global options; remain-by-default and utf8-default are now gone, use global
window options (set-window-option -g) instead.
If upgrading from 1.0, PLEASE NOTE:
- The internal locking mechanism has gone, so the set-password command and -U
command line option have been removed.
- The -d command line flag was dropped. It will now automatically detect the
default colours by using op/AX. Nevertheless, if needed, the
terminal-overrides session option can replace it.
tmux consists of a server part and multiple clients. The server is created when
required and runs continuously unless killed by the user. Clients access the
@@ -37,17 +39,14 @@ The following is a summary of major features implemented in this version:
- Support for VT100 line drawing characters.
- A large command set.
- Vertical window splitting and layout.
- Automatic server locking on inactivity.
- Automatic server locking on inactivity by running an external command.
- A configuration file.
- UTF-8 support.
A more extensive, but rough, todo list is included in the TODO file.
tmux also depends on several features of the client terminal (TERM), if these
are missing it may refuse to run, or not behave correctly. Known working are
TERM=screen (tmux in screen), xterm, xterm-color and rxvt. Note that TERM=xterm
does not support colour on OpenBSD. screen ignores this, tmux does not: use
xterm-color or rxvt for colour.
are missing it may refuse to run, or not behave correctly.
tmux supports UTF-8. To use it, the utf8 option must be set on each window;
this may be turned on for all windows by setting it as a global option, see
@@ -81,6 +80,12 @@ welcome. Please send by email to:
nicm@users.sf.net
This file and the CHANGES, FAQ and TODO files are licensed under the ISC
license. Files under examples/ remain copyright their authors unless otherwise
stated in the file but permission has been received to distribute them with
tmux. All other files have a license and copyright notice at their
start. Please contact me with any queries.
-- Nicholas Marriott <nicm@users.sf.net>
$Id: NOTES,v 1.49 2009-07-06 18:53:24 nicm Exp $
$Id: NOTES,v 1.51 2009-11-05 12:35:47 tcunha Exp $

65
TODO
View File

@@ -9,45 +9,30 @@
- garbage collect window history (100 lines at a time?) if it hasn't been used
in $x time (need window creation/use times)
- lift SHRT_MAX limits for history?
- better mode features: search
- flags to centre screen in window
- better terminal emulation
- activity/bell should be per-window not per-link? what if it is cur win in
session not being watched?
- next prev word etc in command prompt; also ^K
- next prev word etc in command prompt
- many more info() displays for various things
- backspace should perhaps wrap backwards over newlines which were not moved
down by a newline: screen and the OS X terminal does this but xterm and most
others do not. this might be hard: a flag for each grid line (top bit of size
maybe)? a single flag is insufficient as can't then tell when to /stop/
unwrapping
- input.c is too complicated. simplify?
- use a better termcap internally instead of screen, perhaps xterm
- kill all but current pane
- fix rxvt cursor fg issue (text under cursor can have non-white fg)
- client sx/sy should be in tty, then can let the terminal wrap at edge
to allow xterm to pick up it should be one line for its c/p
- should be able to move to a hidden pane and it would be moved into view. pane
number in status line/top-right would be cool for this
- support other mouse modes (highlight etc) and use it in copy mode
- set-remain-on-exit is a bit of a hack, some way to do it generically?
- set-option should be set-session-option and should be overall global options
for stuff like mode keys?
also quiet, utf8 and maybe other flags?
-g is a bit unexpected in conf file
- clear window title on exit
- the output code (tty.c) could do with optimisation depending on term
capibilities
capabilities
- would be nice to be able to use "--" to mark start of command w/ neww etc
to avoid quoting
- goto line and search history in copy/scroll modes
- clone session command
- make command sequences more usable: don't require space after ;, handle
errors better
- key to switch to copy mode from scroll mode
- attach should have a flag to create session if it doesn't exist
- rename split-window -> split-pane??
- fix UTF-8 guesswork on sparc64, improve tty checks
- choice and more mode would be better per client than per window?
- hooks to which commands may be attached, for example: tmux add-hook
"new-session" if-shell "[ -e $HOME/.tmux-session.conf ]" source-file
@@ -59,48 +44,54 @@
- XXX once env stuff is in, default-path and VISUAL/EDITOR should be picked up
when session is started
- what about utmp etc? can tmux update it like screen? setgid?
- H/M/L commands in copy mode with vi-keys, for jumping to the top/middle/last
line on the screen
- split list-windows into separate list-windows and list-panes
- warts on current naming:
- display-time but message-fg/bg/attr
- list-* vs show-*
- server-info
- up-pane/down-pane/swap-pane -U/swap-pane -D vs next-*/previous-*
- pcvt25 doesn't work properly, why? (bce?)
- split-window -> split-pane??
- tidy up and prioritise todo list ;-)
- it is only possible to specify 8 colours to fg/bg options; should be able to
set 256 as well
- neww and attach can create a session if none exists?
would work fine with config file since
- a way for force-width/height to apply to only one pane (how?)
- **** a command to run something without a window and send any output to the
window-more. if no output, info() a line saying "'%s' returned %d". so i can
bind mpc control commands to function keys ;-)
- command to list what is actually running in each window with command line,
pid (need some adaption of the osdep code)
- string option to change/remove the symbols (*-+ etc) in status line
* or to set entire format, eg window-list-format '#N:#W#P' or something,
then could use embedded colours
- support for bce
- it would be nice if the start/end line keys in copy mode were aware of
wrapped lines
- per session locking
- some way to force a screen to use the entire terminal even if it is forced
to be smaller by other clients. pan smaller terminal? (like screen F)
-- idea of a "view" onto a window, need base x/y offsets
for redraw
- a window option which means data is echoed to all panes in a window
- support running tmux from inside tmux [#(), if-shell] --
generic system-like function which may take a callback
also sets up environment (TMUX) and has a timeout
for #(): command schedular, status line queues it with a time, run in
main loop, and uses most recent result -- can also be used for persistent
commands which never exit just continually output
for if-shell, callback??
- handle resize better in copy mode
- way to copy stuff that is off screen due to resize
- fix line wrapping c&p problems in xterm etc
- a way to address panes by name ("top-left") and position ("0,0")
- ability to specify multiple prefix keys
- commands should be able to succeed or fail and have || or && for command
lists
- support the mouse wheel to scroll through history
- some way to KEEP a command running continually and just use its LAST line of
output
- bind commands to mouse buttons
- UTF-8 to a non-UTF-8 terminal should not be able to balls up
the terminal - www/ruby-addressable; make regress
- copy mode needs a tidy/cleanup
- things like display-message will leak job entries if #() is used
- message log
- an option to NOT remove message when key pressed
- would be nice to be able to press 0-9a-zA-Z to select window in choose-window
mode, also to start typing and it searches
- the wrapping stuff should work when redrawn from scroll mode too (screen_write_copy)
- ability to save history (to buffer?)
- multiple keys could be done with tables, ie have prefixes go and instead
bind -n ^A prefix-table "default"
where prefix-table sets command lookup table and sets prefix flag, then next key
is looked up in that table
- check fix UTF-8 and split-window? should be okay
- UTF-8 should be a pointer into a combined string buffer
- check irssi (term_charset) works with UTF-8
- rectangle copy/paste
- half page/up down are missing from key table
- support esc-esc to quit in modes

View File

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

View File

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

6
cfg.c
View File

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

View File

@@ -1,90 +0,0 @@
/* $Id: client-fn.c,v 1.10 2009-08-14 21:04:04 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
void
client_fill_session(struct msg_command_data *data)
{
char *env, *ptr1, *ptr2, buf[256];
size_t len;
const char *errstr;
long long ll;
data->pid = -1;
if ((env = getenv("TMUX")) == NULL)
return;
if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env)
return;
for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--)
;
if (*ptr1 != ',')
return;
ptr1++;
ptr2++;
len = ptr2 - ptr1 - 1;
if (len > (sizeof buf) - 1)
return;
memcpy(buf, ptr1, len);
buf[len] = '\0';
ll = strtonum(buf, 0, LONG_MAX, &errstr);
if (errstr != NULL)
return;
data->pid = ll;
ll = strtonum(ptr2, 0, UINT_MAX, &errstr);
if (errstr != NULL)
return;
data->idx = ll;
}
void
client_write_server(
struct client_ctx *cctx, enum msgtype type, void *buf, size_t len)
{
imsg_compose(&cctx->ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
}
void
client_suspend(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
act.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &act, NULL) != 0)
fatal("sigaction failed");
act.sa_handler = sighandler;
if (sigaction(SIGCONT, &act, NULL) != 0)
fatal("sigaction failed");
kill(getpid(), SIGTSTP);
}

279
client.c
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-link-window.c,v 1.32 2009-08-16 19:16:27 tcunha Exp $ */
/* $Id: cmd-link-window.c,v 1.35 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -43,55 +43,23 @@ int
cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_srcdst_data *data = self->data;
struct session *dst;
struct winlink *wl_src, *wl_dst;
struct session *src, *dst;
struct winlink *wl;
char *cause;
int idx;
int idx, kflag, dflag;
if ((wl_src = cmd_find_window(ctx, data->src, NULL)) == NULL)
if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1);
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
if (data->chflags & CMD_CHFLAG('k')) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, wl_dst);
winlink_stack_remove(&dst->lastw, wl_dst);
winlink_remove(&dst->windows, wl_dst);
/* Force select/redraw if current. */
if (wl_dst == dst->curw) {
data->chflags &= ~CMD_CHFLAG('d');
dst->curw = NULL;
}
}
}
if (idx == -1)
idx = -1 - options_get_number(&dst->options, "base-index");
wl_dst = session_attach(dst, wl_src->window, idx, &cause);
if (wl_dst == NULL) {
ctx->error(ctx, "create session failed: %s", cause);
kflag = data->chflags & CMD_CHFLAG('k');
dflag = data->chflags & CMD_CHFLAG('d');
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
ctx->error(ctx, "can't link window: %s", cause);
xfree(cause);
return (-1);
}
if (data->chflags & CMD_CHFLAG('d'))
server_status_session(dst);
else {
session_select(dst, wl_dst->idx);
server_redraw_session(dst);
}
recalculate_sizes();
return (0);

74
cmd-list-panes.c Normal file
View File

@@ -0,0 +1,74 @@
/* $Id: cmd-list-panes.c,v 1.2 2009-10-15 20:10:28 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#include "tmux.h"
/*
* List panes on given window..
*/
int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_list_panes_entry = {
"list-panes", "lsp",
CMD_TARGET_WINDOW_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_list_panes_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct window_pane *wp;
struct grid *gd;
struct grid_line *gl;
u_int i, n;
unsigned long long size;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
gd = wp->base.grid;
size = 0;
for (i = 0; i < gd->hsize; i++) {
gl = &gd->linedata[i];
size += gl->cellsize * sizeof *gl->celldata;
size += gl->utf8size * sizeof *gl->utf8data;
}
size += gd->hsize * sizeof *gd->linedata;
ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]",
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
n++;
}
return (0);
}

View File

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

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-list-windows.c,v 1.40 2009-08-09 17:28:23 tcunha Exp $ */
/* $Id: cmd-list-windows.c,v 1.41 2009-10-12 00:08:12 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -45,42 +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;
struct window *w;
struct window_pane *wp;
struct grid *gd;
struct grid_line *gl;
u_int i;
unsigned long long size;
const char *name;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
ctx->print(ctx,
"%3d: %s [%ux%u]", wl->idx, w->name, w->sx, w->sy);
TAILQ_FOREACH(wp, &w->panes, entry) {
gd = wp->base.grid;
size = 0;
for (i = 0; i < gd->hsize; i++) {
gl = &gd->linedata[i];
size += gl->cellsize * sizeof *gl->celldata;
size += gl->utf8size * sizeof *gl->utf8data;
}
size += gd->hsize * sizeof *gd->linedata;
name = NULL;
if (wp->fd != -1)
name = ttyname(wp->fd);
if (name == NULL)
name = "unknown";
ctx->print(ctx,
" %s [%ux%u] [history %u/%u, %llu bytes]",
name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
}
ctx->print(ctx, "%d: %s [%ux%u]",
wl->idx, wl->window->name, wl->window->sx, wl->window->sy);
}
return (0);

View File

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

53
cmd-lock-client.c Normal file
View File

@@ -0,0 +1,53 @@
/* $Id: cmd-lock-client.c,v 1.1 2009-09-25 17:51:39 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "tmux.h"
/*
* Lock a single client.
*/
int cmd_lock_client_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_lock_client_entry = {
"lock-client", "lockc",
CMD_TARGET_CLIENT_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_lock_client_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_lock_client_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct client *c;
if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1);
server_lock_client(c);
recalculate_sizes();
return (0);
}

View File

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

View File

@@ -1,7 +1,7 @@
/* $Id: cmd-scroll-mode.c,v 1.23 2009-08-20 11:37:46 tcunha Exp $ */
/* $Id: cmd-lock-session.c,v 1.1 2009-09-25 17:51:39 tcunha Exp $ */
/*
* Copyright (c) 2007 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,50 +21,33 @@
#include "tmux.h"
/*
* Enter scroll mode.
* Lock all clients attached to a session.
*/
void cmd_scroll_mode_init(struct cmd *, int);
int cmd_scroll_mode_exec(struct cmd *, struct cmd_ctx *);
int cmd_lock_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_scroll_mode_entry = {
"scroll-mode", NULL,
"[-u] " CMD_TARGET_PANE_USAGE,
0, CMD_CHFLAG('u'),
cmd_scroll_mode_init,
const struct cmd_entry cmd_lock_session_entry = {
"lock-session", "locks",
CMD_TARGET_SESSION_USAGE,
0, 0,
cmd_target_init,
cmd_target_parse,
cmd_scroll_mode_exec,
cmd_lock_session_exec,
cmd_target_free,
cmd_target_print
};
void
cmd_scroll_mode_init(struct cmd *self, int key)
{
struct cmd_target_data *data;
cmd_target_init(self, key);
data = self->data;
switch (key) {
case KEYC_PPAGE:
data->chflags |= CMD_CHFLAG('u');
break;
}
}
int
cmd_scroll_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd_lock_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct window_pane *wp;
struct session *s;
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
window_pane_set_mode(wp, &window_scroll_mode);
if (wp->mode == &window_scroll_mode && data->chflags & CMD_CHFLAG('u'))
window_scroll_pageup(wp);
server_lock_session(s);
recalculate_sizes();
return (0);
}

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-move-window.c,v 1.9 2009-08-16 19:16:27 tcunha Exp $ */
/* $Id: cmd-move-window.c,v 1.12 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,68 +44,23 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_srcdst_data *data = self->data;
struct session *src, *dst;
struct winlink *wl_src, *wl_dst;
struct client *c;
u_int i;
int destroyed, idx;
struct winlink *wl;
char *cause;
int idx, kflag, dflag;
if ((wl_src = cmd_find_window(ctx, data->src, &src)) == NULL)
if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1);
wl_dst = NULL;
if (idx != -1)
wl_dst = winlink_find_by_index(&dst->windows, idx);
if (wl_dst != NULL) {
if (wl_dst->window == wl_src->window)
return (0);
if (data->chflags & CMD_CHFLAG('k')) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, wl_dst);
winlink_stack_remove(&dst->lastw, wl_dst);
winlink_remove(&dst->windows, wl_dst);
/* Force select/redraw if current. */
if (wl_dst == dst->curw) {
data->chflags &= ~CMD_CHFLAG('d');
dst->curw = NULL;
}
}
}
if (idx == -1)
idx = -1 - options_get_number(&dst->options, "base-index");
wl_dst = session_attach(dst, wl_src->window, idx, &cause);
if (wl_dst == NULL) {
ctx->error(ctx, "attach window failed: %s", cause);
kflag = data->chflags & CMD_CHFLAG('k');
dflag = data->chflags & CMD_CHFLAG('d');
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
ctx->error(ctx, "can't move window: %s", cause);
xfree(cause);
return (-1);
}
destroyed = session_detach(src, wl_src);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != src)
continue;
if (destroyed) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
} else
server_redraw_client(c);
}
if (data->chflags & CMD_CHFLAG('d'))
server_status_session(dst);
else {
session_select(dst, wl_dst->idx);
server_redraw_session(dst);
}
server_unlink_window(src, wl);
recalculate_sizes();
return (0);

View File

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

View File

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

125
cmd-pipe-pane.c Normal file
View File

@@ -0,0 +1,125 @@
/* $Id: cmd-pipe-pane.c,v 1.3 2009-10-23 17:26:40 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Open pipe to redirect pane output. If already open, close first.
*/
int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_pipe_pane_entry = {
"pipe-pane", "pipep",
CMD_TARGET_PANE_USAGE "[-o] [command]",
CMD_ARG01, CMD_CHFLAG('o'),
cmd_target_init,
cmd_target_parse,
cmd_pipe_pane_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct window_pane *wp;
int old_fd, pipe_fd[2], null_fd, mode;
if (cmd_find_pane(ctx, data->target, NULL, &wp) == NULL)
return (-1);
/* Destroy the old pipe. */
old_fd = wp->pipe_fd;
if (wp->pipe_fd != -1) {
buffer_destroy(wp->pipe_buf);
close(wp->pipe_fd);
wp->pipe_fd = -1;
}
/* If no pipe command, that is enough. */
if (data->arg == NULL || *data->arg == '\0')
return (0);
/*
* With -o, only open the new pipe if there was no previous one. This
* allows a pipe to be toggled with a single key, for example:
*
* bind ^p pipep -o 'cat >>~/output'
*/
if (data->chflags & CMD_CHFLAG('o') && old_fd != -1)
return (0);
/* Open the new pipe. */
if (pipe(pipe_fd) != 0) {
ctx->error(ctx, "pipe error: %s", strerror(errno));
return (-1);
}
/* Fork the child. */
switch (fork()) {
case -1:
ctx->error(ctx, "fork error: %s", strerror(errno));
return (-1);
case 0:
/* Child process. */
close(pipe_fd[0]);
sigreset();
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1);
if (pipe_fd[1] != STDIN_FILENO)
close(pipe_fd[1]);
null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
if (dup2(null_fd, STDOUT_FILENO) == -1)
_exit(1);
if (dup2(null_fd, STDERR_FILENO) == -1)
_exit(1);
if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
close(null_fd);
execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL);
_exit(1);
default:
/* Parent process. */
close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0];
wp->pipe_buf = buffer_create(BUFSIZ);
wp->pipe_off = BUFFER_USED(wp->in);
if ((mode = fcntl(wp->pipe_fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
return (0);
}
return (0);
}

View File

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

137
cmd-run-shell.c Normal file
View File

@@ -0,0 +1,137 @@
/* $Id: cmd-run-shell.c,v 1.4 2009-11-02 21:38:26 tcunha Exp $ */
/*
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
* Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include "tmux.h"
/*
* Runs a command without a window.
*/
int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
void cmd_run_shell_callback(struct job *);
void cmd_run_shell_free(void *);
const struct cmd_entry cmd_run_shell_entry = {
"run-shell", "run",
"command",
CMD_ARG1, 0,
cmd_target_init,
cmd_target_parse,
cmd_run_shell_exec,
cmd_target_free,
cmd_target_print
};
struct cmd_run_shell_data {
char *cmd;
struct cmd_ctx ctx;
};
int
cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct cmd_run_shell_data *cdata;
struct job *job;
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(data->arg);
memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
if (ctx->cmdclient != NULL)
ctx->cmdclient->references++;
if (ctx->curclient != NULL)
ctx->curclient->references++;
job = job_add(NULL, 0, NULL,
data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata);
job_run(job);
return (1); /* don't let client exit */
}
void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
struct cmd_ctx *ctx = &cdata->ctx;
char *cmd, *msg, *line, *buf;
size_t off, len, llen;
int retcode;
buf = BUFFER_OUT(job->out);
len = BUFFER_USED(job->out);
cmd = cdata->cmd;
if (len != 0) {
line = buf;
for (off = 0; off < len; off++) {
if (buf[off] == '\n') {
llen = buf + off - line;
if (llen > INT_MAX)
break;
ctx->print(ctx, "%.*s", (int) llen, line);
line = buf + off + 1;
}
}
llen = buf + len - line;
if (llen > 0 && llen < INT_MAX)
ctx->print(ctx, "%.*s", (int) llen, line);
}
msg = NULL;
if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) {
retcode = WTERMSIG(job->status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
}
if (msg != NULL) {
if (len != 0)
ctx->print(ctx, "%s", msg);
else
ctx->info(ctx, "%s", msg);
xfree(msg);
}
}
void
cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
struct cmd_ctx *ctx = &cdata->ctx;
if (ctx->cmdclient != NULL) {
ctx->cmdclient->references--;
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
}
if (ctx->curclient != NULL)
ctx->curclient->references--;
xfree(cdata->cmd);
xfree(cdata);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,145 +0,0 @@
/* $Id: cmd-set-password.c,v 1.8 2009-07-28 22:12:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include "tmux.h"
/*
* Set server password.
*/
int cmd_set_password_parse(struct cmd *, int, char **, char **);
int cmd_set_password_exec(struct cmd *, struct cmd_ctx *);
void cmd_set_password_free(struct cmd *);
void cmd_set_password_init(struct cmd *, int);
size_t cmd_set_password_print(struct cmd *, char *, size_t);
struct cmd_set_password_data {
char *password;
int flag_encrypted;
};
const struct cmd_entry cmd_set_password_entry = {
"set-password", "pass",
"[-c] password",
0, 0,
cmd_set_password_init,
cmd_set_password_parse,
cmd_set_password_exec,
cmd_set_password_free,
cmd_set_password_print
};
void
cmd_set_password_init(struct cmd *self, unused int arg)
{
struct cmd_set_password_data *data;
self->data = data = xmalloc(sizeof *data);
data->password = NULL;
data->flag_encrypted = 0;
}
int
cmd_set_password_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_set_password_data *data;
int opt;
char *out;
self->entry->init(self, 0);
data = self->data;
while ((opt = getopt(argc, argv, "c")) != -1) {
switch (opt) {
case 'c':
data->flag_encrypted = 1;
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (argc != 1)
goto usage;
if (!data->flag_encrypted) {
if ((out = crypt(argv[0], "$1")) != NULL)
data->password = xstrdup(out);
} else
data->password = xstrdup(argv[0]);
return (0);
usage:
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
self->entry->free(self);
return (-1);
}
int
cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_set_password_data *data = self->data;
if (data->password == NULL) {
ctx->error(ctx, "failed to encrypt password");
return (-1);
}
if (server_password != NULL)
xfree(server_password);
if (*data->password == '\0')
server_password = NULL;
else
server_password = xstrdup(data->password);
return (0);
}
void
cmd_set_password_free(struct cmd *self)
{
struct cmd_set_password_data *data = self->data;
if (data->password != NULL)
xfree(data->password);
xfree(data);
}
size_t
cmd_set_password_print(struct cmd *self, char *buf, size_t len)
{
struct cmd_set_password_data *data = self->data;
size_t off = 0;
off += xsnprintf(buf, len, "%s", self->entry->name);
if (data == NULL)
return (off);
if (off < len && data->flag_encrypted)
off += xsnprintf(buf + off, len - off, " -c");
if (off < len && data->password != NULL)
off += xsnprintf(buf + off, len - off, " password");
return (off);
}

View File

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

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-show-options.c,v 1.16 2009-07-28 22:12:16 tcunha Exp $ */
/* $Id: cmd-show-options.c,v 1.17 2009-09-22 13:56:02 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,9 +46,9 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data;
struct session *s;
struct options *oo;
struct options_entry *o;
const struct set_option_entry *entry;
char *vs;
long long vn;
const char *optval;
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_s_options;
@@ -59,46 +59,10 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
}
for (entry = set_option_table; entry->name != NULL; entry++) {
if (options_find1(oo, entry->name) == NULL)
if ((o = options_find1(oo, entry->name)) == NULL)
continue;
switch (entry->type) {
case SET_OPTION_STRING:
vs = options_get_string(oo, entry->name);
ctx->print(ctx, "%s \"%s\"", entry->name, vs);
break;
case SET_OPTION_NUMBER:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %lld", entry->name, vn);
break;
case SET_OPTION_KEY:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, key_string_lookup_key(vn));
break;
case SET_OPTION_COLOUR:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, colour_tostring(vn));
break;
case SET_OPTION_ATTRIBUTES:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, attributes_tostring(vn));
break;
case SET_OPTION_FLAG:
vn = options_get_number(oo, entry->name);
if (vn)
ctx->print(ctx, "%s on", entry->name);
else
ctx->print(ctx, "%s off", entry->name);
break;
case SET_OPTION_CHOICE:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, entry->choices[vn]);
break;
}
optval = set_option_print(entry, o);
ctx->print(ctx, "%s %s", entry->name, optval);
}
return (0);

View File

@@ -1,4 +1,4 @@
/* $Id: cmd-show-window-options.c,v 1.12 2009-07-28 22:12:16 tcunha Exp $ */
/* $Id: cmd-show-window-options.c,v 1.13 2009-09-22 13:56:02 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -46,9 +46,9 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data;
struct winlink *wl;
struct options *oo;
struct options_entry *o;
const struct set_option_entry *entry;
char *vs;
long long vn;
const char *optval;
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_w_options;
@@ -59,46 +59,10 @@ cmd_show_window_options_exec(struct cmd *self, struct cmd_ctx *ctx)
}
for (entry = set_window_option_table; entry->name != NULL; entry++) {
if (options_find1(oo, entry->name) == NULL)
if ((o = options_find1(oo, entry->name)) == NULL)
continue;
switch (entry->type) {
case SET_OPTION_STRING:
vs = options_get_string(oo, entry->name);
ctx->print(ctx, "%s \"%s\"", entry->name, vs);
break;
case SET_OPTION_NUMBER:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %lld", entry->name, vn);
break;
case SET_OPTION_KEY:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, key_string_lookup_key(vn));
break;
case SET_OPTION_COLOUR:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, colour_tostring(vn));
break;
case SET_OPTION_ATTRIBUTES:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, attributes_tostring(vn));
break;
case SET_OPTION_FLAG:
vn = options_get_number(oo, entry->name);
if (vn)
ctx->print(ctx, "%s on", entry->name);
else
ctx->print(ctx, "%s off", entry->name);
break;
case SET_OPTION_CHOICE:
vn = options_get_number(oo, entry->name);
ctx->print(ctx, "%s %s",
entry->name, entry->choices[vn]);
break;
}
optval = set_option_print(entry, o);
ctx->print(ctx, "%s %s", entry->name, optval);
}
return (0);

View File

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

View File

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

View File

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

View File

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

View File

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

138
cmd.c
View File

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

View File

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

View File

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

30
configure vendored
View File

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

View File

@@ -1,3 +1,7 @@
# $Id: h-boetes.conf,v 1.2 2009-10-25 21:45:26 nicm Exp $
#
# From Han Boetes.
set -g default-command zsh
set -g status-right "#(uptime|awk '{print $11}') #(date)"

View File

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

View File

@@ -1,11 +0,0 @@
#!/bin/sh -x
[ ! -z "$TMUX" ] && exit
# I alias this script to "session" in .profile and use it to reconnect to
# the main session (0) on my main tmux server.
TMUX="tmux -dLmain"
$TMUX has -t0 2>/dev/null || $TMUX -qf ~/.tmux.conf.main start
exec $TMUX attach -d -t0

View File

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

104
examples/t-williams.conf Normal file
View File

@@ -0,0 +1,104 @@
# $Id: t-williams.conf,v 1.1 2009-11-02 18:59:28 nicm Exp $
#
# ~/.tmux.conf - tmux terminal multiplexer config
# Thayer Williams (http://cinderwick.ca)
# "Feel free to do whatever you like with it."
# I typically start tmux from ~/.xinitrc with the following:
#
# urxvt -e bash -c "tmux attach -d -t mysession" &
#
# and recall it any time thereafter with xbindkeys (Mod4+s):
#
# "urxvt -e bash -c 'tmux attach -d -t mysession'"
# m:0x50 + c:39
# set prefix key to ctrl+a until I have time to adapt
unbind C-b
set -g prefix C-a
# send the prefix to client inside window (ala nested sessions)
bind-key a send-prefix
# toggle last window like screen
bind-key C-a last-window
# confirm before killing a window or the server
bind-key k confirm kill-window
bind-key K confirm kill-server
# toggle statusbar
bind-key b set-option status
# ctrl+left/right cycles thru windows
bind-key -n C-right next
bind-key -n C-left prev
# open a man page in new window
bind / command-prompt "split-window 'exec man %%'"
# quick view of processes
bind '~' split-window "exec htop"
# scrollback buffer n lines
set -g history-limit 5000
# listen for activity on all windows
set -g bell-action any
# on-screen time for display-panes in ms
set -g display-panes-time 2000
# start window indexing at one instead of zero
set -g base-index 1
# enable wm window titles
set -g set-titles on
# wm window title string (uses statusbar variables)
set -g set-titles-string "tmux.#I.#W"
# session initialization
new -s mysession mutt
neww -t 2
neww -d -t 3
neww -d -t 5 mocp
neww -d -t 6 rtorrent
selectw -t 1
# statusbar --------------------------------------------------------------
set -g display-time 2000
# default statusbar colors
set -g status-fg white
set -g status-bg default
set -g status-attr default
# default window title colors
set-window-option -g window-status-fg cyan
set-window-option -g window-status-bg default
set-window-option -g window-status-attr dim
# active window title colors
set-window-option -g window-status-current-fg white
set-window-option -g window-status-current-bg default
set-window-option -g window-status-current-attr bright
# command/message line colors
set -g message-fg white
set -g message-bg black
set -g message-attr bright
# center align the window list
set -g status-justify centre
# show some useful stats but only when tmux is started
# outside of Xorg, otherwise dwm statusbar shows these already
set -g status-right ""
set -g status-left ""
if '[ -z "$DISPLAY" ]' 'set -g status-left "[#[fg=green] #H #[default]]"'
if '[ -z "$DISPLAY" ]' 'set -g status-right "[ #[fg=magenta]#(cat /proc/loadavg | cut -d \" \" -f 1,2,3)#[default] ][ #[fg=cyan,bright]%a %Y-%m-%d %H:%M #[default]]"'
if '[ -z "$DISPLAY" ]' 'set -g status-right-length 50'

View File

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

View File

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

72
grid.c
View File

@@ -1,4 +1,4 @@
/* $Id: grid.c,v 1.33 2009-09-15 23:54:57 tcunha Exp $ */
/* $Id: grid.c,v 1.34 2009-10-15 01:55:12 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -161,29 +161,77 @@ grid_compare(struct grid *ga, struct grid *gb)
return (0);
}
/* Scroll a line into the history. */
/*
* Collect lines from the history if at the limit. Free the top (oldest) 10%
* and shift up.
*/
void
grid_scroll_line(struct grid *gd)
grid_collect_history(struct grid *gd)
{
u_int yy;
GRID_DEBUG(gd, "");
if (gd->hsize >= gd->hlimit) {
/* If the limit is hit, free the bottom 10% and shift up. */
yy = gd->hlimit / 10;
if (yy < 1)
yy = 1;
if (gd->hsize < gd->hlimit)
return;
grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy);
gd->hsize -= yy;
}
yy = gd->hlimit / 10;
if (yy < 1)
yy = 1;
grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy);
gd->hsize -= yy;
}
/*
* Scroll the entire visible screen, moving one line into the history. Just
* allocate a new line at the bottom and move the history size indicator.
*/
void
grid_scroll_history(struct grid *gd)
{
u_int yy;
GRID_DEBUG(gd, "");
yy = gd->hsize + gd->sy;
gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata);
memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]);
gd->hsize++;
}
/* Scroll a region up, moving the top line into the history. */
void
grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower)
{
struct grid_line *gl_history, *gl_upper, *gl_lower;
u_int yy;
GRID_DEBUG(gd, "upper=%u, lower=%u", upper, lower);
/* Create a space for a new line. */
yy = gd->hsize + gd->sy;
gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata);
/* Move the entire screen down to free a space for this line. */
gl_history = &gd->linedata[gd->hsize];
memmove(gl_history + 1, gl_history, gd->sy * sizeof *gl_history);
/* Adjust the region and find its start and end. */
upper++;
gl_upper = &gd->linedata[upper];
lower++;
gl_lower = &gd->linedata[lower];
/* Move the line into the history. */
memcpy(gl_history, gl_upper, sizeof *gl_history);
/* Then move the region up and clear the bottom line. */
memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper);
memset(gl_lower, 0, sizeof *gl_lower);
/* Move the history offset down over the line. */
gd->hsize++;
}

View File

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

80
input.c
View File

@@ -1,4 +1,4 @@
/* $Id: input.c,v 1.95 2009-08-21 21:07:20 tcunha Exp $ */
/* $Id: input.c,v 1.101 2009-10-28 23:12:38 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -128,7 +128,7 @@ input_sequence_cmp(const void *a, const void *b)
void
input_new_argument(struct input_ctx *ictx)
{
struct input_arg *arg;
struct input_arg *arg;
ARRAY_EXPAND(&ictx->args, 1);
@@ -139,7 +139,7 @@ input_new_argument(struct input_ctx *ictx)
int
input_add_argument(struct input_ctx *ictx, u_char ch)
{
struct input_arg *arg;
struct input_arg *arg;
if (ARRAY_LENGTH(&ictx->args) == 0)
return (0);
@@ -572,15 +572,14 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx)
void
input_state_utf8(u_char ch, struct input_ctx *ictx)
{
log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch);
log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch);
ictx->utf8_buf[ictx->utf8_off++] = ch;
if (--ictx->utf8_len != 0)
return;
if (utf8_append(&ictx->utf8data, ch))
return; /* more to come */
input_state(ictx, input_state_first);
ictx->cell.flags |= GRID_FLAG_UTF8;
screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
ictx->cell.flags &= ~GRID_FLAG_UTF8;
}
@@ -590,40 +589,17 @@ input_handle_character(u_char ch, struct input_ctx *ictx)
struct window_pane *wp = ictx->wp;
if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) {
/*
* UTF-8 sequence.
*
* 11000010-11011111 C2-DF start of 2-byte sequence
* 11100000-11101111 E0-EF start of 3-byte sequence
* 11110000-11110100 F0-F4 start of 4-byte sequence
*/
memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf);
ictx->utf8_buf[0] = ch;
ictx->utf8_off = 1;
if (ch >= 0xc2 && ch <= 0xdf) {
log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch);
if (utf8_open(&ictx->utf8data, ch)) {
log_debug2("-- utf8 size %zu: %zu: %hhu (%c)",
ictx->utf8data.size, ictx->off, ch, ch);
input_state(ictx, input_state_utf8);
ictx->utf8_len = 1;
return;
}
if (ch >= 0xe0 && ch <= 0xef) {
log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch);
input_state(ictx, input_state_utf8);
ictx->utf8_len = 2;
return;
}
if (ch >= 0xf0 && ch <= 0xf4) {
log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch);
input_state(ictx, input_state_utf8);
ictx->utf8_len = 3;
return;
}
}
log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
ictx->cell.data = ch;
screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
}
void
@@ -646,7 +622,7 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx)
ictx->wp->window->flags |= WINDOW_BELL;
break;
case '\010': /* BS */
screen_write_cursorleft(&ictx->ctx, 1);
screen_write_backspace(&ictx->ctx);
break;
case '\011': /* TAB */
/* Don't tab beyond the end of the line. */
@@ -816,7 +792,7 @@ input_handle_sequence(u_char ch, struct input_ctx *ictx)
{
struct input_sequence_entry *entry, find;
struct screen *s = ictx->ctx.s;
u_int i;
u_int i;
struct input_arg *iarg;
log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, "
@@ -1185,6 +1161,10 @@ input_handle_sequence_sm(struct input_ctx *ictx)
screen_write_kcursormode(&ictx->ctx, 1);
log_debug("kcursor on");
break;
case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0);
screen_write_clearscreen(&ictx->ctx);
break;
case 25: /* TCEM */
screen_write_cursormode(&ictx->ctx, 1);
log_debug("cursor on");
@@ -1257,6 +1237,10 @@ input_handle_sequence_rm(struct input_ctx *ictx)
screen_write_kcursormode(&ictx->ctx, 0);
log_debug("kcursor off");
break;
case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0);
screen_write_clearscreen(&ictx->ctx);
break;
case 25: /* TCEM */
screen_write_cursormode(&ictx->ctx, 0);
log_debug("cursor off");
@@ -1486,6 +1470,28 @@ input_handle_sequence_sgr(struct input_ctx *ictx)
gc->flags &= ~GRID_FLAG_BG256;
gc->bg = 8;
break;
case 90:
case 91:
case 92:
case 93:
case 94:
case 95:
case 96:
case 97:
gc->flags |= GRID_FLAG_FG256;
gc->fg = m - 82;
break;
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
gc->flags |= GRID_FLAG_BG256;
gc->bg = m - 92;
break;
}
}
}

196
job.c Normal file
View File

@@ -0,0 +1,196 @@
/* $Id: job.c,v 1.9 2009-11-02 21:38:26 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
/*
* Job scheduling. Run queued commands in the background and record their
* output.
*/
/* All jobs list. */
struct joblist all_jobs = SLIST_HEAD_INITIALIZER(&all_jobs);
RB_GENERATE(jobs, job, entry, job_cmp);
int
job_cmp(struct job *job1, struct job *job2)
{
return (strcmp(job1->cmd, job2->cmd));
}
/* Initialise job tree. */
void
job_tree_init(struct jobs *jobs)
{
RB_INIT(jobs);
}
/* Destroy a job tree. */
void
job_tree_free(struct jobs *jobs)
{
struct job *job;
while (!RB_EMPTY(jobs)) {
job = RB_ROOT(jobs);
RB_REMOVE(jobs, jobs, job);
job_free(job);
}
}
/* Find a job and return it. */
struct job *
job_get(struct jobs *jobs, const char *cmd)
{
struct job job;
job.cmd = (char *) cmd;
return (RB_FIND(jobs, jobs, &job));
}
/* Add a job. */
struct job *
job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd,
void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
{
struct job *job;
job = xmalloc(sizeof *job);
job->cmd = xstrdup(cmd);
job->pid = -1;
job->status = 0;
job->client = c;
job->fd = -1;
job->out = buffer_create(BUFSIZ);
job->callbackfn = callbackfn;
job->freefn = freefn;
job->data = data;
job->flags = flags|JOB_DONE;
if (jobs != NULL)
RB_INSERT(jobs, jobs, job);
SLIST_INSERT_HEAD(&all_jobs, job, lentry);
return (job);
}
/* Remove job from tree and free. */
void
job_remove(struct jobs *jobs, struct job *job)
{
if (jobs != NULL)
RB_REMOVE(jobs, jobs, job);
job_free(job);
}
/* Kill and free an individual job. */
void
job_free(struct job *job)
{
job_kill(job);
SLIST_REMOVE(&all_jobs, job, job, lentry);
xfree(job->cmd);
if (job->freefn != NULL && job->data != NULL)
job->freefn(job->data);
if (job->fd != -1)
close(job->fd);
if (job->out != NULL)
buffer_destroy(job->out);
xfree(job);
}
/* Start a job running, if it isn't already. */
int
job_run(struct job *job)
{
int nullfd, out[2], mode;
if (!(job->flags & JOB_DONE))
return (0);
job->flags &= ~JOB_DONE;
if (pipe(out) != 0)
return (-1);
switch (job->pid = fork()) {
case -1:
return (-1);
case 0: /* child */
sigreset();
/* XXX environ? */
if (dup2(out[1], STDOUT_FILENO) == -1)
fatal("dup2 failed");
if (out[1] != STDOUT_FILENO)
close(out[1]);
close(out[0]);
nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
if (nullfd < 0)
fatal("open failed");
if (dup2(nullfd, STDIN_FILENO) == -1)
fatal("dup2 failed");
if (dup2(nullfd, STDERR_FILENO) == -1)
fatal("dup2 failed");
if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
close(nullfd);
execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
fatal("execl failed");
default: /* parent */
close(out[1]);
job->fd = out[0];
if ((mode = fcntl(job->fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
if (BUFFER_USED(job->out) != 0)
buffer_remove(job->out, BUFFER_USED(job->out));
return (0);
}
}
/* Kill a job. */
void
job_kill(struct job *job)
{
if (job->pid == -1)
return;
kill(job->pid, SIGTERM);
job->pid = -1;
}

View File

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

View File

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

View File

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

10
names.c
View File

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

View File

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

View File

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

View File

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

65
osdep-sunos.c Normal file
View File

@@ -0,0 +1,65 @@
/* $Id: osdep-sunos.c,v 1.2 2009-10-15 07:11:25 nicm Exp $ */
/*
* Copyright (c) 2009 Todd Carson <toc@daybefore.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <procfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
char *
osdep_get_name(int fd, char *tty)
{
struct psinfo p;
struct stat st;
char *path;
ssize_t bytes;
int f;
pid_t pgrp;
if ((f = open(tty, O_RDONLY)) < 0)
return (NULL);
if ((fstat(f, &st) != 0) ||
(ioctl(f, TIOCGPGRP, &pgrp) != 0)) {
close(f);
return (NULL);
}
close(f);
xasprintf(&path, "/proc/%hu/psinfo", pgrp);
f = open(path, O_RDONLY);
xfree(path);
if (f < 0)
return (NULL);
bytes = read(f, &p, sizeof(p));
close(f);
if (bytes != sizeof(p))
return (NULL);
if (p.pr_ttydev != st.st_rdev)
return (NULL);
return (xstrdup(p.pr_fname));
}

View File

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

View File

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

View File

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

View File

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

768
server-client.c Normal file
View File

@@ -0,0 +1,768 @@
/* $Id: server-client.c,v 1.12 2009-11-04 22:46:25 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
void server_client_handle_data(struct client *);
void server_client_check_redraw(struct client *);
void server_client_set_title(struct client *);
void server_client_check_timers(struct client *);
int server_client_msg_dispatch(struct client *);
void server_client_msg_command(struct client *, struct msg_command_data *);
void server_client_msg_identify(
struct client *, struct msg_identify_data *, int);
void server_client_msg_shell(struct client *);
void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...);
void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...);
void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...);
/* Create a new client. */
void
server_client_create(int fd)
{
struct client *c;
int mode;
u_int i;
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
c = xcalloc(1, sizeof *c);
c->references = 0;
imsg_init(&c->ibuf, fd);
if (gettimeofday(&c->creation_time, NULL) != 0)
fatal("gettimeofday failed");
memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
ARRAY_INIT(&c->prompt_hdata);
c->tty.fd = -1;
c->title = NULL;
c->session = NULL;
c->tty.sx = 80;
c->tty.sy = 24;
screen_init(&c->status, c->tty.sx, 1, 0);
job_tree_init(&c->status_jobs);
c->message_string = NULL;
c->prompt_string = NULL;
c->prompt_buffer = NULL;
c->prompt_index = 0;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) == NULL) {
ARRAY_SET(&clients, i, c);
return;
}
}
ARRAY_ADD(&clients, c);
log_debug("new client %d", fd);
}
/* Lost a client. */
void
server_client_lost(struct client *c)
{
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) == c)
ARRAY_SET(&clients, i, NULL);
}
log_debug("lost client %d", c->ibuf.fd);
/*
* If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
* and tty_free might close an unrelated fd.
*/
if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty);
screen_free(&c->status);
job_tree_free(&c->status_jobs);
if (c->title != NULL)
xfree(c->title);
if (c->message_string != NULL)
xfree(c->message_string);
if (c->prompt_string != NULL)
xfree(c->prompt_string);
if (c->prompt_buffer != NULL)
xfree(c->prompt_buffer);
for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
xfree(ARRAY_ITEM(&c->prompt_hdata, i));
ARRAY_FREE(&c->prompt_hdata);
if (c->cwd != NULL)
xfree(c->cwd);
close(c->ibuf.fd);
imsg_clear(&c->ibuf);
for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
if (ARRAY_ITEM(&dead_clients, i) == NULL) {
ARRAY_SET(&dead_clients, i, c);
break;
}
}
if (i == ARRAY_LENGTH(&dead_clients))
ARRAY_ADD(&dead_clients, c);
c->flags |= CLIENT_DEAD;
recalculate_sizes();
}
/* Register clients for poll. */
void
server_client_prepare(void)
{
struct client *c;
u_int i;
int events;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if ((c = ARRAY_ITEM(&clients, i)) == NULL)
continue;
events = 0;
if (!(c->flags & CLIENT_BAD))
events |= POLLIN;
if (c->ibuf.w.queued > 0)
events |= POLLOUT;
server_poll_add(c->ibuf.fd, events, server_client_callback, c);
if (c->tty.fd == -1)
continue;
if (c->flags & CLIENT_SUSPENDED || c->session == NULL)
continue;
events = POLLIN;
if (BUFFER_USED(c->tty.out) > 0)
events |= POLLOUT;
server_poll_add(c->tty.fd, events, server_client_callback, c);
}
}
/* Process a single client event. */
void
server_client_callback(int fd, int events, void *data)
{
struct client *c = data;
if (c->flags & CLIENT_DEAD)
return;
if (fd == c->ibuf.fd) {
if (events & (POLLERR|POLLNVAL|POLLHUP))
goto client_lost;
if (events & POLLOUT && msgbuf_write(&c->ibuf.w) < 0)
goto client_lost;
if (c->flags & CLIENT_BAD) {
if (c->ibuf.w.queued == 0)
goto client_lost;
return;
}
if (events & POLLIN && server_client_msg_dispatch(c) != 0)
goto client_lost;
}
if (c->tty.fd != -1 && fd == c->tty.fd) {
if (c->flags & CLIENT_SUSPENDED || c->session == NULL)
return;
if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0)
goto client_lost;
}
return;
client_lost:
server_client_lost(c);
}
/* Client functions that need to happen every loop. */
void
server_client_loop(void)
{
struct client *c;
struct window *w;
struct window_pane *wp;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
server_client_handle_data(c);
if (c->session != NULL) {
server_client_check_timers(c);
server_client_check_redraw(c);
}
}
/*
* Any windows will have been redrawn as part of clients, so clear
* their flags now.
*/
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
w = ARRAY_ITEM(&windows, i);
if (w == NULL)
continue;
w->flags &= ~WINDOW_REDRAW;
TAILQ_FOREACH(wp, &w->panes, entry)
wp->flags &= ~PANE_REDRAW;
}
}
/* Handle data input or output from client. */
void
server_client_handle_data(struct client *c)
{
struct window *w;
struct window_pane *wp;
struct screen *s;
struct options *oo;
struct timeval tv_add, tv_now;
struct key_binding *bd;
struct keylist *keylist;
struct mouse_event mouse;
int key, status, xtimeout, mode, isprefix;
u_int i;
/* Check and update repeat flag. */
if (gettimeofday(&tv_now, NULL) != 0)
fatal("gettimeofday failed");
xtimeout = options_get_number(&c->session->options, "repeat-time");
if (xtimeout != 0 && c->flags & CLIENT_REPEAT) {
if (timercmp(&tv_now, &c->repeat_timer, >))
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
}
/* Process keys. */
keylist = options_get_data(&c->session->options, "prefix");
while (tty_keys_next(&c->tty, &key, &mouse) == 0) {
if (c->session == NULL)
return;
w = c->session->curw->window;
wp = w->active; /* could die */
oo = &c->session->options;
/* Update activity timer. */
memcpy(&c->activity_time, &tv_now, sizeof c->activity_time);
memcpy(&c->session->activity_time,
&tv_now, sizeof c->session->activity_time);
/* Special case: number keys jump to pane in identify mode. */
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
wp = window_pane_at_index(w, key - '0');
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(w, wp);
server_clear_identify(c);
continue;
}
status_message_clear(c);
server_clear_identify(c);
if (c->prompt_string != NULL) {
status_prompt_key(c, key);
continue;
}
/* Check for mouse keys. */
if (key == KEYC_MOUSE) {
if (options_get_number(oo, "mouse-select-pane")) {
window_set_active_at(w, mouse.x, mouse.y);
wp = w->active;
}
window_pane_mouse(wp, c, &mouse);
continue;
}
/* Is this a prefix key? */
isprefix = 0;
for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
if (key == ARRAY_ITEM(keylist, i)) {
isprefix = 1;
break;
}
}
/* No previous prefix key. */
if (!(c->flags & CLIENT_PREFIX)) {
if (isprefix)
c->flags |= CLIENT_PREFIX;
else {
/* Try as a non-prefix key binding. */
if ((bd = key_bindings_lookup(key)) == NULL)
window_pane_key(wp, c, key);
else
key_bindings_dispatch(bd, c);
}
continue;
}
/* Prefix key already pressed. Reset prefix and lookup key. */
c->flags &= ~CLIENT_PREFIX;
if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
/* If repeating, treat this as a key, else ignore. */
if (c->flags & CLIENT_REPEAT) {
c->flags &= ~CLIENT_REPEAT;
if (isprefix)
c->flags |= CLIENT_PREFIX;
else
window_pane_key(wp, c, key);
}
continue;
}
/* If already repeating, but this key can't repeat, skip it. */
if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
c->flags &= ~CLIENT_REPEAT;
if (isprefix)
c->flags |= CLIENT_PREFIX;
else
window_pane_key(wp, c, key);
continue;
}
/* If this key can repeat, reset the repeat flags and timer. */
if (xtimeout != 0 && bd->can_repeat) {
c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
tv_add.tv_sec = xtimeout / 1000;
tv_add.tv_usec = (xtimeout % 1000) * 1000L;
timeradd(&tv_now, &tv_add, &c->repeat_timer);
}
/* Dispatch the command. */
key_bindings_dispatch(bd, c);
}
if (c->session == NULL)
return;
w = c->session->curw->window;
wp = w->active;
oo = &c->session->options;
s = wp->screen;
/*
* Update cursor position and mode settings. The scroll region and
* attributes are cleared across poll(2) as this is the most likely
* time a user may interrupt tmux, for example with ~^Z in ssh(1). This
* is a compromise between excessive resets and likelihood of an
* interrupt.
*
* tty_region/tty_reset/tty_update_mode already take care of not
* resetting things that are already in their default state.
*/
tty_region(&c->tty, 0, c->tty.sy - 1);
status = options_get_number(oo, "status");
if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
tty_cursor(&c->tty, 0, 0);
else
tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy);
mode = s->mode;
if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
options_get_number(oo, "mouse-select-pane"))
mode |= MODE_MOUSE;
tty_update_mode(&c->tty, mode);
tty_reset(&c->tty);
}
/* Check for client redraws. */
void
server_client_check_redraw(struct client *c)
{
struct session *s = c->session;
struct window_pane *wp;
int flags, redraw;
flags = c->tty.flags & TTY_FREEZE;
c->tty.flags &= ~TTY_FREEZE;
if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
if (options_get_number(&s->options, "set-titles"))
server_client_set_title(c);
if (c->message_string != NULL)
redraw = status_message_redraw(c);
else if (c->prompt_string != NULL)
redraw = status_prompt_redraw(c);
else
redraw = status_redraw(c);
if (!redraw)
c->flags &= ~CLIENT_STATUS;
}
if (c->flags & CLIENT_REDRAW) {
screen_redraw_screen(c, 0);
c->flags &= ~CLIENT_STATUS;
} else {
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
if (wp->flags & PANE_REDRAW)
screen_redraw_pane(c, wp);
}
}
if (c->flags & CLIENT_STATUS)
screen_redraw_screen(c, 1);
c->tty.flags |= flags;
c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS);
}
/* Set client title. */
void
server_client_set_title(struct client *c)
{
struct session *s = c->session;
const char *template;
char *title;
template = options_get_string(&s->options, "set-titles-string");
title = status_replace(c, template, time(NULL));
if (c->title == NULL || strcmp(title, c->title) != 0) {
if (c->title != NULL)
xfree(c->title);
c->title = xstrdup(title);
tty_set_title(&c->tty, c->title);
}
xfree(title);
}
/* Check client timers. */
void
server_client_check_timers(struct client *c)
{
struct session *s = c->session;
struct job *job;
struct timeval tv;
u_int interval;
if (gettimeofday(&tv, NULL) != 0)
fatal("gettimeofday failed");
if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >))
server_clear_identify(c);
if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >))
status_message_clear(c);
if (c->message_string != NULL || c->prompt_string != NULL) {
/*
* Don't need timed redraw for messages/prompts so bail now.
* The status timer isn't reset when they are redrawn anyway.
*/
return;
}
if (!options_get_number(&s->options, "status"))
return;
/* Check timer; resolution is only a second so don't be too clever. */
interval = options_get_number(&s->options, "status-interval");
if (interval == 0)
return;
if (tv.tv_sec < c->status_timer.tv_sec ||
((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) {
/* Run the jobs for this client and schedule for redraw. */
RB_FOREACH(job, jobs, &c->status_jobs)
job_run(job);
c->flags |= CLIENT_STATUS;
}
}
/* Dispatch message from client. */
int
server_client_msg_dispatch(struct client *c)
{
struct imsg imsg;
struct msg_command_data commanddata;
struct msg_identify_data identifydata;
struct msg_environ_data environdata;
ssize_t n, datalen;
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
return (-1);
for (;;) {
if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
return (-1);
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
if (imsg.hdr.peerid != PROTOCOL_VERSION) {
server_write_client(c, MSG_VERSION, NULL, 0);
c->flags |= CLIENT_BAD;
imsg_free(&imsg);
continue;
}
log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
switch (imsg.hdr.type) {
case MSG_COMMAND:
if (datalen != sizeof commanddata)
fatalx("bad MSG_COMMAND size");
memcpy(&commanddata, imsg.data, sizeof commanddata);
server_client_msg_command(c, &commanddata);
break;
case MSG_IDENTIFY:
if (datalen != sizeof identifydata)
fatalx("bad MSG_IDENTIFY size");
if (imsg.fd == -1)
fatalx("MSG_IDENTIFY missing fd");
memcpy(&identifydata, imsg.data, sizeof identifydata);
server_client_msg_identify(c, &identifydata, imsg.fd);
break;
case MSG_RESIZE:
if (datalen != 0)
fatalx("bad MSG_RESIZE size");
tty_resize(&c->tty);
recalculate_sizes();
server_redraw_client(c);
break;
case MSG_EXITING:
if (datalen != 0)
fatalx("bad MSG_EXITING size");
c->session = NULL;
tty_close(&c->tty);
server_write_client(c, MSG_EXITED, NULL, 0);
break;
case MSG_WAKEUP:
case MSG_UNLOCK:
if (datalen != 0)
fatalx("bad MSG_WAKEUP size");
if (!(c->flags & CLIENT_SUSPENDED))
break;
c->flags &= ~CLIENT_SUSPENDED;
if (gettimeofday(&c->activity_time, NULL) != 0)
fatal("gettimeofday");
if (c->session != NULL) {
memcpy(&c->session->activity_time,
&c->activity_time,
sizeof c->session->activity_time);
}
tty_start_tty(&c->tty);
server_redraw_client(c);
recalculate_sizes();
break;
case MSG_ENVIRON:
if (datalen != sizeof environdata)
fatalx("bad MSG_ENVIRON size");
memcpy(&environdata, imsg.data, sizeof environdata);
environdata.var[(sizeof environdata.var) - 1] = '\0';
if (strchr(environdata.var, '=') != NULL)
environ_put(&c->environ, environdata.var);
break;
case MSG_SHELL:
if (datalen != 0)
fatalx("bad MSG_SHELL size");
server_client_msg_shell(c);
break;
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
}
}
/* Callback to send error message to client. */
void printflike2
server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
}
/* Callback to send print message to client. */
void printflike2
server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
}
/* Callback to send print message to client, if not quiet. */
void printflike2
server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
if (be_quiet)
return;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
}
/* Handle command message. */
void
server_client_msg_command(struct client *c, struct msg_command_data *data)
{
struct cmd_ctx ctx;
struct cmd_list *cmdlist = NULL;
struct cmd *cmd;
int argc;
char **argv, *cause;
ctx.error = server_client_msg_error;
ctx.print = server_client_msg_print;
ctx.info = server_client_msg_info;
ctx.msgdata = data;
ctx.curclient = NULL;
ctx.cmdclient = c;
argc = data->argc;
data->argv[(sizeof data->argv) - 1] = '\0';
if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
server_client_msg_error(&ctx, "command too long");
goto error;
}
if (argc == 0) {
argc = 1;
argv = xcalloc(1, sizeof *argv);
*argv = xstrdup("new-session");
}
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
server_client_msg_error(&ctx, "%s", cause);
cmd_free_argv(argc, argv);
goto error;
}
cmd_free_argv(argc, argv);
if (data->pid != -1) {
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (cmd->entry->flags & CMD_CANTNEST) {
server_client_msg_error(&ctx,
"sessions should be nested with care. "
"unset $TMUX to force");
goto error;
}
}
}
if (cmd_list_exec(cmdlist, &ctx) != 1)
server_write_client(c, MSG_EXIT, NULL, 0);
cmd_list_free(cmdlist);
return;
error:
if (cmdlist != NULL)
cmd_list_free(cmdlist);
server_write_client(c, MSG_EXIT, NULL, 0);
}
/* Handle identify message. */
void
server_client_msg_identify(
struct client *c, struct msg_identify_data *data, int fd)
{
c->cwd = NULL;
data->cwd[(sizeof data->cwd) - 1] = '\0';
if (*data->cwd != '\0')
c->cwd = xstrdup(data->cwd);
data->term[(sizeof data->term) - 1] = '\0';
tty_init(&c->tty, fd, data->term);
if (data->flags & IDENTIFY_UTF8)
c->tty.flags |= TTY_UTF8;
if (data->flags & IDENTIFY_256COLOURS)
c->tty.term_flags |= TERM_256COLOURS;
else if (data->flags & IDENTIFY_88COLOURS)
c->tty.term_flags |= TERM_88COLOURS;
tty_resize(&c->tty);
c->flags |= CLIENT_TERMINAL;
}
/* Handle shell message. */
void
server_client_msg_shell(struct client *c)
{
struct msg_shell_data data;
const char *shell;
shell = options_get_string(&global_s_options, "default-shell");
if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL;
if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
server_write_client(c, MSG_SHELL, &data, sizeof data);
c->flags |= CLIENT_BAD; /* it will die after exec */
}

View File

@@ -1,4 +1,4 @@
/* $Id: server-fn.c,v 1.87 2009-09-13 20:37:37 tcunha Exp $ */
/* $Id: server-fn.c,v 1.94 2009-10-12 00:37:41 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,15 +18,12 @@
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
int server_lock_callback(void *, const char *);
void
server_fill_environ(struct session *s, struct environ *env)
{
@@ -107,6 +104,19 @@ server_redraw_session(struct session *s)
}
}
void
server_redraw_session_group(struct session *s)
{
struct session_group *sg;
if ((sg = session_group_find(s)) == NULL)
server_redraw_session(s);
else {
TAILQ_FOREACH(s, &sg->sessions, gentry)
server_redraw_session(s);
}
}
void
server_status_session(struct session *s)
{
@@ -122,6 +132,19 @@ server_status_session(struct session *s)
}
}
void
server_status_session_group(struct session *s)
{
struct session_group *sg;
if ((sg = session_group_find(s)) == NULL)
server_status_session(s);
else {
TAILQ_FOREACH(s, &sg->sessions, gentry)
server_status_session(s);
}
}
void
server_redraw_window(struct window *w)
{
@@ -160,117 +183,52 @@ server_status_window(struct window *w)
void
server_lock(void)
{
struct client *c;
static struct passwd *pw, pwstore;
static char pwbuf[_PW_BUF_LEN];
u_int i;
if (server_locked)
return;
if (getpwuid_r(getuid(), &pwstore, pwbuf, sizeof pwbuf, &pw) != 0) {
server_locked_pw = NULL;
return;
}
server_locked_pw = pw;
struct client *c;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
status_prompt_clear(c);
status_prompt_set(c,
"Password:", server_lock_callback, NULL, c, PROMPT_HIDDEN);
server_redraw_client(c);
server_lock_client(c);
}
server_locked = 1;
}
int
server_lock_callback(unused void *data, const char *s)
{
return (server_unlock(s));
}
int
server_unlock(const char *s)
void
server_lock_session(struct session *s)
{
struct client *c;
#ifdef HAVE_LOGIN_CAP
login_cap_t *lc;
#endif
u_int i;
char *out;
u_int failures, tries, backoff;
if (!server_locked || server_locked_pw == NULL)
return (0);
server_activity = time(NULL);
if (server_activity < password_backoff)
return (-2);
if (server_password != NULL) {
if (s == NULL)
return (-1);
out = crypt(s, server_password);
if (strcmp(out, server_password) != 0)
goto wrong;
}
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL)
if (c == NULL || c->session == NULL || c->session != s)
continue;
server_lock_client(c);
}
}
status_prompt_clear(c);
server_redraw_client(c);
}
void
server_lock_client(struct client *c)
{
const char *cmd;
size_t cmdlen;
struct msg_lock_data lockdata;
server_locked = 0;
password_failures = 0;
password_backoff = 0;
return (0);
if (c->flags & CLIENT_SUSPENDED)
return;
wrong:
password_failures++;
password_backoff = 0;
cmd = options_get_string(&c->session->options, "lock-command");
cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd);
if (cmdlen >= sizeof lockdata.cmd)
return;
tty_stop_tty(&c->tty);
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP));
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR));
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->prompt_buffer == NULL)
continue;
*c->prompt_buffer = '\0';
c->prompt_index = 0;
server_redraw_client(c);
}
/*
* Start slowing down after "login-backoff" attempts and reset every
* "login-tries" attempts.
*/
#ifdef HAVE_LOGIN_CAP
lc = login_getclass(server_locked_pw->pw_class);
if (lc != NULL) {
tries = login_getcapnum(lc, (char *) "login-tries", 10, 10);
backoff = login_getcapnum(lc, (char *) "login-backoff", 3, 3);
} else {
tries = 10;
backoff = 3;
}
#else
tries = 10;
backoff = 3;
#endif
failures = password_failures % tries;
if (failures > backoff) {
password_backoff =
server_activity + ((failures - backoff) * tries / 2);
return (-2);
}
return (-1);
c->flags |= CLIENT_SUSPENDED;
server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata);
}
void
@@ -288,11 +246,86 @@ server_kill_window(struct window *w)
continue;
if (session_detach(s, wl))
server_destroy_session(s);
else
server_destroy_session_group(s);
else {
server_redraw_session(s);
server_status_session_group(s);
}
}
}
int
server_link_window(struct session *src, struct winlink *srcwl,
struct session *dst, int dstidx, int killflag, int selectflag, char **cause)
{
struct winlink *dstwl;
struct session_group *srcsg, *dstsg;
srcsg = session_group_find(src);
dstsg = session_group_find(dst);
if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
xasprintf(cause, "sessions are grouped");
return (-1);
}
dstwl = NULL;
if (dstidx != -1)
dstwl = winlink_find_by_index(&dst->windows, dstidx);
if (dstwl != NULL) {
if (dstwl->window == srcwl->window)
return (0);
if (killflag) {
/*
* Can't use session_detach as it will destroy session
* if this makes it empty.
*/
session_alert_cancel(dst, dstwl);
winlink_stack_remove(&dst->lastw, dstwl);
winlink_remove(&dst->windows, dstwl);
/* Force select/redraw if current. */
if (dstwl == dst->curw) {
selectflag = 1;
dst->curw = NULL;
}
}
}
if (dstidx == -1)
dstidx = -1 - options_get_number(&dst->options, "base-index");
dstwl = session_attach(dst, srcwl->window, dstidx, cause);
if (dstwl == NULL)
return (-1);
if (selectflag)
session_select(dst, dstwl->idx);
server_redraw_session_group(dst);
return (0);
}
void
server_unlink_window(struct session *s, struct winlink *wl)
{
if (session_detach(s, wl))
server_destroy_session_group(s);
else
server_redraw_session_group(s);
}
void
server_destroy_session_group(struct session *s)
{
struct session_group *sg;
if ((sg = session_group_find(s)) == NULL)
server_destroy_session(s);
else {
TAILQ_FOREACH(s, &sg->sessions, gentry)
server_destroy_session(s);
TAILQ_REMOVE(&session_groups, sg, entry);
xfree(sg);
}
recalculate_sizes();
}
void
@@ -321,7 +354,7 @@ server_set_identify(struct client *c)
tv.tv_usec = (delay % 1000) * 1000L;
if (gettimeofday(&c->identify_timer, NULL) != 0)
fatal("gettimeofday");
fatal("gettimeofday failed");
timeradd(&c->identify_timer, &tv, &c->identify_timer);
c->flags |= CLIENT_IDENTIFY;

73
server-job.c Normal file
View File

@@ -0,0 +1,73 @@
/* $Id: server-job.c,v 1.3 2009-11-02 21:38:26 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#include "tmux.h"
/* Register jobs for poll. */
void
server_job_prepare(void)
{
struct job *job;
SLIST_FOREACH(job, &all_jobs, lentry) {
if (job->fd == -1)
continue;
server_poll_add(job->fd, POLLIN, server_job_callback, job);
}
}
/* Process a single job event. */
void
server_job_callback(int fd, int events, void *data)
{
struct job *job = data;
if (job->fd == -1)
return;
if (buffer_poll(fd, events, job->out, NULL) != 0) {
close(job->fd);
job->fd = -1;
}
}
/* Job functions that happen once a loop. */
void
server_job_loop(void)
{
struct job *job;
restart:
SLIST_FOREACH(job, &all_jobs, lentry) {
if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1)
continue;
job->flags |= JOB_DONE;
if (job->callbackfn != NULL) {
job->callbackfn(job);
if ((!job->flags & JOB_PERSIST)) {
job_free(job);
goto restart;
}
}
}
}

View File

@@ -1,292 +0,0 @@
/* $Id: server-msg.c,v 1.84 2009-09-15 23:52:30 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
void server_msg_command(struct client *, struct msg_command_data *);
void server_msg_identify(struct client *, struct msg_identify_data *, int);
void server_msg_resize(struct client *, struct msg_resize_data *);
void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...);
void printflike2 server_msg_command_print(struct cmd_ctx *, const char *, ...);
void printflike2 server_msg_command_info(struct cmd_ctx *, const char *, ...);
int
server_msg_dispatch(struct client *c)
{
struct imsg imsg;
struct msg_command_data commanddata;
struct msg_identify_data identifydata;
struct msg_resize_data resizedata;
struct msg_unlock_data unlockdata;
struct msg_environ_data environdata;
ssize_t n, datalen;
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
return (-1);
for (;;) {
if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
return (-1);
if (n == 0)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
if (imsg.hdr.peerid != PROTOCOL_VERSION) {
server_write_client(c, MSG_VERSION, NULL, 0);
c->flags |= CLIENT_BAD;
imsg_free(&imsg);
continue;
}
log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
switch (imsg.hdr.type) {
case MSG_COMMAND:
if (datalen != sizeof commanddata)
fatalx("bad MSG_COMMAND size");
memcpy(&commanddata, imsg.data, sizeof commanddata);
server_msg_command(c, &commanddata);
break;
case MSG_IDENTIFY:
if (datalen != sizeof identifydata)
fatalx("bad MSG_IDENTIFY size");
memcpy(&identifydata, imsg.data, sizeof identifydata);
server_msg_identify(c, &identifydata, imsg.fd);
break;
case MSG_RESIZE:
if (datalen != sizeof resizedata)
fatalx("bad MSG_RESIZE size");
memcpy(&resizedata, imsg.data, sizeof resizedata);
server_msg_resize(c, &resizedata);
break;
case MSG_EXITING:
if (datalen != 0)
fatalx("bad MSG_EXITING size");
c->session = NULL;
tty_close(&c->tty);
server_write_client(c, MSG_EXITED, NULL, 0);
break;
case MSG_UNLOCK:
if (datalen != sizeof unlockdata)
fatalx("bad MSG_UNLOCK size");
memcpy(&unlockdata, imsg.data, sizeof unlockdata);
unlockdata.pass[(sizeof unlockdata.pass) - 1] = '\0';
switch (server_unlock(unlockdata.pass)) {
case -1:
server_write_error(c, "bad password");
break;
case -2:
server_write_error(c,
"too many bad passwords, sleeping");
break;
}
memset(&unlockdata, 0, sizeof unlockdata);
server_write_client(c, MSG_EXIT, NULL, 0);
break;
case MSG_WAKEUP:
if (datalen != 0)
fatalx("bad MSG_WAKEUP size");
c->flags &= ~CLIENT_SUSPENDED;
tty_start_tty(&c->tty);
server_redraw_client(c);
break;
case MSG_ENVIRON:
if (datalen != sizeof environdata)
fatalx("bad MSG_ENVIRON size");
memcpy(&environdata, imsg.data, sizeof environdata);
environdata.var[(sizeof environdata.var) - 1] = '\0';
if (strchr(environdata.var, '=') != NULL)
environ_put(&c->environ, environdata.var);
break;
default:
fatalx("unexpected message");
}
imsg_free(&imsg);
}
}
void printflike2
server_msg_command_error(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
}
void printflike2
server_msg_command_print(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
}
void printflike2
server_msg_command_info(struct cmd_ctx *ctx, const char *fmt, ...)
{
struct msg_print_data data;
va_list ap;
if (be_quiet)
return;
va_start(ap, fmt);
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
va_end(ap);
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
}
void
server_msg_command(struct client *c, struct msg_command_data *data)
{
struct cmd_ctx ctx;
struct cmd_list *cmdlist = NULL;
struct cmd *cmd;
int argc;
char **argv, *cause;
server_activity = time(NULL);
ctx.error = server_msg_command_error;
ctx.print = server_msg_command_print;
ctx.info = server_msg_command_info;
ctx.msgdata = data;
ctx.curclient = NULL;
ctx.cmdclient = c;
argc = data->argc;
data->argv[(sizeof data->argv) - 1] = '\0';
if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
server_msg_command_error(&ctx, "command too long");
goto error;
}
if (argc == 0) {
argc = 1;
argv = xcalloc(1, sizeof *argv);
*argv = xstrdup("new-session");
}
if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
server_msg_command_error(&ctx, "%s", cause);
cmd_free_argv(argc, argv);
goto error;
}
cmd_free_argv(argc, argv);
if (data->pid != -1) {
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (cmd->entry->flags & CMD_CANTNEST) {
server_msg_command_error(&ctx,
"sessions should be nested with care. "
"unset $TMUX to force");
goto error;
}
}
}
if (cmd_list_exec(cmdlist, &ctx) != 1)
server_write_client(c, MSG_EXIT, NULL, 0);
cmd_list_free(cmdlist);
return;
error:
if (cmdlist != NULL)
cmd_list_free(cmdlist);
server_write_client(c, MSG_EXIT, NULL, 0);
}
void
server_msg_identify(struct client *c, struct msg_identify_data *data, int fd)
{
c->tty.sx = data->sx;
if (c->tty.sx == 0)
c->tty.sx = 80;
c->tty.sy = data->sy;
if (c->tty.sy == 0)
c->tty.sy = 24;
c->cwd = NULL;
data->cwd[(sizeof data->cwd) - 1] = '\0';
if (*data->cwd != '\0')
c->cwd = xstrdup(data->cwd);
data->tty[(sizeof data->tty) - 1] = '\0';
data->term[(sizeof data->term) - 1] = '\0';
tty_init(&c->tty, fd, data->tty, data->term);
if (data->flags & IDENTIFY_UTF8)
c->tty.flags |= TTY_UTF8;
if (data->flags & IDENTIFY_256COLOURS)
c->tty.term_flags |= TERM_256COLOURS;
else if (data->flags & IDENTIFY_88COLOURS)
c->tty.term_flags |= TERM_88COLOURS;
if (data->flags & IDENTIFY_HASDEFAULTS)
c->tty.term_flags |= TERM_HASDEFAULTS;
c->flags |= CLIENT_TERMINAL;
}
void
server_msg_resize(struct client *c, struct msg_resize_data *data)
{
c->tty.sx = data->sx;
if (c->tty.sx == 0)
c->tty.sx = 80;
c->tty.sy = data->sy;
if (c->tty.sy == 0)
c->tty.sy = 24;
c->tty.cx = UINT_MAX;
c->tty.cy = UINT_MAX;
c->tty.rupper = UINT_MAX;
c->tty.rlower = UINT_MAX;
recalculate_sizes();
/* Always redraw this client. */
server_redraw_client(c);
}

341
server-window.c Normal file
View File

@@ -0,0 +1,341 @@
/* $Id: server-window.c,v 1.4 2009-11-04 22:47:29 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#include "tmux.h"
int server_window_backoff(struct window_pane *);
int server_window_check_bell(struct session *, struct window *);
int server_window_check_activity(struct session *, struct window *);
int server_window_check_content(
struct session *, struct window *, struct window_pane *);
void server_window_check_alive(struct window *);
/* Register windows for poll. */
void
server_window_prepare(void)
{
struct window *w;
struct window_pane *wp;
u_int i;
int events;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
if ((w = ARRAY_ITEM(&windows, i)) == NULL)
continue;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
events = 0;
if (!server_window_backoff(wp))
events |= POLLIN;
if (BUFFER_USED(wp->out) > 0)
events |= POLLOUT;
server_poll_add(
wp->fd, events, server_window_callback, wp);
if (wp->pipe_fd == -1)
continue;
events = 0;
if (BUFFER_USED(wp->pipe_buf) > 0)
events |= POLLOUT;
server_poll_add(
wp->pipe_fd, events, server_window_callback, wp);
}
}
}
/* Check if this window should suspend reading. */
int
server_window_backoff(struct window_pane *wp)
{
struct client *c;
u_int i;
if (!window_pane_visible(wp))
return (0);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0)
continue;
if (c->session->curw->window != wp->window)
continue;
if (BUFFER_USED(c->tty.out) > BACKOFF_THRESHOLD)
return (1);
}
return (0);
}
/* Process a single window pane event. */
void
server_window_callback(int fd, int events, void *data)
{
struct window_pane *wp = data;
if (wp->fd == -1)
return;
if (fd == wp->fd) {
if (buffer_poll(fd, events, wp->in, wp->out) != 0) {
close(wp->fd);
wp->fd = -1;
} else
window_pane_parse(wp);
}
if (fd == wp->pipe_fd) {
if (buffer_poll(fd, events, NULL, wp->pipe_buf) != 0) {
buffer_destroy(wp->pipe_buf);
close(wp->pipe_fd);
wp->pipe_fd = -1;
}
}
}
/* Window functions that need to happen every loop. */
void
server_window_loop(void)
{
struct window *w;
struct window_pane *wp;
struct session *s;
u_int i, j;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
w = ARRAY_ITEM(&windows, i);
if (w == NULL)
continue;
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
s = ARRAY_ITEM(&sessions, j);
if (s == NULL || !session_has(s, w))
continue;
if (server_window_check_bell(s, w) ||
server_window_check_activity(s, w))
server_status_session(s);
TAILQ_FOREACH(wp, &w->panes, entry)
server_window_check_content(s, w, wp);
}
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
server_window_check_alive(w);
}
set_window_names();
}
/* Check for bell in window. */
int
server_window_check_bell(struct session *s, struct window *w)
{
struct client *c;
u_int i;
int action, visual;
if (!(w->flags & WINDOW_BELL))
return (0);
if (session_alert_has_window(s, w, WINDOW_BELL))
return (0);
session_alert_add(s, w, WINDOW_BELL);
action = options_get_number(&s->options, "bell-action");
switch (action) {
case BELL_ANY:
if (s->flags & SESSION_UNATTACHED)
break;
visual = options_get_number(&s->options, "visual-bell");
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
if (!visual) {
tty_putcode(&c->tty, TTYC_BEL);
continue;
}
if (c->session->curw->window == w) {
status_message_set(c, "Bell in current window");
continue;
}
status_message_set(c, "Bell in window %u",
winlink_find_by_window(&s->windows, w)->idx);
}
break;
case BELL_CURRENT:
if (s->flags & SESSION_UNATTACHED)
break;
visual = options_get_number(&s->options, "visual-bell");
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
if (c->session->curw->window != w)
continue;
if (!visual) {
tty_putcode(&c->tty, TTYC_BEL);
continue;
}
status_message_set(c, "Bell in current window");
}
break;
}
return (1);
}
/* Check for activity in window. */
int
server_window_check_activity(struct session *s, struct window *w)
{
struct client *c;
u_int i;
if (!(w->flags & WINDOW_ACTIVITY))
return (0);
if (s->curw->window == w)
return (0);
if (!options_get_number(&w->options, "monitor-activity"))
return (0);
if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
return (0);
session_alert_add(s, w, WINDOW_ACTIVITY);
if (s->flags & SESSION_UNATTACHED)
return (0);
if (options_get_number(&s->options, "visual-activity")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
status_message_set(c, "Activity in window %u",
winlink_find_by_window(&s->windows, w)->idx);
}
}
return (1);
}
/* Check for content change in window. */
int
server_window_check_content(
struct session *s, struct window *w, struct window_pane *wp)
{
struct client *c;
u_int i;
char *found, *ptr;
if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */
return (0);
if (s->curw->window == w)
return (0);
ptr = options_get_string(&w->options, "monitor-content");
if (ptr == NULL || *ptr == '\0')
return (0);
if (session_alert_has_window(s, w, WINDOW_CONTENT))
return (0);
if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
return (0);
xfree(found);
session_alert_add(s, w, WINDOW_CONTENT);
if (s->flags & SESSION_UNATTACHED)
return (0);
if (options_get_number(&s->options, "visual-content")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session != s)
continue;
status_message_set(c, "Content in window %u",
winlink_find_by_window(&s->windows, w)->idx);
}
}
return (1);
}
/* Check if window still exists. */
void
server_window_check_alive(struct window *w)
{
struct window_pane *wp, *wq;
struct options *oo = &w->options;
struct session *s;
struct winlink *wl;
u_int i;
int destroyed;
destroyed = 1;
wp = TAILQ_FIRST(&w->panes);
while (wp != NULL) {
wq = TAILQ_NEXT(wp, entry);
/*
* If the pane has died and the remain-on-exit flag is not set,
* remove the pane; otherwise, if the flag is set, don't allow
* the window to be destroyed (or it'll close when the last
* pane dies).
*/
if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) {
layout_close_pane(wp);
window_remove_pane(w, wp);
server_redraw_window(w);
} else
destroyed = 0;
wp = wq;
}
if (!destroyed)
return;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
if (!session_has(s, w))
continue;
restart:
/* Detach window and either redraw or kill clients. */
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window != w)
continue;
if (session_detach(s, wl)) {
server_destroy_session_group(s);
break;
}
server_redraw_session(s);
server_status_session_group(s);
goto restart;
}
}
recalculate_sizes();
}

1207
server.c

File diff suppressed because it is too large Load Diff

197
session.c
View File

@@ -1,4 +1,4 @@
/* $Id: session.c,v 1.66 2009-09-16 12:36:27 nicm Exp $ */
/* $Id: session.c,v 1.70 2009-11-04 22:42:31 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -22,12 +22,14 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "tmux.h"
/* Global session list. */
struct sessions sessions;
struct sessions dead_sessions;
struct session_groups session_groups;
struct winlink *session_next_activity(struct session *, struct winlink *);
struct winlink *session_previous_activity(struct session *, struct winlink *);
@@ -124,11 +126,12 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->references = 0;
s->flags = 0;
if (gettimeofday(&s->tv, NULL) != 0)
fatal("gettimeofday");
if (gettimeofday(&s->creation_time, NULL) != 0)
fatal("gettimeofday failed");
memcpy(&s->activity_time, &s->creation_time, sizeof s->activity_time);
s->curw = NULL;
SLIST_INIT(&s->lastw);
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
SLIST_INIT(&s->alerts);
@@ -161,11 +164,14 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->name = xstrdup(name);
else
xasprintf(&s->name, "%u", i);
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
session_destroy(s);
return (NULL);
if (cmd != NULL) {
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
session_destroy(s);
return (NULL);
}
session_select(s, RB_ROOT(&s->windows)->idx);
}
session_select(s, RB_ROOT(&s->windows)->idx);
log_debug("session %s created", s->name);
@@ -189,13 +195,14 @@ session_destroy(struct session *s)
if (s->tio != NULL)
xfree(s->tio);
session_group_remove(s);
session_alert_cancel(s, NULL);
environ_free(&s->environ);
options_free(&s->options);
paste_free_stack(&s->buffers);
while (!SLIST_EMPTY(&s->lastw))
winlink_stack_remove(&s->lastw, SLIST_FIRST(&s->lastw));
while (!TAILQ_EMPTY(&s->lastw))
winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw));
while (!RB_EMPTY(&s->windows))
winlink_remove(&s->windows, RB_ROOT(&s->windows));
@@ -265,6 +272,7 @@ session_attach(struct session *s, struct window *w, int idx, char **cause)
if ((wl = winlink_add(&s->windows, w, idx)) == NULL)
xasprintf(cause, "index in use: %d", idx);
session_group_synchronize_from(s);
return (wl);
}
@@ -279,6 +287,7 @@ session_detach(struct session *s, struct winlink *wl)
session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
session_group_synchronize_from(s);
if (RB_EMPTY(&s->windows)) {
session_destroy(s);
return (1);
@@ -405,7 +414,7 @@ session_last(struct session *s)
{
struct winlink *wl;
wl = SLIST_FIRST(&s->lastw);
wl = TAILQ_FIRST(&s->lastw);
if (wl == NULL)
return (-1);
if (wl == s->curw)
@@ -417,3 +426,169 @@ session_last(struct session *s)
session_alert_cancel(s, wl);
return (0);
}
/* Find the session group containing a session. */
struct session_group *
session_group_find(struct session *target)
{
struct session_group *sg;
struct session *s;
TAILQ_FOREACH(sg, &session_groups, entry) {
TAILQ_FOREACH(s, &sg->sessions, gentry) {
if (s == target)
return (sg);
}
}
return (NULL);
}
/* Find session group index. */
u_int
session_group_index(struct session_group *sg)
{
struct session_group *sg2;
u_int i;
i = 0;
TAILQ_FOREACH(sg2, &session_groups, entry) {
if (sg == sg2)
return (i);
i++;
}
fatalx("session group not found");
}
/*
* Add a session to the session group containing target, creating it if
* necessary.
*/
void
session_group_add(struct session *target, struct session *s)
{
struct session_group *sg;
if ((sg = session_group_find(target)) == NULL) {
sg = xmalloc(sizeof *sg);
TAILQ_INSERT_TAIL(&session_groups, sg, entry);
TAILQ_INIT(&sg->sessions);
TAILQ_INSERT_TAIL(&sg->sessions, target, gentry);
}
TAILQ_INSERT_TAIL(&sg->sessions, s, gentry);
}
/* Remove a session from its group and destroy the group if empty. */
void
session_group_remove(struct session *s)
{
struct session_group *sg;
if ((sg = session_group_find(s)) == NULL)
return;
TAILQ_REMOVE(&sg->sessions, s, gentry);
if (TAILQ_NEXT(TAILQ_FIRST(&sg->sessions), gentry) == NULL)
TAILQ_REMOVE(&sg->sessions, TAILQ_FIRST(&sg->sessions), gentry);
if (TAILQ_EMPTY(&sg->sessions)) {
TAILQ_REMOVE(&session_groups, sg, entry);
xfree(sg);
}
}
/* Synchronize a session to its session group. */
void
session_group_synchronize_to(struct session *s)
{
struct session_group *sg;
struct session *target;
if ((sg = session_group_find(s)) == NULL)
return;
target = NULL;
TAILQ_FOREACH(target, &sg->sessions, gentry) {
if (target != s)
break;
}
session_group_synchronize1(target, s);
}
/* Synchronize a session group to a session. */
void
session_group_synchronize_from(struct session *target)
{
struct session_group *sg;
struct session *s;
if ((sg = session_group_find(target)) == NULL)
return;
TAILQ_FOREACH(s, &sg->sessions, gentry) {
if (s != target)
session_group_synchronize1(target, s);
}
}
/*
* Synchronize a session with a target session. This means destroying all
* winlinks then recreating them, then updating the current window, last window
* stack and alerts.
*/
void
session_group_synchronize1(struct session *target, struct session *s)
{
struct winlinks old_windows, *ww;
struct winlink_stack old_lastw;
struct winlink *wl, *wl2;
struct session_alert *sa;
/* Don't do anything if the session is empty (it'll be destroyed). */
ww = &target->windows;
if (RB_EMPTY(ww))
return;
/* If the current window has vanished, move to the next now. */
if (s->curw != NULL) {
while (winlink_find_by_index(ww, s->curw->idx) == NULL)
session_next(s, 0);
}
/* Save the old pointer and reset it. */
memcpy(&old_windows, &s->windows, sizeof old_windows);
RB_INIT(&s->windows);
/* Link all the windows from the target. */
RB_FOREACH(wl, winlinks, ww)
winlink_add(&s->windows, wl->window, wl->idx);
/* Fix up the current window. */
if (s->curw != NULL)
s->curw = winlink_find_by_index(&s->windows, s->curw->idx);
else
s->curw = winlink_find_by_index(&s->windows, target->curw->idx);
/* Fix up the last window stack. */
memcpy(&old_lastw, &s->lastw, sizeof old_lastw);
TAILQ_INIT(&s->lastw);
TAILQ_FOREACH(wl, &old_lastw, sentry) {
wl2 = winlink_find_by_index(&s->windows, wl->idx);
if (wl2 != NULL)
TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry);
}
/* And update the alerts list. */
SLIST_FOREACH(sa, &s->alerts, entry) {
wl = winlink_find_by_index(&s->windows, sa->wl->idx);
if (wl == NULL)
session_alert_cancel(s, sa->wl);
else
sa->wl = wl;
}
/* Then free the old winlinks list. */
while (!RB_EMPTY(&old_windows)) {
wl = RB_ROOT(&old_windows);
RB_REMOVE(winlinks, &old_windows, wl);
xfree(wl);
}
}

131
status.c
View File

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

289
tmux.1
View File

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

244
tmux.c
View File

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

403
tmux.h
View File

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

View File

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

View File

@@ -1,4 +1,4 @@
/* $Id: tty-keys.c,v 1.29 2009-07-28 22:37:02 tcunha Exp $ */
/* $Id: tty-keys.c,v 1.38 2009-10-28 23:05:01 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -25,9 +25,12 @@
#include "tmux.h"
/*
* Handle keys input from the outside terminal.
*/
void tty_keys_add(struct tty *, const char *, int, int);
int tty_keys_parse_xterm(struct tty *, char *, size_t, size_t *);
int tty_keys_parse_mouse(struct tty *, char *, size_t, size_t *, u_char *);
int tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *);
struct tty_key_ent {
enum tty_code_code code;
@@ -39,85 +42,145 @@ struct tty_key_ent {
struct tty_key_ent tty_keys[] = {
/* Function keys. */
{ TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL },
{ TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL },
{ TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL },
{ TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL },
{ TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL },
{ TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL },
{ TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL },
{ TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL },
{ TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL },
{ TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL },
{ TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL },
{ TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL },
{ TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL },
{ TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL },
{ TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL },
{ TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL },
{ TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL },
{ TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL },
{ TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL },
{ TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL },
{ TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL },
{ TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL },
{ TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL },
{ TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL },
{ TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL },
{ TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL },
{ TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL },
{ TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL },
{ TTYC_KF1, NULL, KEYC_F1, TTYKEY_CTRL },
{ TTYC_KF2, NULL, KEYC_F2, TTYKEY_CTRL },
{ TTYC_KF3, NULL, KEYC_F3, TTYKEY_CTRL },
{ TTYC_KF4, NULL, KEYC_F4, TTYKEY_CTRL },
{ TTYC_KF5, NULL, KEYC_F5, TTYKEY_CTRL },
{ TTYC_KF6, NULL, KEYC_F6, TTYKEY_CTRL },
{ TTYC_KF7, NULL, KEYC_F7, TTYKEY_CTRL },
{ TTYC_KF8, NULL, KEYC_F8, TTYKEY_CTRL },
{ TTYC_KF9, NULL, KEYC_F9, TTYKEY_CTRL },
{ TTYC_KF10, NULL, KEYC_F10, TTYKEY_CTRL },
{ TTYC_KF11, NULL, KEYC_F11, TTYKEY_CTRL },
{ TTYC_KF12, NULL, KEYC_F12, TTYKEY_CTRL },
{ TTYC_KF13, NULL, KEYC_F13, TTYKEY_CTRL },
{ TTYC_KF14, NULL, KEYC_F14, TTYKEY_CTRL },
{ TTYC_KF15, NULL, KEYC_F15, TTYKEY_CTRL },
{ TTYC_KF16, NULL, KEYC_F16, TTYKEY_CTRL },
{ TTYC_KF17, NULL, KEYC_F17, TTYKEY_CTRL },
{ TTYC_KF18, NULL, KEYC_F18, TTYKEY_CTRL },
{ TTYC_KF19, NULL, KEYC_F19, TTYKEY_CTRL },
{ TTYC_KF20, NULL, KEYC_F20, TTYKEY_CTRL },
{ TTYC_KICH1, NULL, KEYC_IC, TTYKEY_CTRL },
{ TTYC_KDCH1, NULL, KEYC_DC, TTYKEY_CTRL },
{ TTYC_KHOME, NULL, KEYC_HOME, TTYKEY_CTRL },
{ TTYC_KEND, NULL, KEYC_END, TTYKEY_CTRL },
{ TTYC_KNP, NULL, KEYC_NPAGE, TTYKEY_CTRL },
{ TTYC_KPP, NULL, KEYC_PPAGE, TTYKEY_CTRL },
{ TTYC_KCBT, NULL, KEYC_BTAB, TTYKEY_CTRL },
/* Arrow keys. */
{ 0, "\033OA", KEYC_UP, TTYKEY_RAW },
{ 0, "\033OB", KEYC_DOWN, TTYKEY_RAW },
{ 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW },
{ 0, "\033OD", KEYC_LEFT, TTYKEY_RAW },
{ 0, "\033OA", KEYC_UP, TTYKEY_RAW },
{ 0, "\033OB", KEYC_DOWN, TTYKEY_RAW },
{ 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW },
{ 0, "\033OD", KEYC_LEFT, TTYKEY_RAW },
{ 0, "\033[A", KEYC_UP, TTYKEY_RAW },
{ 0, "\033[B", KEYC_DOWN, TTYKEY_RAW },
{ 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW },
{ 0, "\033[D", KEYC_LEFT, TTYKEY_RAW },
{ 0, "\033[A", KEYC_UP, TTYKEY_RAW },
{ 0, "\033[B", KEYC_DOWN, TTYKEY_RAW },
{ 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW },
{ 0, "\033[D", KEYC_LEFT, TTYKEY_RAW },
{ 0, "\033Oa", KEYC_UP | KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033Ob", KEYC_DOWN | KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033Oc", KEYC_RIGHT | KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033Od", KEYC_LEFT | KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033[a", KEYC_UP | KEYC_SHIFT, TTYKEY_RAW },
{ 0, "\033[b", KEYC_DOWN | KEYC_SHIFT, TTYKEY_RAW },
{ 0, "\033[c", KEYC_RIGHT | KEYC_SHIFT, TTYKEY_RAW },
{ 0, "\033[d", KEYC_LEFT | KEYC_SHIFT, TTYKEY_RAW },
{ TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL },
{ TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL },
{ TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL },
{ TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL },
{ TTYC_KCUU1, NULL, KEYC_UP, TTYKEY_CTRL },
{ TTYC_KCUD1, NULL, KEYC_DOWN, TTYKEY_CTRL },
{ TTYC_KCUB1, NULL, KEYC_LEFT, TTYKEY_CTRL },
{ TTYC_KCUF1, NULL, KEYC_RIGHT, TTYKEY_CTRL },
/* Special-case arrow keys for rxvt until terminfo has kRIT5 etc. */
{ 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW },
{ 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW },
{ 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW },
{ 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW },
{ 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW },
/*
* Numeric keypad. termcap and terminfo are totally confusing for this.
* There are definitions for some keypad keys and for function keys,
* but these seem to now be used for the real function keys rather than
* for the keypad keys in application mode (which is different from
* what it says in the termcap file). So, we just hardcode the vt100
* escape sequences here and always put the terminal into keypad_xmit
* mode. Translation of numbers mode/applications mode is done in
* input-keys.c.
* Numeric keypad. Just use the vt100 escape sequences here and always
* put the terminal into keypad_xmit mode. Translation of numbers
* mode/applications mode is done in input-keys.c.
*/
{ 0, "\033Oo", KEYC_KP0_1, TTYKEY_RAW },
{ 0, "\033Oj", KEYC_KP0_2, TTYKEY_RAW },
{ 0, "\033Om", KEYC_KP0_3, TTYKEY_RAW },
{ 0, "\033Ow", KEYC_KP1_0, TTYKEY_RAW },
{ 0, "\033Ox", KEYC_KP1_1, TTYKEY_RAW },
{ 0, "\033Oy", KEYC_KP1_2, TTYKEY_RAW },
{ 0, "\033Ok", KEYC_KP1_3, TTYKEY_RAW },
{ 0, "\033Ot", KEYC_KP2_0, TTYKEY_RAW },
{ 0, "\033Ou", KEYC_KP2_1, TTYKEY_RAW },
{ 0, "\033Ov", KEYC_KP2_2, TTYKEY_RAW },
{ 0, "\033Oq", KEYC_KP3_0, TTYKEY_RAW },
{ 0, "\033Or", KEYC_KP3_1, TTYKEY_RAW },
{ 0, "\033Os", KEYC_KP3_2, TTYKEY_RAW },
{ 0, "\033OM", KEYC_KP3_3, TTYKEY_RAW },
{ 0, "\033Op", KEYC_KP4_0, TTYKEY_RAW },
{ 0, "\033On", KEYC_KP4_2, TTYKEY_RAW },
{ 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW },
{ 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW },
{ 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW },
{ 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW },
{ 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW },
{ 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW },
{ 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW },
{ 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW },
{ 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW },
{ 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW },
{ 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW },
{ 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW },
{ 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW },
{ 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW },
{ 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW },
{ 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW },
/* Key and modifier capabilities. */
{ TTYC_KDC2, NULL, KEYC_DC|KEYC_SHIFT, 0 },
{ TTYC_KDC3, NULL, KEYC_DC|KEYC_ESCAPE, 0 },
{ TTYC_KDC4, NULL, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KDC5, NULL, KEYC_DC|KEYC_CTRL, 0 },
{ TTYC_KDC6, NULL, KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KDC7, NULL, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KDN2, NULL, KEYC_DOWN|KEYC_SHIFT, 0 },
{ TTYC_KDN3, NULL, KEYC_DOWN|KEYC_ESCAPE, 0 },
{ TTYC_KDN4, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KDN5, NULL, KEYC_DOWN|KEYC_CTRL, 0 },
{ TTYC_KDN6, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KDN7, NULL, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KEND2, NULL, KEYC_END|KEYC_SHIFT, 0 },
{ TTYC_KEND3, NULL, KEYC_END|KEYC_ESCAPE, 0 },
{ TTYC_KEND4, NULL, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KEND5, NULL, KEYC_END|KEYC_CTRL, 0 },
{ TTYC_KEND6, NULL, KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KEND7, NULL, KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KHOM2, NULL, KEYC_HOME|KEYC_SHIFT, 0 },
{ TTYC_KHOM3, NULL, KEYC_HOME|KEYC_ESCAPE, 0 },
{ TTYC_KHOM4, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KHOM5, NULL, KEYC_HOME|KEYC_CTRL, 0 },
{ TTYC_KHOM6, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KHOM7, NULL, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KIC2, NULL, KEYC_IC|KEYC_SHIFT, 0 },
{ TTYC_KIC3, NULL, KEYC_IC|KEYC_ESCAPE, 0 },
{ TTYC_KIC4, NULL, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KIC5, NULL, KEYC_IC|KEYC_CTRL, 0 },
{ TTYC_KIC6, NULL, KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KIC7, NULL, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KLFT2, NULL, KEYC_LEFT|KEYC_SHIFT, 0 },
{ TTYC_KLFT3, NULL, KEYC_LEFT|KEYC_ESCAPE, 0 },
{ TTYC_KLFT4, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KLFT5, NULL, KEYC_LEFT|KEYC_CTRL, 0 },
{ TTYC_KLFT6, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KLFT7, NULL, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KNXT2, NULL, KEYC_NPAGE|KEYC_SHIFT, 0 },
{ TTYC_KNXT3, NULL, KEYC_NPAGE|KEYC_ESCAPE, 0 },
{ TTYC_KNXT4, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KNXT5, NULL, KEYC_NPAGE|KEYC_CTRL, 0 },
{ TTYC_KNXT6, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KNXT7, NULL, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KPRV2, NULL, KEYC_PPAGE|KEYC_SHIFT, 0 },
{ TTYC_KPRV3, NULL, KEYC_PPAGE|KEYC_ESCAPE, 0 },
{ TTYC_KPRV4, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KPRV5, NULL, KEYC_PPAGE|KEYC_CTRL, 0 },
{ TTYC_KPRV6, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KPRV7, NULL, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KRIT2, NULL, KEYC_RIGHT|KEYC_SHIFT, 0 },
{ TTYC_KRIT3, NULL, KEYC_RIGHT|KEYC_ESCAPE, 0 },
{ TTYC_KRIT4, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KRIT5, NULL, KEYC_RIGHT|KEYC_CTRL, 0 },
{ TTYC_KRIT6, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KRIT7, NULL, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 },
{ TTYC_KUP2, NULL, KEYC_UP|KEYC_SHIFT, 0 },
{ TTYC_KUP3, NULL, KEYC_UP|KEYC_ESCAPE, 0 },
{ TTYC_KUP4, NULL, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE, 0 },
{ TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 },
{ TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 },
{ TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 },
};
RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp);
@@ -231,7 +294,7 @@ tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size)
}
int
tty_keys_next(struct tty *tty, int *key, u_char *mouse)
tty_keys_next(struct tty *tty, int *key, struct mouse_event *mouse)
{
struct tty_key *tk;
struct timeval tv;
@@ -269,14 +332,14 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse)
}
/* Not found. Is this a mouse key press? */
*key = tty_keys_parse_mouse(tty, buf, len, &size, mouse);
*key = tty_keys_mouse(buf, len, &size, mouse);
if (*key != KEYC_NONE) {
buffer_remove(tty->in, size);
goto found;
}
/* Not found. Try to parse xterm-type arguments. */
*key = tty_keys_parse_xterm(tty, buf, len, &size);
/* Not found. Try to parse a key with an xterm-style modifier. */
*key = xterm_keys_find(buf, len, &size);
if (*key != KEYC_NONE) {
buffer_remove(tty->in, size);
goto found;
@@ -287,7 +350,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse)
tv.tv_sec = 0;
tv.tv_usec = ESCAPE_PERIOD * 1000L;
if (gettimeofday(&tty->key_timer, NULL) != 0)
fatal("gettimeofday");
fatal("gettimeofday failed");
timeradd(&tty->key_timer, &tv, &tty->key_timer);
tty->flags |= TTY_ESCAPE;
@@ -317,7 +380,7 @@ tty_keys_next(struct tty *tty, int *key, u_char *mouse)
/* If the timer hasn't expired, keep waiting. */
if (gettimeofday(&tv, NULL) != 0)
fatal("gettimeofday");
fatal("gettimeofday failed");
if (timercmp(&tty->key_timer, &tv, >))
return (1);
@@ -331,8 +394,7 @@ found:
}
int
tty_keys_parse_mouse(
unused struct tty *tty, char *buf, size_t len, size_t *size, u_char *mouse)
tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m)
{
/*
* Mouse sequences are \033[M followed by three characters indicating
@@ -344,76 +406,13 @@ tty_keys_parse_mouse(
return (KEYC_NONE);
*size = 6;
if (buf[3] < 32 || buf[4] < 33 || buf[5] < 33)
m->b = buf[3];
m->x = buf[4];
m->y = buf[5];
if (m->b < 32 || m->x < 33 || m->y < 33)
return (KEYC_NONE);
mouse[0] = buf[3] - 32;
mouse[1] = buf[4] - 33;
mouse[2] = buf[5] - 33;
m->b -= 32;
m->x -= 33;
m->y -= 33;
return (KEYC_MOUSE);
}
int
tty_keys_parse_xterm(struct tty *tty, char *buf, size_t len, size_t *size)
{
struct tty_key *tk;
char tmp[5];
size_t tmplen;
int key;
/*
* xterm sequences with modifier keys are of the form:
*
* ^[[1;xD becomes ^[[D
* ^[[5;x~ becomes ^[[5~
*
* This function is a bit of a hack. Need to figure out what exact
* format and meaning xterm outputs and fix it. XXX
*/
log_debug("xterm input is: %.*s", (int) len, buf);
if (len != 6 || memcmp(buf, "\033[1;", 4) != 0)
return (KEYC_NONE);
*size = 6;
tmplen = 0;
tmp[tmplen++] = '[';
if (buf[5] == '~') {
tmp[tmplen++] = buf[2];
tmp[tmplen++] = '~';
} else
tmp[tmplen++] = buf[5];
log_debug("xterm output is: %.*s", (int) tmplen, tmp);
tk = tty_keys_find(tty, tmp, tmplen, size);
if (tk == NULL)
return (KEYC_NONE);
key = tk->key;
switch (buf[4]) {
case '8':
key |= KEYC_SHIFT|KEYC_ESCAPE|KEYC_CTRL;
break;
case '7':
key |= KEYC_ESCAPE|KEYC_CTRL;
break;
case '6':
key |= KEYC_SHIFT|KEYC_CTRL;
break;
case '5':
key |= KEYC_CTRL;
break;
case '4':
key |= KEYC_SHIFT|KEYC_ESCAPE;
break;
case '3':
key |= KEYC_ESCAPE;
break;
case '2':
key |= KEYC_SHIFT;
break;
}
*size = 6;
return (key);
}

View File

@@ -1,4 +1,4 @@
/* $Id: tty-term.c,v 1.30 2009-08-23 11:50:39 nicm Exp $ */
/* $Id: tty-term.c,v 1.35 2009-10-28 23:01:44 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -32,8 +32,8 @@ char *tty_term_strip(const char *);
struct tty_terms tty_terms = SLIST_HEAD_INITIALIZER(tty_terms);
struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_AX, TTYCODE_FLAG, "AX" },
{ TTYC_ACSC, TTYCODE_STRING, "acsc" },
{ TTYC_AX, TTYCODE_FLAG, "AX" },
{ TTYC_BEL, TTYCODE_STRING, "bel" },
{ TTYC_BLINK, TTYCODE_STRING, "blink" },
{ TTYC_BOLD, TTYCODE_STRING, "bold" },
@@ -42,9 +42,15 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_CNORM, TTYCODE_STRING, "cnorm" },
{ TTYC_COLORS, TTYCODE_NUMBER, "colors" },
{ TTYC_CSR, TTYCODE_STRING, "csr" },
{ TTYC_CUB, TTYCODE_STRING, "cub" },
{ TTYC_CUB1, TTYCODE_STRING, "cub1" },
{ TTYC_CUD, TTYCODE_STRING, "cud" },
{ TTYC_CUD1, TTYCODE_STRING, "cud1" },
{ TTYC_CUF, TTYCODE_STRING, "cuf" },
{ TTYC_CUF1, TTYCODE_STRING, "cuf1" },
{ TTYC_CUP, TTYCODE_STRING, "cup" },
{ TTYC_CUU, TTYCODE_STRING, "cuu" },
{ TTYC_CUU1, TTYCODE_STRING, "cuu1" },
{ TTYC_DCH, TTYCODE_STRING, "dch" },
{ TTYC_DCH1, TTYCODE_STRING, "dch1" },
{ TTYC_DIM, TTYCODE_STRING, "dim" },
@@ -53,6 +59,8 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_EL, TTYCODE_STRING, "el" },
{ TTYC_EL1, TTYCODE_STRING, "el1" },
{ TTYC_ENACS, TTYCODE_STRING, "enacs" },
{ TTYC_HOME, TTYCODE_STRING, "home" },
{ TTYC_HPA, TTYCODE_STRING, "hpa" },
{ TTYC_ICH, TTYCODE_STRING, "ich" },
{ TTYC_ICH1, TTYCODE_STRING, "ich1" },
{ TTYC_IL, TTYCODE_STRING, "il" },
@@ -66,8 +74,26 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_KCUD1, TTYCODE_STRING, "kcud1" },
{ TTYC_KCUF1, TTYCODE_STRING, "kcuf1" },
{ TTYC_KCUU1, TTYCODE_STRING, "kcuu1" },
{ TTYC_KDC2, TTYCODE_STRING, "kDC" },
{ TTYC_KDC3, TTYCODE_STRING, "kDC3" },
{ TTYC_KDC4, TTYCODE_STRING, "kDC4" },
{ TTYC_KDC5, TTYCODE_STRING, "kDC5" },
{ TTYC_KDC6, TTYCODE_STRING, "kDC6" },
{ TTYC_KDC7, TTYCODE_STRING, "kDC7" },
{ TTYC_KDCH1, TTYCODE_STRING, "kdch1" },
{ TTYC_KDN2, TTYCODE_STRING, "kDN" },
{ TTYC_KDN3, TTYCODE_STRING, "kDN3" },
{ TTYC_KDN4, TTYCODE_STRING, "kDN4" },
{ TTYC_KDN5, TTYCODE_STRING, "kDN5" },
{ TTYC_KDN6, TTYCODE_STRING, "kDN6" },
{ TTYC_KDN7, TTYCODE_STRING, "kDN7" },
{ TTYC_KEND, TTYCODE_STRING, "kend" },
{ TTYC_KEND2, TTYCODE_STRING, "kEND" },
{ TTYC_KEND3, TTYCODE_STRING, "kEND3" },
{ TTYC_KEND4, TTYCODE_STRING, "kEND4" },
{ TTYC_KEND5, TTYCODE_STRING, "kEND5" },
{ TTYC_KEND6, TTYCODE_STRING, "kEND6" },
{ TTYC_KEND7, TTYCODE_STRING, "kEND7" },
{ TTYC_KF1, TTYCODE_STRING, "kf1" },
{ TTYC_KF10, TTYCODE_STRING, "kf10" },
{ TTYC_KF11, TTYCODE_STRING, "kf11" },
@@ -79,8 +105,8 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_KF17, TTYCODE_STRING, "kf17" },
{ TTYC_KF18, TTYCODE_STRING, "kf18" },
{ TTYC_KF19, TTYCODE_STRING, "kf19" },
{ TTYC_KF20, TTYCODE_STRING, "kf20" },
{ TTYC_KF2, TTYCODE_STRING, "kf2" },
{ TTYC_KF20, TTYCODE_STRING, "kf20" },
{ TTYC_KF3, TTYCODE_STRING, "kf3" },
{ TTYC_KF4, TTYCODE_STRING, "kf4" },
{ TTYC_KF5, TTYCODE_STRING, "kf5" },
@@ -88,11 +114,53 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_KF7, TTYCODE_STRING, "kf7" },
{ TTYC_KF8, TTYCODE_STRING, "kf8" },
{ TTYC_KF9, TTYCODE_STRING, "kf9" },
{ TTYC_KHOM2, TTYCODE_STRING, "kHOM" },
{ TTYC_KHOM3, TTYCODE_STRING, "kHOM3" },
{ TTYC_KHOM4, TTYCODE_STRING, "kHOM4" },
{ TTYC_KHOM5, TTYCODE_STRING, "kHOM5" },
{ TTYC_KHOM6, TTYCODE_STRING, "kHOM6" },
{ TTYC_KHOM7, TTYCODE_STRING, "kHOM7" },
{ TTYC_KHOME, TTYCODE_STRING, "khome" },
{ TTYC_KIC2, TTYCODE_STRING, "kIC" },
{ TTYC_KIC3, TTYCODE_STRING, "kIC3" },
{ TTYC_KIC4, TTYCODE_STRING, "kIC4" },
{ TTYC_KIC5, TTYCODE_STRING, "kIC5" },
{ TTYC_KIC6, TTYCODE_STRING, "kIC6" },
{ TTYC_KIC7, TTYCODE_STRING, "kIC7" },
{ TTYC_KICH1, TTYCODE_STRING, "kich1" },
{ TTYC_KLFT2, TTYCODE_STRING, "kLFT" },
{ TTYC_KLFT3, TTYCODE_STRING, "kLFT3" },
{ TTYC_KLFT4, TTYCODE_STRING, "kLFT4" },
{ TTYC_KLFT5, TTYCODE_STRING, "kLFT5" },
{ TTYC_KLFT6, TTYCODE_STRING, "kLFT6" },
{ TTYC_KLFT7, TTYCODE_STRING, "kLFT7" },
{ TTYC_KMOUS, TTYCODE_STRING, "kmous" },
{ TTYC_KNP, TTYCODE_STRING, "knp" },
{ TTYC_KNXT2, TTYCODE_STRING, "kNXT" },
{ TTYC_KNXT3, TTYCODE_STRING, "kNXT3" },
{ TTYC_KNXT4, TTYCODE_STRING, "kNXT4" },
{ TTYC_KNXT5, TTYCODE_STRING, "kNXT5" },
{ TTYC_KNXT6, TTYCODE_STRING, "kNXT6" },
{ TTYC_KNXT7, TTYCODE_STRING, "kNXT7" },
{ TTYC_KPP, TTYCODE_STRING, "kpp" },
{ TTYC_KPRV2, TTYCODE_STRING, "kPRV" },
{ TTYC_KPRV3, TTYCODE_STRING, "kPRV3" },
{ TTYC_KPRV4, TTYCODE_STRING, "kPRV4" },
{ TTYC_KPRV5, TTYCODE_STRING, "kPRV5" },
{ TTYC_KPRV6, TTYCODE_STRING, "kPRV6" },
{ TTYC_KPRV7, TTYCODE_STRING, "kPRV7" },
{ TTYC_KRIT2, TTYCODE_STRING, "kRIT" },
{ TTYC_KRIT3, TTYCODE_STRING, "kRIT3" },
{ TTYC_KRIT4, TTYCODE_STRING, "kRIT4" },
{ TTYC_KRIT5, TTYCODE_STRING, "kRIT5" },
{ TTYC_KRIT6, TTYCODE_STRING, "kRIT6" },
{ TTYC_KRIT7, TTYCODE_STRING, "kRIT7" },
{ TTYC_KUP2, TTYCODE_STRING, "kUP" },
{ TTYC_KUP3, TTYCODE_STRING, "kUP3" },
{ TTYC_KUP4, TTYCODE_STRING, "kUP4" },
{ TTYC_KUP5, TTYCODE_STRING, "kUP5" },
{ TTYC_KUP6, TTYCODE_STRING, "kUP6" },
{ TTYC_KUP7, TTYCODE_STRING, "kUP7" },
{ TTYC_OP, TTYCODE_STRING, "op" },
{ TTYC_REV, TTYCODE_STRING, "rev" },
{ TTYC_RI, TTYCODE_STRING, "ri" },
@@ -109,6 +177,7 @@ struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
{ TTYC_SMKX, TTYCODE_STRING, "smkx" },
{ TTYC_SMSO, TTYCODE_STRING, "smso" },
{ TTYC_SMUL, TTYCODE_STRING, "smul" },
{ TTYC_VPA, TTYCODE_STRING, "vpa" },
{ TTYC_XENL, TTYCODE_FLAG, "xenl" },
};
@@ -338,22 +407,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
goto error;
}
/*
* Figure out if terminal support default colours. AX is a screen
* extension which indicates this. Also check if op (orig_pair) uses
* the default colours - if it does, this is a good indication the
* terminal supports them.
*/
if (tty_term_flag(term, TTYC_AX))
term->flags |= TERM_HASDEFAULTS;
if (strcmp(tty_term_string(term, TTYC_OP), "\033[39;49m") == 0)
term->flags |= TERM_HASDEFAULTS;
/*
* Try to figure out if we have 256 or 88 colours. The standard xterm
* definitions are broken (well, or the way they are parsed is: in any
* case they end up returning 8). So also do a hack.
*/
/* Figure out if we have 256 or 88 colours. */
if (tty_term_number(term, TTYC_COLORS) == 256)
term->flags |= TERM_256COLOURS;
if (tty_term_number(term, TTYC_COLORS) == 88)
@@ -417,13 +471,13 @@ tty_term_string(struct tty_term *term, enum tty_code_code code)
const char *
tty_term_string1(struct tty_term *term, enum tty_code_code code, int a)
{
return (tparm((char *) tty_term_string(term, code), a));
return (tparm((char *) tty_term_string(term, code), a, 0, 0, 0, 0, 0, 0, 0, 0));
}
const char *
tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b)
{
return (tparm((char *) tty_term_string(term, code), a, b));
return (tparm((char *) tty_term_string(term, code), a, b, 0, 0, 0, 0, 0, 0, 0));
}
int

766
tty.c

File diff suppressed because it is too large Load Diff

118
utf8.c
View File

@@ -1,4 +1,4 @@
/* $Id: utf8.c,v 1.9 2009-06-25 16:21:32 nicm Exp $ */
/* $Id: utf8.c,v 1.11 2009-10-23 17:21:34 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -196,9 +196,56 @@ struct utf8_width_entry utf8_width_table[] = {
struct utf8_width_entry *utf8_width_root = NULL;
int utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *);
void utf8_print(struct utf8_width_entry *, int);
u_int utf8_combine(const u_char *);
u_int utf8_combine(const struct utf8_data *);
u_int utf8_width(const struct utf8_data *);
/*
* Open UTF-8 sequence.
*
* 11000010-11011111 C2-DF start of 2-byte sequence
* 11100000-11101111 E0-EF start of 3-byte sequence
* 11110000-11110100 F0-F4 start of 4-byte sequence
*
* Returns 1 if more UTF-8 to come, 0 if not UTF-8.
*/
int
utf8_open(struct utf8_data *utf8data, u_char ch)
{
memset(utf8data, 0, sizeof *utf8data);
if (ch >= 0xc2 && ch <= 0xdf)
utf8data->size = 2;
else if (ch >= 0xe0 && ch <= 0xef)
utf8data->size = 3;
else if (ch >= 0xf0 && ch <= 0xf4)
utf8data->size = 4;
else
return (0);
utf8_append(utf8data, ch);
return (1);
}
/*
* Append character to UTF-8, closing if finished.
*
* Returns 1 if more UTF-8 data to come, 0 if finished.
*/
int
utf8_append(struct utf8_data *utf8data, u_char ch)
{
if (utf8data->have >= utf8data->size)
fatalx("UTF-8 character overflow");
if (utf8data->size > sizeof utf8data->data)
fatalx("UTF-8 character size too large");
utf8data->data[utf8data->have++] = ch;
if (utf8data->have != utf8data->size)
return (1);
utf8data->width = utf8_width(utf8data);
return (0);
}
/* Check if two width tree entries overlap. */
int
utf8_overlap(
struct utf8_width_entry *item1, struct utf8_width_entry *item2)
@@ -214,6 +261,7 @@ utf8_overlap(
return (0);
}
/* Build UTF-8 width tree. */
void
utf8_build(void)
{
@@ -240,52 +288,50 @@ utf8_build(void)
}
}
void
utf8_print(struct utf8_width_entry *node, int n)
{
log_debug("%*s%04x -> %04x", n, " ", node->first, node->last);
if (node->left != NULL)
utf8_print(node->left, n + 1);
if (node->right != NULL)
utf8_print(node->right, n + 1);
}
/* Combine UTF-8 into 32-bit Unicode. */
u_int
utf8_combine(const u_char *data)
utf8_combine(const struct utf8_data *utf8data)
{
u_int uvalue;
u_int value;
if (data[1] == 0xff)
uvalue = data[0];
else if (data[2] == 0xff) {
uvalue = data[1] & 0x3f;
uvalue |= (data[0] & 0x1f) << 6;
} else if (data[3] == 0xff) {
uvalue = data[2] & 0x3f;
uvalue |= (data[1] & 0x3f) << 6;
uvalue |= (data[0] & 0x0f) << 12;
} else {
uvalue = data[3] & 0x3f;
uvalue |= (data[2] & 0x3f) << 6;
uvalue |= (data[1] & 0x3f) << 12;
uvalue |= (data[0] & 0x3f) << 18;
value = 0xff;
switch (utf8data->size) {
case 1:
value = utf8data->data[0];
break;
case 2:
value = utf8data->data[1] & 0x3f;
value |= (utf8data->data[0] & 0x1f) << 6;
break;
case 3:
value = utf8data->data[2] & 0x3f;
value |= (utf8data->data[1] & 0x3f) << 6;
value |= (utf8data->data[0] & 0x0f) << 12;
break;
case 4:
value = utf8data->data[3] & 0x3f;
value |= (utf8data->data[2] & 0x3f) << 6;
value |= (utf8data->data[1] & 0x3f) << 12;
value |= (utf8data->data[0] & 0x3f) << 18;
break;
}
return (uvalue);
return (value);
}
int
utf8_width(const u_char *udata)
/* Lookup width of UTF-8 data in tree. */
u_int
utf8_width(const struct utf8_data *utf8data)
{
struct utf8_width_entry *item;
u_int uvalue;
u_int value;
uvalue = utf8_combine(udata);
value = utf8_combine(utf8data);
item = utf8_width_root;
while (item != NULL) {
if (uvalue < item->first)
if (value < item->first)
item = item->left;
else if (uvalue > item->last)
else if (value > item->last)
item = item->right;
else
return (item->width);

View File

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

View File

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

View File

@@ -1,323 +0,0 @@
/* $Id: window-scroll.c,v 1.41 2009-09-11 14:13:52 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include "tmux.h"
struct screen *window_scroll_init(struct window_pane *);
void window_scroll_free(struct window_pane *);
void window_scroll_resize(struct window_pane *, u_int, u_int);
void window_scroll_key(struct window_pane *, struct client *, int);
void window_scroll_redraw_screen(struct window_pane *);
void window_scroll_write_line(
struct window_pane *, struct screen_write_ctx *, u_int);
void window_scroll_write_column(
struct window_pane *, struct screen_write_ctx *, u_int);
void window_scroll_scroll_up(struct window_pane *);
void window_scroll_scroll_down(struct window_pane *);
void window_scroll_scroll_left(struct window_pane *);
void window_scroll_scroll_right(struct window_pane *);
const struct window_mode window_scroll_mode = {
window_scroll_init,
window_scroll_free,
window_scroll_resize,
window_scroll_key,
NULL,
NULL,
};
struct window_scroll_mode_data {
struct screen screen;
struct mode_key_data mdata;
u_int ox;
u_int oy;
};
struct screen *
window_scroll_init(struct window_pane *wp)
{
struct window_scroll_mode_data *data;
struct screen *s;
struct screen_write_ctx ctx;
u_int i;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
data->ox = 0;
data->oy = 0;
s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
s->mode &= ~MODE_CURSOR;
keys = options_get_number(&wp->window->options, "mode-keys");
if (keys == MODEKEY_EMACS)
mode_key_init(&data->mdata, &mode_key_tree_emacs_copy);
else
mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
screen_write_start(&ctx, NULL, s);
for (i = 0; i < screen_size_y(s); i++)
window_scroll_write_line(wp, &ctx, i);
screen_write_stop(&ctx);
return (s);
}
void
window_scroll_free(struct window_pane *wp)
{
struct window_scroll_mode_data *data = wp->modedata;
screen_free(&data->screen);
xfree(data);
}
void
window_scroll_pageup(struct window_pane *wp)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int n;
n = 1;
if (screen_size_y(s) > 2)
n = screen_size_y(s) - 2;
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
else
data->oy += n;
window_scroll_redraw_screen(wp);
}
void
window_scroll_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
screen_resize(s, sx, sy);
screen_write_start(&ctx, NULL, s);
for (i = 0; i < screen_size_y(s); i++)
window_scroll_write_line(wp, &ctx, i);
screen_write_stop(&ctx);
}
void
window_scroll_key(struct window_pane *wp, unused struct client *c, int key)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int n;
switch (mode_key_lookup(&data->mdata, key)) {
case MODEKEYCOPY_CANCEL:
window_pane_reset_mode(wp);
break;
case MODEKEYCOPY_LEFT:
window_scroll_scroll_left(wp);
break;
case MODEKEYCOPY_RIGHT:
window_scroll_scroll_right(wp);
break;
case MODEKEYCOPY_UP:
window_scroll_scroll_up(wp);
break;
case MODEKEYCOPY_DOWN:
window_scroll_scroll_down(wp);
break;
case MODEKEYCOPY_PREVIOUSPAGE:
window_scroll_pageup(wp);
break;
case MODEKEYCOPY_NEXTPAGE:
n = 1;
if (screen_size_y(s) > 2)
n = screen_size_y(s) - 2;
if (data->oy < n)
data->oy = 0;
else
data->oy -= n;
window_scroll_redraw_screen(wp);
break;
case MODEKEYCOPY_HALFPAGEUP:
n = screen_size_y(s) / 2;
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
else
data->oy += n;
window_scroll_redraw_screen(wp);
break;
case MODEKEYCOPY_HALFPAGEDOWN:
n = screen_size_y(s) / 2;
if (data->oy < n)
data->oy = 0;
else
data->oy -= n;
window_scroll_redraw_screen(wp);
break;
default:
break;
}
}
void
window_scroll_write_line(
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct options *oo = &wp->window->options;
struct grid_cell gc;
char hdr[32];
size_t size;
if (py == 0) {
memcpy(&gc, &grid_default_cell, sizeof gc);
size = xsnprintf(hdr, sizeof hdr,
"[%u,%u/%u]", data->ox, data->oy, screen_hsize(&wp->base));
colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
gc.attr |= options_get_number(oo, "mode-attr");
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
screen_write_puts(ctx, &gc, "%s", hdr);
memcpy(&gc, &grid_default_cell, sizeof gc);
} else
size = 0;
screen_write_cursormove(ctx, 0, py);
screen_write_copy(ctx, &wp->base, data->ox, (screen_hsize(&wp->base) -
data->oy) + py, screen_size_x(s) - size, 1);
}
void
window_scroll_write_column(
struct window_pane *wp, struct screen_write_ctx *ctx, u_int px)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
screen_write_cursormove(ctx, px, 0);
screen_write_copy(ctx, &wp->base, data->ox + px,
screen_hsize(&wp->base) - data->oy, 1, screen_size_y(s));
}
void
window_scroll_redraw_screen(struct window_pane *wp)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
screen_write_start(&ctx, wp, NULL);
for (i = 0; i < screen_size_y(s); i++)
window_scroll_write_line(wp, &ctx, i);
screen_write_stop(&ctx);
}
void
window_scroll_scroll_up(struct window_pane *wp)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen_write_ctx ctx;
if (data->oy >= screen_hsize(&wp->base))
return;
data->oy++;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, 1);
window_scroll_write_line(wp, &ctx, 0);
window_scroll_write_line(wp, &ctx, 1);
screen_write_stop(&ctx);
}
void
window_scroll_scroll_down(struct window_pane *wp)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (data->oy == 0)
return;
data->oy--;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_deleteline(&ctx, 1);
window_scroll_write_line(wp, &ctx, screen_size_y(s) - 1);
window_scroll_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}
void
window_scroll_scroll_right(struct window_pane *wp)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
if (data->ox >= SHRT_MAX)
return;
data->ox++;
screen_write_start(&ctx, wp, NULL);
for (i = 1; i < screen_size_y(s); i++) {
screen_write_cursormove(&ctx, 0, i);
screen_write_deletecharacter(&ctx, 1);
}
window_scroll_write_column(wp, &ctx, screen_size_x(s) - 1);
window_scroll_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}
void
window_scroll_scroll_left(struct window_pane *wp)
{
struct window_scroll_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
if (data->ox == 0)
return;
data->ox--;
screen_write_start(&ctx, wp, NULL);
for (i = 1; i < screen_size_y(s); i++) {
screen_write_cursormove(&ctx, 0, i);
screen_write_insertcharacter(&ctx, 1);
}
window_scroll_write_column(wp, &ctx, 0);
window_scroll_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

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

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