297 Commits
2.8 ... 2.9

Author SHA1 Message Date
Nicholas Marriott
cb75ec25c8 2.9 now. 2019-04-24 22:35:23 +01:00
nicm
7d06216289 Do not loop forever if there is a nonprintable character in the format. 2019-04-24 22:34:56 +01:00
Nicholas Marriott
d24a44230a Update CHANGES for 2.9. 2019-04-18 22:12:15 +01:00
nicm
cd4c94f76b Current window style also needs to be tested for default. 2019-04-11 09:34:22 +01:00
Nicholas Marriott
bba1809eac Merge a number of fixes from master for layouts, mostly prompted by testing by
Thomas Sattler.
2019-04-11 09:26:34 +01:00
nicm
73b54a0e5f Fix size check for splitw -f and top level pane size for tiled layout,
problems reported by Thomas Sattler.
2019-04-04 18:31:35 +01:00
nicm
481c3f3f2e screen_write_fast_copy can no longer assume the target screen is default
(it isn't for the pane status lines).
2019-04-03 09:31:32 +01:00
nicm
8968acd678 Silence flag should use the same option as activity, reported by Thomas
Sattler.
2019-04-02 22:20:36 +01:00
Nicholas Marriott
916c4c499d Version RC2. 2019-04-02 11:12:24 +01:00
Nicholas Marriott
fac792dc27 Update regress from master. 2019-04-02 11:11:19 +01:00
nicm
bbcfee362f Store and restore cursor across reflow by working out a position based
on unwrapped lines, rather than a grid offset. Fixes problems reported
by Thomas Sattler and Paul de Weerd.
2019-04-02 11:11:12 +01:00
nicm
6d071c468c Restore a check to stop scrolled lines becoming larger than total lines,
fixes a crash reported by Thomas Sattler.
2019-04-02 07:33:33 +01:00
nicm
92da105b58 Free old strings after they have been expanded in format_choose. 2019-03-29 11:19:55 +00:00
nicm
00fda57ddf Fix offset of list ranges. 2019-03-29 07:05:40 +00:00
Nicholas Marriott
e0e08fcd2d Update CHANGES & TODO. 2019-03-26 15:05:28 +00:00
Nicholas Marriott
4f7a5d1e40 2.9 bits. 2019-03-26 14:37:27 +00:00
Thomas Adam
6ac84585e6 Merge branch 'obsd-master' 2019-03-25 20:02:38 +00:00
nicm
d21f8ecc13 Add StatusDefault binding for the mouse on any otherwise unassigned
parts of the status line, from Avi Halachmi.
2019-03-25 18:59:55 +00:00
Thomas Adam
5e2150cf18 Merge branch 'obsd-master' 2019-03-25 16:00:36 +00:00
Thomas Adam
a07ad6b5a3 Merge branch 'obsd-master' 2019-03-25 15:57:47 +00:00
nicm
ff4d7d541f Fix columns of cursor_character format in list. 2019-03-25 14:29:36 +00:00
Nicholas Marriott
e8f4ca6a52 Tweaks to example config. 2019-03-25 12:05:58 +00:00
Nicholas Marriott
a084f2dcb7 Add to TODO. 2019-03-25 10:06:03 +00:00
nicm
517d673dbe Ignore mouse on status line which are not part of a range, GitHub issue 1649. 2019-03-25 09:22:09 +00:00
nicm
b4a301f8fe Clarify that styles can be space or comma separated, from Stephen Zapatka. 2019-03-22 10:45:17 +00:00
nicm
04a1fc9d36 I forgot to document resize-window, window-size and default-size;
reminded by okan@.
2019-03-22 09:33:04 +00:00
Thomas Adam
0292243b29 Merge branch 'obsd-master' 2019-03-20 20:02:37 +00:00
Nicholas Marriott
ef38a420b2 Update TODO. 2019-03-20 20:02:13 +00:00
Nicholas Marriott
7536d57b16 Update TODO. 2019-03-20 19:26:20 +00:00
nicm
9ee1a8f701 Improve cursor positioning after reflow by storing the position as an
offset into the entire history before reflow and restoring it aftewards.
2019-03-20 19:19:11 +00:00
Nicholas Marriott
0e0f2f765b Update CHANGES. 2019-03-20 14:01:46 +00:00
Thomas Adam
bff957a475 Merge branch 'obsd-master' 2019-03-20 08:02:38 +00:00
nicm
ed962e7612 Include function name in logging. 2019-03-20 07:30:05 +00:00
nicm
458b87150b Do not leak ranges on error. 2019-03-20 07:28:31 +00:00
nicm
ae46a19b8e Ignore invalid styles rather than throwing away the whole format, this
matches what we used to do.
2019-03-20 07:24:03 +00:00
nicm
3b959c05ff Bit more logging to show drawing errors. 2019-03-20 07:13:02 +00:00
Thomas Adam
46f642b030 Merge branch 'obsd-master' 2019-03-19 22:02:36 +00:00
nicm
8b74e959ef Include window-status-style and window-status-current style in the format. 2019-03-19 21:09:51 +00:00
Thomas Adam
320237fdb8 Merge branch 'obsd-master' 2019-03-19 20:02:37 +00:00
nicm
161b57869e Add a cursor_character format. 2019-03-19 19:01:50 +00:00
Nicholas Marriott
92732a2540 Add to TODO. 2019-03-19 14:39:55 +00:00
Thomas Adam
b3eebdec48 Merge branch 'obsd-master' 2019-03-19 14:02:36 +00:00
nicm
b24c9e34a9 Rename the first KEY BINDINGS section to DEFAULT KEY BINDINGS. 2019-03-19 13:35:42 +00:00
Thomas Adam
073d439965 Merge branch 'obsd-master' 2019-03-19 00:02:39 +00:00
Thomas Adam
f956c17c09 Merge branch 'obsd-master' 2019-03-18 22:02:36 +00:00
nicm
0406ec0ec2 Free temporary screens when writing format. 2019-03-18 21:55:04 +00:00
nicm
f34ebfed76 The individual -fg, -bg and -attr options have been deprecated (in
favour of -style), undocumented and hidden from show-options since
2014. Remove them, except for status-fg and status-bg.
2019-03-18 21:46:01 +00:00
Thomas Adam
962f255ee8 Merge branch 'obsd-master' 2019-03-18 21:24:49 +00:00
nicm
c62404673e Add some bits to the STATUS LINE section about the new option. 2019-03-18 21:01:04 +00:00
nicm
979313832c Extend the #[] style syntax and use that together with previous format
changes to allow the status line to be entirely configured with a single
option.

Now that it is possible to configure their content, enable the existing
code that lets the status line be multiple lines in height. The status
option can now take a value of 2, 3, 4 or 5 (as well as the previous on
or off) to configure more than one line. The new status-format array
option configures the format of each line, the default just references
the existing status-* options, although some of the more obscure status
options may be eliminated in time.

Additions to the #[] syntax are: "align" to specify alignment (left,
centre, right), "list" for the window list and "range" to configure
ranges of text for the mouse bindings.

The "align" keyword can also be used to specify alignment of entries in
tree mode and the pane status lines.
2019-03-18 20:53:33 +00:00
Thomas Adam
1d6fe43c7b Merge branch 'obsd-master' 2019-03-18 18:02:38 +00:00
Thomas Adam
4cbf596dc5 Merge branch 'obsd-master' 2019-03-18 15:30:55 +00:00
nicm
d738d51688 Mode init needs to be fired with the mode on the list or it will not be
resized correctly.
2019-03-18 15:25:36 +00:00
Thomas Adam
acb2413852 Merge branch 'obsd-master' 2019-03-18 15:07:51 +00:00
nicm
2628af573d Add format variables for the default formats for the various modes
(tree_mode_format and so on) and add a -a flag to display-message to
list variables with values.
2019-03-18 14:10:25 +00:00
Nicholas Marriott
aa2b3472c5 Update TODO. 2019-03-18 12:00:10 +00:00
nicm
ce6be7afd4 Make array options a sparse tree instead of an array of char * and
remove the size limit.
2019-03-18 11:58:40 +00:00
nicm
d2d43987d0 With force, kill previous job before starting new. Fixes problem
reported by Scott Mcdermott in GitHub issue 1627.
2019-03-18 09:46:42 +00:00
nicm
bd3332b211 Break description of styles into its own section. 2019-03-17 19:33:12 +00:00
Nicholas Marriott
3a298454ce Add to TODO. 2019-03-17 08:05:58 +00:00
nicm
b588b1729a Use a pointer for the active screen in the status line instead of
copying them around all the time.
2019-03-16 19:12:13 +00:00
nicm
818fda0363 Give status_save_old the client so it can do the reinit too. 2019-03-16 17:53:55 +00:00
nicm
b4f5b99e4b Tidy and rename some bits of status line code. 2019-03-16 17:14:07 +00:00
nicm
e8b33af780 Add a way to set individual defaults for an array option. 2019-03-15 21:54:47 +00:00
nicm
1d306e926a Add a : to make error messages clearer. 2019-03-15 15:20:00 +00:00
nicm
33595a255f Copy recursion counter into new formats when looping. 2019-03-15 15:02:25 +00:00
nicm
85044a634b Move status line free into its own function. 2019-03-15 14:46:58 +00:00
nicm
2d71bef0ca Remove unused member of struct client. 2019-03-15 10:48:05 +00:00
nicm
f6d34f066c Only print format logging when the flag is set, even if also sending to log_debug. 2019-03-15 10:22:57 +00:00
nicm
672c49d512 The pane and window loops need to pass the window and pane tags when
they build their format.
2019-03-15 10:07:24 +00:00
nicm
27578815da Add a -v flag to display-message to show verbose messages as the format
is parsed, this gives the user a way to debug problems with formats
rather than just being confronted with (for example) a blank status
line.
2019-03-15 10:04:13 +00:00
nicm
25e2e22791 Add a limit on how far format_expand can recurse. 2019-03-14 23:34:41 +00:00
nicm
10d60faba5 Store the time in the format tree rather than passing it around. 2019-03-14 23:14:27 +00:00
Thomas Adam
2c755e3c55 Merge branch 'obsd-master' 2019-03-14 22:02:39 +00:00
nicm
bace79a571 Remove some unnecessary temporary variables and be much less strict
about spacing in style_parse.
2019-03-14 21:46:08 +00:00
nicm
4206bcc10e Add format flags for start and end window. 2019-03-14 21:41:30 +00:00
nicm
38064e7593 Add T format modifier like E but also do strftime(3). 2019-03-14 21:31:43 +00:00
nicm
1416ceb575 Accept 0 time as a shorthand for now to format_expand_time. 2019-03-14 21:27:26 +00:00
Thomas Adam
d58bccfc63 Merge branch 'obsd-master' 2019-03-14 20:02:38 +00:00
nicm
9bd4b96766 Fix ED1 (clear end of screen), reported by Marc Reisner. 2019-03-14 17:58:52 +00:00
Thomas Adam
0b32fa81b6 Merge branch 'obsd-master' 2019-03-14 12:02:41 +00:00
nicm
0425e3178d A little tidying in style_parse. 2019-03-14 10:19:52 +00:00
nicm
13f9a061ac Add a wrapper (struct style) around styles rather than using the
grid_cell directly. There will be some non-cell members soon.
2019-03-14 09:53:52 +00:00
Thomas Adam
f33d2ab29e Merge branch 'obsd-master' 2019-03-14 08:02:37 +00:00
nicm
1e9f8a3523 Missing space in capture-pane usage, from Ben Boeckel.
Also man page fixed from jmc.
2019-03-14 06:36:21 +00:00
nicm
2fbd491ff0 Add actual HPA (\033[`), the existing one is CHA. From Marc Reisner. 2019-03-14 06:33:43 +00:00
Thomas Adam
81b393a493 Merge branch 'obsd-master' 2019-03-14 00:02:37 +00:00
nicm
5755bfc619 Need to set attributes before clearing. 2019-03-13 22:01:22 +00:00
nicm
10f0094be9 The pane's style should be initialized to default before parsing the
argument.
2019-03-13 21:39:21 +00:00
Thomas Adam
786f5e505e Merge branch 'obsd-master' 2019-03-13 20:02:36 +00:00
nicm
6dffbc4849 Tweak format_replace logging. 2019-03-13 18:09:12 +00:00
Thomas Adam
e6fd429d58 Merge branch 'obsd-master' 2019-03-13 16:02:41 +00:00
nicm
95ab1aaaec Add formats to list sessions, windows or panes. 2019-03-13 15:37:28 +00:00
Nicholas Marriott
f628afc850 Update TODO. 2019-03-13 14:51:19 +00:00
nicm
49f04a997a Apply length limits and substitution even to literal formats. 2019-03-13 14:27:17 +00:00
Nicholas Marriott
1aeac384f3 Add to TODO. 2019-03-13 14:20:58 +00:00
nicm
9032ac2a05 Add E: format to expand a format twice (useful to expand the value of an
option).
2019-03-13 14:19:54 +00:00
nicm
71e00c718c Make format parsing build the modifiers into a list, standardize how
arguments are given and allow multiple modifiers on a format (separated
by ;).
2019-03-13 14:10:34 +00:00
Nicholas Marriott
7a6b21de65 Add to TODO. 2019-03-13 09:30:42 +00:00
Nicholas Marriott
4f5cb88c2b Add to TODO. 2019-03-13 09:30:42 +00:00
Thomas Adam
0e6eda02a6 Merge branch 'obsd-master' 2019-03-13 08:02:35 +00:00
nicm
feaa5660a3 Do not use origin for VPA. 2019-03-13 07:34:36 +00:00
Thomas Adam
b03f58b977 Merge branch 'obsd-master' 2019-03-13 00:02:38 +00:00
nicm
b2bc34af12 Set a flag on cells are genuinely empty (cleared and never written to)
and use tty_clear_line (which will choose the best escape sequence) to
clear any batches of cells with that flag when redrawing a line from the
stored screen.
2019-03-12 23:21:45 +00:00
Thomas Adam
400529eea0 Merge branch 'obsd-master' 2019-03-12 22:02:42 +00:00
nicm
938156d73b DECRC and DECSC apparently need to preserve origin mode as well, based
on a fix from Marc Reisner.
2019-03-12 20:02:47 +00:00
Thomas Adam
ba4a884d75 Merge branch 'obsd-master' 2019-03-12 20:02:38 +00:00
nicm
2796ae81d0 Fix HPA in origin mode. 2019-03-12 18:30:08 +00:00
nicm
f3f534a3a0 Tidy up a lot of &ictx->ctx by using a local variable. 2019-03-12 18:26:57 +00:00
Nicholas Marriott
6c3ee42568 Add a couple of things. 2019-03-12 17:59:46 +00:00
Nicholas Marriott
2f0ffe6adb Add to TODO. 2019-03-12 17:52:22 +00:00
Nicholas Marriott
4002dbf0c1 Fix session size regress. 2019-03-12 17:36:58 +00:00
Thomas Adam
162d3cb1f4 Merge branch 'obsd-master' 2019-03-12 16:02:37 +00:00
Thomas Adam
7d2004a8dd Merge branch 'obsd-master' 2019-03-12 14:02:40 +00:00
Nicholas Marriott
860acecc0d Fix up regress test for control client size. 2019-03-12 13:57:06 +00:00
nicm
028f9d1d87 Fix resizing of control clients, should be ignored until SIZECHANGED flag set. 2019-03-12 13:56:30 +00:00
nicm
303d20a758 Fix wrapping after origin mode change. 2019-03-12 13:14:14 +00:00
nicm
3f0efc050a When asked for a window index, return it even if the window exists. 2019-03-12 13:14:04 +00:00
nicm
7804fa1b82 Revert to not clearing history on RIS, apparently some bootloaders send
this and it doesn't really do any harm.
2019-03-12 12:58:40 +00:00
nicm
7b819357ff Tweak target debug logging. 2019-03-12 12:49:46 +00:00
Nicholas Marriott
595b52490e Add to TODO. 2019-03-12 12:12:35 +00:00
Thomas Adam
3ec05e9405 Merge branch 'obsd-master' 2019-03-12 12:02:42 +00:00
Nicholas Marriott
f8a30e1588 Update CHANGES. 2019-03-12 11:20:21 +00:00
nicm
3f6bfbaf2b Allow multiple modes to be open in a pane. A stack of open modes is kept
and the previous restored when the top is exited. If a mode that is
already on the stack is entered, the existing instance is moved to the
top as the active mode rather than being opened new.
2019-03-12 11:16:49 +00:00
Thomas Adam
95d340cc4f Merge branch 'obsd-master' 2019-03-12 10:02:39 +00:00
nicm
ff4c80d53d Add support for origin mode (DECOM, SM/RM ?6), from Marc Reisner. 2019-03-12 07:39:27 +00:00
Thomas Adam
bc72cf2f52 Merge branch 'obsd-master' 2019-03-08 12:02:39 +00:00
nicm
de730f68a4 Make the mode used to view command output (a variant of copy mode) use
its own mode definition struct with a different init function rather
than calling special setup functions.
2019-03-08 10:34:20 +00:00
nicm
9cc04a0f9a Do not use window mode entry after free. 2019-03-08 10:29:25 +00:00
Thomas Adam
349aeb806a Merge branch 'obsd-master' 2019-03-07 22:02:42 +00:00
nicm
f98c66ece8 Add a separate mode struct for the active window mode if any. 2019-03-07 20:24:21 +00:00
Thomas Adam
a1009e7bd3 Merge branch 'obsd-master' 2019-03-07 20:02:41 +00:00
nicm
3c24bc5617 Tidy changing the mode into window_copy_init_for_output. 2019-03-07 19:34:22 +00:00
nicm
7f093fcddc Make adding mode formats a function pointer as well. 2019-03-07 19:01:21 +00:00
Nicholas Marriott
5a564a0c1a Add to TODO. 2019-03-07 15:34:24 +00:00
Thomas Adam
9ebd630675 Merge branch 'obsd-master' 2019-03-04 12:01:28 +00:00
nicm
5cdd578906 Fix sense of aggressive-resize flag. 2019-03-04 09:29:52 +00:00
nicm
a870c255c4 Don't set client offset if client is not a terminal 2019-03-04 09:29:40 +00:00
Thomas Adam
d5c837904b Merge branch 'obsd-master' 2019-02-16 20:02:36 +00:00
nicm
fa33603dc1 Do not look at next key byte if the length is 0, originally from Shingo
NISHIOKA in GitHub issue 1601.
2019-02-16 19:04:34 +00:00
Thomas Adam
fa8294436c Merge branch 'obsd-master' 2019-02-16 14:02:37 +00:00
nicm
82f0c859a2 Use starting client cwd in config file, GitHub issue 1606. 2019-02-16 11:42:08 +00:00
Thomas Adam
9768091ee4 Merge branch 'obsd-master' 2019-02-09 20:02:36 +00:00
nicm
f9c396db41 Completion of command-alias members. 2019-02-09 18:18:36 +00:00
Nicholas Marriott
bdb7e48cba Redirect which stderr. 2019-02-06 14:45:35 +00:00
Thomas Adam
c42e89a598 Merge branch 'obsd-master' 2019-02-06 08:02:37 +00:00
nicm
afd3127d89 Add -b to display-panes like run-shell, GitHub issue 1559. 2019-02-06 07:36:06 +00:00
Thomas Adam
4ab3b18b36 Merge branch 'obsd-master' 2019-01-20 18:02:36 +00:00
nicm
2ea22fce5e Should use DECFRA if not default, not if default. From Karl Beldan. 2019-01-20 15:57:27 +00:00
Thomas Adam
cd8a7fb07b Merge branch 'obsd-master' 2019-01-15 14:02:37 +00:00
nicm
cd39920abd Should save the bg colour when setting it to default, not the fg. 2019-01-15 12:08:53 +00:00
Thomas Adam
469a9e9439 Merge branch 'obsd-master' 2019-01-15 12:02:36 +00:00
nicm
34c0807be6 Do not highlight characters which will not be copied, reported by
Jaroslaw Rzeszotko.
2019-01-15 09:56:31 +00:00
Thomas Adam
c9d482ab48 Merge branch 'obsd-master' 2018-12-18 14:02:40 +00:00
nicm
bde0224deb Pass window into mode functions. 2018-12-18 13:20:44 +00:00
Thomas Adam
b6cdac05c7 Merge branch 'obsd-master' 2018-12-18 00:02:37 +00:00
nicm
4e3d661284 Fix parsing of empty colon-separated fields, reported by Siarhei Siniak. 2018-12-17 21:52:59 +00:00
Thomas Adam
1c5093c1c4 Merge branch 'obsd-master' 2018-11-30 10:02:37 +00:00
nicm
67254ed8df Clear PANE_EXITED flag when starting new child process in case the pane
has been respawned.
2018-11-30 08:44:40 +00:00
Nicholas Marriott
6cf2f74fe9 osdep_get_cwd for NetBSD, from Leonardo Taccari. 2018-11-29 10:37:27 +00:00
Thomas Adam
1ed994a6c8 Merge branch 'obsd-master' 2018-11-28 12:02:36 +00:00
nicm
40d246b29c Handle UTF-8 in word-separators option, GitHub issue 1551. 2018-11-28 11:20:13 +00:00
Thomas Adam
2977317243 Merge branch 'obsd-master' 2018-11-22 12:02:38 +00:00
nicm
3a7b9d5735 Do not use PWD unless it actually matches the real working directory. 2018-11-22 10:36:40 +00:00
Nicholas Marriott
2eca63b98e Add to TODO. 2018-11-21 09:50:53 +00:00
Nicholas Marriott
c4b04b1624 Fixes for GNU/kFreeBSD from James Clarke. 2018-11-21 08:50:22 +00:00
Thomas Adam
efd01f3bfd Merge branch 'obsd-master' 2018-11-19 14:02:41 +00:00
nicm
749f67b7d8 evbuffer_new and bufferevent_new can both fail (when malloc fails) and
return NULL. GitHub issue 1547.
2018-11-19 13:35:40 +00:00
Thomas Adam
a7da2357a5 Merge branch 'obsd-master' 2018-11-15 12:02:37 +00:00
kn
f103927a52 Add [template] to display-panes and choose-{buffer,client,tree} usage
OK nicm
2018-11-15 10:38:53 +00:00
Thomas Adam
0fd73f238d Merge branch 'obsd-master' 2018-11-13 12:02:38 +00:00
nicm
50cdfc06fb Initialize context property in alignment test handler function. 2018-11-13 11:36:37 +00:00
Thomas Adam
3c6cdf0115 Merge branch 'obsd-master' 2018-11-12 16:02:37 +00:00
nicm
86e648d906 Allow style #[] in mode formats. 2018-11-12 14:18:10 +00:00
Thomas Adam
849d06c0df Merge branch 'obsd-master' 2018-11-08 20:02:37 +00:00
nicm
09aee53763 It isn't possible to specify buffer name to copy mode commands now, so
remove the function argument.
2018-11-08 18:49:19 +00:00
Thomas Adam
4efba0bf9f Merge branch 'obsd-master' 2018-11-07 10:02:39 +00:00
nicm
0c7f64458f If a non-repeating key is used when repeating, it should be treated as
an entirely new key press, not checked in root table and ignored if not
found. GitHub issue 1513.
2018-11-07 08:06:28 +00:00
Nicholas Marriott
ff77010f70 Add to TODO. 2018-11-07 08:00:15 +00:00
nicm
7339845c01 There is no reason wait-for has to be restricted to outside tmux. 2018-11-07 07:58:16 +00:00
Thomas Adam
99072e1d81 Merge branch 'obsd-master' 2018-11-06 16:02:37 +00:00
nicm
f9881b3b5d Correctly unzoom and redraw panes in switch-client. 2018-11-06 15:13:13 +00:00
Thomas Adam
b1ad075d11 Merge branch 'obsd-master' 2018-10-31 12:02:38 +00:00
nicm
ef904cfef2 Reset all flags in screen_write_reset, reported by Benjamin Poirier. 2018-10-31 10:05:47 +00:00
Thomas Adam
ddffda4da5 Merge branch 'obsd-master' 2018-10-28 18:02:36 +00:00
nicm
d5b92ac37e Do not printf NULL. 2018-10-28 16:10:02 +00:00
Thomas Adam
0a54a07909 Merge branch 'obsd-master' 2018-10-28 16:02:37 +00:00
nicm
65dd7345e0 Do not check for a key again without an escape if only \033 is present. 2018-10-28 15:34:27 +00:00
Nicholas Marriott
0cefdff1b6 Add to CHANGES. 2018-10-26 11:36:36 +01:00
Thomas Adam
e771f10dc6 Merge branch 'obsd-master' 2018-10-25 17:02:42 +01:00
nicm
fc41bf46ac Add a "terminal" colour which can be used instead of "default" in style
options for the terminal default colour, bypassing any inheritance from
other options. Prompted by a discussion with abieber@.
2018-10-25 15:13:38 +00:00
Nicholas Marriott
2808f8261c Tweak wording. 2018-10-19 08:38:12 +01:00
Nicholas Marriott
c234032fcf Do not use master here. 2018-10-19 08:37:31 +01:00
Nicholas Marriott
bc6211cca5 Instead of "master" for the version number, use "next-X.X". It is more
useful to include the next version number.
2018-10-19 08:35:23 +01:00
Thomas Adam
164590e34c Merge branch 'obsd-master' 2018-10-18 15:02:38 +01:00
nicm
9feb35b7c4 Document new refresh-client flags. 2018-10-18 13:03:45 +00:00
Thomas Adam
f44d02c7f5 Merge branch 'obsd-master' 2018-10-18 11:09:54 +01:00
nicm
646995384d Support for windows larger than visible on the attached client. This has
been a limitation for a long time.

There are two new options, window-size and default-size, and a new
command, resize-window. The force-width and force-height options and the
session_width and session_height formats have been removed.

The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and manual
means that it does not automatically resize windows. The default is
currently largest but this may change. aggressive-resize modifies the
choice of session for largest and smallest as it did before.

If a window is in a session attached to a client that is too small, only
part of the window is shown. tmux attempts to keep the cursor visible,
so the part of the window displayed is changed as the cursor moves (with
a small delay, to try and avoid excess redrawing when applications
redraw status lines or similar that are not currently visible). The
offset of the visible portion of the window is shown in status-right.

Drawing windows which are larger than the client is not as efficient as
those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).

The resize-window command can be used to resize a window manually. If it
is used, the window-size option is automatically set to manual for the
window (undo this with "setw -u window-size"). resize-window works in a
similar way to resize-pane (-U -D -L -R -x -y flags) but also has -a and
-A flags. -a sets the window to the size of the smallest client (what it
would be if window-size was smallest) and -A the largest.

For the same behaviour as force-width or force-height, use resize-window
-x or -y, and "setw -u window-size" to revert to automatic sizing..

If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.

The maximum size of a window is 10000x10000. But expect applications to
complain and much higher memory use if making a window excessively
big. The minimum size is the size required for the current layout
including borders.

The refresh-client command can be used to pan around a window, -U -D -L
-R moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
2018-10-18 08:38:01 +00:00
Nicholas Marriott
2dfdb55ace Handle pan correctly when the terminal is bigger than the window. 2018-10-18 09:24:15 +01:00
nicm
a51668ca06 Support OSC 52 ? to read the top buffer inside tmux (when set-clipboard
is changed to on), also add refresh-client -l to ask tmux to use the
same mechanism to get the clipboard from the terminal outside
tmux. GitHub issue 1477.
2018-10-18 08:04:14 +00:00
nicm
bc0e527f32 Support for extended underline styles on terminals which offer them,
enabled by adding the Smulx capability with terminal-overrides (add
something like ',vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
2018-10-18 07:57:57 +00:00
Nicholas Marriott
f54f171d5c Merge branch '2.8-rc' 2018-10-17 19:33:43 +01:00
Nicholas Marriott
a2c52d9f26 Add to TODO. 2018-10-16 14:16:48 +01:00
Nicholas Marriott
407075d8c7 Add to TODO. 2018-10-16 14:12:33 +01:00
Nicholas Marriott
cdd8c93f54 Add to TODO file. 2018-10-15 09:09:40 +01:00
Nicholas Marriott
c88e945bc5 Support OSC 52 ? to read the top buffer inside tmux, also add
refresh-client -l to get the clipboard outside tmux. GitHub issue
1477.
2018-10-11 16:20:14 +01:00
Nicholas Marriott
018f1b8a80 Use :: for escaping : in terminal-overrides not \:. 2018-10-08 19:42:55 +01:00
Nicholas Marriott
4b9e76aaaa Support for extended underline styles, enabled by adding the Smulx
capability with terminal-overrides (add something like
'vte*:Smulx=\E[4\:%p1%dm'). GitHub issue 1492.
2018-10-08 13:21:37 +01:00
Nicholas Marriott
46847e9b2e Update TODO. 2018-10-08 13:06:37 +01:00
Nicholas Marriott
1952b3f746 Update CHANGES. 2018-10-07 15:06:40 +01:00
Nicholas Marriott
546060f340 Update TODO. 2018-10-07 15:01:41 +01:00
Thomas Adam
c44bb2df17 Merge branch 'obsd-master' 2018-10-03 17:02:38 +01:00
nicm
f7c85f3ed8 Do not move the cursor when the mouse wheel is used, GitHub issue 1493. 2018-10-03 15:27:55 +00:00
Nicholas Marriott
5a7cf897f2 Correctly check offset for drawing multiple cells, GitHub issue 1481. 2018-10-01 19:47:58 +01:00
Nicholas Marriott
8053b65f1e Fix select-pane -m, GitHub issuie 1490. 2018-09-28 09:38:22 +01:00
Thomas Adam
a00cdcdfcb Merge branch 'obsd-master' 2018-09-27 11:02:37 +01:00
nicm
228e1a3951 Use same working directory rules for jobs as new windows rather than
always starting in home, GitHub issue 1488.
2018-09-27 07:43:18 +00:00
Nicholas Marriott
ebaf54251a Add formats for when window is larger than client, and show offset in
status-right by default when larger.
2018-09-26 18:41:18 +01:00
Nicholas Marriott
b74b047730 More of revert. 2018-09-26 16:49:03 +01:00
Nicholas Marriott
04c6db2d0f Revert "Add a B flag to mark windows bigger than the client."
This reverts commit b4e74f4310.
2018-09-26 16:42:29 +01:00
Nicholas Marriott
6abb62df1e Change the B into a +. 2018-09-25 21:57:29 +01:00
Thomas Adam
7cf00d6b72 Merge branch 'obsd-master' 2018-09-25 17:02:41 +01:00
nicm
7d59f82cf9 Allow panes to be 1 line or column by redrawing instead of using the
scroll region, from Soeren Tempel in GitHub issue 1487.
2018-09-25 14:27:20 +00:00
Nicholas Marriott
cbf1504fca Do not clamp to needed size since it may be too big. 2018-09-25 15:15:44 +01:00
Nicholas Marriott
83b2d5c513 window_printable_flags needs an additional argument. 2018-09-25 09:55:49 +01:00
Nicholas Marriott
b4e74f4310 Add a B flag to mark windows bigger than the client. 2018-09-25 09:54:47 +01:00
Nicholas Marriott
26d73a7736 Ignore clients that are suspended or exiting. 2018-09-25 09:48:48 +01:00
Nicholas Marriott
57069287a1 Add to TODO. 2018-09-25 08:27:53 +01:00
Thomas Adam
4799f43298 Merge branch 'obsd-master' 2018-09-24 17:02:38 +01:00
nicm
7bc6c105b7 Only include pane status in minimum size if it is turned on, GitHub
issue 1480.
2018-09-24 15:29:56 +00:00
Nicholas Marriott
ad71e7f9d2 Calculate size when trimming RHS correctly. 2018-09-24 12:17:29 +01:00
Nicholas Marriott
71d2ab184b Fix up merge. 2018-09-12 07:15:27 +01:00
Thomas Adam
c067af8e7d Merge branch 'obsd-master' 2018-09-11 20:11:11 +01:00
Nicholas Marriott
3fa538181b Restore window_pane_visible for drawing panes and borders, fixes issue
1458 reported by Felix Rosencrantz, problem located by Avi Halachmi.
2018-09-11 18:34:53 +01:00
nicm
be2201200f The cursor position is limited to the margins for CUF and CUB, so turn
margins off for printing cells (like most everything else already
does). Problem reported by Thomas Sattler.
2018-09-11 17:31:01 +00:00
Nicholas Marriott
84df87011c x,y -> px,py. 2018-09-11 09:39:28 +01:00
Thomas Adam
5e36d52651 Merge branch 'obsd-master' 2018-09-11 09:21:16 +01:00
nicm
bd9133b31d Do not check for mouse events on pane borders when zoomed, based on a
fix from Avi Halachmi.
2018-09-11 06:37:54 +00:00
Thomas Adam
9b32758a0c Merge branch 'obsd-master' 2018-09-10 09:02:39 +01:00
Nicholas Marriott
5aa435a9f0 window_get_active_at needs to check visible also. 2018-09-10 07:51:11 +01:00
nicm
1b92afa799 Do not clear selection when searching. 2018-09-10 06:48:01 +00:00
Nicholas Marriott
a618271e12 Bring back window_pane_visible to stop input going to panes which are
hidden by zoom.
2018-09-10 07:19:17 +01:00
Nicholas Marriott
8598fd1bc5 Add to TODO. 2018-09-09 07:52:28 +01:00
Nicholas Marriott
59df942e09 Fixes to resize-window from Ben Boeckel. 2018-09-05 08:43:58 +01:00
Nicholas Marriott
621bb15b83 Cast parameters to tparm, from Christos Zoulas via Leonardo Taccari. 2018-09-05 08:42:17 +01:00
Thomas Adam
8e24b0bb3e Makefile.am: Add space between -f and argument
Required for some (older) aek instance -- namely NetBSD.
2018-09-04 13:13:32 +01:00
Thomas Adam
0c07b10b30 Merge branch 'obsd-master' 2018-09-03 11:02:39 +01:00
nicm
8f9491ddfe Allow a large line number to go to the end with goto-line, from Mark
Kelly in GitHub issue 1460.
2018-09-03 08:51:43 +00:00
nicm
9bab73f489 Fix selection test, from Takeshi Banse. 2018-09-03 08:47:27 +00:00
Nicholas Marriott
4e867202e8 Add to TODO. 2018-08-31 14:10:51 +01:00
Thomas Adam
e27b588b6c Merge branch 'obsd-master' 2018-08-29 21:02:37 +01:00
Nicholas Marriott
479cac4896 Fix target line for fast path in tty_draw_pane. 2018-08-29 20:52:27 +01:00
nicm
95e3e363ff Reset line flag when clearing selection, GitHub issue 1454. 2018-08-29 18:54:23 +00:00
Nicholas Marriott
7637518b07 Fix refresh-client flags. 2018-08-29 18:59:43 +01:00
Nicholas Marriott
9263a65b5f Update TODO. 2018-08-29 18:52:04 +01:00
Thomas Adam
b29028a914 Merge branch 'obsd-master' 2018-08-29 13:02:38 +01:00
Thomas Adam
1ea17a72f0 Merge branch 'obsd-master' 2018-08-29 11:02:36 +01:00
nicm
f57aa143c1 Keep any text killed in the command prompt with C-w and yank it with
C-y, only use the top buffer if no text has previously been killed. This
and previous change promped by discussion with kn@.
2018-08-29 09:50:32 +00:00
nicm
e53094bc5f Add C-Left and C-Right as aliases for M-b and M-f. 2018-08-29 08:56:51 +00:00
Thomas Adam
18b611bc8d Merge branch 'obsd-master' 2018-08-27 13:02:38 +01:00
nicm
79d2351ce8 Memory leaks, from Gang Fan in GitHub issue 1453. 2018-08-27 11:03:34 +00:00
Nicholas Marriott
79a9472dbc tty_clamp_* need to use wp->xoff and wp->yoff for the check (which
don't include status line, line ox and oy), but ctx->xoff and yp->off
to calculate the position (which do have the statu line).
2018-08-26 14:10:39 +01:00
Thomas Adam
d64daf874f Merge branch 'obsd-master' 2018-08-26 11:02:38 +01:00
nicm
1b4402c823 Add q: format prefix to escape sh(1) special characters. Suggested by
someone ages ago and then more recently in GitHub issue 1449.
2018-08-26 09:28:42 +00:00
Nicholas Marriott
7fbd2f5498 Do not draw cells which have no cell (zoomed and they are not active). 2018-08-25 13:55:50 +01:00
Thomas Adam
45841400f2 Merge branch 'obsd-master' 2018-08-23 21:02:36 +01:00
nicm
f38b5a1b58 all_jobs can be static. 2018-08-23 18:39:12 +00:00
Thomas Adam
da5d563375 Merge branch 'obsd-master' 2018-08-23 19:02:40 +01:00
nicm
bceccc6b63 Move job struct into job.c. 2018-08-23 15:45:05 +00:00
Nicholas Marriott
183193bdbc Update CHANGES. 2018-08-23 08:52:22 +01:00
Thomas Adam
5b93f0fcd3 Merge branch 'obsd-master' 2018-08-22 23:02:43 +01:00
Nicholas Marriott
ee3e0eb183 Update TODO. 2018-08-22 21:29:30 +01:00
nicm
55db3623bf Add StatusLeft and StatusRight mouse key modifiers for the left and
right parts of the status line.
2018-08-22 20:06:14 +00:00
Nicholas Marriott
db8849e7ca Update TODO. 2018-08-21 09:29:12 +01:00
Nicholas Marriott
bfc9fb4b3b Add flags to refresh-client (-U -D -L -R and -c) to pan a window that
is larger than the client manually. Bound to S-Up, S-Down, S-Left,
S-Right and Delete manually.

Also add aliases for keys DC = Delete, IC = Insert, and make
refresh-client -C accept XxY as well as X,Y to match default-size.
2018-08-21 09:27:19 +01:00
Nicholas Marriott
314ee137a9 The stored mouse position should not include the status line offset if any. 2018-08-21 09:10:23 +01:00
Thomas Adam
f36d2ecb07 Merge branch 'obsd-master' 2018-08-20 23:02:38 +01:00
nicm
98a478ceb3 Move offset of window list into status struct. 2018-08-20 20:41:58 +00:00
Nicholas Marriott
9f39470b38 Only screen-redraw.c needs to adjust for message or prompt when the
status line is off, get rid of tty_status_lines and just pass the
client into status_line_size so it can check the CLIENT_STATUSOFF flag
as well.
2018-08-20 20:05:34 +01:00
Nicholas Marriott
458b4b7701 Need to adjust for lines if at top. 2018-08-20 19:45:32 +01:00
Nicholas Marriott
31508228bc Use the y offset from the context which has already been adjusted for
the status line, also make tty_clamp_line adjust the y position.
2018-08-20 19:34:04 +01:00
Nicholas Marriott
1e8c9fb490 Update CHANGES. 2018-08-20 17:52:27 +01:00
Thomas Adam
098967a085 Merge branch 'obsd-master' 2018-08-20 17:02:39 +01:00
nicm
665f046950 Add -Z to find-window as well. 2018-08-20 15:00:42 +00:00
Nicholas Marriott
641191ab20 Support for windows larger than the client.
This adds two new options, window-size and default-size, and a new
command, resize-window.

The force-width and force-height options, and the session_width and
session_height formats have been removed.

The new window-size option tells tmux how to work out the size of
windows: largest means it picks the size of the largest session,
smallest the smallest session (similar to the old behaviour) and
manual means that it does not automatically resize
windows. aggressive-resize modifies the choice of session for largest
and smallest as it did before.

If a window is in a session attached to a client that is too small,
only part of the window is shown. tmux attempts to keep the cursor
visible, so the part of the window displayed is changed as the cursor
moves (with a small delay, to try and avoid excess redrawing when
applications redraw status lines or similar that are not currently
visible).

Drawing windows which are larger than the client is not as efficient
as those which fit, particularly when the cursor moves, so it is
recommended to avoid using this on slow machines or networks (set
window-size to smallest or manual).

The resize-window command can be used to resize a window manually. If
it is used, the window-size option is automatically set to manual for
the window (undo this with "setw -u window-size"). resize-window works
in a similar way to resize-pane (-U -D -L -R -x -y flags) but also has
-a and -A flags. -a sets the window to the size of the smallest client
(what it would be if window-size was smallest) and -A the largest.

For the same behaviour as force-width or force-height, use
resize-width -x or -y.

If the global window-size option is set to manual, the default-size
option is used for new windows. If -x or -y is used with new-session,
that sets the default-size option for the new session.

The maximum size of a window is 10000x10000. But expect applications
to complain and higher memory use if you make a window that big. The
minimum size is the size required for the current layout including
borders.

This change allows some code improvements, most notably that since
windows can now never be cropped, that code can be removed from the
layout code, and since panes can now never be outside the size of the
window, window_pane_visible can be removed.
2018-08-20 15:22:14 +01:00
nicm
9f2db6a0af Fix problems with page scrolling in copy mode, GitHub issue 1440 from
Amos Bird.
2018-08-20 13:51:09 +00:00
Thomas Adam
bf03197e18 Merge branch 'obsd-master' 2018-08-19 21:40:26 +01:00
nicm
cac4eadca0 Add a flag to force redrawing of the status line even if the content
hasn't changed, needed for resizing.
2018-08-19 20:13:07 +00:00
Thomas Adam
3310972d75 Merge branch 'obsd-master' 2018-08-19 21:02:37 +01:00
nicm
d95fad3d5f Expand \u and \U escape sequences in command strings, from Christopher
Hunt in GitHub issue 1443.
2018-08-19 19:03:46 +00:00
Thomas Adam
9ecf657703 Merge branch 'obsd-master' 2018-08-19 19:02:40 +01:00
nicm
88327c7698 Add a client redraw-window flag instead of the redraw-all flag and for
all just use the three flags together (window, borders, status).
2018-08-19 16:45:03 +00:00
Thomas Adam
e811132b05 Merge branch 'obsd-master' 2018-08-18 23:02:40 +01:00
nicm
bd2896b65e SESSION_UNATTACHED flag is no longer necessary now we have an attached
count instead.
2018-08-18 20:08:52 +00:00
Thomas Adam
522d751eee Merge branch 'obsd-master' 2018-08-18 19:02:39 +01:00
nicm
3bc08b0dc0 Some tidying and helper functions. 2018-08-18 16:14:03 +00:00
Nicholas Marriott
af679326b2 Now master again. 2018-08-17 11:46:08 +01:00
98 changed files with 7321 additions and 3795 deletions

135
CHANGES
View File

@@ -1,3 +1,128 @@
CHANGES FROM 2.8 to 2.9
* Attempt to preserve horizontal cursor position as well as vertical with
reflow.
* Rewrite main-vertical and horizontal and change layouts to better handle the
case where all panes won't fit into the window size, reduce problems with
pane border status lines and fix other bugs mostly found by Thomas Sattler.
* Add format variables for the default formats in the various modes
(tree_mode_format and so on) and add a -a flag to display-message to list
variables with values.
* Add a -v flag to display-message to show verbose messages as the format is
parsed, this allows formats to be debugged
* Add support for HPA (\033[`).
* Add support for origin mode (\033[?6h).
* No longer clear history on RIS.
* Extend the #[] style syntax and use that together with previous format
changes to allow the status line to be entirely configured with a single
option.
Now that it is possible to configure their content, enable the existing code
that lets the status line be multiple lines in height. The status option can
now take a value of 2, 3, 4 or 5 (as well as the previous on or off) to
configure more than one line. The new status-format array option configures
the format of each line, the default just references the existing status-*
options, although some of the more obscure status options may be eliminated
in time.
Additions to the #[] syntax are: "align" to specify alignment (left, centre,
right), "list" for the window list and "range" to configure ranges of text
for the mouse bindings.
The "align" keyword can also be used to specify alignment of entries in tree
mode and the pane status lines.
* Add E: and T: format modifiers to expand a format twice (useful to expand the
value of an option).
* The individual -fg, -bg and -attr options have been removed; they
were superseded by -style options in tmux 1.9.
* Allow more than one mode to be opened in a pane. Modes are kept on a stack
and retrieved if the same mode is entered again. Exiting the active mode goes
back to the previous one.
* When showing command output in copy mode, call it view mode instead (affects
pane_mode format).
* Add -b to display-panes like run-shell.
* Handle UTF-8 in word-separators option.
* New "terminal" colour allowing options to use the terminal default colour
rather than inheriting the default from a parent option.
* Do not move the cursor in copy mode when the mouse wheel is used.
* Use the same working directory rules for jobs as new windows rather than
always starting in the user's home.
* Allow panes to be one line or column in size.
* Go to last line when goto-line number is out of range in copy mode.
* Yank previously cut text if any with C-y in the command prompt, only use the
buffer if no text has been cut.
* Add q: format modifier to quote shell special characters.
* Add StatusLeft and StatusRight mouse locations (keys such as
MouseDown1StatusLeft) for the status-left and status-right areas of the
status line.
* Add -Z to find-window.
* Support for windows larger than the client. This adds two new options,
window-size and default-size, and a new command, resize-window. The
force-width and force-height options and the session_width and session_height
formats have been removed.
The new window-size option tells tmux how to work out the size of windows:
largest means it picks the size of the largest session, smallest the smallest
session (similar to the old behaviour) and manual means that it does not
automatically resize windows. aggressive-resize modifies the choice of
session for largest and smallest as it did before.
If a window is in a session attached to a client that is too small, only part
of the window is shown. tmux attempts to keep the cursor visible, so the part
of the window displayed is changed as the cursor moves (with a small delay,
to try and avoid excess redrawing when applications redraw status lines or
similar that are not currently visible).
Drawing windows which are larger than the client is not as efficient as those
which fit, particularly when the cursor moves, so it is recommended to avoid
using this on slow machines or networks (set window-size to smallest or
manual).
The resize-window command can be used to resize a window manually. If it is
used, the window-size option is automatically set to manual for the window
(undo this with "setw -u window-size"). resize-window works in a similar way
to resize-pane (-U -D -L -R -x -y flags) but also has -a and -A flags. -a
sets the window to the size of the smallest client (what it would be if
window-size was smallest) and -A the largest.
For the same behaviour as force-width or force-height, use resize-window -x
or -y.
If the global window-size option is set to manual, the default-size option is
used for new windows. If -x or -y is used with new-session, that sets the
default-size option for the new session.
The maximum size of a window is 10000x10000. But expect applications to
complain and higher memory use if making a window that big. The minimum size
is the size required for the current layout including borders.
The refresh-client command can be used to pan around a window, -U -D -L -R
moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
CHANGES FROM 2.7 to 2.8 CHANGES FROM 2.7 to 2.8
* Make display-panes block the client until a pane is chosen or it * Make display-panes block the client until a pane is chosen or it
@@ -291,7 +416,7 @@ CHANGES FROM 2.4 TO 2.5, 09 May 2017
* Do not redraw a client unless we realistically think it can accept the data - * Do not redraw a client unless we realistically think it can accept the data -
defer redraws until the client has nothing else waiting to write. defer redraws until the client has nothing else waiting to write.
CHANGES FROM 2.3 TO 2.4, 20 April 2017 CHANGES FROM 2.3 TO 2.4, 20 April 2017
Incompatible Changes Incompatible Changes
@@ -577,7 +702,7 @@ Normal Changes
============== ==============
* Fix crash due to uninitialized lastwp member of layout_cell * Fix crash due to uninitialized lastwp member of layout_cell
* Fix -fg/-bg/-style with 256 colour terminals. * Fix -fg/-bg/-style with 256 colour terminals.
CHANGES FROM 1.8 TO 1.9, 20 February 2014 CHANGES FROM 1.8 TO 1.9, 20 February 2014
@@ -935,7 +1060,7 @@ CHANGES FROM 1.2 TO 1.3, 18 July 2010
* Run job commands explicitly in the global environment (which can be modified * Run job commands explicitly in the global environment (which can be modified
with setenv -g), rather than with the environment tmux started with. with setenv -g), rather than with the environment tmux started with.
* Use the machine's hostname as the default title, instead of an empty string. * Use the machine's hostname as the default title, instead of an empty string.
* Prevent double free if the window option remain-on-exit is set. * Prevent double free if the window option remain-on-exit is set.
* Key string conversions rewritten. * Key string conversions rewritten.
* Mark zombie windows as dead in the choose-window list. * Mark zombie windows as dead in the choose-window list.
* Tiled layout added. * Tiled layout added.
@@ -1037,7 +1162,7 @@ CHANGES FROM 1.0 TO 1.1, 05 November 2009
* New lock-client (alias lockc), and lock-session (alias locks) commands to * New lock-client (alias lockc), and lock-session (alias locks) commands to
lock a particular client, or all clients attached to a session. 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. * 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. * Use : for goto line rather than g in vi mode.
* Try to guess which client to use when no target client was specified. Finds * 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, the current session, and if only one client is present, use it. Otherwise,
return the most recently used client. return the most recently used client.
@@ -1168,7 +1293,7 @@ The list of older changes is below.
* main-horizontal layout and main-pane-height option to match vertical. * main-horizontal layout and main-pane-height option to match vertical.
* New window option main-pane-width to set the width of the large left pane with * New window option main-pane-width to set the width of the large left pane with
main-vertical (was left-vertical) layout. main-vertical (was left-vertical) layout.
* Lots of layout cleanup. manual layout is now manual-vertical. * Lots of layout cleanup. manual layout is now manual-vertical.
16 May 2009 16 May 2009

View File

@@ -18,7 +18,7 @@ This should include at least the output of:
$ uname -sp && tmux -V && echo $TERM $ uname -sp && tmux -V && echo $TERM
Please do not report bugs (crashes, incorrect behaviour) without reproducing on Please do not report bugs (crashes, incorrect behaviour) without reproducing on
a tmux built from Git master. a tmux built from the latest code in Git.
Note that TERM inside tmux must be a variant of screen or tmux (for example: Note that TERM inside tmux must be a variant of screen or tmux (for example:
screen or screen-256color, tmux or tmux-256color). Please ensure this is the screen or screen-256color, tmux or tmux-256color). Please ensure this is the

View File

@@ -100,6 +100,7 @@ dist_tmux_SOURCES = \
cmd-rename-session.c \ cmd-rename-session.c \
cmd-rename-window.c \ cmd-rename-window.c \
cmd-resize-pane.c \ cmd-resize-pane.c \
cmd-resize-window.c \
cmd-respawn-pane.c \ cmd-respawn-pane.c \
cmd-respawn-window.c \ cmd-respawn-window.c \
cmd-rotate-window.c \ cmd-rotate-window.c \
@@ -131,6 +132,7 @@ dist_tmux_SOURCES = \
control.c \ control.c \
environ.c \ environ.c \
format.c \ format.c \
format-draw.c \
grid-view.c \ grid-view.c \
grid.c \ grid.c \
hooks.c \ hooks.c \
@@ -195,7 +197,7 @@ install-exec-hook:
>$(srcdir)/tmux.1.mdoc; \ >$(srcdir)/tmux.1.mdoc; \
else \ else \
sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \ sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
$(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \ $(AWK) -f $(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
fi fi
$(mkdir_p) $(DESTDIR)$(mandir)/man1 $(mkdir_p) $(DESTDIR)$(mandir)/man1
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \ $(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \

38
TODO
View File

@@ -16,13 +16,11 @@
* way to set socket path from config file * way to set socket path from config file
- format improvements: - format improvements:
* option to quote format (#{q:session_name})
* some way to pad # stuff with spaces * some way to pad # stuff with spaces
* formats to show if a window is linked into multiple sessions, into * formats to show if a window is linked into multiple sessions, into
multiple attached sessions, and is the active window in multiple multiple attached sessions, and is the active window in multiple
attached sessions? attached sessions?
* comparison operators like < and > (for #{version}?) * comparison operators like < and > (for #{version}?)
* %else statement in config file
- improve monitor-*: - improve monitor-*:
* straighten out rules for multiple clients * straighten out rules for multiple clients
@@ -31,7 +29,7 @@
* perhaps monitor /all/ panes in the window not just one * perhaps monitor /all/ panes in the window not just one
- improve mouse support: - improve mouse support:
* bind commands to mouse in different areas? * bind commands to mouse in different areas?
* commands executed when clicking on a pattern (URL) * commands executed when clicking on a pattern (URL)
- warts on current naming: - warts on current naming:
@@ -50,6 +48,11 @@
dragging it should select by word. compare how xterm works. GitHub dragging it should select by word. compare how xterm works. GitHub
issue 682) issue 682)
* key to search for word under cursor (GitHub issue 1240) * key to search for word under cursor (GitHub issue 1240)
* when entering copy mode, should copy grid so that input does not
need to be suspended
* allow the prefix for automatic buffers to be specified as part of the
key binding to allow session buffers or similar (GitHub issue 1501)
* copy-pipe should be synchronous (GitHub issue 1517)
- layout stuff - layout stuff
* way to tag a layout as a number/name * way to tag a layout as a number/name
@@ -61,7 +64,6 @@
not attached to a cell at all. this could be the time to introduce not attached to a cell at all. this could be the time to introduce
panelink to replace layout_cell panelink to replace layout_cell
* way to set hints/limits about pane size for resizing * way to set hints/limits about pane size for resizing
* panning over window (window larger than visible)
* a mode where one application can cross two panes (ie x|y, width = * a mode where one application can cross two panes (ie x|y, width =
COLUMNS/2 but height = ROWS * 2) COLUMNS/2 but height = ROWS * 2)
* separate active panes for different clients * separate active panes for different clients
@@ -109,11 +111,15 @@
* marks in history, automatically add (move?) one when pane is changed * marks in history, automatically add (move?) one when pane is changed
* this doesn't work, need pane reference count probably: * this doesn't work, need pane reference count probably:
bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window bind -n DoubleClick3Status confirm-before -p "kill-window #I? (y/n)" kill-window
* respawn -c flag same as neww etc
* marker lines in history (GitHub issue 1042) * marker lines in history (GitHub issue 1042)
* tree mode stuff: make command prompt (:) common code so all modes get it, * tree mode stuff: make command prompt (:) common code so all modes get it,
predefined filters, tag-all key, ... predefined filters, tag-all key, ...
* drag panes and windows around to move/swap them in choose mode * drag panes and windows around to move/swap them in choose mode
* flag to specify environment to new-window, split-window,
new-session (issue 1498)
* multiple column panes (issue 1503)
* support for ZERO WIDTH JOINER U+200D
* individual pane synchronize-panes (with pane options?); issue 1638
- hooks - hooks
* more hooks for various things * more hooks for various things
@@ -131,3 +137,25 @@
* finish hooks for notifys * finish hooks for notifys
* for session_closed, if no sessions at all, perhaps fake up a * for session_closed, if no sessions at all, perhaps fake up a
temporary one temporary one
- pan
* tty_window_offset should try to keep as much off active pane
visible as possible
* rather than centering cursor it might be better if only
moved offset when it gets close to an edge?
----
TODO soonish maybe:
- Store hooks as options, issue 1619.
- Support buffer prefixes, issue 1501.
- copy-pipe should be synchronous, issue 1517.
- -E flag to pass environment to new-*, issue 1498.
- Copy mode searching is slow when there is a big history, issue 1545.
- Grid "block" stuff, issue 1269. Can be used potentially for compression of
history (bit silly really though), reflow performance (can reflow blocks on
demand). It would possibly be good if history-limit could be global and
collected LRU.
- Command aliases should be able to override builtin commands in order to add
default flags (some mechanism needed to avoid recursion). GitHub issue 1630.

View File

@@ -25,13 +25,13 @@
const char * const char *
attributes_tostring(int attr) attributes_tostring(int attr)
{ {
static char buf[128]; static char buf[512];
size_t len; size_t len;
if (attr == 0) if (attr == 0)
return ("none"); return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s", len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "", (attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "", (attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "", (attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
@@ -39,7 +39,11 @@ attributes_tostring(int attr)
(attr & GRID_ATTR_REVERSE) ? "reverse," : "", (attr & GRID_ATTR_REVERSE) ? "reverse," : "",
(attr & GRID_ATTR_HIDDEN) ? "hidden," : "", (attr & GRID_ATTR_HIDDEN) ? "hidden," : "",
(attr & GRID_ATTR_ITALICS) ? "italics," : "", (attr & GRID_ATTR_ITALICS) ? "italics," : "",
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : ""); (attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "",
(attr & GRID_ATTR_UNDERSCORE_2) ? "double-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "");
if (len > 0) if (len > 0)
buf[len - 1] = '\0'; buf[len - 1] = '\0';
@@ -52,6 +56,25 @@ attributes_fromstring(const char *str)
const char delimiters[] = " ,|"; const char delimiters[] = " ,|";
int attr; int attr;
size_t end; size_t end;
u_int i;
struct {
const char* name;
int attr;
} table[] = {
{ "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM },
{ "underscore", GRID_ATTR_UNDERSCORE },
{ "blink", GRID_ATTR_BLINK },
{ "reverse", GRID_ATTR_REVERSE },
{ "hidden", GRID_ATTR_HIDDEN },
{ "italics", GRID_ATTR_ITALICS },
{ "strikethrough", GRID_ATTR_STRIKETHROUGH },
{ "double-underscore", GRID_ATTR_UNDERSCORE_2 },
{ "curly-underscore", GRID_ATTR_UNDERSCORE_3 },
{ "dotted-underscore", GRID_ATTR_UNDERSCORE_4 },
{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 }
};
if (*str == '\0' || strcspn(str, delimiters) == 0) if (*str == '\0' || strcspn(str, delimiters) == 0)
return (-1); return (-1);
@@ -64,24 +87,15 @@ attributes_fromstring(const char *str)
attr = 0; attr = 0;
do { do {
end = strcspn(str, delimiters); end = strcspn(str, delimiters);
if ((end == 6 && strncasecmp(str, "bright", end) == 0) || for (i = 0; i < nitems(table); i++) {
(end == 4 && strncasecmp(str, "bold", end) == 0)) if (end != strlen(table[i].name))
attr |= GRID_ATTR_BRIGHT; continue;
else if (end == 3 && strncasecmp(str, "dim", end) == 0) if (strncasecmp(str, table[i].name, end) == 0) {
attr |= GRID_ATTR_DIM; attr |= table[i].attr;
else if (end == 10 && strncasecmp(str, "underscore", end) == 0) break;
attr |= GRID_ATTR_UNDERSCORE; }
else if (end == 5 && strncasecmp(str, "blink", end) == 0) }
attr |= GRID_ATTR_BLINK; if (i == nitems(table))
else if (end == 7 && strncasecmp(str, "reverse", end) == 0)
attr |= GRID_ATTR_REVERSE;
else if (end == 6 && strncasecmp(str, "hidden", end) == 0)
attr |= GRID_ATTR_HIDDEN;
else if (end == 7 && strncasecmp(str, "italics", end) == 0)
attr |= GRID_ATTR_ITALICS;
else if (end == 13 && strncasecmp(str, "strikethrough", end) == 0)
attr |= GRID_ATTR_STRIKETHROUGH;
else
return (-1); return (-1);
str += end + strspn(str + end, delimiters); str += end + strspn(str + end, delimiters);
} while (*str != '\0'); } while (*str != '\0');

13
cfg.c
View File

@@ -37,6 +37,7 @@ struct cfg_cond {
}; };
TAILQ_HEAD(cfg_conds, cfg_cond); TAILQ_HEAD(cfg_conds, cfg_cond);
struct client *cfg_client;
static char *cfg_file; static char *cfg_file;
int cfg_finished; int cfg_finished;
static char **cfg_causes; static char **cfg_causes;
@@ -94,7 +95,7 @@ start_cfg(void)
* command queue is currently empty and our callback will be at the * command queue is currently empty and our callback will be at the
* front - we need to get in before MSG_COMMAND. * front - we need to get in before MSG_COMMAND.
*/ */
c = TAILQ_FIRST(&clients); cfg_client = c = TAILQ_FIRST(&clients);
if (c != NULL) { if (c != NULL) {
cfg_item = cmdq_get_callback(cfg_client_done, NULL); cfg_item = cmdq_get_callback(cfg_client_done, NULL);
cmdq_append(c, cfg_item); cmdq_append(c, cfg_item);
@@ -339,15 +340,17 @@ cfg_print_causes(struct cmdq_item *item)
void void
cfg_show_causes(struct session *s) cfg_show_causes(struct session *s)
{ {
struct window_pane *wp; struct window_pane *wp;
u_int i; struct window_mode_entry *wme;
u_int i;
if (s == NULL || cfg_ncauses == 0) if (s == NULL || cfg_ncauses == 0)
return; return;
wp = s->curw->window->active; wp = s->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode, NULL, NULL); wme = TAILQ_FIRST(&wp->modes);
window_copy_init_for_output(wp); if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
for (i = 0; i < cfg_ncauses; i++) { for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, "%s", cfg_causes[i]); window_copy_add(wp, "%s", cfg_causes[i]);
free(cfg_causes[i]); free(cfg_causes[i]);

View File

@@ -222,7 +222,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
const char *ttynam, *cwd; const char *ttynam, *cwd;
pid_t ppid; pid_t ppid;
enum msgtype msg; enum msgtype msg;
char *cause, path[PATH_MAX]; char *cause;
struct termios tio, saved_tio; struct termios tio, saved_tio;
size_t size; size_t size;
@@ -277,9 +277,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL); client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
/* Save these before pledge(). */ /* Save these before pledge(). */
if ((cwd = getenv("PWD")) == NULL && if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
(cwd = getcwd(path, sizeof path)) == NULL &&
(cwd = find_home()) == NULL)
cwd = "/"; cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL) if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = ""; ttynam = "";

View File

@@ -115,6 +115,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
c->session = s; c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);
@@ -142,6 +143,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
c->session = s; c->session = s;
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);

View File

@@ -76,7 +76,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
window_lost_pane(w, wp); window_lost_pane(w, wp);
layout_close_pane(wp); layout_close_pane(wp);
w = wp->window = window_create(dst_s->sx, dst_s->sy); w = wp->window = window_create(w->sx, w->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp; w->active = wp;

View File

@@ -41,7 +41,7 @@ const struct cmd_entry cmd_capture_pane_entry = {
.args = { "ab:CeE:JpPqS:t:", 0, 0 }, .args = { "ab:CeE:JpPqS:t:", 0, 0 },
.usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] " .usage = "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line]" CMD_TARGET_PANE_USAGE, "[-S start-line] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -199,8 +199,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
size_t len; size_t len;
if (self->entry == &cmd_clear_history_entry) { if (self->entry == &cmd_clear_history_entry) {
if (wp->mode == &window_copy_mode) window_pane_reset_mode_all(wp);
window_pane_reset_mode(wp);
grid_clear_history(wp->base.grid); grid_clear_history(wp->base.grid);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -32,7 +32,7 @@ const struct cmd_entry cmd_choose_tree_entry = {
.args = { "F:Gf:NO:st:wZ", 0, 1 }, .args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] " .usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_choose_client_entry = {
.args = { "F:f:NO:t:Z", 0, 1 }, .args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] " .usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -60,7 +60,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.args = { "F:f:NO:t:Z", 0, 1 }, .args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] " .usage = "[-N] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },

View File

@@ -60,7 +60,6 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
struct client *c = item->client; struct client *c = item->client;
struct session *s; struct session *s;
struct window_pane *wp = item->target.wp; struct window_pane *wp = item->target.wp;
int flag;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL) if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
@@ -74,18 +73,11 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (wp->mode != &window_copy_mode) { if (window_pane_set_mode(wp, &window_copy_mode, NULL, args) != 0)
flag = window_pane_set_mode(wp, &window_copy_mode, NULL, NULL); return (CMD_RETURN_NORMAL);
if (flag != 0) if (args_has(args, 'M'))
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp, args_has(self->args, 'e'));
}
if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &shared->mouse); window_copy_start_drag(c, &shared->mouse);
} if (args_has(self->args, 'u'))
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message", .name = "display-message",
.alias = "display", .alias = "display",
.args = { "c:pt:F:", 0, 1 }, .args = { "ac:pt:F:v", 0, 1 },
.usage = "[-p] [-c target-client] [-F format] " .usage = "[-apv] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]", CMD_TARGET_PANE_USAGE " [message]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -49,6 +49,14 @@ const struct cmd_entry cmd_display_message_entry = {
.exec = cmd_display_message_exec .exec = cmd_display_message_exec
}; };
static void
cmd_display_message_each(const char *key, const char *value, void *arg)
{
struct cmdq_item *item = arg;
cmdq_print(item, "%s=%s", key, value);
}
static enum cmd_retval static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item) cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{ {
@@ -60,6 +68,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
const char *template; const char *template;
char *msg; char *msg;
struct format_tree *ft; struct format_tree *ft;
int flags;
if (args_has(args, 'F') && args->argc != 0) { if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(item, "only one of -F or argument must be given"); cmdq_error(item, "only one of -F or argument must be given");
@@ -83,10 +92,20 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
target_c = c; target_c = c;
else else
target_c = cmd_find_best_client(s); target_c = cmd_find_best_client(s);
ft = format_create(item->client, item, FORMAT_NONE, 0); if (args_has(self->args, 'v'))
flags = FORMAT_VERBOSE;
else
flags = 0;
ft = format_create(item->client, item, FORMAT_NONE, flags);
format_defaults(ft, target_c, s, wl, wp); format_defaults(ft, target_c, s, wl, wp);
msg = format_expand_time(ft, template, time(NULL)); if (args_has(args, 'a')) {
if (item != NULL)
format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL);
}
msg = format_expand_time(ft, template);
if (args_has(self->args, 'p')) if (args_has(self->args, 'p'))
cmdq_print(item, "%s", msg); cmdq_print(item, "%s", msg);
else if (c != NULL) else if (c != NULL)

View File

@@ -37,8 +37,8 @@ const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes", .name = "display-panes",
.alias = "displayp", .alias = "displayp",
.args = { "d:t:", 0, 1 }, .args = { "bd:t:", 0, 1 },
.usage = "[-d duration] " CMD_TARGET_CLIENT_USAGE, .usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec .exec = cmd_display_panes_exec
@@ -65,7 +65,10 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
c->identify_callback_data = xstrdup(args->argv[0]); c->identify_callback_data = xstrdup(args->argv[0]);
else else
c->identify_callback_data = xstrdup("select-pane -t '%%'"); c->identify_callback_data = xstrdup("select-pane -t '%%'");
c->identify_callback_item = item; if (args_has(args, 'b'))
c->identify_callback_item = NULL;
else
c->identify_callback_item = item;
if (args_has(args, 'd')) { if (args_has(args, 'd')) {
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause); delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
@@ -78,6 +81,8 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
delay = options_get_number(s->options, "display-panes-time"); delay = options_get_number(s->options, "display-panes-time");
server_client_set_identify(c, delay); server_client_set_identify(c, delay);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
@@ -115,15 +120,21 @@ cmd_display_panes_callback(struct client *c, struct window_pane *wp)
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }
if (new_item != NULL) if (new_item != NULL) {
cmdq_insert_after(c->identify_callback_item, new_item); if (c->identify_callback_item != NULL)
cmdq_insert_after(c->identify_callback_item, new_item);
else
cmdq_append(c, new_item);
}
free(cmd); free(cmd);
free(expanded); free(expanded);
out: out:
c->identify_callback_item->flags &= ~CMDQ_WAITING; if (c->identify_callback_item != NULL) {
c->identify_callback_item = NULL; c->identify_callback_item->flags &= ~CMDQ_WAITING;
c->identify_callback_item = NULL;
}
free(c->identify_callback_data); free(c->identify_callback_data);
c->identify_callback_data = NULL; c->identify_callback_data = NULL;

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_find_window_entry = {
.name = "find-window", .name = "find-window",
.alias = "findw", .alias = "findw",
.args = { "CNt:T", 1, 1 }, .args = { "CNt:TZ", 1, 1 },
.usage = "[-CNT] " CMD_TARGET_PANE_USAGE " match-string", .usage = "[-CNTZ] " CMD_TARGET_PANE_USAGE " match-string",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -83,6 +83,8 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s); xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
new_args = args_parse("", 1, &argv); new_args = args_parse("", 1, &argv);
if (args_has(args, 'Z'))
args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter); args_set(new_args, 'f', filter);
window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args); window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args);

View File

@@ -135,7 +135,7 @@ cmd_find_best_client(struct session *s)
{ {
struct client *c_loop, *c; struct client *c_loop, *c;
if (s->flags & SESSION_UNATTACHED) if (s->attached == 0)
s = NULL; s = NULL;
c = NULL; c = NULL;
@@ -159,10 +159,10 @@ cmd_find_session_better(struct session *s, struct session *than, int flags)
if (than == NULL) if (than == NULL)
return (1); return (1);
if (flags & CMD_FIND_PREFER_UNATTACHED) { if (flags & CMD_FIND_PREFER_UNATTACHED) {
attached = (~than->flags & SESSION_UNATTACHED); attached = (than->attached != 0);
if (attached && (s->flags & SESSION_UNATTACHED)) if (attached && s->attached == 0)
return (1); return (1);
else if (!attached && (~s->flags & SESSION_UNATTACHED)) else if (!attached && s->attached != 0)
return (0); return (0);
} }
return (timercmp(&s->activity_time, &than->activity_time, >)); return (timercmp(&s->activity_time, &than->activity_time, >));
@@ -453,6 +453,7 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
if (errstr == NULL) { if (errstr == NULL) {
fs->wl = winlink_find_by_index(&fs->s->windows, idx); fs->wl = winlink_find_by_index(&fs->s->windows, idx);
if (fs->wl != NULL) { if (fs->wl != NULL) {
fs->idx = fs->wl->idx;
fs->w = fs->wl->window; fs->w = fs->wl->window;
return (0); return (0);
} }
@@ -970,7 +971,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
{ {
struct mouse_event *m; struct mouse_event *m;
struct cmd_find_state current; struct cmd_find_state current;
char *colon, *period, *copy = NULL; char *colon, *period, *copy = NULL, tmp[256];
const char *session, *window, *pane, *s; const char *session, *window, *pane, *s;
int window_only = 0, pane_only = 0; int window_only = 0, pane_only = 0;
@@ -987,11 +988,25 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
s = "session"; s = "session";
else else
s = "unknown"; s = "unknown";
if (target == NULL) *tmp = '\0';
log_debug("%s: target none, type %s", __func__, s); if (flags & CMD_FIND_PREFER_UNATTACHED)
else strlcat(tmp, "PREFER_UNATTACHED,", sizeof tmp);
log_debug("%s: target %s, type %s", __func__, target, s); if (flags & CMD_FIND_QUIET)
log_debug("%s: item %p, flags %#x", __func__, item, flags); strlcat(tmp, "QUIET,", sizeof tmp);
if (flags & CMD_FIND_WINDOW_INDEX)
strlcat(tmp, "WINDOW_INDEX,", sizeof tmp);
if (flags & CMD_FIND_DEFAULT_MARKED)
strlcat(tmp, "DEFAULT_MARKED,", sizeof tmp);
if (flags & CMD_FIND_EXACT_SESSION)
strlcat(tmp, "EXACT_SESSION,", sizeof tmp);
if (flags & CMD_FIND_EXACT_WINDOW)
strlcat(tmp, "EXACT_WINDOW,", sizeof tmp);
if (flags & CMD_FIND_CANFAIL)
strlcat(tmp, "CANFAIL,", sizeof tmp);
if (*tmp != '\0')
tmp[strlen(tmp) - 1] = '\0';
log_debug("%s: target %s, type %s, item %p, flags %s", __func__,
target == NULL ? "none" : target, s, item, tmp);
/* Clear new state. */ /* Clear new state. */
cmd_find_clear_state(fs, flags); cmd_find_clear_state(fs, flags);
@@ -1131,9 +1146,16 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
if (pane != NULL) if (pane != NULL)
pane = cmd_find_map_table(cmd_find_pane_table, pane); pane = cmd_find_map_table(cmd_find_pane_table, pane);
log_debug("%s: target %s (flags %#x): session=%s, window=%s, pane=%s", if (session != NULL || window != NULL || pane != NULL) {
__func__, target, flags, session == NULL ? "none" : session, log_debug("%s: target %s is %s%s%s%s%s%s",
window == NULL ? "none" : window, pane == NULL ? "none" : pane); __func__, target,
session == NULL ? "" : "session ",
session == NULL ? "" : session,
window == NULL ? "" : "window ",
window == NULL ? "" : window,
pane == NULL ? "" : "pane ",
pane == NULL ? "" : pane);
}
/* No pane is allowed if want an index. */ /* No pane is allowed if want an index. */
if (pane != NULL && (flags & CMD_FIND_WINDOW_INDEX)) { if (pane != NULL && (flags & CMD_FIND_WINDOW_INDEX)) {
@@ -1241,17 +1263,17 @@ found:
no_session: no_session:
if (~flags & CMD_FIND_QUIET) if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find session %s", session); cmdq_error(item, "can't find session: %s", session);
goto error; goto error;
no_window: no_window:
if (~flags & CMD_FIND_QUIET) if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find window %s", window); cmdq_error(item, "can't find window: %s", window);
goto error; goto error;
no_pane: no_pane:
if (~flags & CMD_FIND_QUIET) if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find pane %s", pane); cmdq_error(item, "can't find pane: %s", pane);
goto error; goto error;
} }
@@ -1321,7 +1343,7 @@ cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
/* If no client found, report an error. */ /* If no client found, report an error. */
if (c == NULL && !quiet) if (c == NULL && !quiet)
cmdq_error(item, "can't find client %s", copy); cmdq_error(item, "can't find client: %s", copy);
free(copy); free(copy);
log_debug("%s: target %s, return %p", __func__, target, c); log_debug("%s: target %s, return %p", __func__, target, c);

View File

@@ -120,8 +120,13 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->item = NULL; cdata->item = NULL;
memcpy(&cdata->mouse, &shared->mouse, sizeof cdata->mouse); memcpy(&cdata->mouse, &shared->mouse, sizeof cdata->mouse);
job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL, if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0); cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd);
free(cdata);
return (CMD_RETURN_ERROR);
}
free(shellcmd); free(shellcmd);
if (args_has(args, 'b')) if (args_has(args, 'b'))
@@ -132,14 +137,16 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
static void static void
cmd_if_shell_callback(struct job *job) cmd_if_shell_callback(struct job *job)
{ {
struct cmd_if_shell_data *cdata = job->data; struct cmd_if_shell_data *cdata = job_get_data(job);
struct client *c = cdata->client; struct client *c = cdata->client;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmdq_item *new_item; struct cmdq_item *new_item;
char *cause, *cmd, *file = cdata->file; char *cause, *cmd, *file = cdata->file;
u_int line = cdata->line; u_int line = cdata->line;
int status;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) status = job_get_status(job);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
cmd = cdata->cmd_else; cmd = cdata->cmd_else;
else else
cmd = cdata->cmd_if; cmd = cdata->cmd_if;

View File

@@ -30,8 +30,7 @@
#define LIST_SESSIONS_TEMPLATE \ #define LIST_SESSIONS_TEMPLATE \
"#{session_name}: #{session_windows} windows " \ "#{session_name}: #{session_windows} windows " \
"(created #{t:session_created}) " \ "(created #{t:session_created})" \
"[#{session_width}x#{session_height}]" \
"#{?session_grouped, (group ,}" \ "#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \ "#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}" "#{?session_attached, (attached),}"

View File

@@ -87,6 +87,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (error != 0) { if (error != 0) {
cmdq_error(item, "-: %s", cause); cmdq_error(item, "-: %s", cause);
free(cause); free(cause);
free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);

View File

@@ -71,14 +71,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
struct session *s, *as, *groupwith; struct session *s, *as, *groupwith;
struct window *w; struct window *w;
struct environ *env; struct environ *env;
struct options *oo;
struct termios tio, *tiop; struct termios tio, *tiop;
struct session_group *sg; struct session_group *sg;
const char *errstr, *template, *group, *prefix; const char *errstr, *template, *group, *prefix;
const char *path, *cmd, *tmp; const char *path, *cmd, *tmp, *value;
char **argv, *cause, *cp, *newname, *cwd = NULL; char **argv, *cause, *cp, *newname, *cwd = NULL;
int detached, already_attached, idx, argc; int detached, already_attached, idx, argc;
int is_control = 0; int is_control = 0;
u_int sx, sy; u_int sx, sy, dsx = 80, dsy = 24;
struct environ_entry *envent; struct environ_entry *envent;
struct cmd_find_state fs; struct cmd_find_state fs;
enum cmd_retval retval; enum cmd_retval retval;
@@ -189,44 +190,51 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} }
} }
/* Find new session size. */ /* Get default session size. */
if (!detached) { if (args_has(args, 'x')) {
sx = c->tty.sx;
sy = c->tty.sy;
if (!is_control &&
sy > 0 &&
options_get_number(global_s_options, "status"))
sy--;
} else {
sx = 80;
sy = 24;
}
if ((is_control || detached) && args_has(args, 'x')) {
tmp = args_get(args, 'x'); tmp = args_get(args, 'x');
if (strcmp(tmp, "-") == 0) { if (strcmp(tmp, "-") == 0) {
if (c != NULL) if (c != NULL)
sx = c->tty.sx; dsx = c->tty.sx;
} else { } else {
sx = strtonum(tmp, 1, USHRT_MAX, &errstr); dsx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(item, "width %s", errstr); cmdq_error(item, "width %s", errstr);
goto error; goto error;
} }
} }
} }
if ((is_control || detached) && args_has(args, 'y')) { if (args_has(args, 'y')) {
tmp = args_get(args, 'y'); tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) { if (strcmp(tmp, "-") == 0) {
if (c != NULL) if (c != NULL)
sy = c->tty.sy; dsy = c->tty.sy;
} else { } else {
sy = strtonum(tmp, 1, USHRT_MAX, &errstr); dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(item, "height %s", errstr); cmdq_error(item, "height %s", errstr);
goto error; goto error;
} }
} }
} }
/* Find new session size. */
if (!detached && !is_control) {
sx = c->tty.sx;
sy = c->tty.sy;
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
} else {
value = options_get_string(global_s_options, "default-size");
if (sscanf(value, "%ux%u", &sx, &sy) != 2) {
sx = 80;
sy = 24;
}
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
}
if (sx == 0) if (sx == 0)
sx = 1; sx = 1;
if (sy == 0) if (sy == 0)
@@ -262,10 +270,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (c != NULL && !args_has(args, 'E')) if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env); environ_update(global_s_options, c->environ, env);
/* Set up the options. */
oo = options_create(global_s_options);
if (args_has(args, 'x') || args_has(args, 'y'))
options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
/* Create the new session. */ /* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index"); idx = -1 - options_get_number(global_s_options, "base-index");
s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop, s = session_create(prefix, newname, argc, argv, path, cwd, env, oo,
idx, sx, sy, &cause); tiop, idx, &cause);
environ_free(env); environ_free(env);
if (s == NULL) { if (s == NULL) {
cmdq_error(item, "create session failed: %s", cause); cmdq_error(item, "create session failed: %s", cause);
@@ -313,6 +326,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
c->session = s; c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);

View File

@@ -109,7 +109,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
/* Expand the command. */ /* Expand the command. */
ft = format_create(item->client, item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0], time(NULL)); cmd = format_expand_time(ft, args->argv[0]);
format_free(ft); format_free(ft);
/* Fork the child. */ /* Fork the child. */
@@ -157,7 +157,10 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
close(pipe_fd[1]); close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0]; wp->pipe_fd = pipe_fd[0];
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); if (wp->fd != -1)
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
else
wp->pipe_off = 0;
setblocking(wp->pipe_fd, 0); setblocking(wp->pipe_fd, 0);
wp->pipe_event = bufferevent_new(wp->pipe_fd, wp->pipe_event = bufferevent_new(wp->pipe_fd,
@@ -165,6 +168,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
cmd_pipe_pane_write_callback, cmd_pipe_pane_write_callback,
cmd_pipe_pane_error_callback, cmd_pipe_pane_error_callback,
wp); wp);
if (wp->pipe_event == NULL)
fatalx("out of memory");
if (out) if (out)
bufferevent_enable(wp->pipe_event, EV_WRITE); bufferevent_enable(wp->pipe_event, EV_WRITE);
if (in) if (in)

View File

@@ -404,10 +404,11 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
void void
cmdq_print(struct cmdq_item *item, const char *fmt, ...) cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{ {
struct client *c = item->client; struct client *c = item->client;
struct window *w; struct window_pane *wp;
va_list ap; struct window_mode_entry *wme;
char *tmp, *msg; va_list ap;
char *tmp, *msg;
va_start(ap, fmt); va_start(ap, fmt);
@@ -425,14 +426,11 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
evbuffer_add(c->stdout_data, "\n", 1); evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c); server_client_push_stdout(c);
} else { } else {
w = c->session->curw->window; wp = c->session->curw->window->active;
if (w->active->mode != &window_copy_mode) { wme = TAILQ_FIRST(&wp->modes);
window_pane_reset_mode(w->active); if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(w->active, &window_copy_mode, NULL, window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
NULL); window_copy_vadd(wp, fmt, ap);
window_copy_init_for_output(w->active);
}
window_copy_vadd(w->active, fmt, ap);
} }
va_end(ap); va_end(ap);

View File

@@ -18,6 +18,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
/* /*
@@ -31,8 +33,8 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", .name = "refresh-client",
.alias = "refresh", .alias = "refresh",
.args = { "C:St:", 0, 0 }, .args = { "cC:DlLRSt:U", 0, 1 },
.usage = "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, .usage = "[-cDlLRSU] [-C size] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec .exec = cmd_refresh_client_exec
@@ -43,23 +45,80 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c; struct client *c;
const char *size; struct tty *tty;
u_int w, h; struct window *w;
const char *size, *errstr;
u_int x, y, adjust;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL) if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
tty = &c->tty;
if (args_has(args, 'C')) { if (args_has(args, 'c') ||
args_has(args, 'L') ||
args_has(args, 'R') ||
args_has(args, 'U') ||
args_has(args, 'D'))
{
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'c'))
c->pan_window = NULL;
else {
w = c->session->curw->window;
if (c->pan_window != w) {
c->pan_window = w;
c->pan_ox = tty->oox;
c->pan_oy = tty->ooy;
}
if (args_has(args, 'L')) {
if (c->pan_ox > adjust)
c->pan_ox -= adjust;
else
c->pan_ox = 0;
} else if (args_has(args, 'R')) {
c->pan_ox += adjust;
if (c->pan_ox > w->sx - tty->osx)
c->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) {
if (c->pan_oy > adjust)
c->pan_oy -= adjust;
else
c->pan_oy = 0;
} else if (args_has(args, 'D')) {
c->pan_oy += adjust;
if (c->pan_oy > w->sy - tty->osy)
c->pan_oy = w->sy - tty->osy;
}
}
tty_update_client_offset(c);
server_redraw_client(c);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'l')) {
if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
} else if (args_has(args, 'C')) {
if ((size = args_get(args, 'C')) == NULL) { if ((size = args_get(args, 'C')) == NULL) {
cmdq_error(item, "missing size"); cmdq_error(item, "missing size");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (sscanf(size, "%u,%u", &w, &h) != 2) { if (sscanf(size, "%u,%u", &x, &y) != 2 &&
sscanf(size, "%ux%u", &x, &y)) {
cmdq_error(item, "bad size argument"); cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (w < PANE_MINIMUM || w > 5000 || if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
h < PANE_MINIMUM || h > 5000) { y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big"); cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -67,16 +126,18 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "not a control client"); cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
tty_set_size(&c->tty, w, h); tty_set_size(&c->tty, x, y);
c->flags |= CLIENT_SIZECHANGED; c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes(); recalculate_sizes();
} else if (args_has(args, 'S')) { return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'S')) {
c->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_status_client(c); server_status_client(c);
} else { } else {
c->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(c); server_redraw_client(c);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -91,9 +91,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
} }
if (args_has(self->args, 'x')) { if (args_has(args, 'x')) {
x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX, x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX, &cause);
&cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "width %s", cause); cmdq_error(item, "width %s", cause);
free(cause); free(cause);
@@ -101,9 +100,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x); layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
} }
if (args_has(self->args, 'y')) { if (args_has(args, 'y')) {
y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX, y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX, &cause);
&cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "height %s", cause); cmdq_error(item, "height %s", cause);
free(cause); free(cause);
@@ -112,13 +110,13 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
} }
if (args_has(self->args, 'L')) if (args_has(args, 'L'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1); layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1);
else if (args_has(self->args, 'R')) else if (args_has(args, 'R'))
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1); layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1);
else if (args_has(self->args, 'U')) else if (args_has(args, 'U'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1); layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1);
else if (args_has(self->args, 'D')) else if (args_has(args, 'D'))
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1); layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1);
server_redraw_window(wl->window); server_redraw_window(wl->window);

109
cmd-resize-window.c Normal file
View File

@@ -0,0 +1,109 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2018 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include "tmux.h"
/*
* Increase or decrease window size.
*/
static enum cmd_retval cmd_resize_window_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_resize_window_entry = {
.name = "resize-window",
.alias = "resizew",
.args = { "aADLRt:Ux:y:", 0, 1 },
.usage = "[-aADLRU] [-x width] [-y height] " CMD_TARGET_WINDOW_USAGE " "
"[adjustment]",
.target = { 't', CMD_FIND_WINDOW, 0 },
.flags = CMD_AFTERHOOK,
.exec = cmd_resize_window_exec
};
static enum cmd_retval
cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct winlink *wl = item->target.wl;
struct window *w = wl->window;
struct session *s = item->target.s;
const char *errstr;
char *cause;
u_int adjust, sx, sy;
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR);
}
}
sx = w->sx;
sy = w->sy;
if (args_has(args, 'x')) {
sx = args_strtonum(args, 'x', WINDOW_MINIMUM, WINDOW_MAXIMUM,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'y')) {
sy = args_strtonum(args, 'y', WINDOW_MINIMUM, WINDOW_MAXIMUM,
&cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'L')) {
if (sx >= adjust)
sx -= adjust;
} else if (args_has(args, 'R'))
sx += adjust;
else if (args_has(args, 'U')) {
if (sy >= adjust)
sy -= adjust;
} else if (args_has(args, 'D'))
sy += adjust;
if (args_has(args, 'A'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_LARGEST);
else if (args_has(args, 'a'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_SMALLEST);
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
resize_window(w, sx, sy);
return (CMD_RETURN_NORMAL);
}

View File

@@ -67,7 +67,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
window_pane_reset_mode(wp); window_pane_reset_mode_all(wp);
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);

View File

@@ -99,7 +99,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
free(cwd); free(cwd);
layout_init(w, wp); layout_init(w, wp);
window_pane_reset_mode(wp); window_pane_reset_mode_all(wp);
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);
window_set_active_pane(w, wp); window_set_active_pane(w, wp);

View File

@@ -57,9 +57,10 @@ struct cmd_run_shell_data {
static void static void
cmd_run_shell_print(struct job *job, const char *msg) cmd_run_shell_print(struct job *job, const char *msg)
{ {
struct cmd_run_shell_data *cdata = job->data; struct cmd_run_shell_data *cdata = job_get_data(job);
struct window_pane *wp = NULL; struct window_pane *wp = NULL;
struct cmd_find_state fs; struct cmd_find_state fs;
struct window_mode_entry *wme;
if (cdata->wp_id != -1) if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id); wp = window_pane_find_by_id(cdata->wp_id);
@@ -75,10 +76,10 @@ cmd_run_shell_print(struct job *job, const char *msg)
return; return;
} }
if (window_pane_set_mode(wp, &window_copy_mode, NULL, NULL) == 0) wme = TAILQ_FIRST(&wp->modes);
window_copy_init_for_output(wp); if (wme == NULL || wme->mode != &window_view_mode)
if (wp->mode == &window_copy_mode) window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg); window_copy_add(wp, "%s", msg);
} }
static enum cmd_retval static enum cmd_retval
@@ -102,8 +103,12 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b')) if (!args_has(args, 'b'))
cdata->item = item; cdata->item = item;
job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL, if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_run_shell_callback, cmd_run_shell_free, cdata, 0); cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", cdata->cmd);
free(cdata);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'b')) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -113,22 +118,23 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
static void static void
cmd_run_shell_callback(struct job *job) cmd_run_shell_callback(struct job *job)
{ {
struct cmd_run_shell_data *cdata = job->data; struct cmd_run_shell_data *cdata = job_get_data(job);
char *cmd = cdata->cmd, *msg, *line; struct bufferevent *event = job_get_event(job);
char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size; size_t size;
int retcode; int retcode, status;
do { do {
if ((line = evbuffer_readline(job->event->input)) != NULL) { if ((line = evbuffer_readline(event->input)) != NULL) {
cmd_run_shell_print(job, line); cmd_run_shell_print(job, line);
free(line); free(line);
} }
} while (line != NULL); } while (line != NULL);
size = EVBUFFER_LENGTH(job->event->input); size = EVBUFFER_LENGTH(event->input);
if (size != 0) { if (size != 0) {
line = xmalloc(size + 1); line = xmalloc(size + 1);
memcpy(line, EVBUFFER_DATA(job->event->input), size); memcpy(line, EVBUFFER_DATA(event->input), size);
line[size] = '\0'; line[size] = '\0';
cmd_run_shell_print(job, line); cmd_run_shell_print(job, line);
@@ -136,12 +142,12 @@ cmd_run_shell_callback(struct job *job)
free(line); free(line);
} }
msg = NULL; status = job_get_status(job);
if (WIFEXITED(job->status)) { if (WIFEXITED(status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0) if ((retcode = WEXITSTATUS(status)) != 0)
xasprintf(&msg, "'%s' returned %d", cmd, retcode); xasprintf(&msg, "'%s' returned %d", cmd, retcode);
} else if (WIFSIGNALED(job->status)) { } else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(job->status); retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
} }
if (msg != NULL) if (msg != NULL)

View File

@@ -135,6 +135,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
changed: changed:
free(oldlayout); free(oldlayout);
recalculate_sizes();
server_redraw_window(w); server_redraw_window(w);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -19,6 +19,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "tmux.h" #include "tmux.h"
@@ -54,6 +55,31 @@ const struct cmd_entry cmd_last_pane_entry = {
.exec = cmd_select_pane_exec .exec = cmd_select_pane_exec
}; };
static void
cmd_select_pane_redraw(struct window *w)
{
struct client *c;
/*
* Redraw entire window if it is bigger than the client (the
* offset may change), otherwise just draw borders.
*/
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL)
continue;
if (c->session->curw->window == w && tty_window_bigger(&c->tty))
server_redraw_client(c);
else {
if (c->session->curw->window == w)
c->flags |= CLIENT_REDRAWBORDERS;
if (session_has(c->session, w))
c->flags |= CLIENT_REDRAWSTATUS;
}
}
}
static enum cmd_retval static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
@@ -64,6 +90,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = item->target.s; struct session *s = item->target.s;
struct window_pane *wp = item->target.wp, *lastwp, *markedwp; struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
struct style *sy = &wp->style;
char *pane_title; char *pane_title;
const char *style; const char *style;
@@ -87,8 +114,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
window_redraw_active_switch(w, lastwp); window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp)) { if (window_set_active_pane(w, lastwp)) {
cmd_find_from_winlink(current, wl, 0); cmd_find_from_winlink(current, wl, 0);
server_status_window(w); cmd_select_pane_redraw(w);
server_redraw_window_borders(w);
} }
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -117,17 +143,16 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(self->args, 'P') || args_has(self->args, 'g')) { if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) { if ((style = args_get(args, 'P')) != NULL) {
style = args_get(args, 'P'); style_set(sy, &grid_default_cell);
if (style_parse(&grid_default_cell, &wp->colgc, if (style_parse(sy, &grid_default_cell, style) == -1) {
style) == -1) {
cmdq_error(item, "bad style: %s", style); cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
} }
if (args_has(self->args, 'g')) if (args_has(self->args, 'g'))
cmdq_print(item, "%s", style_tostring(&wp->colgc)); cmdq_print(item, "%s", style_tostring(sy));
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -168,16 +193,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (wp == w->active) if (wp == w->active)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window); server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
cmdq_error(item, "pane not visible");
return (CMD_RETURN_ERROR);
}
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp)) { if (window_set_active_pane(w, wp)) {
cmd_find_from_winlink_pane(current, wl, wp, 0); cmd_find_from_winlink_pane(current, wl, wp, 0);
hooks_insert(s->hooks, item, current, "after-select-pane"); hooks_insert(s->hooks, item, current, "after-select-pane");
server_status_window(w); cmd_select_pane_redraw(w);
server_redraw_window_borders(w);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -58,18 +58,21 @@ const struct cmd_entry cmd_send_prefix_entry = {
static void static void
cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key) cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
{ {
struct window_pane *wp = item->target.wp; struct window_pane *wp = item->target.wp;
struct session *s = item->target.s; struct session *s = item->target.s;
struct key_table *table; struct winlink *wl = item->target.wl;
struct key_binding *bd; struct window_mode_entry *wme;
struct key_table *table;
struct key_binding *bd;
if (wp->mode == NULL || wp->mode->key_table == NULL) { wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode->key_table == NULL) {
if (options_get_number(wp->window->options, "xterm-keys")) if (options_get_number(wp->window->options, "xterm-keys"))
key |= KEYC_XTERM; key |= KEYC_XTERM;
window_pane_key(wp, NULL, s, key, NULL); window_pane_key(wp, NULL, s, wl, key, NULL);
return; return;
} }
table = key_bindings_get_table(wp->mode->key_table(wp), 1); table = key_bindings_get_table(wme->mode->key_table(wme), 1);
bd = key_bindings_get(table, key & ~KEYC_XTERM); bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) { if (bd != NULL) {
@@ -82,17 +85,19 @@ cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key)
static enum cmd_retval static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmd_find_client(item, NULL, 1); struct client *c = cmd_find_client(item, NULL, 1);
struct window_pane *wp = item->target.wp; struct window_pane *wp = item->target.wp;
struct session *s = item->target.s; struct session *s = item->target.s;
struct mouse_event *m = &item->shared->mouse; struct winlink *wl = item->target.wl;
struct utf8_data *ud, *uc; struct mouse_event *m = &item->shared->mouse;
wchar_t wc; struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
int i, literal; struct utf8_data *ud, *uc;
key_code key; wchar_t wc;
u_int np = 1; int i, literal;
char *cause = NULL; key_code key;
u_int np = 1;
char *cause = NULL;
if (args_has(args, 'N')) { if (args_has(args, 'N')) {
np = args_strtonum(args, 'N', 1, UINT_MAX, &cause); np = args_strtonum(args, 'N', 1, UINT_MAX, &cause);
@@ -101,19 +106,23 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'X') || args->argc == 0) if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
wp->modeprefix = np; if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR);
}
wme->prefix = np;
}
} }
if (args_has(args, 'X')) { if (args_has(args, 'X')) {
if (wp->mode == NULL || wp->mode->command == NULL) { if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode"); cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (!m->valid) if (!m->valid)
wp->mode->command(wp, c, s, args, NULL); m = NULL;
else wme->mode->command(wme, c, s, wl, args, m);
wp->mode->command(wp, c, s, args, m);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -123,7 +132,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no mouse target"); cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
window_pane_key(wp, NULL, s, m->key, m); window_pane_key(wp, NULL, s, wl, m->key, m);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -80,6 +81,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
char *name, *argument, *value = NULL, *cause; char *name, *argument, *value = NULL, *cause;
const char *target; const char *target;
int window, idx, already, error, ambiguous; int window, idx, already, error, ambiguous;
struct style *sy;
/* Expand argument. */ /* Expand argument. */
c = cmd_find_client(item, NULL, 1); c = cmd_find_client(item, NULL, 1);
@@ -162,11 +164,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name); parent = options_get(oo, name);
/* Check that array options and indexes match up. */ /* Check that array options and indexes match up. */
if (idx != -1) { if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
if (*name == '@' || options_array_size(parent, NULL) == -1) { cmdq_error(item, "not an array: %s", argument);
cmdq_error(item, "not an array: %s", argument); goto fail;
goto fail;
}
} }
/* With -o, check this option is not already set. */ /* With -o, check this option is not already set. */
@@ -208,7 +208,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
options_set_string(oo, name, append, "%s", value); options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && options_array_size(parent, NULL) == -1) { } else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value); error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0) if (error != 0)
goto fail; goto fail;
@@ -248,6 +248,16 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
tty_keys_build(&loop->tty); tty_keys_build(&loop->tty);
} }
} }
if (strcmp(name, "status-fg") == 0 || strcmp(name, "status-bg") == 0) {
sy = options_get_style(oo, "status-style");
sy->gc.fg = options_get_number(oo, "status-fg");
sy->gc.bg = options_get_number(oo, "status-bg");
}
if (strcmp(name, "status-style") == 0) {
sy = options_get_style(oo, "status-style");
options_set_number(oo, "status-fg", sy->gc.fg);
options_set_number(oo, "status-bg", sy->gc.bg);
}
if (strcmp(name, "status") == 0 || if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0) strcmp(name, "status-interval") == 0)
status_timer_start_all(); status_timer_start_all();
@@ -260,10 +270,10 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
} }
if (strcmp(name, "pane-border-status") == 0) { if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows) RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
} }
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
status_update_saved(s); status_update_cache(s);
/* /*
* Update sizes and redraw. May not always be necessary but do it * Update sizes and redraw. May not always be necessary but do it
@@ -297,7 +307,8 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
int append = args_has(args, 'a'); int append = args_has(args, 'a');
struct options_entry *o; struct options_entry *o;
long long number; long long number;
const char *errstr; const char *errstr, *new;
char *old;
key_code key; key_code key;
oe = options_table_entry(parent); oe = options_table_entry(parent);
@@ -310,7 +321,16 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
switch (oe->type) { switch (oe->type) {
case OPTIONS_TABLE_STRING: case OPTIONS_TABLE_STRING:
old = xstrdup(options_get_string(oo, oe->name));
options_set_string(oo, oe->name, append, "%s", value); options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
cmdq_error(item, "value is invalid: %s", value);
return (-1);
}
free(old);
return (0); return (0);
case OPTIONS_TABLE_NUMBER: case OPTIONS_TABLE_NUMBER:
number = strtonum(value, oe->minimum, oe->maximum, &errstr); number = strtonum(value, oe->minimum, oe->maximum, &errstr);
@@ -333,16 +353,7 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
cmdq_error(item, "bad colour: %s", value); cmdq_error(item, "bad colour: %s", value);
return (-1); return (-1);
} }
o = options_set_number(oo, oe->name, number); options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0);
case OPTIONS_TABLE_ATTRIBUTES:
if ((number = attributes_fromstring(value)) == -1) {
cmdq_error(item, "bad attributes: %s", value);
return (-1);
}
o = options_set_number(oo, oe->name, number);
options_style_update_new(oo, o);
return (0); return (0);
case OPTIONS_TABLE_FLAG: case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value)); return (cmd_set_option_flag(item, oe, oo, value));
@@ -354,7 +365,6 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
cmdq_error(item, "bad style: %s", value); cmdq_error(item, "bad style: %s", value);
return (-1); return (-1);
} }
options_style_update_old(oo, o);
return (0); return (0);
case OPTIONS_TABLE_ARRAY: case OPTIONS_TABLE_ARRAY:
break; break;

View File

@@ -43,7 +43,6 @@ const struct cmd_entry cmd_show_messages_entry = {
}; };
static int cmd_show_messages_terminals(struct cmdq_item *, int); static int cmd_show_messages_terminals(struct cmdq_item *, int);
static int cmd_show_messages_jobs(struct cmdq_item *, int);
static int static int
cmd_show_messages_terminals(struct cmdq_item *item, int blank) cmd_show_messages_terminals(struct cmdq_item *item, int blank)
@@ -66,25 +65,6 @@ cmd_show_messages_terminals(struct cmdq_item *item, int blank)
return (n != 0); return (n != 0);
} }
static int
cmd_show_messages_jobs(struct cmdq_item *item, int blank)
{
struct job *job;
u_int n;
n = 0;
LIST_FOREACH(job, &all_jobs, entry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
n, job->cmd, job->fd, (long)job->pid, job->status);
n++;
}
return (n != 0);
}
static enum cmd_retval static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item) cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{ {
@@ -103,7 +83,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
done = 1; done = 1;
} }
if (args_has(args, 'J')) { if (args_has(args, 'J')) {
cmd_show_messages_jobs(item, blank); job_print_summary(item, blank);
done = 1; done = 1;
} }
if (done) if (done)

View File

@@ -88,20 +88,20 @@ static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item, cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx) struct options_entry *o, int idx)
{ {
const char *name; struct options_array_item *a;
const char *value; const char *name, *value;
char *tmp, *escaped; char *tmp, *escaped;
u_int size, i;
if (idx != -1) { if (idx != -1) {
xasprintf(&tmp, "%s[%d]", options_name(o), idx); xasprintf(&tmp, "%s[%d]", options_name(o), idx);
name = tmp; name = tmp;
} else { } else {
if (options_array_size(o, &size) != -1) { if (options_isarray(o)) {
for (i = 0; i < size; i++) { a = options_array_first(o);
if (options_array_get(o, i) == NULL) while (a != NULL) {
continue; idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, i); cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
} }
return; return;
} }
@@ -164,24 +164,22 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
struct options *oo) struct options *oo)
{ {
struct options_entry *o; struct options_entry *o;
const struct options_table_entry *oe; const struct options_table_entry *oe;
u_int size, idx; struct options_array_item *a;
u_int idx;
o = options_first(oo); o = options_first(oo);
while (o != NULL) { while (o != NULL) {
oe = options_table_entry(o); oe = options_table_entry(o);
if (oe != NULL && oe->style != NULL) { if (!options_isarray(o))
o = options_next(o);
continue;
}
if (options_array_size(o, &size) == -1)
cmd_show_options_print(self, item, o, -1); cmd_show_options_print(self, item, o, -1);
else { else {
for (idx = 0; idx < size; idx++) { a = options_array_first(o);
if (options_array_get(o, idx) == NULL) while (a != NULL) {
continue; idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx); cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
} }
} }
o = options_next(o); o = options_next(o);

View File

@@ -147,7 +147,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
} }
environ_free(env); environ_free(env);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
server_redraw_window(w); server_redraw_window(w);
if (!args_has(args, 'd')) { if (!args_has(args, 'd')) {

View File

@@ -54,6 +54,22 @@ cmd_string_ungetc(size_t *p)
(*p)--; (*p)--;
} }
static int
cmd_string_unicode(wchar_t *wc, const char *s, size_t *p, char ch)
{
int size = (ch == 'u') ? 4 : 8;
u_int tmp;
if (size == 4 && sscanf(s + *p, "%4x", &tmp) != 1)
return (-1);
if (size == 8 && sscanf(s + *p, "%8x", &tmp) != 1)
return (-1);
*p += size;
*wc = (wchar_t)tmp;
return (0);
}
int int
cmd_string_split(const char *s, int *rargc, char ***rargv) cmd_string_split(const char *s, int *rargc, char ***rargv)
{ {
@@ -191,12 +207,11 @@ cmd_string_copy(char **dst, char *src, size_t *len)
static char * static char *
cmd_string_string(const char *s, size_t *p, char endch, int esc) cmd_string_string(const char *s, size_t *p, char endch, int esc)
{ {
int ch; int ch;
char *buf, *t; wchar_t wc;
size_t len; struct utf8_data ud;
char *buf = NULL, *t;
buf = NULL; size_t len = 0;
len = 0;
while ((ch = cmd_string_getc(s, p)) != endch) { while ((ch = cmd_string_getc(s, p)) != endch) {
switch (ch) { switch (ch) {
@@ -220,6 +235,18 @@ cmd_string_string(const char *s, size_t *p, char endch, int esc)
case 't': case 't':
ch = '\t'; ch = '\t';
break; break;
case 'u':
case 'U':
if (cmd_string_unicode(&wc, s, p, ch) != 0)
goto error;
if (utf8_split(wc, &ud) != UTF8_DONE)
goto error;
if (len >= SIZE_MAX - ud.size - 1)
goto error;
buf = xrealloc(buf, len + ud.size);
memcpy(buf + len, ud.data, ud.size);
len += ud.size;
continue;
} }
break; break;
case '$': case '$':

View File

@@ -105,8 +105,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
window_set_active_pane(dst_w, src_wp); window_set_active_pane(dst_w, src_wp);
} else { } else {
tmp_wp = dst_wp; tmp_wp = dst_wp;
if (!window_pane_visible(tmp_wp))
tmp_wp = src_wp;
window_set_active_pane(src_w, tmp_wp); window_set_active_pane(src_w, tmp_wp);
} }
} else { } else {

View File

@@ -113,8 +113,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if (item->client == NULL) if (item->client == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (wl != NULL) { if (wl != NULL) {
if (wp != NULL) server_unzoom_window(wl->window);
if (wp != NULL) {
window_redraw_active_switch(wp->window, wp);
window_set_active_pane(wp->window, wp); window_set_active_pane(wp->window, wp);
}
session_set_current(s, wl); session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s, 0); cmd_find_from_session(&item->shared->current, s, 0);
} }
@@ -128,6 +131,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
c->session = s; c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c); notify_client("client-session-changed", c);
session_update_activity(s, NULL); session_update_activity(s, NULL);

View File

@@ -170,7 +170,7 @@ cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct client *c = item->client; struct client *c = item->client;
struct wait_item *wi; struct wait_item *wi;
if (c == NULL || c->session != NULL) { if (c == NULL) {
cmdq_error(item, "not able to wait"); cmdq_error(item, "not able to wait");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{ {
struct wait_item *wi; struct wait_item *wi;
if (item->client == NULL || item->client->session != NULL) { if (item->client == NULL) {
cmdq_error(item, "not able to lock"); cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

40
cmd.c
View File

@@ -80,6 +80,7 @@ extern const struct cmd_entry cmd_refresh_client_entry;
extern const struct cmd_entry cmd_rename_session_entry; extern const struct cmd_entry cmd_rename_session_entry;
extern const struct cmd_entry cmd_rename_window_entry; extern const struct cmd_entry cmd_rename_window_entry;
extern const struct cmd_entry cmd_resize_pane_entry; extern const struct cmd_entry cmd_resize_pane_entry;
extern const struct cmd_entry cmd_resize_window_entry;
extern const struct cmd_entry cmd_respawn_pane_entry; extern const struct cmd_entry cmd_respawn_pane_entry;
extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_respawn_window_entry;
extern const struct cmd_entry cmd_rotate_window_entry; extern const struct cmd_entry cmd_rotate_window_entry;
@@ -166,6 +167,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_rename_session_entry, &cmd_rename_session_entry,
&cmd_rename_window_entry, &cmd_rename_window_entry,
&cmd_resize_pane_entry, &cmd_resize_pane_entry,
&cmd_resize_window_entry,
&cmd_respawn_pane_entry, &cmd_respawn_pane_entry,
&cmd_respawn_window_entry, &cmd_respawn_window_entry,
&cmd_rotate_window_entry, &cmd_rotate_window_entry,
@@ -316,31 +318,31 @@ cmd_stringify_argv(int argc, char **argv)
static int static int
cmd_try_alias(int *argc, char ***argv) cmd_try_alias(int *argc, char ***argv)
{ {
struct options_entry *o; struct options_entry *o;
int old_argc = *argc, new_argc; struct options_array_item *a;
char **old_argv = *argv, **new_argv; int old_argc = *argc, new_argc, i;
u_int size, idx; char **old_argv = *argv, **new_argv;
int i; size_t wanted;
size_t wanted; const char *s, *cp = NULL;
const char *s, *cp = NULL;
o = options_get_only(global_options, "command-alias"); o = options_get_only(global_options, "command-alias");
if (o == NULL || options_array_size(o, &size) == -1 || size == 0) if (o == NULL)
return (-1); return (-1);
wanted = strlen(old_argv[0]); wanted = strlen(old_argv[0]);
for (idx = 0; idx < size; idx++) {
s = options_array_get(o, idx);
if (s == NULL)
continue;
cp = strchr(s, '='); a = options_array_first(o);
if (cp == NULL || (size_t)(cp - s) != wanted) while (a != NULL) {
continue; s = options_array_item_value(a);
if (strncmp(old_argv[0], s, wanted) == 0) if (s != NULL) {
break; cp = strchr(s, '=');
if (cp != NULL &&
(size_t)(cp - s) == wanted &&
strncmp(old_argv[0], s, wanted) == 0)
break;
}
a = options_array_next(a);
} }
if (idx == size) if (a == NULL)
return (-1); return (-1);
if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0) if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0)

View File

@@ -141,6 +141,8 @@ colour_tostring(int c)
return ("white"); return ("white");
case 8: case 8:
return ("default"); return ("default");
case 9:
return ("terminal");
case 90: case 90:
return ("brightblack"); return ("brightblack");
case 91: case 91:
@@ -158,7 +160,7 @@ colour_tostring(int c)
case 97: case 97:
return ("brightwhite"); return ("brightwhite");
} }
return (NULL); return ("invalid");
} }
/* Convert colour from string. */ /* Convert colour from string. */
@@ -188,6 +190,11 @@ colour_fromstring(const char *s)
return (n | COLOUR_FLAG_256); return (n | COLOUR_FLAG_256);
} }
if (strcasecmp(s, "default") == 0)
return (8);
if (strcasecmp(s, "terminal") == 0)
return (9);
if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0) if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
return (0); return (0);
if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0) if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
@@ -204,8 +211,6 @@ colour_fromstring(const char *s)
return (6); return (6);
if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0) if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0)
return (7); return (7);
if (strcasecmp(s, "default") == 0 || strcmp(s, "8") == 0)
return (8);
if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0) if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0)
return (90); return (90);
if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0) if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0)

View File

@@ -1,6 +1,6 @@
# configure.ac # configure.ac
AC_INIT(tmux, 2.8) AC_INIT([tmux], 2.9)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc) AC_CONFIG_AUX_DIR(etc)
@@ -35,7 +35,7 @@ AC_USE_SYSTEM_EXTENSIONS
test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
# Is this --enable-debug? # Is this --enable-debug?
test "x$VERSION" = xmaster && enable_debug=yes case "x$VERSION" in xnext*) enable_debug=yes;; esac
AC_ARG_ENABLE( AC_ARG_ENABLE(
debug, debug,
AC_HELP_STRING(--enable-debug, enable debug build flags), AC_HELP_STRING(--enable-debug, enable debug build flags),
@@ -478,6 +478,9 @@ if test "x$found_forkpty" = xyes; then
fi fi
AM_CONDITIONAL(NEED_FORKPTY, test "x$found_forkpty" = xno) AM_CONDITIONAL(NEED_FORKPTY, test "x$found_forkpty" = xno)
# Look for kinfo_getfile in libutil.
AC_SEARCH_LIBS(kinfo_getfile, [util util-freebsd])
# Look for a suitable queue.h. # Look for a suitable queue.h.
AC_CHECK_DECL( AC_CHECK_DECL(
TAILQ_CONCAT, TAILQ_CONCAT,

View File

@@ -47,6 +47,8 @@ control_notify_input(struct client *c, struct window_pane *wp,
*/ */
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) { if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
message = evbuffer_new(); message = evbuffer_new();
if (message == NULL)
fatalx("out of memory");
evbuffer_add_printf(message, "%%output %%%u ", wp->id); evbuffer_add_printf(message, "%%output %%%u ", wp->id);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (buf[i] < ' ' || buf[i] == '\\') if (buf[i] < ' ' || buf[i] == '\\')

View File

@@ -174,22 +174,26 @@ environ_unset(struct environ *env, const char *name)
void void
environ_update(struct options *oo, struct environ *src, struct environ *dst) environ_update(struct options *oo, struct environ *src, struct environ *dst)
{ {
struct environ_entry *envent; struct environ_entry *envent;
struct options_entry *o; struct options_entry *o;
u_int size, idx; struct options_array_item *a;
const char *value; const char *value;
o = options_get(oo, "update-environment"); o = options_get(oo, "update-environment");
if (o == NULL || options_array_size(o, &size) == -1) if (o == NULL)
return; return;
for (idx = 0; idx < size; idx++) { a = options_array_first(o);
value = options_array_get(o, idx); while (a != NULL) {
if (value == NULL) value = options_array_item_value(a);
if (value == NULL) {
a = options_array_next(a);
continue; continue;
}
if ((envent = environ_find(src, value)) == NULL) if ((envent = environ_find(src, value)) == NULL)
environ_clear(dst, value); environ_clear(dst, value);
else else
environ_set(dst, envent->name, "%s", envent->value); environ_set(dst, envent->name, "%s", envent->value);
a = options_array_next(a);
} }
} }

View File

@@ -49,11 +49,15 @@ bind F10 selectw -t:19
bind F11 selectw -t:20 bind F11 selectw -t:20
bind F12 selectw -t:21 bind F12 selectw -t:21
# Keys to toggle monitoring activity in a window, and synchronize-panes # A key to toggle between smallest and largest sizes if a window is visible in
# multiple places
bind F set -w window-size
# Keys to toggle monitoring activity in a window and the synchronize-panes option
bind m set monitor-activity bind m set monitor-activity
bind y set synchronize-panes\; display 'synchronize-panes #{?synchronize-panes,on,off}' bind y set synchronize-panes\; display 'synchronize-panes #{?synchronize-panes,on,off}'
# Create a single default session, because a session is created here, tmux # Create a single default session - because a session is created here, tmux
# should be started with "tmux attach" rather than "tmux new" # should be started with "tmux attach" rather than "tmux new"
new -d -s0 -nirssi 'exec irssi' new -d -s0 -nirssi 'exec irssi'
set -t0:0 monitor-activity on set -t0:0 monitor-activity on

892
format-draw.c Normal file
View File

@@ -0,0 +1,892 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF 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 "tmux.h"
/* Format range. */
struct format_range {
u_int index;
struct screen *s;
u_int start;
u_int end;
enum style_range_type type;
u_int argument;
TAILQ_ENTRY(format_range) entry;
};
TAILQ_HEAD(format_ranges, format_range);
/* Does this range match this style? */
static int
format_is_type(struct format_range *fr, struct style *sy)
{
if (fr->type != sy->range_type)
return (0);
if (fr->type == STYLE_RANGE_WINDOW &&
fr->argument != sy->range_argument)
return (0);
return (1);
}
/* Free a range. */
static void
format_free_range(struct format_ranges *frs, struct format_range *fr)
{
TAILQ_REMOVE(frs, fr, entry);
free(fr);
}
/* Fix range positions. */
static void
format_update_ranges(struct format_ranges *frs, struct screen *s, u_int offset,
u_int start, u_int width)
{
struct format_range *fr, *fr1;
if (frs == NULL)
return;
TAILQ_FOREACH_SAFE(fr, frs, entry, fr1) {
if (fr->s != s)
continue;
if (fr->end <= start || fr->start >= start + width) {
format_free_range(frs, fr);
continue;
}
if (fr->start < start)
fr->start = start;
if (fr->end > start + width)
fr->end = start + width;
if (fr->start == fr->end) {
format_free_range(frs, fr);
continue;
}
fr->start -= start;
fr->end -= start;
fr->start += offset;
fr->end += offset;
}
}
/* Draw a part of the format. */
static void
format_draw_put(struct screen_write_ctx *octx, u_int ocx, u_int ocy,
struct screen *s, struct format_ranges *frs, u_int offset, u_int start,
u_int width)
{
/*
* The offset is how far from the cursor on the target screen; start
* and width how much to copy from the source screen.
*/
screen_write_cursormove(octx, ocx + offset, ocy, 0);
screen_write_fast_copy(octx, s, start, 0, width, 1);
format_update_ranges(frs, s, offset, start, width);
}
/* Draw list part of format. */
static void
format_draw_put_list(struct screen_write_ctx *octx,
u_int ocx, u_int ocy, u_int offset, u_int width, struct screen *list,
struct screen *list_left, struct screen *list_right, int focus_start,
int focus_end, struct format_ranges *frs)
{
u_int start, focus_centre;
/* If there is enough space for the list, draw it entirely. */
if (width >= list->cx) {
format_draw_put(octx, ocx, ocy, list, frs, offset, 0, width);
return;
}
/* The list needs to be trimmed. Try to keep the focus visible. */
focus_centre = focus_start + (focus_end - focus_start) / 2;
if (focus_centre < width / 2)
start = 0;
else
start = focus_centre - width / 2;
if (start + width > list->cx)
start = list->cx - width;
/* Draw <> markers at either side if needed. */
if (start != 0 && width > list_left->cx) {
screen_write_cursormove(octx, ocx + offset, ocy, 0);
screen_write_fast_copy(octx, list_left, 0, 0, list_left->cx, 1);
offset += list_left->cx;
start += list_left->cx;
width -= list_left->cx;
}
if (start + width < list->cx && width > list_right->cx) {
screen_write_cursormove(octx, ocx + offset + width - 1, ocy, 0);
screen_write_fast_copy(octx, list_right, 0, 0, list_right->cx,
1);
width -= list_right->cx;
}
/* Draw the list screen itself. */
format_draw_put(octx, ocx, ocy, list, frs, offset, start, width);
}
/* Draw format with no list. */
static void
format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
/*
* Try to keep as much of the left and right as possible at the expense
* of the centre.
*/
while (width_left + width_centre + width_right > available) {
if (width_centre > 0)
width_centre--;
else if (width_right > 0)
width_right--;
else
width_left--;
}
/* Write left. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/*
* Write centre halfway between
* width_left
* and
* available - width_right.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
width_left
+ ((available - width_right) - width_left) / 2
- width_centre / 2,
centre->cx / 2 - width_centre / 2,
width_centre);
}
/* Draw format with list on the left. */
static void
format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first the centre, then the list, then the right, then after the
* list, then the left.
*/
while (width_left +
width_centre +
width_right +
width_list +
width_after > available) {
if (width_centre > 0)
width_centre--;
else if (width_list > 0)
width_list--;
else if (width_right > 0)
width_right--;
else if (width_after > 0)
width_after--;
else
width_left--;
}
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, left);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
return;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/* Write after at width_left + width_list. */
format_draw_put(octx, ocx, ocy, after, frs,
width_left + width_list,
0,
width_after);
/*
* Write centre halfway between
* width_left + width_list + width_after
* and
* available - width_right.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
(width_left + width_list + width_after)
+ ((available - width_right)
- (width_left + width_list + width_after)) / 2
- width_centre / 2,
centre->cx / 2 - width_centre / 2,
width_centre);
/*
* The list now goes from
* width_left
* to
* width_left + width_list.
* If there is no focus given, keep the left in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = 0;
format_draw_put_list(octx, ocx, ocy, width_left, width_list, list,
list_left, list_right, focus_start, focus_end, frs);
}
/* Draw format with list in the centre. */
static void
format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after, middle;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first the list, then after the list, then the centre, then the
* right, then the left.
*/
while (width_left +
width_centre +
width_right +
width_list +
width_after > available) {
if (width_list > 0)
width_list--;
else if (width_after > 0)
width_after--;
else if (width_centre > 0)
width_centre--;
else if (width_right > 0)
width_right--;
else
width_left--;
}
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, centre);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
return;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write after at available - width_after. */
format_draw_put(octx, ocx, ocy, after, frs,
available - width_after,
after->cx - width_after,
width_after);
/* Write right at available - width_right. */
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right,
right->cx - width_right,
width_right);
/*
* All three centre sections are offset from the middle of the
* available space.
*/
middle = (width_left + ((available - width_right) - width_left) / 2);
/*
* Write centre at
* middle - width_list / 2 - width_centre.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
middle - width_list / 2 - width_centre,
0,
width_centre);
/*
* Write after at
* middle + width_list / 2 - width_centre.
*/
format_draw_put(octx, ocx, ocy, after, frs,
middle + width_list / 2,
0,
width_after);
/*
* The list now goes from
* middle - width_list / 2
* to
* middle + width_list / 2
* If there is no focus given, keep the centre in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = list->cx / 2;
format_draw_put_list(octx, ocx, ocy, middle - width_list / 2,
width_list, list, list_left, list_right, focus_start, focus_end,
frs);
}
/* Draw format with list on the right. */
static void
format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
struct screen *list, struct screen *list_left, struct screen *list_right,
struct screen *after, int focus_start, int focus_end,
struct format_ranges *frs)
{
u_int width_left, width_centre, width_right;
u_int width_list, width_after;
struct screen_write_ctx ctx;
width_left = left->cx;
width_centre = centre->cx;
width_right = right->cx;
width_list = list->cx;
width_after = after->cx;
/*
* Trim first the centre, then the list, then the right, then
* after the list, then the left.
*/
while (width_left +
width_centre +
width_right +
width_list +
width_after > available) {
if (width_centre > 0)
width_centre--;
else if (width_list > 0)
width_list--;
else if (width_right > 0)
width_right--;
else if (width_after > 0)
width_after--;
else
width_left--;
}
/* If there is no list left, pass off to the no list function. */
if (width_list == 0) {
screen_write_start(&ctx, NULL, right);
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
screen_write_stop(&ctx);
format_draw_none(octx, available, ocx, ocy, left, centre,
right, frs);
return;
}
/* Write left at 0. */
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
/* Write after at available - width_after. */
format_draw_put(octx, ocx, ocy, after, frs,
available - width_after,
after->cx - width_after,
width_after);
/*
* Write right at
* available - width_right - width_list - width_after.
*/
format_draw_put(octx, ocx, ocy, right, frs,
available - width_right - width_list - width_after,
0,
width_right);
/*
* Write centre halfway between
* width_left
* and
* available - width_right - width_list - width_after.
*/
format_draw_put(octx, ocx, ocy, centre, frs,
width_left
+ ((available - width_right - width_list - width_after)
- width_left) / 2
- width_centre / 2,
centre->cx / 2 - width_centre / 2,
width_centre);
/*
* The list now goes from
* available - width_list - width_after
* to
* available - width_after
* If there is no focus given, keep the right in focus.
*/
if (focus_start == -1 || focus_end == -1)
focus_start = focus_end = 0;
format_draw_put_list(octx, ocx, ocy, available - width_list -
width_after, width_list, list, list_left, list_right, focus_start,
focus_end, frs);
}
/* Draw a format to a screen. */
void
format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
u_int available, const char *expanded, struct style_ranges *srs)
{
enum { LEFT,
CENTRE,
RIGHT,
LIST,
LIST_LEFT,
LIST_RIGHT,
AFTER,
TOTAL } current = LEFT, last = LEFT;
const char *names[] = { "LEFT",
"CENTRE",
"RIGHT",
"LIST",
"LIST_LEFT",
"LIST_RIGHT",
"AFTER" };
size_t size = strlen(expanded);
struct screen *os = octx->s, s[TOTAL];
struct screen_write_ctx ctx[TOTAL];
u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
int focus_start = -1, focus_end = -1;
int list_state = -1;
enum style_align list_align = STYLE_ALIGN_DEFAULT;
struct style sy;
struct utf8_data *ud = &sy.gc.data;
const char *cp, *end;
enum utf8_state more;
char *tmp;
struct format_range *fr = NULL, *fr1;
struct format_ranges frs;
struct style_range *sr;
style_set(&sy, base);
TAILQ_INIT(&frs);
log_debug("%s: %s", __func__, expanded);
/*
* We build three screens for left, right, centre alignment, one for
* the list, one for anything after the list and two for the list left
* and right markers.
*/
for (i = 0; i < TOTAL; i++) {
screen_init(&s[i], size, 1, 0);
screen_write_start(&ctx[i], NULL, &s[i]);
screen_write_clearendofline(&ctx[i], base->bg);
width[i] = 0;
}
/*
* Walk the string and add to the corresponding screens,
* parsing styles as we go.
*/
cp = expanded;
while (*cp != '\0') {
if (cp[0] != '#' || cp[1] != '[') {
/* See if this is a UTF-8 character. */
if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(ud, *cp);
if (more != UTF8_DONE)
cp -= ud->have;
}
/* Not a UTF-8 character - ASCII or not valid. */
if (more != UTF8_DONE) {
if (*cp < 0x20 || *cp > 0x7e) {
/* Ignore nonprintable characters. */
cp++;
continue;
}
utf8_set(ud, *cp);
cp++;
}
/* Draw the cell to th current screen. */
screen_write_cell(&ctx[current], &sy.gc);
width[current] += ud->width;
continue;
}
/* This is a style. Work out where the end is and parse it. */
end = format_skip(cp + 2, "]");
if (end == NULL) {
log_debug("%s: no terminating ] at '%s'", __func__,
cp + 2);
TAILQ_FOREACH_SAFE(fr, &frs, entry, fr1)
format_free_range(&frs, fr);
goto out;
}
tmp = xstrndup(cp + 2, end - (cp + 2));
if (style_parse(&sy, base, tmp) != 0) {
log_debug("%s: invalid style '%s'", __func__, tmp);
free(tmp);
cp = end + 1;
continue;
}
log_debug("%s: style '%s' -> '%s'", __func__, tmp,
style_tostring(&sy));
free(tmp);
/* Check the list state. */
switch (sy.list) {
case STYLE_LIST_ON:
/*
* Entering the list, exiting a marker, or exiting the
* focus.
*/
if (list_state != 0) {
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
list_state = 0;
list_align = sy.align;
}
/* End the focus if started. */
if (focus_start != -1 && focus_end == -1)
focus_end = s[LIST].cx;
current = LIST;
break;
case STYLE_LIST_FOCUS:
/* Entering the focus. */
if (list_state != 0) /* not inside the list */
break;
if (focus_start == -1) /* focus already started */
focus_start = s[LIST].cx;
break;
case STYLE_LIST_OFF:
/* Exiting or outside the list. */
if (list_state == 0) {
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
if (focus_start != -1 && focus_end == -1)
focus_end = s[LIST].cx;
map[list_align] = AFTER;
if (list_align == STYLE_ALIGN_LEFT)
map[STYLE_ALIGN_DEFAULT] = AFTER;
list_state = 1;
}
current = map[sy.align];
break;
case STYLE_LIST_LEFT_MARKER:
/* Entering left marker. */
if (list_state != 0) /* not inside the list */
break;
if (s[LIST_LEFT].cx != 0) /* already have marker */
break;
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
if (focus_start != -1 && focus_end == -1)
focus_start = focus_end = -1;
current = LIST_LEFT;
break;
case STYLE_LIST_RIGHT_MARKER:
/* Entering right marker. */
if (list_state != 0) /* not inside the list */
break;
if (s[LIST_RIGHT].cx != 0) /* already have marker */
break;
if (fr != NULL) { /* abort any region */
free(fr);
fr = NULL;
}
if (focus_start != -1 && focus_end == -1)
focus_start = focus_end = -1;
current = LIST_RIGHT;
break;
}
if (current != last) {
log_debug("%s: change %s -> %s", __func__,
names[last], names[current]);
last = current;
}
/*
* Check if the range style has changed and if so end the
* current range and start a new one if needed.
*/
if (srs != NULL) {
if (fr != NULL && !format_is_type(fr, &sy)) {
if (s[current].cx != fr->start) {
fr->end = s[current].cx + 1;
TAILQ_INSERT_TAIL(&frs, fr, entry);
} else
free(fr);
fr = NULL;
}
if (fr == NULL && sy.range_type != STYLE_RANGE_NONE) {
fr = xcalloc(1, sizeof *fr);
fr->index = current;
fr->s = &s[current];
fr->start = s[current].cx;
fr->type = sy.range_type;
fr->argument = sy.range_argument;
}
}
cp = end + 1;
}
free(fr);
for (i = 0; i < TOTAL; i++) {
screen_write_stop(&ctx[i]);
log_debug("%s: width %s is %u", __func__, names[i], width[i]);
}
if (focus_start != -1 && focus_end != -1)
log_debug("%s: focus %d-%d", __func__, focus_start, focus_end);
TAILQ_FOREACH(fr, &frs, entry) {
log_debug("%s: range %d|%u is %s %u-%u", __func__, fr->type,
fr->argument, names[fr->index], fr->start, fr->end);
}
/*
* Draw the screens. How they are arranged depends on where the list
* appearsq.
*/
switch (list_align) {
case STYLE_ALIGN_DEFAULT:
/* No list. */
format_draw_none(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &frs);
break;
case STYLE_ALIGN_LEFT:
/* List is part of the left. */
format_draw_left(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_CENTRE:
/* List is part of the centre. */
format_draw_centre(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
break;
case STYLE_ALIGN_RIGHT:
/* List is part of the right. */
format_draw_right(octx, available, ocx, ocy, &s[LEFT],
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
break;
}
/* Create ranges to return. */
TAILQ_FOREACH_SAFE(fr, &frs, entry, fr1) {
sr = xcalloc(1, sizeof *sr);
sr->type = fr->type;
sr->argument = fr->argument;
sr->start = fr->start;
sr->end = fr->end;
TAILQ_INSERT_TAIL(srs, sr, entry);
log_debug("%s: range %d|%u at %u-%u", __func__, sr->type,
sr->argument, sr->start, sr->end);
format_free_range(&frs, fr);
}
out:
/* Free the screens. */
for (i = 0; i < TOTAL; i++)
screen_free(&s[i]);
/* Restore the original cursor position. */
screen_write_cursormove(octx, ocx, ocy, 0);
}
/* Get width, taking #[] into account. */
u_int
format_width(const char *expanded)
{
const char *cp, *end;
u_int width = 0;
struct utf8_data ud;
enum utf8_state more;
cp = expanded;
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
end = format_skip(cp + 2, "]");
if (end == NULL)
return 0;
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(&ud, *cp);
if (more == UTF8_DONE)
width += ud.width;
else
cp -= ud.have;
} else if (*cp > 0x1f && *cp < 0x7f) {
width++;
cp++;
}
}
return (width);
}
/* Trim on the left, taking #[] into account. */
char *
format_trim_left(const char *expanded, u_int limit)
{
char *copy, *out;
const char *cp = expanded, *end;
u_int width = 0;
struct utf8_data ud;
enum utf8_state more;
out = copy = xmalloc(strlen(expanded) + 1);
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
end = format_skip(cp + 2, "]");
if (end == NULL)
break;
memcpy(out, cp, end + 1 - cp);
out += (end + 1 - cp);
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(&ud, *cp);
if (more == UTF8_DONE) {
if (width + ud.width <= limit) {
memcpy(out, ud.data, ud.size);
out += ud.size;
}
width += ud.width;
} else
cp -= ud.have;
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width + 1 <= limit)
*out++ = *cp;
width++;
cp++;
} else
cp++;
}
*out = '\0';
return (copy);
}
/* Trim on the right, taking #[] into account. */
char *
format_trim_right(const char *expanded, u_int limit)
{
char *copy, *out;
const char *cp = expanded, *end;
u_int width = 0, total_width, skip;
struct utf8_data ud;
enum utf8_state more;
total_width = format_width(expanded);
if (total_width <= limit)
return (xstrdup(expanded));
skip = total_width - limit;
out = copy = xmalloc(strlen(expanded) + 1);
while (*cp != '\0') {
if (cp[0] == '#' && cp[1] == '[') {
end = format_skip(cp + 2, "]");
if (end == NULL)
break;
memcpy(out, cp, end + 1 - cp);
out += (end + 1 - cp);
cp = end + 1;
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)
more = utf8_append(&ud, *cp);
if (more == UTF8_DONE) {
if (width >= skip) {
memcpy(out, ud.data, ud.size);
out += ud.size;
}
width += ud.width;
} else
cp -= ud.have;
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width >= skip)
*out++ = *cp;
width++;
cp++;
} else
cp++;
}
*out = '\0';
return (copy);
}

1038
format.c

File diff suppressed because it is too large Load Diff

219
grid.c
View File

@@ -39,8 +39,13 @@
const struct grid_cell grid_default_cell = { const struct grid_cell grid_default_cell = {
0, 0, 8, 8, { { ' ' }, 0, 1, 1 } 0, 0, 8, 8, { { ' ' }, 0, 1, 1 }
}; };
static const struct grid_cell_entry grid_default_entry = {
0, { .data = { 0, 8, 8, ' ' } } /* Cleared grid cell data. */
const struct grid_cell grid_cleared_cell = {
GRID_FLAG_CLEARED, 0, 8, 8, { { ' ' }, 0, 1, 1 }
};
static const struct grid_cell_entry grid_cleared_entry = {
GRID_FLAG_CLEARED, { .data = { 0, 8, 8, ' ' } }
}; };
static void grid_empty_line(struct grid *, u_int, u_int); static void grid_empty_line(struct grid *, u_int, u_int);
@@ -50,7 +55,7 @@ static void
grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc, grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
u_char c) u_char c)
{ {
gce->flags = gc->flags; gce->flags = (gc->flags & ~GRID_FLAG_CLEARED);
gce->data.fg = gc->fg & 0xff; gce->data.fg = gc->fg & 0xff;
if (gc->fg & COLOUR_FLAG_256) if (gc->fg & COLOUR_FLAG_256)
@@ -64,7 +69,7 @@ grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
gce->data.data = c; gce->data.data = c;
} }
/* Check if a cell should be extended. */ /* Check if a cell should be an extended cell. */
static int static int
grid_need_extended_cell(const struct grid_cell_entry *gce, grid_need_extended_cell(const struct grid_cell_entry *gce,
const struct grid_cell *gc) const struct grid_cell *gc)
@@ -80,6 +85,40 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
return (0); return (0);
} }
/* Get an extended cell. */
static void
grid_get_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
int flags)
{
u_int at = gl->extdsize + 1;
gl->extddata = xreallocarray(gl->extddata, at, sizeof *gl->extddata);
gl->extdsize = at;
gce->offset = at - 1;
gce->flags = (flags | GRID_FLAG_EXTENDED);
}
/* Set cell as extended. */
static struct grid_cell *
grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
const struct grid_cell *gc)
{
struct grid_cell *gcp;
int flags = (gc->flags & ~GRID_FLAG_CLEARED);
if (~gce->flags & GRID_FLAG_EXTENDED)
grid_get_extended_cell(gl, gce, flags);
else if (gce->offset >= gl->extdsize)
fatalx("offset too big");
gl->flags |= GRID_LINE_EXTENDED;
gcp = &gl->extddata[gce->offset];
memcpy(gcp, gc, sizeof *gcp);
gcp->flags = flags;
return (gcp);
}
/* Free up unused extended cells. */ /* Free up unused extended cells. */
static void static void
grid_compact_line(struct grid_line *gl) grid_compact_line(struct grid_line *gl)
@@ -122,29 +161,6 @@ grid_compact_line(struct grid_line *gl)
gl->extdsize = new_extdsize; gl->extdsize = new_extdsize;
} }
/* Set cell as extended. */
static struct grid_cell *
grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
const struct grid_cell *gc)
{
struct grid_cell *gcp;
gl->flags |= GRID_LINE_EXTENDED;
if (~gce->flags & GRID_FLAG_EXTENDED) {
gl->extddata = xreallocarray(gl->extddata, gl->extdsize + 1,
sizeof *gl->extddata);
gce->offset = gl->extdsize++;
gce->flags = gc->flags | GRID_FLAG_EXTENDED;
}
if (gce->offset >= gl->extdsize)
fatalx("offset too big");
gcp = &gl->extddata[gce->offset];
memcpy(gcp, gc, sizeof *gcp);
return (gcp);
}
/* Get line data. */ /* Get line data. */
struct grid_line * struct grid_line *
grid_get_line(struct grid *gd, u_int line) grid_get_line(struct grid *gd, u_int line)
@@ -167,9 +183,13 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
struct grid_cell_entry *gce = &gl->celldata[px]; struct grid_cell_entry *gce = &gl->celldata[px];
struct grid_cell *gc; struct grid_cell *gc;
memcpy(gce, &grid_default_entry, sizeof *gce); memcpy(gce, &grid_cleared_entry, sizeof *gce);
if (bg & COLOUR_FLAG_RGB) { if (bg & COLOUR_FLAG_RGB) {
gc = grid_extended_cell(gl, gce, &grid_default_cell); grid_get_extended_cell(gl, gce, gce->flags);
gl->flags |= GRID_LINE_EXTENDED;
gc = &gl->extddata[gce->offset];
memcpy(gc, &grid_cleared_cell, sizeof *gc);
gc->bg = bg; gc->bg = bg;
} else { } else {
if (bg & COLOUR_FLAG_256) if (bg & COLOUR_FLAG_256)
@@ -418,7 +438,7 @@ static void
grid_empty_line(struct grid *gd, u_int py, u_int bg) grid_empty_line(struct grid *gd, u_int py, u_int bg)
{ {
memset(&gd->linedata[py], 0, sizeof gd->linedata[py]); memset(&gd->linedata[py], 0, sizeof gd->linedata[py]);
if (bg != 8) if (!COLOUR_DEFAULT(bg))
grid_expand_line(gd, py, gd->sx, bg); grid_expand_line(gd, py, gd->sx, bg);
} }
@@ -461,11 +481,10 @@ void
grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc) grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
{ {
if (grid_check_y(gd, __func__, py) != 0 || if (grid_check_y(gd, __func__, py) != 0 ||
px >= gd->linedata[py].cellsize) { px >= gd->linedata[py].cellsize)
memcpy(gc, &grid_default_cell, sizeof *gc); memcpy(gc, &grid_default_cell, sizeof *gc);
return; else
} grid_get_cell1(&gd->linedata[py], px, gc);
return (grid_get_cell1(&gd->linedata[py], px, gc));
} }
/* Set cell at relative position. */ /* Set cell at relative position. */
@@ -524,7 +543,8 @@ grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
void void
grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg) grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
{ {
u_int xx, yy; struct grid_line *gl;
u_int xx, yy;
if (nx == 0 || ny == 0) if (nx == 0 || ny == 0)
return; return;
@@ -540,12 +560,13 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
return; return;
for (yy = py; yy < py + ny; yy++) { for (yy = py; yy < py + ny; yy++) {
if (px + nx >= gd->sx && px < gd->linedata[yy].cellused) gl = &gd->linedata[yy];
gd->linedata[yy].cellused = px; if (px + nx >= gd->sx && px < gl->cellused)
if (px > gd->linedata[yy].cellsize && bg == 8) gl->cellused = px;
if (px > gl->cellsize && COLOUR_DEFAULT(bg))
continue; continue;
if (px + nx >= gd->linedata[yy].cellsize && bg == 8) { if (px + nx >= gl->cellsize && COLOUR_DEFAULT(bg)) {
gd->linedata[yy].cellsize = px; gl->cellsize = px;
continue; continue;
} }
grid_expand_line(gd, yy, px + nx, 8); /* default bg first */ grid_expand_line(gd, yy, px + nx, 8); /* default bg first */
@@ -764,7 +785,11 @@ grid_string_cells_code(const struct grid_cell *lastgc,
{ GRID_ATTR_BLINK, 5 }, { GRID_ATTR_BLINK, 5 },
{ GRID_ATTR_REVERSE, 7 }, { GRID_ATTR_REVERSE, 7 },
{ GRID_ATTR_HIDDEN, 8 }, { GRID_ATTR_HIDDEN, 8 },
{ GRID_ATTR_STRIKETHROUGH, 9 } { GRID_ATTR_STRIKETHROUGH, 9 },
{ GRID_ATTR_UNDERSCORE_2, 42 },
{ GRID_ATTR_UNDERSCORE_3, 43 },
{ GRID_ATTR_UNDERSCORE_4, 44 },
{ GRID_ATTR_UNDERSCORE_5, 45 },
}; };
n = 0; n = 0;
@@ -790,11 +815,15 @@ grid_string_cells_code(const struct grid_cell *lastgc,
else else
strlcat(buf, "\033[", len); strlcat(buf, "\033[", len);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (i + 1 < n) if (s[i] < 10)
xsnprintf(tmp, sizeof tmp, "%d;", s[i]);
else
xsnprintf(tmp, sizeof tmp, "%d", s[i]); xsnprintf(tmp, sizeof tmp, "%d", s[i]);
else {
xsnprintf(tmp, sizeof tmp, "%d:%d", s[i] / 10,
s[i] % 10);
}
strlcat(buf, tmp, len); strlcat(buf, tmp, len);
if (i + 1 < n)
strlcat(buf, ";", len);
} }
strlcat(buf, "m", len); strlcat(buf, "m", len);
} }
@@ -1001,7 +1030,7 @@ grid_reflow_move(struct grid *gd, struct grid_line *from)
/* Join line below onto this one. */ /* Join line below onto this one. */
static void static void
grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
u_int width, u_int *cy, int already) u_int width, int already)
{ {
struct grid_line *gl, *from = NULL; struct grid_line *gl, *from = NULL;
struct grid_cell gc; struct grid_cell gc;
@@ -1099,11 +1128,7 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
grid_reflow_dead(&gd->linedata[i]); grid_reflow_dead(&gd->linedata[i]);
} }
/* Adjust cursor and scroll positions. */ /* Adjust scroll position. */
if (*cy > to + lines)
*cy -= lines;
else if (*cy > to)
*cy = to;
if (gd->hscrolled > to + lines) if (gd->hscrolled > to + lines)
gd->hscrolled -= lines; gd->hscrolled -= lines;
else if (gd->hscrolled > to) else if (gd->hscrolled > to)
@@ -1113,7 +1138,7 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
/* Split this line into several new ones */ /* Split this line into several new ones */
static void static void
grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy, grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
u_int at, u_int *cy) u_int at)
{ {
struct grid_line *gl = &gd->linedata[yy], *first; struct grid_line *gl = &gd->linedata[yy], *first;
struct grid_cell gc; struct grid_cell gc;
@@ -1166,9 +1191,7 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
memcpy(first, gl, sizeof *first); memcpy(first, gl, sizeof *first);
grid_reflow_dead(gl); grid_reflow_dead(gl);
/* Adjust the cursor and scroll positions. */ /* Adjust the scroll position. */
if (yy <= *cy)
(*cy) += lines - 1;
if (yy <= gd->hscrolled) if (yy <= gd->hscrolled)
gd->hscrolled += lines - 1; gd->hscrolled += lines - 1;
@@ -1177,24 +1200,17 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
* in the last new line, try to join with the next lines. * in the last new line, try to join with the next lines.
*/ */
if (width < sx && (flags & GRID_LINE_WRAPPED)) if (width < sx && (flags & GRID_LINE_WRAPPED))
grid_reflow_join(target, gd, sx, yy, width, cy, 1); grid_reflow_join(target, gd, sx, yy, width, 1);
} }
/* Reflow lines on grid to new width. */ /* Reflow lines on grid to new width. */
void void
grid_reflow(struct grid *gd, u_int sx, u_int *cursor) grid_reflow(struct grid *gd, u_int sx)
{ {
struct grid *target; struct grid *target;
struct grid_line *gl; struct grid_line *gl;
struct grid_cell gc; struct grid_cell gc;
u_int yy, cy, width, i, at, first; u_int yy, width, i, at, first;
struct timeval start, tv;
gettimeofday(&start, NULL);
log_debug("%s: %u lines, new width %u", __func__, gd->hsize + gd->sy,
sx);
cy = gd->hsize + (*cursor);
/* /*
* Create a destination grid. This is just used as a container for the * Create a destination grid. This is just used as a container for the
@@ -1248,7 +1264,7 @@ grid_reflow(struct grid *gd, u_int sx, u_int *cursor)
* it was previously wrapped. * it was previously wrapped.
*/ */
if (width > sx) { if (width > sx) {
grid_reflow_split(target, gd, sx, yy, at, &cy); grid_reflow_split(target, gd, sx, yy, at);
continue; continue;
} }
@@ -1257,7 +1273,7 @@ grid_reflow(struct grid *gd, u_int sx, u_int *cursor)
* of the next line. * of the next line.
*/ */
if (gl->flags & GRID_LINE_WRAPPED) if (gl->flags & GRID_LINE_WRAPPED)
grid_reflow_join(target, gd, sx, yy, width, &cy, 0); grid_reflow_join(target, gd, sx, yy, width, 0);
else else
grid_reflow_move(target, gl); grid_reflow_move(target, gl);
} }
@@ -1268,23 +1284,68 @@ grid_reflow(struct grid *gd, u_int sx, u_int *cursor)
if (target->sy < gd->sy) if (target->sy < gd->sy)
grid_reflow_add(target, gd->sy - target->sy); grid_reflow_add(target, gd->sy - target->sy);
gd->hsize = target->sy - gd->sy; gd->hsize = target->sy - gd->sy;
if (gd->hscrolled > gd->hsize)
gd->hscrolled = gd->hsize;
free(gd->linedata); free(gd->linedata);
gd->linedata = target->linedata; gd->linedata = target->linedata;
free(target); free(target);
}
/* Convert to position based on wrapped lines. */
void
grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
{
u_int ax = 0, ay = 0, yy;
for (yy = 0; yy < py; yy++) {
if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
ax += gd->linedata[yy].cellused;
else {
ax = 0;
ay++;
}
}
if (px >= gd->linedata[yy].cellused)
ax = UINT_MAX;
else
ax += px;
*wx = ax;
*wy = ay;
}
/* Convert position based on wrapped lines back. */
void
grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
{
u_int yy, ax = 0, ay = 0;
for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
if (ay == wy)
break;
if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
ax += gd->linedata[yy].cellused;
else {
ax = 0;
ay++;
}
}
/* /*
* Update scrolled and cursor positions. * yy is now 0 on the unwrapped line which contains wx. Walk forwards
* until we find the end or the line now containing wx.
*/ */
if (gd->hscrolled > gd->hsize) if (wx == UINT_MAX) {
gd->hscrolled = gd->hsize; while (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
if (cy < gd->hsize) yy++;
*cursor = 0; wx = gd->linedata[yy].cellused;
else } else {
*cursor = cy - gd->hsize; while (gd->linedata[yy].flags & GRID_LINE_WRAPPED) {
if (wx < gd->linedata[yy].cellused)
gettimeofday(&tv, NULL); break;
timersub(&tv, &start, &tv); wx -= gd->linedata[yy].cellused;
log_debug("%s: now %u lines (in %llu.%06u seconds)", __func__, yy++;
gd->hsize + gd->sy, (unsigned long long)tv.tv_sec, }
(u_int)tv.tv_usec); }
*px = wx;
*py = yy;
} }

View File

@@ -247,10 +247,10 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
if ((mode & ALL_MOUSE_MODES) == 0) if ((mode & ALL_MOUSE_MODES) == 0)
return; return;
if (!window_pane_visible(wp))
return;
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0) if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
return; return;
if (!window_pane_visible(wp))
return;
/* If this pane is not in button or all mode, discard motion events. */ /* If this pane is not in button or all mode, discard motion events. */
if (MOUSE_DRAG(m->b) && if (MOUSE_DRAG(m->b) &&

371
input.c
View File

@@ -81,6 +81,7 @@ struct input_ctx {
struct input_cell old_cell; struct input_cell old_cell;
u_int old_cx; u_int old_cx;
u_int old_cy; u_int old_cy;
int old_mode;
u_char interm_buf[4]; u_char interm_buf[4];
size_t interm_len; size_t interm_len;
@@ -93,6 +94,10 @@ struct input_ctx {
u_char *input_buf; u_char *input_buf;
size_t input_len; size_t input_len;
size_t input_space; size_t input_space;
enum {
INPUT_END_ST,
INPUT_END_BEL
} input_end;
struct input_param param_list[24]; struct input_param param_list[24];
u_int param_list_len; u_int param_list_len;
@@ -126,11 +131,11 @@ static void input_set_state(struct window_pane *,
const struct input_transition *); const struct input_transition *);
static void input_reset_cell(struct input_ctx *); static void input_reset_cell(struct input_ctx *);
static void input_osc_4(struct window_pane *, const char *); static void input_osc_4(struct input_ctx *, const char *);
static void input_osc_10(struct window_pane *, const char *); static void input_osc_10(struct input_ctx *, const char *);
static void input_osc_11(struct window_pane *, const char *); static void input_osc_11(struct input_ctx *, const char *);
static void input_osc_52(struct window_pane *, const char *); static void input_osc_52(struct input_ctx *, const char *);
static void input_osc_104(struct window_pane *, const char *); static void input_osc_104(struct input_ctx *, const char *);
/* Transition entry/exit handlers. */ /* Transition entry/exit handlers. */
static void input_clear(struct input_ctx *); static void input_clear(struct input_ctx *);
@@ -161,6 +166,7 @@ static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
static void input_csi_dispatch_sgr(struct input_ctx *); static void input_csi_dispatch_sgr(struct input_ctx *);
static int input_dcs_dispatch(struct input_ctx *); static int input_dcs_dispatch(struct input_ctx *);
static int input_top_bit_set(struct input_ctx *); static int input_top_bit_set(struct input_ctx *);
static int input_end_bel(struct input_ctx *);
/* Command table comparison function. */ /* Command table comparison function. */
static int input_table_compare(const void *, const void *); static int input_table_compare(const void *, const void *);
@@ -266,6 +272,7 @@ static const struct input_table_entry input_csi_table[] = {
{ 'S', "", INPUT_CSI_SU }, { 'S', "", INPUT_CSI_SU },
{ 'X', "", INPUT_CSI_ECH }, { 'X', "", INPUT_CSI_ECH },
{ 'Z', "", INPUT_CSI_CBT }, { 'Z', "", INPUT_CSI_CBT },
{ '`', "", INPUT_CSI_HPA },
{ 'b', "", INPUT_CSI_REP }, { 'b', "", INPUT_CSI_REP },
{ 'c', "", INPUT_CSI_DA }, { 'c', "", INPUT_CSI_DA },
{ 'c', ">", INPUT_CSI_DA_TWO }, { 'c', ">", INPUT_CSI_DA_TWO },
@@ -487,7 +494,7 @@ static const struct input_transition input_state_esc_enter_table[] = {
{ -1, -1, NULL, NULL } { -1, -1, NULL, NULL }
}; };
/* esc_interm state table. */ /* esc_intermediate state table. */
static const struct input_transition input_state_esc_intermediate_table[] = { static const struct input_transition input_state_esc_intermediate_table[] = {
INPUT_STATE_ANYWHERE, INPUT_STATE_ANYWHERE,
@@ -602,7 +609,7 @@ static const struct input_transition input_state_dcs_parameter_table[] = {
{ -1, -1, NULL, NULL } { -1, -1, NULL, NULL }
}; };
/* dcs_interm state table. */ /* dcs_intermediate state table. */
static const struct input_transition input_state_dcs_intermediate_table[] = { static const struct input_transition input_state_dcs_intermediate_table[] = {
INPUT_STATE_ANYWHERE, INPUT_STATE_ANYWHERE,
@@ -655,12 +662,12 @@ static const struct input_transition input_state_dcs_ignore_table[] = {
static const struct input_transition input_state_osc_string_table[] = { static const struct input_transition input_state_osc_string_table[] = {
INPUT_STATE_ANYWHERE, INPUT_STATE_ANYWHERE,
{ 0x00, 0x06, NULL, NULL }, { 0x00, 0x06, NULL, NULL },
{ 0x07, 0x07, NULL, &input_state_ground }, { 0x07, 0x07, input_end_bel, &input_state_ground },
{ 0x08, 0x17, NULL, NULL }, { 0x08, 0x17, NULL, NULL },
{ 0x19, 0x19, NULL, NULL }, { 0x19, 0x19, NULL, NULL },
{ 0x1c, 0x1f, NULL, NULL }, { 0x1c, 0x1f, NULL, NULL },
{ 0x20, 0xff, input_input, NULL }, { 0x20, 0xff, input_input, NULL },
{ -1, -1, NULL, NULL } { -1, -1, NULL, NULL }
}; };
@@ -750,6 +757,32 @@ input_reset_cell(struct input_ctx *ictx)
ictx->old_cy = 0; ictx->old_cy = 0;
} }
/* Save screen state. */
static void
input_save_state(struct input_ctx *ictx)
{
struct screen_write_ctx *sctx = &ictx->ctx;
struct screen *s = sctx->s;
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
ictx->old_cx = s->cx;
ictx->old_cy = s->cy;
ictx->old_mode = s->mode;
}
static void
input_restore_state(struct input_ctx *ictx)
{
struct screen_write_ctx *sctx = &ictx->ctx;
memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
if (ictx->old_mode & MODE_ORIGIN)
screen_write_mode_set(sctx, MODE_ORIGIN);
else
screen_write_mode_clear(sctx, MODE_ORIGIN);
screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0);
}
/* Initialise input parser. */ /* Initialise input parser. */
void void
input_init(struct window_pane *wp) input_init(struct window_pane *wp)
@@ -762,6 +795,8 @@ input_init(struct window_pane *wp)
ictx->input_buf = xmalloc(INPUT_BUF_START); ictx->input_buf = xmalloc(INPUT_BUF_START);
ictx->since_ground = evbuffer_new(); ictx->since_ground = evbuffer_new();
if (ictx->since_ground == NULL)
fatalx("out of memory");
evtimer_set(&ictx->timer, input_timer_callback, ictx); evtimer_set(&ictx->timer, input_timer_callback, ictx);
@@ -794,16 +829,17 @@ void
input_reset(struct window_pane *wp, int clear) input_reset(struct window_pane *wp, int clear)
{ {
struct input_ctx *ictx = wp->ictx; struct input_ctx *ictx = wp->ictx;
struct screen_write_ctx *sctx = &ictx->ctx;
input_reset_cell(ictx); input_reset_cell(ictx);
if (clear) { if (clear) {
if (wp->mode == NULL) if (TAILQ_EMPTY(&wp->modes))
screen_write_start(&ictx->ctx, wp, &wp->base); screen_write_start(sctx, wp, &wp->base);
else else
screen_write_start(&ictx->ctx, NULL, &wp->base); screen_write_start(sctx, NULL, &wp->base);
screen_write_reset(&ictx->ctx); screen_write_reset(sctx);
screen_write_stop(&ictx->ctx); screen_write_stop(sctx);
} }
input_clear(ictx); input_clear(ictx);
@@ -839,6 +875,7 @@ void
input_parse(struct window_pane *wp) input_parse(struct window_pane *wp)
{ {
struct input_ctx *ictx = wp->ictx; struct input_ctx *ictx = wp->ictx;
struct screen_write_ctx *sctx = &ictx->ctx;
const struct input_transition *itr; const struct input_transition *itr;
struct evbuffer *evb = wp->event->input; struct evbuffer *evb = wp->event->input;
u_char *buf; u_char *buf;
@@ -854,10 +891,10 @@ input_parse(struct window_pane *wp)
* Open the screen. Use NULL wp if there is a mode set as don't want to * Open the screen. Use NULL wp if there is a mode set as don't want to
* update the tty. * update the tty.
*/ */
if (wp->mode == NULL) if (TAILQ_EMPTY(&wp->modes))
screen_write_start(&ictx->ctx, wp, &wp->base); screen_write_start(sctx, wp, &wp->base);
else else
screen_write_start(&ictx->ctx, NULL, &wp->base); screen_write_start(sctx, NULL, &wp->base);
ictx->wp = wp; ictx->wp = wp;
buf = EVBUFFER_DATA(evb); buf = EVBUFFER_DATA(evb);
@@ -893,7 +930,7 @@ input_parse(struct window_pane *wp)
* be the minority. * be the minority.
*/ */
if (itr->handler != input_print) if (itr->handler != input_print)
screen_write_collect_end(&ictx->ctx); screen_write_collect_end(sctx);
/* /*
* Execute the handler, if any. Don't switch state if it * Execute the handler, if any. Don't switch state if it
@@ -912,7 +949,7 @@ input_parse(struct window_pane *wp)
} }
/* Close the screen. */ /* Close the screen. */
screen_write_stop(&ictx->ctx); screen_write_stop(sctx);
evbuffer_drain(evb, len); evbuffer_drain(evb, len);
} }
@@ -993,8 +1030,8 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
static void static void
input_reply(struct input_ctx *ictx, const char *fmt, ...) input_reply(struct input_ctx *ictx, const char *fmt, ...)
{ {
va_list ap; va_list ap;
char *reply; char *reply;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&reply, fmt, ap); xvasprintf(&reply, fmt, ap);
@@ -1019,6 +1056,8 @@ input_clear(struct input_ctx *ictx)
*ictx->input_buf = '\0'; *ictx->input_buf = '\0';
ictx->input_len = 0; ictx->input_len = 0;
ictx->input_end = INPUT_END_ST;
ictx->flags &= ~INPUT_DISCARD; ictx->flags &= ~INPUT_DISCARD;
} }
@@ -1039,7 +1078,8 @@ input_ground(struct input_ctx *ictx)
static int static int
input_print(struct input_ctx *ictx) input_print(struct input_ctx *ictx)
{ {
int set; struct screen_write_ctx *sctx = &ictx->ctx;
int set;
ictx->utf8started = 0; /* can't be valid UTF-8 */ ictx->utf8started = 0; /* can't be valid UTF-8 */
@@ -1050,7 +1090,7 @@ input_print(struct input_ctx *ictx)
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
utf8_set(&ictx->cell.cell.data, ictx->ch); utf8_set(&ictx->cell.cell.data, ictx->ch);
screen_write_collect_add(&ictx->ctx, &ictx->cell.cell); screen_write_collect_add(sctx, &ictx->cell.cell);
ictx->last = ictx->ch; ictx->last = ictx->ch;
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
@@ -1188,7 +1228,6 @@ input_esc_dispatch(struct input_ctx *ictx)
window_pane_reset_palette(ictx->wp); window_pane_reset_palette(ictx->wp);
input_reset_cell(ictx); input_reset_cell(ictx);
screen_write_reset(sctx); screen_write_reset(sctx);
screen_write_clearhistory(sctx);
break; break;
case INPUT_ESC_IND: case INPUT_ESC_IND:
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
@@ -1211,13 +1250,10 @@ input_esc_dispatch(struct input_ctx *ictx)
screen_write_mode_clear(sctx, MODE_KKEYPAD); screen_write_mode_clear(sctx, MODE_KKEYPAD);
break; break;
case INPUT_ESC_DECSC: case INPUT_ESC_DECSC:
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); input_save_state(ictx);
ictx->old_cx = s->cx;
ictx->old_cy = s->cy;
break; break;
case INPUT_ESC_DECRC: case INPUT_ESC_DECRC:
memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); input_restore_state(ictx);
screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
break; break;
case INPUT_ESC_DECALN: case INPUT_ESC_DECALN:
screen_write_alignmenttest(sctx); screen_write_alignmenttest(sctx);
@@ -1304,7 +1340,7 @@ input_csi_dispatch(struct input_ctx *ictx)
n = input_get(ictx, 0, 1, 1); n = input_get(ictx, 0, 1, 1);
m = input_get(ictx, 1, 1, 1); m = input_get(ictx, 1, 1, 1);
if (n != -1 && m != -1) if (n != -1 && m != -1)
screen_write_cursormove(sctx, m - 1, n - 1); screen_write_cursormove(sctx, m - 1, n - 1, 1);
break; break;
case INPUT_CSI_WINOPS: case INPUT_CSI_WINOPS:
input_csi_dispatch_winops(ictx); input_csi_dispatch_winops(ictx);
@@ -1436,7 +1472,7 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_HPA: case INPUT_CSI_HPA:
n = input_get(ictx, 0, 1, 1); n = input_get(ictx, 0, 1, 1);
if (n != -1) if (n != -1)
screen_write_cursormove(sctx, n - 1, s->cy); screen_write_cursormove(sctx, n - 1, -1, 1);
break; break;
case INPUT_CSI_ICH: case INPUT_CSI_ICH:
n = input_get(ictx, 0, 1, 1); n = input_get(ictx, 0, 1, 1);
@@ -1461,8 +1497,7 @@ input_csi_dispatch(struct input_ctx *ictx)
input_print(ictx); input_print(ictx);
break; break;
case INPUT_CSI_RCP: case INPUT_CSI_RCP:
memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); input_restore_state(ictx);
screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
break; break;
case INPUT_CSI_RM: case INPUT_CSI_RM:
input_csi_dispatch_rm(ictx); input_csi_dispatch_rm(ictx);
@@ -1471,9 +1506,7 @@ input_csi_dispatch(struct input_ctx *ictx)
input_csi_dispatch_rm_private(ictx); input_csi_dispatch_rm_private(ictx);
break; break;
case INPUT_CSI_SCP: case INPUT_CSI_SCP:
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); input_save_state(ictx);
ictx->old_cx = s->cx;
ictx->old_cy = s->cy;
break; break;
case INPUT_CSI_SGR: case INPUT_CSI_SGR:
input_csi_dispatch_sgr(ictx); input_csi_dispatch_sgr(ictx);
@@ -1508,7 +1541,7 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_VPA: case INPUT_CSI_VPA:
n = input_get(ictx, 0, 1, 1); n = input_get(ictx, 0, 1, 1);
if (n != -1) if (n != -1)
screen_write_cursormove(sctx, s->cx, n - 1); screen_write_cursormove(sctx, -1, n - 1, 1);
break; break;
case INPUT_CSI_DECSCUSR: case INPUT_CSI_DECSCUSR:
n = input_get(ictx, 0, 0, 0); n = input_get(ictx, 0, 0, 0);
@@ -1525,17 +1558,18 @@ input_csi_dispatch(struct input_ctx *ictx)
static void static void
input_csi_dispatch_rm(struct input_ctx *ictx) input_csi_dispatch_rm(struct input_ctx *ictx)
{ {
u_int i; struct screen_write_ctx *sctx = &ictx->ctx;
u_int i;
for (i = 0; i < ictx->param_list_len; i++) { for (i = 0; i < ictx->param_list_len; i++) {
switch (input_get(ictx, i, 0, -1)) { switch (input_get(ictx, i, 0, -1)) {
case -1: case -1:
break; break;
case 4: /* IRM */ case 4: /* IRM */
screen_write_mode_clear(&ictx->ctx, MODE_INSERT); screen_write_mode_clear(sctx, MODE_INSERT);
break; break;
case 34: case 34:
screen_write_mode_set(&ictx->ctx, MODE_BLINKING); screen_write_mode_set(sctx, MODE_BLINKING);
break; break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1548,6 +1582,7 @@ input_csi_dispatch_rm(struct input_ctx *ictx)
static void static void
input_csi_dispatch_rm_private(struct input_ctx *ictx) input_csi_dispatch_rm_private(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
u_int i; u_int i;
@@ -1556,36 +1591,39 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
case -1: case -1:
break; break;
case 1: /* DECCKM */ case 1: /* DECCKM */
screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR); screen_write_mode_clear(sctx, MODE_KCURSOR);
break; break;
case 3: /* DECCOLM */ case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_cursormove(sctx, 0, 0, 1);
screen_write_clearscreen(&ictx->ctx, screen_write_clearscreen(sctx, ictx->cell.cell.bg);
ictx->cell.cell.bg); break;
case 6: /* DECOM */
screen_write_mode_clear(sctx, MODE_ORIGIN);
screen_write_cursormove(sctx, 0, 0, 1);
break; break;
case 7: /* DECAWM */ case 7: /* DECAWM */
screen_write_mode_clear(&ictx->ctx, MODE_WRAP); screen_write_mode_clear(sctx, MODE_WRAP);
break; break;
case 12: case 12:
screen_write_mode_clear(&ictx->ctx, MODE_BLINKING); screen_write_mode_clear(sctx, MODE_BLINKING);
break; break;
case 25: /* TCEM */ case 25: /* TCEM */
screen_write_mode_clear(&ictx->ctx, MODE_CURSOR); screen_write_mode_clear(sctx, MODE_CURSOR);
break; break;
case 1000: case 1000:
case 1001: case 1001:
case 1002: case 1002:
case 1003: case 1003:
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
break; break;
case 1004: case 1004:
screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON); screen_write_mode_clear(sctx, MODE_FOCUSON);
break; break;
case 1005: case 1005:
screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8); screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
break; break;
case 1006: case 1006:
screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR); screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
break; break;
case 47: case 47:
case 1047: case 1047:
@@ -1595,7 +1633,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
window_pane_alternate_off(wp, &ictx->cell.cell, 1); window_pane_alternate_off(wp, &ictx->cell.cell, 1);
break; break;
case 2004: case 2004:
screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE); screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
break; break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1608,17 +1646,18 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
static void static void
input_csi_dispatch_sm(struct input_ctx *ictx) input_csi_dispatch_sm(struct input_ctx *ictx)
{ {
u_int i; struct screen_write_ctx *sctx = &ictx->ctx;
u_int i;
for (i = 0; i < ictx->param_list_len; i++) { for (i = 0; i < ictx->param_list_len; i++) {
switch (input_get(ictx, i, 0, -1)) { switch (input_get(ictx, i, 0, -1)) {
case -1: case -1:
break; break;
case 4: /* IRM */ case 4: /* IRM */
screen_write_mode_set(&ictx->ctx, MODE_INSERT); screen_write_mode_set(sctx, MODE_INSERT);
break; break;
case 34: case 34:
screen_write_mode_clear(&ictx->ctx, MODE_BLINKING); screen_write_mode_clear(sctx, MODE_BLINKING);
break; break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1631,6 +1670,7 @@ input_csi_dispatch_sm(struct input_ctx *ictx)
static void static void
input_csi_dispatch_sm_private(struct input_ctx *ictx) input_csi_dispatch_sm_private(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
u_int i; u_int i;
@@ -1639,45 +1679,48 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
case -1: case -1:
break; break;
case 1: /* DECCKM */ case 1: /* DECCKM */
screen_write_mode_set(&ictx->ctx, MODE_KCURSOR); screen_write_mode_set(sctx, MODE_KCURSOR);
break; break;
case 3: /* DECCOLM */ case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_cursormove(sctx, 0, 0, 1);
screen_write_clearscreen(&ictx->ctx, screen_write_clearscreen(sctx, ictx->cell.cell.bg);
ictx->cell.cell.bg); break;
case 6: /* DECOM */
screen_write_mode_set(sctx, MODE_ORIGIN);
screen_write_cursormove(sctx, 0, 0, 1);
break; break;
case 7: /* DECAWM */ case 7: /* DECAWM */
screen_write_mode_set(&ictx->ctx, MODE_WRAP); screen_write_mode_set(sctx, MODE_WRAP);
break; break;
case 12: case 12:
screen_write_mode_set(&ictx->ctx, MODE_BLINKING); screen_write_mode_set(sctx, MODE_BLINKING);
break; break;
case 25: /* TCEM */ case 25: /* TCEM */
screen_write_mode_set(&ictx->ctx, MODE_CURSOR); screen_write_mode_set(sctx, MODE_CURSOR);
break; break;
case 1000: case 1000:
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD); screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
break; break;
case 1002: case 1002:
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON); screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
break; break;
case 1003: case 1003:
screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ALL); screen_write_mode_set(sctx, MODE_MOUSE_ALL);
break; break;
case 1004: case 1004:
if (ictx->ctx.s->mode & MODE_FOCUSON) if (sctx->s->mode & MODE_FOCUSON)
break; break;
screen_write_mode_set(&ictx->ctx, MODE_FOCUSON); screen_write_mode_set(sctx, MODE_FOCUSON);
wp->flags |= PANE_FOCUSPUSH; /* force update */ wp->flags |= PANE_FOCUSPUSH; /* force update */
break; break;
case 1005: case 1005:
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
break; break;
case 1006: case 1006:
screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR); screen_write_mode_set(sctx, MODE_MOUSE_SGR);
break; break;
case 47: case 47:
case 1047: case 1047:
@@ -1687,7 +1730,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
window_pane_alternate_on(wp, &ictx->cell.cell, 1); window_pane_alternate_on(wp, &ictx->cell.cell, 1);
break; break;
case 2004: case 2004:
screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE); screen_write_mode_set(sctx, MODE_BRACKETPASTE);
break; break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1700,6 +1743,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
static void static void
input_csi_dispatch_winops(struct input_ctx *ictx) input_csi_dispatch_winops(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
int n, m; int n, m;
@@ -1739,7 +1783,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
return; return;
case 0: case 0:
case 2: case 2:
screen_push_title(ictx->ctx.s); screen_push_title(sctx->s);
break; break;
} }
break; break;
@@ -1750,7 +1794,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
return; return;
case 0: case 0:
case 2: case 2:
screen_pop_title(ictx->ctx.s); screen_pop_title(sctx->s);
server_status_window(ictx->wp->window); server_status_window(ictx->wp->window);
break; break;
} }
@@ -1835,10 +1879,11 @@ input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
static void static void
input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i) input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
{ {
char *s = ictx->param_list[i].str, *copy, *ptr, *out; struct grid_cell *gc = &ictx->cell.cell;
int p[8]; char *s = ictx->param_list[i].str, *copy, *ptr, *out;
u_int n; int p[8];
const char *errstr; u_int n;
const char *errstr;
for (n = 0; n < nitems(p); n++) for (n = 0; n < nitems(p); n++)
p[n] = -1; p[n] = -1;
@@ -1852,12 +1897,45 @@ input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
free(copy); free(copy);
return; return;
} }
} } else
n++;
log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]); log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
} }
free(copy); free(copy);
if (n == 0 || (p[0] != 38 && p[0] != 48)) if (n == 0)
return;
if (p[0] == 4) {
if (n != 2)
return;
switch (p[1]) {
case 0:
gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
break;
case 1:
gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
gc->attr |= GRID_ATTR_UNDERSCORE;
break;
case 2:
gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
gc->attr |= GRID_ATTR_UNDERSCORE_2;
break;
case 3:
gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
gc->attr |= GRID_ATTR_UNDERSCORE_3;
break;
case 4:
gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
gc->attr |= GRID_ATTR_UNDERSCORE_4;
break;
case 5:
gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
gc->attr |= GRID_ATTR_UNDERSCORE_5;
break;
}
return;
}
if (p[0] != 38 && p[0] != 48)
return; return;
if (p[1] == -1) if (p[1] == -1)
i = 2; i = 2;
@@ -1927,6 +2005,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
gc->attr |= GRID_ATTR_ITALICS; gc->attr |= GRID_ATTR_ITALICS;
break; break;
case 4: case 4:
gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
gc->attr |= GRID_ATTR_UNDERSCORE; gc->attr |= GRID_ATTR_UNDERSCORE;
break; break;
case 5: case 5:
@@ -1948,7 +2027,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
gc->attr &= ~GRID_ATTR_ITALICS; gc->attr &= ~GRID_ATTR_ITALICS;
break; break;
case 24: case 24:
gc->attr &= ~GRID_ATTR_UNDERSCORE; gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
break; break;
case 25: case 25:
gc->attr &= ~GRID_ATTR_BLINK; gc->attr &= ~GRID_ATTR_BLINK;
@@ -2012,6 +2091,17 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
} }
} }
/* End of input with BEL. */
static int
input_end_bel(struct input_ctx *ictx)
{
log_debug("%s", __func__);
ictx->input_end = INPUT_END_BEL;
return (0);
}
/* DCS string started. */ /* DCS string started. */
static void static void
input_enter_dcs(struct input_ctx *ictx) input_enter_dcs(struct input_ctx *ictx)
@@ -2027,20 +2117,19 @@ input_enter_dcs(struct input_ctx *ictx)
static int static int
input_dcs_dispatch(struct input_ctx *ictx) input_dcs_dispatch(struct input_ctx *ictx)
{ {
const char prefix[] = "tmux;"; struct screen_write_ctx *sctx = &ictx->ctx;
const u_int prefix_len = (sizeof prefix) - 1; u_char *buf = ictx->input_buf;
size_t len = ictx->input_len;
const char prefix[] = "tmux;";
const u_int prefixlen = (sizeof prefix) - 1;
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return (0); return (0);
log_debug("%s: \"%s\"", __func__, ictx->input_buf); log_debug("%s: \"%s\"", __func__, buf);
/* Check for tmux prefix. */ if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
if (ictx->input_len >= prefix_len && screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
screen_write_rawstring(&ictx->ctx,
ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
}
return (0); return (0);
} }
@@ -2060,15 +2149,17 @@ input_enter_osc(struct input_ctx *ictx)
static void static void
input_exit_osc(struct input_ctx *ictx) input_exit_osc(struct input_ctx *ictx)
{ {
u_char *p = ictx->input_buf; struct screen_write_ctx *sctx = &ictx->ctx;
u_int option; u_char *p = ictx->input_buf;
u_int option;
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return; return;
if (ictx->input_len < 1 || *p < '0' || *p > '9') if (ictx->input_len < 1 || *p < '0' || *p > '9')
return; return;
log_debug("%s: \"%s\"", __func__, p); log_debug("%s: \"%s\" (end %s)", __func__, p,
ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
option = 0; option = 0;
while (*p >= '0' && *p <= '9') while (*p >= '0' && *p <= '9')
@@ -2080,32 +2171,32 @@ input_exit_osc(struct input_ctx *ictx)
case 0: case 0:
case 2: case 2:
if (utf8_isvalid(p)) { if (utf8_isvalid(p)) {
screen_set_title(ictx->ctx.s, p); screen_set_title(sctx->s, p);
server_status_window(ictx->wp->window); server_status_window(ictx->wp->window);
} }
break; break;
case 4: case 4:
input_osc_4(ictx->wp, p); input_osc_4(ictx, p);
break; break;
case 10: case 10:
input_osc_10(ictx->wp, p); input_osc_10(ictx, p);
break; break;
case 11: case 11:
input_osc_11(ictx->wp, p); input_osc_11(ictx, p);
break; break;
case 12: case 12:
if (utf8_isvalid(p) && *p != '?') /* ? is colour request */ if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
screen_set_cursor_colour(ictx->ctx.s, p); screen_set_cursor_colour(sctx->s, p);
break; break;
case 52: case 52:
input_osc_52(ictx->wp, p); input_osc_52(ictx, p);
break; break;
case 104: case 104:
input_osc_104(ictx->wp, p); input_osc_104(ictx, p);
break; break;
case 112: case 112:
if (*p == '\0') /* no arguments allowed */ if (*p == '\0') /* no arguments allowed */
screen_set_cursor_colour(ictx->ctx.s, ""); screen_set_cursor_colour(sctx->s, "");
break; break;
default: default:
log_debug("%s: unknown '%u'", __func__, option); log_debug("%s: unknown '%u'", __func__, option);
@@ -2128,13 +2219,15 @@ input_enter_apc(struct input_ctx *ictx)
static void static void
input_exit_apc(struct input_ctx *ictx) input_exit_apc(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx;
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return; return;
log_debug("%s: \"%s\"", __func__, ictx->input_buf); log_debug("%s: \"%s\"", __func__, ictx->input_buf);
if (!utf8_isvalid(ictx->input_buf)) if (!utf8_isvalid(ictx->input_buf))
return; return;
screen_set_title(ictx->ctx.s, ictx->input_buf); screen_set_title(sctx->s, ictx->input_buf);
server_status_window(ictx->wp->window); server_status_window(ictx->wp->window);
} }
@@ -2170,6 +2263,7 @@ input_exit_rename(struct input_ctx *ictx)
static int static int
input_top_bit_set(struct input_ctx *ictx) input_top_bit_set(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx;
struct utf8_data *ud = &ictx->utf8data; struct utf8_data *ud = &ictx->utf8data;
ictx->last = -1; ictx->last = -1;
@@ -2196,18 +2290,19 @@ input_top_bit_set(struct input_ctx *ictx)
(int)ud->size, ud->data, ud->width); (int)ud->size, ud->data, ud->width);
utf8_copy(&ictx->cell.cell.data, ud); utf8_copy(&ictx->cell.cell.data, ud);
screen_write_collect_add(&ictx->ctx, &ictx->cell.cell); screen_write_collect_add(sctx, &ictx->cell.cell);
return (0); return (0);
} }
/* Handle the OSC 4 sequence for setting (multiple) palette entries. */ /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
static void static void
input_osc_4(struct window_pane *wp, const char *p) input_osc_4(struct input_ctx *ictx, const char *p)
{ {
char *copy, *s, *next = NULL; struct window_pane *wp = ictx->wp;
long idx; char *copy, *s, *next = NULL;
u_int r, g, b; long idx;
u_int r, g, b;
copy = s = xstrdup(p); copy = s = xstrdup(p);
while (s != NULL && *s != '\0') { while (s != NULL && *s != '\0') {
@@ -2237,14 +2332,15 @@ bad:
/* Handle the OSC 10 sequence for setting foreground colour. */ /* Handle the OSC 10 sequence for setting foreground colour. */
static void static void
input_osc_10(struct window_pane *wp, const char *p) input_osc_10(struct input_ctx *ictx, const char *p)
{ {
u_int r, g, b; struct window_pane *wp = ictx->wp;
u_int r, g, b;
if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
goto bad; goto bad;
wp->colgc.fg = colour_join_rgb(r, g, b); wp->style.gc.fg = colour_join_rgb(r, g, b);
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
return; return;
@@ -2255,14 +2351,15 @@ bad:
/* Handle the OSC 11 sequence for setting background colour. */ /* Handle the OSC 11 sequence for setting background colour. */
static void static void
input_osc_11(struct window_pane *wp, const char *p) input_osc_11(struct input_ctx *ictx, const char *p)
{ {
u_int r, g, b; struct window_pane *wp = ictx->wp;
u_int r, g, b;
if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
goto bad; goto bad;
wp->colgc.bg = colour_join_rgb(r, g, b); wp->style.gc.bg = colour_join_rgb(r, g, b);
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
return; return;
@@ -2273,13 +2370,16 @@ bad:
/* Handle the OSC 52 sequence for setting the clipboard. */ /* Handle the OSC 52 sequence for setting the clipboard. */
static void static void
input_osc_52(struct window_pane *wp, const char *p) input_osc_52(struct input_ctx *ictx, const char *p)
{ {
struct window_pane *wp = ictx->wp;
char *end; char *end;
const char *buf;
size_t len; size_t len;
u_char *out; u_char *out;
int outlen, state; int outlen, state;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct paste_buffer *pb;
state = options_get_number(global_options, "set-clipboard"); state = options_get_number(global_options, "set-clipboard");
if (state != 2) if (state != 2)
@@ -2290,6 +2390,32 @@ input_osc_52(struct window_pane *wp, const char *p)
end++; end++;
if (*end == '\0') if (*end == '\0')
return; return;
log_debug("%s: %s", __func__, end);
if (strcmp(end, "?") == 0) {
if ((pb = paste_get_top(NULL)) != NULL) {
buf = paste_buffer_data(pb, &len);
outlen = 4 * ((len + 2) / 3) + 1;
out = xmalloc(outlen);
if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
abort();
free(out);
return;
}
} else {
outlen = 0;
out = NULL;
}
bufferevent_write(wp->event, "\033]52;;", 6);
if (outlen != 0)
bufferevent_write(wp->event, out, outlen);
if (ictx->input_end == INPUT_END_BEL)
bufferevent_write(wp->event, "\007", 1);
else
bufferevent_write(wp->event, "\033\\", 2);
free(out);
return;
}
len = (strlen(end) / 4) * 3; len = (strlen(end) / 4) * 3;
if (len == 0) if (len == 0)
@@ -2311,10 +2437,11 @@ input_osc_52(struct window_pane *wp, const char *p)
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */ /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
static void static void
input_osc_104(struct window_pane *wp, const char *p) input_osc_104(struct input_ctx *ictx, const char *p)
{ {
char *copy, *s; struct window_pane *wp = ictx->wp;
long idx; char *copy, *s;
long idx;
if (*p == '\0') { if (*p == '\0') {
window_pane_reset_palette(wp); window_pane_reset_palette(wp);

104
job.c
View File

@@ -36,8 +36,33 @@ static void job_read_callback(struct bufferevent *, void *);
static void job_write_callback(struct bufferevent *, void *); static void job_write_callback(struct bufferevent *, void *);
static void job_error_callback(struct bufferevent *, short, void *); static void job_error_callback(struct bufferevent *, short, void *);
/* A single job. */
struct job {
enum {
JOB_RUNNING,
JOB_DEAD,
JOB_CLOSED
} state;
int flags;
char *cmd;
pid_t pid;
int status;
int fd;
struct bufferevent *event;
job_update_cb updatecb;
job_complete_cb completecb;
job_free_cb freecb;
void *data;
LIST_ENTRY(job) entry;
};
/* All jobs list. */ /* All jobs list. */
struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs); static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
/* Start a job running, if it isn't already. */ /* Start a job running, if it isn't already. */
struct job * struct job *
@@ -54,6 +79,7 @@ job_run(const char *cmd, struct session *s, const char *cwd,
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
return (NULL); return (NULL);
log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, cwd == NULL ? "" : cwd);
/* /*
* Do not set TERM during .tmux.conf, it is nice to be able to use * Do not set TERM during .tmux.conf, it is nice to be able to use
@@ -128,6 +154,8 @@ job_run(const char *cmd, struct session *s, const char *cwd,
job->event = bufferevent_new(job->fd, job_read_callback, job->event = bufferevent_new(job->fd, job_read_callback,
job_write_callback, job_error_callback, job); job_write_callback, job_error_callback, job);
if (job->event == NULL)
fatalx("out of memory");
bufferevent_enable(job->event, EV_READ|EV_WRITE); bufferevent_enable(job->event, EV_READ|EV_WRITE);
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
@@ -207,8 +235,16 @@ job_error_callback(__unused struct bufferevent *bufev, __unused short events,
/* Job died (waitpid() returned its pid). */ /* Job died (waitpid() returned its pid). */
void void
job_died(struct job *job, int status) job_check_died(pid_t pid, int status)
{ {
struct job *job;
LIST_FOREACH(job, &all_jobs, entry) {
if (pid == job->pid)
break;
}
if (job == NULL)
return;
log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid); log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid);
job->status = status; job->status = status;
@@ -222,3 +258,67 @@ job_died(struct job *job, int status)
job->state = JOB_DEAD; job->state = JOB_DEAD;
} }
} }
/* Get job status. */
int
job_get_status(struct job *job)
{
return (job->status);
}
/* Get job data. */
void *
job_get_data(struct job *job)
{
return (job->data);
}
/* Get job event. */
struct bufferevent *
job_get_event(struct job *job)
{
return (job->event);
}
/* Kill all jobs. */
void
job_kill_all(void)
{
struct job *job;
LIST_FOREACH(job, &all_jobs, entry) {
if (job->pid != -1)
kill(job->pid, SIGTERM);
}
}
/* Are any jobs still running? */
int
job_still_running(void)
{
struct job *job;
LIST_FOREACH(job, &all_jobs, entry) {
if ((~job->flags & JOB_NOWAIT) && job->state == JOB_RUNNING)
return (1);
}
return (0);
}
/* Print job summary. */
void
job_print_summary(struct cmdq_item *item, int blank)
{
struct job *job;
u_int n = 0;
LIST_FOREACH(job, &all_jobs, entry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
}
cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
n, job->cmd, job->fd, (long)job->pid, job->status);
n++;
}
}

View File

@@ -228,7 +228,7 @@ key_bindings_init(void)
"bind ] paste-buffer", "bind ] paste-buffer",
"bind c new-window", "bind c new-window",
"bind d detach-client", "bind d detach-client",
"bind f command-prompt \"find-window -- '%%'\"", "bind f command-prompt \"find-window -Z -- '%%'\"",
"bind i display-message", "bind i display-message",
"bind l last-window", "bind l last-window",
"bind m select-pane -m", "bind m select-pane -m",
@@ -258,6 +258,11 @@ key_bindings_init(void)
"bind M-n next-window -a", "bind M-n next-window -a",
"bind M-o rotate-window -D", "bind M-o rotate-window -D",
"bind M-p previous-window -a", "bind M-p previous-window -a",
"bind -r S-Up refresh-client -U 10",
"bind -r S-Down refresh-client -D 10",
"bind -r S-Left refresh-client -L 10",
"bind -r S-Right refresh-client -R 10",
"bind -r DC refresh-client -c",
"bind -r M-Up resize-pane -U 5", "bind -r M-Up resize-pane -U 5",
"bind -r M-Down resize-pane -D 5", "bind -r M-Down resize-pane -D 5",
"bind -r M-Left resize-pane -L 5", "bind -r M-Left resize-pane -L 5",

View File

@@ -43,7 +43,9 @@ static const struct {
{ "F11", KEYC_F11 }, { "F11", KEYC_F11 },
{ "F12", KEYC_F12 }, { "F12", KEYC_F12 },
{ "IC", KEYC_IC }, { "IC", KEYC_IC },
{ "Insert", KEYC_IC },
{ "DC", KEYC_DC }, { "DC", KEYC_DC },
{ "Delete", KEYC_DC },
{ "Home", KEYC_HOME }, { "Home", KEYC_HOME },
{ "End", KEYC_END }, { "End", KEYC_END },
{ "NPage", KEYC_NPAGE }, { "NPage", KEYC_NPAGE },
@@ -271,6 +273,10 @@ key_string_lookup_key(key_code key)
return ("MouseMovePane"); return ("MouseMovePane");
if (key == KEYC_MOUSEMOVE_STATUS) if (key == KEYC_MOUSEMOVE_STATUS)
return ("MouseMoveStatus"); return ("MouseMoveStatus");
if (key == KEYC_MOUSEMOVE_STATUS_LEFT)
return ("MouseMoveStatusLeft");
if (key == KEYC_MOUSEMOVE_STATUS_RIGHT)
return ("MouseMoveStatusRight");
if (key == KEYC_MOUSEMOVE_BORDER) if (key == KEYC_MOUSEMOVE_BORDER)
return ("MouseMoveBorder"); return ("MouseMoveBorder");
if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) { if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) {

View File

@@ -167,7 +167,7 @@ layout_parse(struct window *w, const char *layout)
/* Update pane offsets and sizes. */ /* Update pane offsets and sizes. */
layout_fix_offsets(lc); layout_fix_offsets(lc);
layout_fix_panes(w, lc->sx, lc->sy); layout_fix_panes(w);
/* Then resize the layout back to the original window size. */ /* Then resize the layout back to the original window size. */
layout_resize(w, sx, sy); layout_resize(w, sx, sy);

View File

@@ -119,7 +119,7 @@ layout_set_even(struct window *w, enum layout_type type)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc, *lcnew; struct layout_cell *lc, *lcnew;
u_int n; u_int n, sx, sy;
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
@@ -131,7 +131,18 @@ layout_set_even(struct window *w, enum layout_type type)
/* Free the old root and construct a new. */ /* Free the old root and construct a new. */
layout_free(w); layout_free(w);
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, w->sy, 0, 0); if (type == LAYOUT_LEFTRIGHT) {
sx = (n * (PANE_MINIMUM + 1)) - 1;
if (sx < w->sx)
sx = w->sx;
sy = w->sy;
} else {
sy = (n * (PANE_MINIMUM + 1)) - 1;
if (sy < w->sy)
sy = w->sy;
sx = w->sx;
}
layout_set_size(lc, sx, sy, 0, 0);
layout_make_node(lc, type); layout_make_node(lc, type);
/* Build new leaf cells. */ /* Build new leaf cells. */
@@ -148,10 +159,11 @@ layout_set_even(struct window *w, enum layout_type type)
/* Fix cell offsets. */ /* Fix cell offsets. */
layout_fix_offsets(lc); layout_fix_offsets(lc);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
server_redraw_window(w); server_redraw_window(w);
} }
@@ -172,9 +184,8 @@ static void
layout_set_main_h(struct window *w) layout_set_main_h(struct window *w)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcrow, *lcchild; struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainheight, otherheight, width, height; u_int n, mainh, otherh, sx;
u_int used, i, j, columns, rows, totalrows;
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
@@ -184,110 +195,65 @@ layout_set_main_h(struct window *w)
return; return;
n--; /* take off main pane */ n--; /* take off main pane */
/* How many rows and columns will be needed, not counting main? */ /* Get the main pane height and work out the other pane height. */
columns = (w->sx + 1) / (PANE_MINIMUM + 1); /* maximum columns */ mainh = options_get_number(w->options, "main-pane-height");
if (columns == 0) if (mainh + PANE_MINIMUM + 1 >= w->sy) {
columns = 1; if (w->sy <= PANE_MINIMUM + 1 + PANE_MINIMUM)
rows = 1 + (n - 1) / columns; mainh = PANE_MINIMUM;
columns = 1 + (n - 1) / rows;
width = (w->sx - (n - 1)) / columns;
/* Get the main pane height and add one for separator line. */
mainheight = options_get_number(w->options, "main-pane-height") + 1;
/* Get the optional other pane height and add one for separator line. */
otherheight = options_get_number(w->options, "other-pane-height") + 1;
/*
* If an other pane height was specified, honour it so long as it
* doesn't shrink the main height to less than the main-pane-height
*/
if (otherheight > 1 && w->sy - otherheight > mainheight)
mainheight = w->sy - otherheight;
if (mainheight < PANE_MINIMUM + 1)
mainheight = PANE_MINIMUM + 1;
/* Try and make everything fit. */
totalrows = rows * (PANE_MINIMUM + 1) - 1;
if (mainheight + totalrows > w->sy) {
if (totalrows + PANE_MINIMUM + 1 > w->sy)
mainheight = PANE_MINIMUM + 2;
else else
mainheight = w->sy - totalrows; mainh = w->sy - (PANE_MINIMUM + 1);
height = PANE_MINIMUM; otherh = PANE_MINIMUM;
} else } else {
height = (w->sy - mainheight - (rows - 1)) / rows; otherh = options_get_number(w->options, "other-pane-height");
if (otherh == 0)
otherh = w->sy - mainh;
else if (otherh > w->sy || w->sy - otherh < mainh)
otherh = w->sy - mainh;
else
mainh = w->sy - otherh;
}
/* Work out what height is needed. */
sx = (n * (PANE_MINIMUM + 1)) - 1;
if (sx < w->sx)
sx = w->sx;
/* Free old tree and create a new root. */ /* Free old tree and create a new root. */
layout_free(w); layout_free(w);
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0); layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM); layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create the main pane. */ /* Create the main pane. */
lcmain = layout_create_cell(lc); lcmain = layout_create_cell(lc);
layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0); layout_set_size(lcmain, sx, mainh, 0, 0);
layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
/* Create a grid of the remaining cells. */ /* Create the other pane. */
wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); lcother = layout_create_cell(lc);
for (j = 0; j < rows; j++) { layout_set_size(lcother, sx, otherh, 0, 0);
/* If this is the last cell, all done. */ layout_make_node(lcother, LAYOUT_LEFTRIGHT);
if (wp == NULL) TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
break;
/* Create the new row. */ /* Add the remaining panes as children. */
lcrow = layout_create_cell(lc); TAILQ_FOREACH(wp, &w->panes, entry) {
layout_set_size(lcrow, w->sx, height, 0, 0); if (wp == TAILQ_FIRST(&w->panes))
TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
/* If only one column, just use the row directly. */
if (columns == 1) {
layout_make_leaf(lcrow, wp);
wp = TAILQ_NEXT(wp, entry);
continue; continue;
} lcchild = layout_create_cell(lc);
layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
/* Add in the columns. */ layout_make_leaf(lcchild, wp);
layout_make_node(lcrow, LAYOUT_LEFTRIGHT); TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
for (i = 0; i < columns; i++) {
/* Create and add a pane cell. */
lcchild = layout_create_cell(lcrow);
layout_set_size(lcchild, width, height, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
/* Move to the next cell. */
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
break;
}
/* Adjust the row to fit the full width if necessary. */
if (i == columns)
i--;
used = ((i + 1) * (width + 1)) - 1;
if (w->sx <= used)
continue;
lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
w->sx - used);
}
/* Adjust the last row height to fit if necessary. */
used = mainheight + (rows * height) + rows - 1;
if (w->sy > used) {
lcrow = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
w->sy - used);
} }
layout_spread_cell(w, lcother);
/* Fix cell offsets. */ /* Fix cell offsets. */
layout_fix_offsets(lc); layout_fix_offsets(lc);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
server_redraw_window(w); server_redraw_window(w);
} }
@@ -296,9 +262,8 @@ static void
layout_set_main_v(struct window *w) layout_set_main_v(struct window *w)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lccolumn, *lcchild; struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainwidth, otherwidth, width, height; u_int n, mainw, otherw, sy;
u_int used, i, j, columns, rows, totalcolumns;
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
@@ -308,110 +273,65 @@ layout_set_main_v(struct window *w)
return; return;
n--; /* take off main pane */ n--; /* take off main pane */
/* How many rows and columns will be needed, not counting main? */ /* Get the main pane width and work out the other pane width. */
rows = (w->sy + 1) / (PANE_MINIMUM + 1); /* maximum rows */ mainw = options_get_number(w->options, "main-pane-width");
if (rows == 0) if (mainw + PANE_MINIMUM + 1 >= w->sx) {
rows = 1; if (w->sx <= PANE_MINIMUM + 1 + PANE_MINIMUM)
columns = 1 + (n - 1) / rows; mainw = PANE_MINIMUM;
rows = 1 + (n - 1) / columns;
height = (w->sy - (n - 1)) / rows;
/* Get the main pane width and add one for separator line. */
mainwidth = options_get_number(w->options, "main-pane-width") + 1;
/* Get the optional other pane width and add one for separator line. */
otherwidth = options_get_number(w->options, "other-pane-width") + 1;
/*
* If an other pane width was specified, honour it so long as it
* doesn't shrink the main width to less than the main-pane-width
*/
if (otherwidth > 1 && w->sx - otherwidth > mainwidth)
mainwidth = w->sx - otherwidth;
if (mainwidth < PANE_MINIMUM + 1)
mainwidth = PANE_MINIMUM + 1;
/* Try and make everything fit. */
totalcolumns = columns * (PANE_MINIMUM + 1) - 1;
if (mainwidth + totalcolumns > w->sx) {
if (totalcolumns + PANE_MINIMUM + 1 > w->sx)
mainwidth = PANE_MINIMUM + 2;
else else
mainwidth = w->sx - totalcolumns; mainw = w->sx - (PANE_MINIMUM + 1);
width = PANE_MINIMUM; otherw = PANE_MINIMUM;
} else } else {
width = (w->sx - mainwidth - (columns - 1)) / columns; otherw = options_get_number(w->options, "other-pane-width");
if (otherw == 0)
otherw = w->sx - mainw;
else if (otherw > w->sx || w->sx - otherw < mainw)
otherw = w->sx - mainw;
else
mainw = w->sx - otherw;
}
/* Work out what height is needed. */
sy = (n * (PANE_MINIMUM + 1)) - 1;
if (sy < w->sy)
sy = w->sy;
/* Free old tree and create a new root. */ /* Free old tree and create a new root. */
layout_free(w); layout_free(w);
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0); layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
layout_make_node(lc, LAYOUT_LEFTRIGHT); layout_make_node(lc, LAYOUT_LEFTRIGHT);
/* Create the main pane. */ /* Create the main pane. */
lcmain = layout_create_cell(lc); lcmain = layout_create_cell(lc);
layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0); layout_set_size(lcmain, mainw, sy, 0, 0);
layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
/* Create a grid of the remaining cells. */ /* Create the other pane. */
wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); lcother = layout_create_cell(lc);
for (j = 0; j < columns; j++) { layout_set_size(lcother, otherw, sy, 0, 0);
/* If this is the last cell, all done. */ layout_make_node(lcother, LAYOUT_TOPBOTTOM);
if (wp == NULL) TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
break;
/* Create the new column. */ /* Add the remaining panes as children. */
lccolumn = layout_create_cell(lc); TAILQ_FOREACH(wp, &w->panes, entry) {
layout_set_size(lccolumn, width, w->sy, 0, 0); if (wp == TAILQ_FIRST(&w->panes))
TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
/* If only one row, just use the row directly. */
if (rows == 1) {
layout_make_leaf(lccolumn, wp);
wp = TAILQ_NEXT(wp, entry);
continue; continue;
} lcchild = layout_create_cell(lc);
layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
/* Add in the rows. */ layout_make_leaf(lcchild, wp);
layout_make_node(lccolumn, LAYOUT_TOPBOTTOM); TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
for (i = 0; i < rows; i++) {
/* Create and add a pane cell. */
lcchild = layout_create_cell(lccolumn);
layout_set_size(lcchild, width, height, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
/* Move to the next cell. */
if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
break;
}
/* Adjust the column to fit the full height if necessary. */
if (i == rows)
i--;
used = ((i + 1) * (height + 1)) - 1;
if (w->sy <= used)
continue;
lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
layout_resize_adjust(w, lcchild, LAYOUT_TOPBOTTOM,
w->sy - used);
}
/* Adjust the last column width to fit if necessary. */
used = mainwidth + (columns * width) + columns - 1;
if (w->sx > used) {
lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
layout_resize_adjust(w, lccolumn, LAYOUT_LEFTRIGHT,
w->sx - used);
} }
layout_spread_cell(w, lcother);
/* Fix cell offsets. */ /* Fix cell offsets. */
layout_fix_offsets(lc); layout_fix_offsets(lc);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
server_redraw_window(w); server_redraw_window(w);
} }
@@ -421,7 +341,7 @@ layout_set_tiled(struct window *w)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc, *lcrow, *lcchild; struct layout_cell *lc, *lcrow, *lcchild;
u_int n, width, height, used; u_int n, width, height, used, sx, sy;
u_int i, j, columns, rows; u_int i, j, columns, rows;
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
@@ -450,8 +370,13 @@ layout_set_tiled(struct window *w)
/* Free old tree and create a new root. */ /* Free old tree and create a new root. */
layout_free(w); layout_free(w);
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, (width + 1) * columns - 1, sx = ((width + 1) * columns) - 1;
(height + 1) * rows - 1, 0, 0); if (sx < w->sx)
sx = w->sx;
sy = ((height + 1) * rows) - 1;
if (sy < w->sy)
sy = w->sy;
layout_set_size(lc, sx, sy, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM); layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create a grid of the cells. */ /* Create a grid of the cells. */
@@ -511,10 +436,11 @@ layout_set_tiled(struct window *w)
/* Fix cell offsets. */ /* Fix cell offsets. */
layout_fix_offsets(lc); layout_fix_offsets(lc);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
layout_print_cell(w->layout_root, __func__, 1); layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
server_redraw_window(w); server_redraw_window(w);
} }

126
layout.c
View File

@@ -236,7 +236,7 @@ layout_need_status(struct layout_cell *lc, int at_top)
{ {
struct layout_cell *first_lc; struct layout_cell *first_lc;
if (lc->parent) { if (lc->parent != NULL) {
if (lc->parent->type == LAYOUT_LEFTRIGHT) if (lc->parent->type == LAYOUT_LEFTRIGHT)
return (layout_need_status(lc->parent, at_top)); return (layout_need_status(lc->parent, at_top));
@@ -253,71 +253,29 @@ layout_need_status(struct layout_cell *lc, int at_top)
/* Update pane offsets and sizes based on their cells. */ /* Update pane offsets and sizes based on their cells. */
void void
layout_fix_panes(struct window *w, u_int wsx, u_int wsy) layout_fix_panes(struct window *w)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc; struct layout_cell *lc;
u_int sx, sy; int shift, status;
int shift, status, at_top;
status = options_get_number(w->options, "pane-border-status"); status = options_get_number(w->options, "pane-border-status");
at_top = (status == 1);
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL) if ((lc = wp->layout_cell) == NULL)
continue; continue;
if (status != 0) if (status != 0)
shift = layout_need_status(lc, at_top); shift = layout_need_status(lc, status == 1);
else else
shift = 0; shift = 0;
wp->xoff = lc->xoff; wp->xoff = lc->xoff;
wp->yoff = lc->yoff; wp->yoff = lc->yoff;
if (shift && at_top) if (shift && status == 1)
wp->yoff += 1; wp->yoff += 1;
/* window_pane_resize(wp, lc->sx, lc->sy - shift);
* Layout cells are limited by the smallest size of other cells
* within the same row or column; if this isn't the case
* resizing becomes difficult.
*
* However, panes do not have to take up their entire cell, so
* they can be cropped to the window edge if the layout
* overflows and they are partly visible.
*
* This stops cells being hidden unnecessarily.
*/
/*
* Work out the horizontal size. If the pane is actually
* outside the window or the entire pane is already visible,
* don't crop.
*/
if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx)
sx = lc->sx;
else {
sx = wsx - lc->xoff;
if (sx < 1)
sx = lc->sx;
}
/*
* Similarly for the vertical size; the minimum vertical size
* is two because scroll regions cannot be one line.
*/
if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy)
sy = lc->sy;
else {
sy = wsy - lc->yoff;
if (sy < 2)
sy = lc->sy;
}
if (shift)
sy -= 1;
window_pane_resize(wp, sx, sy);
} }
} }
@@ -349,7 +307,9 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
{ {
struct layout_cell *lcchild; struct layout_cell *lcchild;
u_int available, minimum; u_int available, minimum;
int status;
status = options_get_number(w->options, "pane-border-status");
if (lc->type == LAYOUT_WINDOWPANE) { if (lc->type == LAYOUT_WINDOWPANE) {
/* Space available in this cell only. */ /* Space available in this cell only. */
minimum = PANE_MINIMUM; minimum = PANE_MINIMUM;
@@ -357,9 +317,8 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
available = lc->sx; available = lc->sx;
else { else {
available = lc->sy; available = lc->sy;
minimum += layout_need_status(lc, if (status != 0)
options_get_number(w->options, minimum += layout_need_status(lc, status == 1);
"pane-border-status") == 1);
} }
if (available > minimum) if (available > minimum)
available -= minimum; available -= minimum;
@@ -491,8 +450,7 @@ layout_init(struct window *w, struct window_pane *wp)
lc = w->layout_root = layout_create_cell(NULL); lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, w->sy, 0, 0); layout_set_size(lc, w->sx, w->sy, 0, 0);
layout_make_leaf(lc, wp); layout_make_leaf(lc, wp);
layout_fix_panes(w);
layout_fix_panes(w, w->sx, w->sy);
} }
void void
@@ -521,7 +479,7 @@ layout_resize(struct window *w, u_int sx, u_int sy)
* out proportionately - this should leave the layout fitting the new * out proportionately - this should leave the layout fitting the new
* window size. * window size.
*/ */
xchange = sx - w->sx; xchange = sx - lc->sx;
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT); xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
if (xchange < 0 && xchange < -xlimit) if (xchange < 0 && xchange < -xlimit)
xchange = -xlimit; xchange = -xlimit;
@@ -535,7 +493,7 @@ layout_resize(struct window *w, u_int sx, u_int sy)
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange); layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange);
/* Adjust vertically in a similar fashion. */ /* Adjust vertically in a similar fashion. */
ychange = sy - w->sy; ychange = sy - lc->sy;
ylimit = layout_resize_check(w, lc, LAYOUT_TOPBOTTOM); ylimit = layout_resize_check(w, lc, LAYOUT_TOPBOTTOM);
if (ychange < 0 && ychange < -ylimit) if (ychange < 0 && ychange < -ylimit)
ychange = -ylimit; ychange = -ylimit;
@@ -550,7 +508,7 @@ layout_resize(struct window *w, u_int sx, u_int sy)
/* Fix cell offsets. */ /* Fix cell offsets. */
layout_fix_offsets(lc); layout_fix_offsets(lc);
layout_fix_panes(w, sx, sy); layout_fix_panes(w);
} }
/* Resize a pane to an absolute size. */ /* Resize a pane to an absolute size. */
@@ -610,7 +568,7 @@ layout_resize_layout(struct window *w, struct layout_cell *lc,
/* Fix cell offsets. */ /* Fix cell offsets. */
layout_fix_offsets(w->layout_root); layout_fix_offsets(w->layout_root);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
} }
@@ -717,7 +675,7 @@ void
layout_assign_pane(struct layout_cell *lc, struct window_pane *wp) layout_assign_pane(struct layout_cell *lc, struct window_pane *wp)
{ {
layout_make_leaf(lc, wp); layout_make_leaf(lc, wp);
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy); layout_fix_panes(wp->window);
} }
/* Calculate the new pane size for resized parent. */ /* Calculate the new pane size for resized parent. */
@@ -764,7 +722,7 @@ layout_set_size_check(struct window *w, struct layout_cell *lc,
enum layout_type type, int size) enum layout_type type, int size)
{ {
struct layout_cell *lcchild; struct layout_cell *lcchild;
u_int new_size, available, previous, count, idx; u_int new_size, available, previous, count, idx;
/* Cells with no children must just be bigger than minimum. */ /* Cells with no children must just be bigger than minimum. */
if (lc->type == LAYOUT_WINDOWPANE) if (lc->type == LAYOUT_WINDOWPANE)
@@ -778,6 +736,9 @@ layout_set_size_check(struct window *w, struct layout_cell *lc,
/* Check new size will work for each child. */ /* Check new size will work for each child. */
if (lc->type == type) { if (lc->type == type) {
if (available < (count * 2) - 1)
return (0);
if (type == LAYOUT_LEFTRIGHT) if (type == LAYOUT_LEFTRIGHT)
previous = lc->sx; previous = lc->sx;
else else
@@ -787,13 +748,17 @@ layout_set_size_check(struct window *w, struct layout_cell *lc,
TAILQ_FOREACH(lcchild, &lc->cells, entry) { TAILQ_FOREACH(lcchild, &lc->cells, entry) {
new_size = layout_new_pane_size(w, previous, lcchild, new_size = layout_new_pane_size(w, previous, lcchild,
type, size, count - idx, available); type, size, count - idx, available);
if (new_size > available) if (idx == count - 1) {
return (0); if (new_size > available)
return (0);
available -= (new_size + 1); available -= new_size;
} else {
if (new_size + 1 > available)
return (0);
available -= new_size + 1;
}
if (!layout_set_size_check(w, lcchild, type, new_size)) if (!layout_set_size_check(w, lcchild, type, new_size))
return (0); return (0);
idx++; idx++;
} }
} else { } else {
@@ -869,8 +834,9 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
int insert_before, int full_size) int insert_before, int full_size)
{ {
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2; struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
u_int sx, sy, xoff, yoff, size1, size2; u_int sx, sy, xoff, yoff, size1, size2, minimum;
u_int new_size, saved_size, resize_first = 0; u_int new_size, saved_size, resize_first = 0;
int status;
/* /*
* If full_size is specified, add a new cell at the top of the window * If full_size is specified, add a new cell at the top of the window
@@ -880,6 +846,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
lc = wp->window->layout_root; lc = wp->window->layout_root;
else else
lc = wp->layout_cell; lc = wp->layout_cell;
status = options_get_number(wp->window->options, "pane-border-status");
/* Copy the old cell size. */ /* Copy the old cell size. */
sx = lc->sx; sx = lc->sx;
@@ -894,7 +861,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
return (NULL); return (NULL);
break; break;
case LAYOUT_TOPBOTTOM: case LAYOUT_TOPBOTTOM:
if (sy < PANE_MINIMUM * 2 + 1) minimum = PANE_MINIMUM * 2 + 1;
if (status != 0)
minimum += layout_need_status(lc, status == 1);
if (sy < minimum)
return (NULL); return (NULL);
break; break;
default: default:
@@ -1037,7 +1007,7 @@ layout_close_pane(struct window_pane *wp)
/* Fix pane offsets and sizes. */ /* Fix pane offsets and sizes. */
if (w->layout_root != NULL) { if (w->layout_root != NULL) {
layout_fix_offsets(w->layout_root); layout_fix_offsets(w->layout_root);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
} }
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
} }
@@ -1046,22 +1016,29 @@ int
layout_spread_cell(struct window *w, struct layout_cell *parent) layout_spread_cell(struct window *w, struct layout_cell *parent)
{ {
struct layout_cell *lc; struct layout_cell *lc;
u_int number, each, size; u_int number, each, size, this;
int change, changed; int change, changed, status;
number = 0; number = 0;
TAILQ_FOREACH (lc, &parent->cells, entry) TAILQ_FOREACH (lc, &parent->cells, entry)
number++; number++;
if (number <= 1) if (number <= 1)
return (0); return (0);
status = options_get_number(w->options, "pane-border-status");
if (parent->type == LAYOUT_LEFTRIGHT) if (parent->type == LAYOUT_LEFTRIGHT)
size = parent->sx; size = parent->sx;
else if (parent->type == LAYOUT_TOPBOTTOM) else if (parent->type == LAYOUT_TOPBOTTOM) {
size = parent->sy; size = parent->sy;
else if (status != 0)
size -= layout_need_status(parent, status == 1);
} else
return (0);
if (size < number - 1)
return (0); return (0);
each = (size - (number - 1)) / number; each = (size - (number - 1)) / number;
if (each == 0)
return (0);
changed = 0; changed = 0;
TAILQ_FOREACH (lc, &parent->cells, entry) { TAILQ_FOREACH (lc, &parent->cells, entry) {
@@ -1072,7 +1049,10 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
change = each - (int)lc->sx; change = each - (int)lc->sx;
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change); layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change);
} else if (parent->type == LAYOUT_TOPBOTTOM) { } else if (parent->type == LAYOUT_TOPBOTTOM) {
change = each - (int)lc->sy; this = each;
if (status != 0)
this += layout_need_status(lc, status == 1);
change = this - (int)lc->sy;
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change); layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
} }
if (change != 0) if (change != 0)
@@ -1094,7 +1074,7 @@ layout_spread_out(struct window_pane *wp)
do { do {
if (layout_spread_cell(w, parent)) { if (layout_spread_cell(w, parent)) {
layout_fix_offsets(parent); layout_fix_offsets(parent);
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
break; break;
} }
} while ((parent = parent->parent) != NULL); } while ((parent = parent->parent) != NULL);

View File

@@ -497,7 +497,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
struct options *oo = wp->window->options; struct options *oo = wp->window->options;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct grid_cell gc0, gc; struct grid_cell gc0, gc;
u_int w, h, i, j, sy, box_x, box_y; u_int w, h, i, j, sy, box_x, box_y, width;
char *text, *start, key[7]; char *text, *start, key[7];
const char *tag, *symbol; const char *tag, *symbol;
size_t size, n; size_t size, n;
@@ -530,7 +530,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
line = &mtd->line_list[i]; line = &mtd->line_list[i];
mti = line->item; mti = line->item;
screen_write_cursormove(&ctx, 0, i - mtd->offset); screen_write_cursormove(&ctx, 0, i - mtd->offset, 0);
if (i < 10) if (i < 10)
snprintf(key, sizeof key, "(%c) ", '0' + i); snprintf(key, sizeof key, "(%c) ", '0' + i);
@@ -572,8 +572,9 @@ mode_tree_draw(struct mode_tree_data *mtd)
tag = "*"; tag = "*";
else else
tag = ""; tag = "";
xasprintf(&text, "%-*s%s%s%s: %s", keylen, key, start, xasprintf(&text, "%-*s%s%s%s: ", keylen, key, start, mti->name,
mti->name, tag, mti->text); tag);
width = utf8_cstrwidth(text);
free(start); free(start);
if (mti->tagged) { if (mti->tagged) {
@@ -582,11 +583,13 @@ mode_tree_draw(struct mode_tree_data *mtd)
} }
if (i != mtd->current) { if (i != mtd->current) {
screen_write_nputs(&ctx, w, &gc0, "%s", text);
screen_write_clearendofline(&ctx, 8); screen_write_clearendofline(&ctx, 8);
screen_write_puts(&ctx, &gc0, "%s", text);
format_draw(&ctx, &gc0, w - width, mti->text, NULL);
} else { } else {
screen_write_nputs(&ctx, w, &gc, "%s", text);
screen_write_clearendofline(&ctx, gc.bg); screen_write_clearendofline(&ctx, gc.bg);
screen_write_puts(&ctx, &gc, "%s", text);
format_draw(&ctx, &gc, w - width, mti->text, NULL);
} }
free(text); free(text);
@@ -605,13 +608,13 @@ mode_tree_draw(struct mode_tree_data *mtd)
line = &mtd->line_list[mtd->current]; line = &mtd->line_list[mtd->current];
mti = line->item; mti = line->item;
screen_write_cursormove(&ctx, 0, h); screen_write_cursormove(&ctx, 0, h, 0);
screen_write_box(&ctx, w, sy - h); screen_write_box(&ctx, w, sy - h);
xasprintf(&text, " %s (sort: %s)", mti->name, xasprintf(&text, " %s (sort: %s)", mti->name,
mtd->sort_list[mtd->sort_type]); mtd->sort_list[mtd->sort_type]);
if (w - 2 >= strlen(text)) { if (w - 2 >= strlen(text)) {
screen_write_cursormove(&ctx, 1, h); screen_write_cursormove(&ctx, 1, h, 0);
screen_write_puts(&ctx, &gc0, "%s", text); screen_write_puts(&ctx, &gc0, "%s", text);
if (mtd->no_matches) if (mtd->no_matches)
@@ -633,7 +636,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
box_y = sy - h - 2; box_y = sy - h - 2;
if (box_x != 0 && box_y != 0) { if (box_x != 0 && box_y != 0) {
screen_write_cursormove(&ctx, 2, h + 1); screen_write_cursormove(&ctx, 2, h + 1, 0);
mtd->drawcb(mtd->modedata, mti->itemdata, &ctx, box_x, box_y); mtd->drawcb(mtd->modedata, mti->itemdata, &ctx, box_x, box_y);
} }

View File

@@ -38,6 +38,9 @@ static const char *options_table_mode_keys_list[] = {
static const char *options_table_clock_mode_style_list[] = { static const char *options_table_clock_mode_style_list[] = {
"12", "24", NULL "12", "24", NULL
}; };
static const char *options_table_status_list[] = {
"off", "on", "2", "3", "4", "5", NULL
};
static const char *options_table_status_keys_list[] = { static const char *options_table_status_keys_list[] = {
"emacs", "vi", NULL "emacs", "vi", NULL
}; };
@@ -59,6 +62,72 @@ static const char *options_table_pane_status_list[] = {
static const char *options_table_set_clipboard_list[] = { static const char *options_table_set_clipboard_list[] = {
"off", "external", "on", NULL "off", "external", "on", NULL
}; };
static const char *options_table_window_size_list[] = {
"largest", "smallest", "manual", NULL
};
/* Status line format. */
#define OPTIONS_TABLE_STATUS_FORMAT1 \
"#[align=left range=left #{status-left-style}]" \
"#{T;=/#{status-left-length}:status-left}#[norange default]" \
"#[list=on align=#{status-justify}]" \
"#[list=left-marker]<#[list=right-marker]>#[list=on]" \
"#{W:" \
"#[range=window|#{window_index} " \
"#{window-status-style}" \
"#{?#{&&:#{window_last_flag}," \
"#{!=:#{window-status-last-style},default}}, " \
"#{window-status-last-style}," \
"}" \
"#{?#{&&:#{window_bell_flag}," \
"#{!=:#{window-status-bell-style},default}}, " \
"#{window-status-bell-style}," \
"#{?#{&&:#{||:#{window_activity_flag}," \
"#{window_silence_flag}}," \
"#{!=:" \
"#{window-status-activity-style}," \
"default}}, " \
"#{window-status-activity-style}," \
"}" \
"}" \
"]" \
"#{T:window-status-format}" \
"#[norange default]" \
"#{?window_end_flag,,#{window-status-separator}}" \
"," \
"#[range=window|#{window_index} list=focus " \
"#{?#{!=:#{window-status-current-style},default}," \
"#{window-status-current-style}," \
"#{window-status-style}" \
"}" \
"#{?#{&&:#{window_last_flag}," \
"#{!=:#{window-status-last-style},default}}, " \
"#{window-status-last-style}," \
"}" \
"#{?#{&&:#{window_bell_flag}," \
"#{!=:#{window-status-bell-style},default}}, " \
"#{window-status-bell-style}," \
"#{?#{&&:#{||:#{window_activity_flag}," \
"#{window_silence_flag}}," \
"#{!=:" \
"#{window-status-activity-style}," \
"default}}, " \
"#{window-status-activity-style}," \
"}" \
"}" \
"]" \
"#{T:window-status-current-format}" \
"#[norange list=on default]" \
"#{?window_end_flag,,#{window-status-separator}}" \
"}" \
"#[nolist align=right range=right #{status-right-style}]" \
"#{T;=/#{status-right-length}:status-right}#[norange default]"
#define OPTIONS_TABLE_STATUS_FORMAT2 \
"#[align=centre]#{P:#{?pane_active,#[reverse],}" \
"#{pane_index}[#{pane_width}x#{pane_height}]#[default] }"
static const char *options_table_status_format_default[] = {
OPTIONS_TABLE_STATUS_FORMAT1, OPTIONS_TABLE_STATUS_FORMAT2, NULL
};
/* Top-level options. */ /* Top-level options. */
const struct options_table_entry options_table[] = { const struct options_table_entry options_table[] = {
@@ -193,6 +262,13 @@ const struct options_table_entry options_table[] = {
.default_str = _PATH_BSHELL .default_str = _PATH_BSHELL
}, },
{ .name = "default-size",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.pattern = "[0-9]*x[0-9]*",
.default_str = "80x24"
},
{ .name = "destroy-unattached", { .name = "destroy-unattached",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
@@ -261,54 +337,12 @@ const struct options_table_entry options_table[] = {
.default_str = "lock -np" .default_str = "lock -np"
}, },
{ .name = "message-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0,
.style = "message-style"
},
{ .name = "message-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 3,
.style = "message-style"
},
{ .name = "message-command-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0,
.style = "message-command-style"
},
{ .name = "message-command-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0,
.style = "message-command-style"
},
{ .name = "message-command-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 3,
.style = "message-command-style"
},
{ .name = "message-command-style", { .name = "message-command-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=black,fg=yellow" .default_str = "bg=black,fg=yellow"
}, },
{ .name = "message-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0,
.style = "message-style"
},
{ .name = "message-style", { .name = "message-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
@@ -367,30 +401,28 @@ const struct options_table_entry options_table[] = {
}, },
{ .name = "status", { .name = "status",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.choices = options_table_status_list,
.default_num = 1 .default_num = 1
}, },
{ .name = "status-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0,
.style = "status-style"
},
{ .name = "status-bg", { .name = "status-bg",
.type = OPTIONS_TABLE_COLOUR, .type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_num = 2, .default_num = 2,
.style = "status-style"
}, },
{ .name = "status-fg", { .name = "status-fg",
.type = OPTIONS_TABLE_COLOUR, .type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_num = 0, .default_num = 0,
.style = "status-style" },
{ .name = "status-format",
.type = OPTIONS_TABLE_ARRAY,
.scope = OPTIONS_TABLE_SESSION,
.default_arr = options_table_status_format_default,
}, },
{ .name = "status-interval", { .name = "status-interval",
@@ -421,27 +453,6 @@ const struct options_table_entry options_table[] = {
.default_str = "[#S] " .default_str = "[#S] "
}, },
{ .name = "status-left-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0,
.style = "status-left-style"
},
{ .name = "status-left-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 8,
.style = "status-left-style"
},
{ .name = "status-left-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 8,
.style = "status-left-style"
},
{ .name = "status-left-length", { .name = "status-left-length",
.type = OPTIONS_TABLE_NUMBER, .type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
@@ -466,28 +477,9 @@ const struct options_table_entry options_table[] = {
{ .name = "status-right", { .name = "status-right",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_str = " \"#{=21:pane_title}\" %H:%M %d-%b-%y" .default_str = "#{?window_bigger,"
}, "[#{window_offset_x}#,#{window_offset_y}] ,}"
"\"#{=21:pane_title}\" %H:%M %d-%b-%y"
{ .name = "status-right-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0,
.style = "status-right-style"
},
{ .name = "status-right-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 8,
.style = "status-right-style"
},
{ .name = "status-right-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 8,
.style = "status-right-style"
}, },
{ .name = "status-right-length", { .name = "status-right-length",
@@ -588,22 +580,6 @@ const struct options_table_entry options_table[] = {
.default_num = 1 .default_num = 1
}, },
{ .name = "force-height",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_WINDOW,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 0
},
{ .name = "force-width",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_WINDOW,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 0
},
{ .name = "main-pane-height", { .name = "main-pane-height",
.type = OPTIONS_TABLE_NUMBER, .type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@@ -620,27 +596,6 @@ const struct options_table_entry options_table[] = {
.default_num = 80 .default_num = 80
}, },
{ .name = "mode-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0,
.style = "mode-style"
},
{ .name = "mode-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 3,
.style = "mode-style"
},
{ .name = "mode-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0,
.style = "mode-style"
},
{ .name = "mode-keys", { .name = "mode-keys",
.type = OPTIONS_TABLE_CHOICE, .type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@@ -690,20 +645,6 @@ const struct options_table_entry options_table[] = {
.default_num = 0 .default_num = 0
}, },
{ .name = "pane-active-border-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "pane-active-border-style"
},
{ .name = "pane-active-border-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 2,
.style = "pane-active-border-style"
},
{ .name = "pane-active-border-style", { .name = "pane-active-border-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@@ -718,20 +659,6 @@ const struct options_table_entry options_table[] = {
.default_num = 0 .default_num = 0
}, },
{ .name = "pane-border-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "pane-border-style"
},
{ .name = "pane-border-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "pane-border-style"
},
{ .name = "pane-border-format", { .name = "pane-border-format",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@@ -770,101 +697,31 @@ const struct options_table_entry options_table[] = {
.default_str = "default" .default_str = "default"
}, },
{ .name = "window-size",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_window_size_list,
.default_num = WINDOW_SIZE_SMALLEST
},
{ .name = "window-style", { .name = "window-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
.default_str = "default" .default_str = "default"
}, },
{ .name = "window-status-activity-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = GRID_ATTR_REVERSE,
.style = "window-status-activity-style"
},
{ .name = "window-status-activity-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-activity-style"
},
{ .name = "window-status-activity-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-activity-style"
},
{ .name = "window-status-activity-style", { .name = "window-status-activity-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
.default_str = "reverse" .default_str = "reverse"
}, },
{ .name = "window-status-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0,
.style = "window-status-style"
},
{ .name = "window-status-bell-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = GRID_ATTR_REVERSE,
.style = "window-status-bell-style"
},
{ .name = "window-status-bell-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-bell-style"
},
{ .name = "window-status-bell-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-bell-style"
},
{ .name = "window-status-bell-style", { .name = "window-status-bell-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
.default_str = "reverse" .default_str = "reverse"
}, },
{ .name = "window-status-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-style"
},
{ .name = "window-status-current-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0,
.style = "window-status-current-style"
},
{ .name = "window-status-current-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-current-style"
},
{ .name = "window-status-current-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-current-style"
},
{ .name = "window-status-current-format", { .name = "window-status-current-format",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@@ -877,40 +734,12 @@ const struct options_table_entry options_table[] = {
.default_str = "default" .default_str = "default"
}, },
{ .name = "window-status-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-style"
},
{ .name = "window-status-format", { .name = "window-status-format",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
.default_str = "#I:#W#{?window_flags,#{window_flags}, }" .default_str = "#I:#W#{?window_flags,#{window_flags}, }"
}, },
{ .name = "window-status-last-attr",
.type = OPTIONS_TABLE_ATTRIBUTES,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0,
.style = "window-status-last-style"
},
{ .name = "window-status-last-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-last-style"
},
{ .name = "window-status-last-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 8,
.style = "window-status-last-style"
},
{ .name = "window-status-last-style", { .name = "window-status-last-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,

238
options.c
View File

@@ -30,6 +30,23 @@
* a red-black tree. * a red-black tree.
*/ */
struct options_array_item {
u_int index;
char *value;
RB_ENTRY(options_array_item) entry;
};
RB_HEAD(options_array, options_array_item);
static int
options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
{
if (a1->index < a2->index)
return (-1);
if (a1->index > a2->index)
return (1);
return (0);
}
RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp);
struct options_entry { struct options_entry {
struct options *owner; struct options *owner;
@@ -39,11 +56,8 @@ struct options_entry {
union { union {
char *string; char *string;
long long number; long long number;
struct grid_cell style; struct style style;
struct { struct options_array array;
const char **array;
u_int arraysize;
};
}; };
RB_ENTRY(options_entry) entry; RB_ENTRY(options_entry) entry;
@@ -56,8 +70,6 @@ struct options {
static struct options_entry *options_add(struct options *, const char *); static struct options_entry *options_add(struct options *, const char *);
#define OPTIONS_ARRAY_LIMIT 1000
#define OPTIONS_IS_STRING(o) \ #define OPTIONS_IS_STRING(o) \
((o)->tableentry == NULL || \ ((o)->tableentry == NULL || \
(o)->tableentry->type == OPTIONS_TABLE_STRING) (o)->tableentry->type == OPTIONS_TABLE_STRING)
@@ -66,7 +78,6 @@ static struct options_entry *options_add(struct options *, const char *);
((o)->tableentry->type == OPTIONS_TABLE_NUMBER || \ ((o)->tableentry->type == OPTIONS_TABLE_NUMBER || \
(o)->tableentry->type == OPTIONS_TABLE_KEY || \ (o)->tableentry->type == OPTIONS_TABLE_KEY || \
(o)->tableentry->type == OPTIONS_TABLE_COLOUR || \ (o)->tableentry->type == OPTIONS_TABLE_COLOUR || \
(o)->tableentry->type == OPTIONS_TABLE_ATTRIBUTES || \
(o)->tableentry->type == OPTIONS_TABLE_FLAG || \ (o)->tableentry->type == OPTIONS_TABLE_FLAG || \
(o)->tableentry->type == OPTIONS_TABLE_CHOICE)) (o)->tableentry->type == OPTIONS_TABLE_CHOICE))
#define OPTIONS_IS_STYLE(o) \ #define OPTIONS_IS_STYLE(o) \
@@ -163,22 +174,30 @@ options_empty(struct options *oo, const struct options_table_entry *oe)
o = options_add(oo, oe->name); o = options_add(oo, oe->name);
o->tableentry = oe; o->tableentry = oe;
if (oe->type == OPTIONS_TABLE_ARRAY)
RB_INIT(&o->array);
return (o); return (o);
} }
struct options_entry * struct options_entry *
options_default(struct options *oo, const struct options_table_entry *oe) options_default(struct options *oo, const struct options_table_entry *oe)
{ {
struct options_entry *o; struct options_entry *o;
u_int i;
o = options_empty(oo, oe); o = options_empty(oo, oe);
if (oe->type == OPTIONS_TABLE_ARRAY) if (oe->type == OPTIONS_TABLE_ARRAY) {
options_array_assign(o, oe->default_str); if (oe->default_arr != NULL) {
else if (oe->type == OPTIONS_TABLE_STRING) for (i = 0; oe->default_arr[i] != NULL; i++)
options_array_set(o, i, oe->default_arr[i], 0);
} else
options_array_assign(o, oe->default_str);
} else if (oe->type == OPTIONS_TABLE_STRING)
o->string = xstrdup(oe->default_str); o->string = xstrdup(oe->default_str);
else if (oe->type == OPTIONS_TABLE_STYLE) { else if (oe->type == OPTIONS_TABLE_STYLE) {
memcpy(&o->style, &grid_default_cell, sizeof o->style); style_set(&o->style, &grid_default_cell);
style_parse(&grid_default_cell, &o->style, oe->default_str); style_parse(&o->style, &grid_default_cell, oe->default_str);
} else } else
o->number = oe->default_num; o->number = oe->default_num;
return (o); return (o);
@@ -205,15 +224,11 @@ void
options_remove(struct options_entry *o) options_remove(struct options_entry *o)
{ {
struct options *oo = o->owner; struct options *oo = o->owner;
u_int i;
if (OPTIONS_IS_STRING(o)) if (OPTIONS_IS_STRING(o))
free((void *)o->string); free(o->string);
else if (OPTIONS_IS_ARRAY(o)) { else if (OPTIONS_IS_ARRAY(o))
for (i = 0; i < o->arraysize; i++) options_array_clear(o);
free((void *)o->array[i]);
free(o->array);
}
RB_REMOVE(options_tree, &oo->tree, o); RB_REMOVE(options_tree, &oo->tree, o);
free(o); free(o);
@@ -231,62 +246,79 @@ options_table_entry(struct options_entry *o)
return (o->tableentry); return (o->tableentry);
} }
static struct options_array_item *
options_array_item(struct options_entry *o, u_int idx)
{
struct options_array_item a;
a.index = idx;
return (RB_FIND(options_array, &o->array, &a));
}
static void
options_array_free(struct options_entry *o, struct options_array_item *a)
{
free(a->value);
RB_REMOVE(options_array, &o->array, a);
free(a);
}
void void
options_array_clear(struct options_entry *o) options_array_clear(struct options_entry *o)
{ {
if (OPTIONS_IS_ARRAY(o)) struct options_array_item *a, *a1;
o->arraysize = 0;
if (!OPTIONS_IS_ARRAY(o))
return;
RB_FOREACH_SAFE(a, options_array, &o->array, a1)
options_array_free(o, a);
} }
const char * const char *
options_array_get(struct options_entry *o, u_int idx) options_array_get(struct options_entry *o, u_int idx)
{ {
struct options_array_item *a;
if (!OPTIONS_IS_ARRAY(o)) if (!OPTIONS_IS_ARRAY(o))
return (NULL); return (NULL);
if (idx >= o->arraysize) a = options_array_item(o, idx);
if (a == NULL)
return (NULL); return (NULL);
return (o->array[idx]); return (a->value);
} }
int int
options_array_set(struct options_entry *o, u_int idx, const char *value, options_array_set(struct options_entry *o, u_int idx, const char *value,
int append) int append)
{ {
char *new; struct options_array_item *a;
u_int i; char *new;
if (!OPTIONS_IS_ARRAY(o)) if (!OPTIONS_IS_ARRAY(o))
return (-1); return (-1);
if (idx >= OPTIONS_ARRAY_LIMIT) a = options_array_item(o, idx);
return (-1); if (value == NULL) {
if (idx >= o->arraysize) { if (a != NULL)
o->array = xreallocarray(o->array, idx + 1, sizeof *o->array); options_array_free(o, a);
for (i = o->arraysize; i < idx + 1; i++) return (0);
o->array[i] = NULL;
o->arraysize = idx + 1;
} }
new = NULL; if (a == NULL) {
if (value != NULL) { a = xcalloc(1, sizeof *a);
if (o->array[idx] != NULL && append) a->index = idx;
xasprintf(&new, "%s%s", o->array[idx], value); a->value = xstrdup(value);
RB_INSERT(options_array, &o->array, a);
} else {
free(a->value);
if (a != NULL && append)
xasprintf(&new, "%s%s", a->value, value);
else else
new = xstrdup(value); new = xstrdup(value);
a->value = new;
} }
free((void *)o->array[idx]);
o->array[idx] = new;
return (0);
}
int
options_array_size(struct options_entry *o, u_int *size)
{
if (!OPTIONS_IS_ARRAY(o))
return (-1);
if (size != NULL)
*size = o->arraysize;
return (0); return (0);
} }
@@ -305,37 +337,69 @@ options_array_assign(struct options_entry *o, const char *s)
while ((next = strsep(&string, separator)) != NULL) { while ((next = strsep(&string, separator)) != NULL) {
if (*next == '\0') if (*next == '\0')
continue; continue;
for (i = 0; i < OPTIONS_ARRAY_LIMIT; i++) { for (i = 0; i < UINT_MAX; i++) {
if (i >= o->arraysize || o->array[i] == NULL) if (options_array_item(o, i) == NULL)
break; break;
} }
if (i == OPTIONS_ARRAY_LIMIT) if (i == UINT_MAX)
break; break;
options_array_set(o, i, next, 0); options_array_set(o, i, next, 0);
} }
free(copy); free(copy);
} }
struct options_array_item *
options_array_first(struct options_entry *o)
{
if (!OPTIONS_IS_ARRAY(o))
return (NULL);
return (RB_MIN(options_array, &o->array));
}
struct options_array_item *
options_array_next(struct options_array_item *a)
{
return (RB_NEXT(options_array, &o->array, a));
}
u_int
options_array_item_index(struct options_array_item *a)
{
return (a->index);
}
const char *
options_array_item_value(struct options_array_item *a)
{
return (a->value);
}
int
options_isarray(struct options_entry *o)
{
return (OPTIONS_IS_ARRAY(o));
}
int int
options_isstring(struct options_entry *o) options_isstring(struct options_entry *o)
{ {
if (o->tableentry == NULL)
return (1);
return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o)); return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o));
} }
const char * const char *
options_tostring(struct options_entry *o, int idx, int numeric) options_tostring(struct options_entry *o, int idx, int numeric)
{ {
static char s[1024]; static char s[1024];
const char *tmp; const char *tmp;
struct options_array_item *a;
if (OPTIONS_IS_ARRAY(o)) { if (OPTIONS_IS_ARRAY(o)) {
if (idx == -1) if (idx == -1)
return (NULL); return (NULL);
if ((u_int)idx >= o->arraysize || o->array[idx] == NULL) a = options_array_item(o, idx);
if (a == NULL)
return (""); return ("");
return (o->array[idx]); return (a->value);
} }
if (OPTIONS_IS_STYLE(o)) if (OPTIONS_IS_STYLE(o))
return (style_tostring(&o->style)); return (style_tostring(&o->style));
@@ -351,9 +415,6 @@ options_tostring(struct options_entry *o, int idx, int numeric)
case OPTIONS_TABLE_COLOUR: case OPTIONS_TABLE_COLOUR:
tmp = colour_tostring(o->number); tmp = colour_tostring(o->number);
break; break;
case OPTIONS_TABLE_ATTRIBUTES:
tmp = attributes_tostring(o->number);
break;
case OPTIONS_TABLE_FLAG: case OPTIONS_TABLE_FLAG:
if (numeric) if (numeric)
xsnprintf(s, sizeof s, "%lld", o->number); xsnprintf(s, sizeof s, "%lld", o->number);
@@ -504,7 +565,7 @@ options_get_number(struct options *oo, const char *name)
return (o->number); return (o->number);
} }
const struct grid_cell * struct style *
options_get_style(struct options *oo, const char *name) options_get_style(struct options *oo, const char *name)
{ {
struct options_entry *o; struct options_entry *o;
@@ -576,17 +637,17 @@ options_set_style(struct options *oo, const char *name, int append,
const char *value) const char *value)
{ {
struct options_entry *o; struct options_entry *o;
struct grid_cell gc; struct style sy;
if (*name == '@') if (*name == '@')
fatalx("user option %s must be a string", name); fatalx("user option %s must be a string", name);
o = options_get_only(oo, name); o = options_get_only(oo, name);
if (o != NULL && append && OPTIONS_IS_STYLE(o)) if (o != NULL && append && OPTIONS_IS_STYLE(o))
memcpy(&gc, &o->style, sizeof gc); style_copy(&sy, &o->style);
else else
memcpy(&gc, &grid_default_cell, sizeof gc); style_set(&sy, &grid_default_cell);
if (style_parse(&grid_default_cell, &gc, value) == -1) if (style_parse(&sy, &grid_default_cell, value) == -1)
return (NULL); return (NULL);
if (o == NULL) { if (o == NULL) {
o = options_default(oo, options_parent_table_entry(oo, name)); o = options_default(oo, options_parent_table_entry(oo, name));
@@ -596,7 +657,7 @@ options_set_style(struct options *oo, const char *name, int append,
if (!OPTIONS_IS_STYLE(o)) if (!OPTIONS_IS_STYLE(o))
fatalx("option %s is not a style", name); fatalx("option %s is not a style", name);
memcpy(&o->style, &gc, sizeof o->style); style_copy(&o->style, &sy);
return (o); return (o);
} }
@@ -643,44 +704,3 @@ options_scope_from_flags(struct args *args, int window,
return (OPTIONS_TABLE_SESSION); return (OPTIONS_TABLE_SESSION);
} }
} }
void
options_style_update_new(struct options *oo, struct options_entry *o)
{
const char *newname = o->tableentry->style;
struct options_entry *new;
if (newname == NULL)
return;
new = options_get_only(oo, newname);
if (new == NULL)
new = options_set_style(oo, newname, 0, "default");
if (strstr(o->name, "-bg") != NULL)
new->style.bg = o->number;
else if (strstr(o->name, "-fg") != NULL)
new->style.fg = o->number;
else if (strstr(o->name, "-attr") != NULL)
new->style.attr = o->number;
}
void
options_style_update_old(struct options *oo, struct options_entry *o)
{
char newname[128];
int size;
size = strrchr(o->name, '-') - o->name;
xsnprintf(newname, sizeof newname, "%.*s-bg", size, o->name);
if (options_get(oo, newname) != NULL)
options_set_number(oo, newname, o->style.bg);
xsnprintf(newname, sizeof newname, "%.*s-fg", size, o->name);
if (options_get(oo, newname) != NULL)
options_set_number(oo, newname, o->style.fg);
xsnprintf(newname, sizeof newname, "%.*s-attr", size, o->name);
if (options_get(oo, newname) != NULL)
options_set_number(oo, newname, o->style.attr);
}

View File

@@ -31,6 +31,8 @@
#include <unistd.h> #include <unistd.h>
#include <libutil.h> #include <libutil.h>
#include "compat.h"
struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *); struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
char *osdep_get_name(int, char *); char *osdep_get_name(int, char *);
char *osdep_get_cwd(int); char *osdep_get_cwd(int);

View File

@@ -23,14 +23,17 @@
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
#include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h"
#define is_runnable(p) \ #define is_runnable(p) \
((p)->p_stat == LSRUN || (p)->p_stat == SIDL) ((p)->p_stat == LSRUN || (p)->p_stat == SIDL)
#define is_stopped(p) \ #define is_stopped(p) \
((p)->p_stat == SSTOP || (p)->p_stat == SZOMB) ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB)
struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *); struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *);
char *osdep_get_name(int, char *); char *osdep_get_name(int, char *);
@@ -129,6 +132,22 @@ error:
char * char *
osdep_get_cwd(int fd) osdep_get_cwd(int fd)
{ {
static char target[PATH_MAX + 1];
char *path;
pid_t pgrp;
ssize_t n;
if ((pgrp = tcgetpgrp(fd)) == -1)
return (NULL);
xasprintf(&path, "/proc/%lld/cwd", (long long) pgrp);
n = readlink(path, target, sizeof(target) - 1);
free(path);
if (n > 0) {
target[n] = '\0';
return (target);
}
return (NULL); return (NULL);
} }

View File

@@ -7,3 +7,4 @@ all: $(TESTS)
$(TESTS): $(TESTS):
sh $*.sh sh $*.sh
sleep 1

View File

@@ -13,37 +13,37 @@ $TMUX kill-server 2>/dev/null
TMP=$(mktemp) TMP=$(mktemp)
OUT=$(mktemp) OUT=$(mktemp)
#trap "rm -f $TMP $OUT" 0 1 15 trap "rm -f $TMP $OUT" 0 1 15
$TMUX -f/dev/null new -d || exit 1 $TMUX -f/dev/null new -d || exit 1
sleep 1 sleep 1
cat <<EOF|$TMUX -C a >$TMP cat <<EOF|$TMUX -C a >$TMP
ls -F':#{session_width} #{session_height}' ls -F':#{window_width} #{window_height}'
refresh -C 100,50 refresh -C 100,50
ls -F':#{session_width} #{session_height}' ls -F':#{window_width} #{window_height}'
EOF EOF
grep ^: $TMP >$OUT grep ^: $TMP >$OUT
printf ":80 24\n:100 50\n"|cmp -s $OUT - || exit 1 printf ":80 24\n:100 49\n"|cmp -s $OUT - || exit 1
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX -f/dev/null new -d || exit 1 $TMUX -f/dev/null new -d || exit 1
sleep 1 sleep 1
cat <<EOF|$TMUX -C a >$TMP cat <<EOF|$TMUX -f/dev/null -C a >$TMP
ls -F':#{session_width} #{session_height}' ls -F':#{window_width} #{window_height}'
refresh -C 80,24 refresh -C 80,24
ls -F':#{session_width} #{session_height}' ls -F':#{window_width} #{window_height}'
EOF EOF
grep ^: $TMP >$OUT grep ^: $TMP >$OUT
printf ":80 24\n:80 24\n"|cmp -s $OUT - || exit 1 printf ":80 24\n:80 23\n"|cmp -s $OUT - || exit 1
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
cat <<EOF|$TMUX -C new -x 100 -y 50 >$TMP cat <<EOF|$TMUX -f/dev/null -C new -x 100 -y 50 >$TMP
ls -F':#{session_width} #{session_height}' ls -F':#{window_width} #{window_height}'
refresh -C 80,24 refresh -C 80,24
ls -F':#{session_width} #{session_height}' ls -F':#{window_width} #{window_height}'
EOF EOF
grep ^: $TMP >$OUT grep ^: $TMP >$OUT
printf ":100 50\n:80 24\n"|cmp -s $OUT - || exit 1 printf ":100 50\n:80 23\n"|cmp -s $OUT - || exit 1
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
exit 0 exit 0

6
regress/cursor-test.txt Normal file
View File

@@ -0,0 +1,6 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.

View File

@@ -0,0 +1,33 @@
14 8 t
0 ud exercitation ullamco laboris nisi ut
1 aliquip ex ea
2 commodo consequat. Duis aute
3 irure dolor in reprehenderit in voluptat
4 e velit esse cillum dolore eu fugiat
5 nulla pariatur. Excepteur sint occaecat
6 cupidatat non proident, sunt in culpa qu
7 i officia
8 deserunt mollit anim id est laborum.
9
4 6 t
0 cupidatat
1 non proide
2 nt, sunt i
3 n culpa qu
4 i officia
5 deserunt m
6 ollit anim
7 id est la
8 borum.
9
14 8 t
0 incididunt ut labore et dolore magna aliqua. Ut en
1 im ad minim veniam, quis nostrud exercitation ulla
2 mco laboris nisi ut aliquip ex ea
3 commodo consequat. Duis aute
4 irure dolor in reprehenderit in voluptate velit es
5 se cillum dolore eu fugiat
6 nulla pariatur. Excepteur sint occaecat cupidatat
7 non proident, sunt in culpa qui officia
8 deserunt mollit anim id est laborum.
9

29
regress/cursor-test1.sh Normal file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -f/dev/null -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
$TMUX -f/dev/null new -d -x40 -y10 \
"cat cursor-test.txt; printf '\e[9;15H'; cat" || exit 1
$TMUX set -g window-size manual || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x10 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x50 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
cmp -s $TMP cursor-test1.result || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,33 @@
9 7 a
0 cupidatat
1 non proide
2 nt, sunt i
3 n culpa qu
4 i officia
5 deserunt m
6 ollit anim
7 id est la
8 borum.
9
4 6 a
0 icia
1 deser
2 unt m
3 ollit
4 anim
5 id e
6 st la
7 borum
8 .
9
29 8 a
0 incididunt ut labore et dolore magna aliqua. Ut en
1 im ad minim veniam, quis nostrud exercitation ulla
2 mco laboris nisi ut aliquip ex ea
3 commodo consequat. Duis aute
4 irure dolor in reprehenderit in voluptate velit es
5 se cillum dolore eu fugiat
6 nulla pariatur. Excepteur sint occaecat cupidatat
7 non proident, sunt in culpa qui officia
8 deserunt mollit anim id est laborum.
9

29
regress/cursor-test2.sh Normal file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
$TMUX -f/dev/null new -d -x10 -y10 \
"cat cursor-test.txt; printf '\e[8;10H'; cat" || exit 1
$TMUX set -g window-size manual || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x5 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x50 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
cmp -s $TMP cursor-test2.result || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,9 @@
6 1 b
0 abcdefa
1 bcdefab
3 1 b
0 fabcd
1 efab
6 1 b
0 abcdefa
1 bcdefab

29
regress/cursor-test3.sh Normal file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
$TMUX -f/dev/null new -d -x7 -y2 \
"printf 'abcdefabcdefab'; printf '\e[2;7H'; cat" || exit 1
$TMUX set -g window-size manual || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x5 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x7 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
cmp -s $TMP cursor-test3.result || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -0,0 +1,16 @@
0 1
0 abcdef
1
2
0 1
0 abcdef
1
2
0 1
0 def
1
2
0 1
0 abcdef
1
2

31
regress/cursor-test4.sh Normal file
View File

@@ -0,0 +1,31 @@
#!/bin/sh
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
$TMUX -f/dev/null new -d -x10 -y3 "printf 'abcdef\n'; cat" || exit 1
$TMUX set -g window-size manual || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x20 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x3 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
$TMUX resizew -x10 || exit 1
$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
cmp -s $TMP cursor-test4.result || exit 1
$TMUX kill-server 2>/dev/null
exit 0

View File

@@ -9,9 +9,9 @@ TERM=screen
TMUX="$TEST_TMUX -Ltest" TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX new -d 'sleep 1000' || exit 1 $TMUX -f/dev/null new -d 'sleep 1000' || exit 1
P=$($TMUX display -pt0:0.0 '#{pane_pid}') P=$($TMUX display -pt0:0.0 '#{pane_pid}')
$TMUX new -d || exit 1 $TMUX -f/dev/null new -d || exit 1
sleep 1 sleep 1
$TMUX kill-session -t0: $TMUX kill-session -t0:
sleep 1 sleep 1

View File

@@ -14,13 +14,13 @@ trap "rm -f $TMP" 0 1 15
$TMUX -f/dev/null new -d </dev/null || exit 1 $TMUX -f/dev/null new -d </dev/null || exit 1
sleep 1 sleep 1
$TMUX ls -F "#{session_width} #{session_height}" >$TMP $TMUX ls -F "#{window_width} #{window_height}" >$TMP
printf "80 24\n"|cmp -s $TMP - || exit 1 printf "80 24\n"|cmp -s $TMP - || exit 1
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX -f/dev/null new -d -x 100 -y 50 </dev/null || exit 1 $TMUX -f/dev/null new -d -x 100 -y 50 </dev/null || exit 1
sleep 1 sleep 1
$TMUX ls -F "#{session_width} #{session_height}" >$TMP $TMUX ls -F "#{window_width} #{window_height}" >$TMP
printf "100 50\n"|cmp -s $TMP - || exit 1 printf "100 50\n"|cmp -s $TMP - || exit 1
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null

341
resize.c
View File

@@ -22,151 +22,234 @@
#include "tmux.h" #include "tmux.h"
/* void
* Recalculate window and session sizes. resize_window(struct window *w, u_int sx, u_int sy)
* {
* Every session has the size of the smallest client it is attached to and int zoomed;
* every window the size of the smallest session it is attached to.
* /* Check size limits. */
* So, when a client is resized or a session attached to or detached from a if (sx < WINDOW_MINIMUM)
* client, the window sizes must be recalculated. For each session, find the sx = WINDOW_MINIMUM;
* smallest client it is attached to, and resize it to that size. Then for if (sx > WINDOW_MAXIMUM)
* every window, find the smallest session it is attached to, resize it to that sx = WINDOW_MAXIMUM;
* size and clear and redraw every client with it as the current window. if (sy < WINDOW_MINIMUM)
* sy = WINDOW_MINIMUM;
* This is quite inefficient - better/additional data structures are needed if (sy > WINDOW_MAXIMUM)
* to make it better. sy = WINDOW_MAXIMUM;
*
* As a side effect, this function updates the SESSION_UNATTACHED flag. This /* If the window is zoomed, unzoom. */
* flag is necessary to make sure unattached sessions do not limit the size of zoomed = w->flags & WINDOW_ZOOMED;
* windows that are attached both to them and to other (attached) sessions. if (zoomed)
*/ window_unzoom(w);
/* Resize the layout first. */
layout_resize(w, sx, sy);
/* Resize the window, it can be no smaller than the layout. */
if (sx < w->layout_root->sx)
sx = w->layout_root->sx;
if (sy < w->layout_root->sy)
sy = w->layout_root->sy;
window_resize(w, sx, sy);
log_debug("%s: @%u resized to %u,%u; layout %u,%u", __func__, w->id,
sx, sy, w->layout_root->sx, w->layout_root->sy);
/* Restore the window zoom state. */
if (zoomed)
window_zoom(w->active);
tty_update_window_offset(w);
server_redraw_window(w);
notify_window("window-layout-changed", w);
}
static int
ignore_client_size(struct client *c)
{
if (c->session == NULL)
return (1);
if (c->flags & CLIENT_NOSIZEFLAGS)
return (1);
if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED))
return (1);
return (0);
}
void
default_window_size(struct session *s, struct window *w, u_int *sx, u_int *sy,
int type)
{
struct client *c;
u_int cx, cy;
const char *value;
if (type == -1)
type = options_get_number(global_w_options, "window-size");
if (type == WINDOW_SIZE_MANUAL)
goto manual;
if (type == WINDOW_SIZE_LARGEST) {
*sx = *sy = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
if (w != NULL && !session_has(c->session, w))
continue;
if (w == NULL && c->session != s)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx > *sx)
*sx = cx;
if (cy > *sy)
*sy = cy;
}
if (*sx == 0 || *sy == 0)
goto manual;
} else {
*sx = *sy = UINT_MAX;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
if (w != NULL && !session_has(c->session, w))
continue;
if (w == NULL && c->session != s)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx < *sx)
*sx = cx;
if (cy < *sy)
*sy = cy;
}
if (*sx == UINT_MAX || *sy == UINT_MAX)
goto manual;
}
goto done;
manual:
value = options_get_string(s->options, "default-size");
if (sscanf(value, "%ux%u", sx, sy) != 2) {
*sx = 80;
*sy = 24;
}
done:
if (*sx < WINDOW_MINIMUM)
*sx = WINDOW_MINIMUM;
if (*sx > WINDOW_MAXIMUM)
*sx = WINDOW_MAXIMUM;
if (*sy < WINDOW_MINIMUM)
*sy = WINDOW_MINIMUM;
if (*sy > WINDOW_MAXIMUM)
*sy = WINDOW_MAXIMUM;
}
void void
recalculate_sizes(void) recalculate_sizes(void)
{ {
struct session *s; struct session *s;
struct client *c; struct client *c;
struct window *w; struct window *w;
struct window_pane *wp; u_int sx, sy, cx, cy;
u_int ssx, ssy, has, limit, lines; int type, current, has, changed;
int flag, is_zoomed, forced;
/*
* Clear attached count and update saved status line information for
* each session.
*/
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
lines = status_line_size(s);
s->attached = 0; s->attached = 0;
ssx = ssy = UINT_MAX; status_update_cache(s);
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_SUSPENDED)
continue;
if ((c->flags & (CLIENT_CONTROL|CLIENT_SIZECHANGED)) ==
CLIENT_CONTROL)
continue;
if (c->session == s) {
if (c->tty.sx < ssx)
ssx = c->tty.sx;
c->flags &= ~CLIENT_STATUSOFF;
if (lines != 0 && lines + PANE_MINIMUM > c->tty.sy)
c->flags |= CLIENT_STATUSOFF;
if ((~c->flags & CLIENT_STATUSOFF) &&
!(c->flags & CLIENT_CONTROL) &&
c->tty.sy > lines &&
c->tty.sy - lines < ssy)
ssy = c->tty.sy - lines;
else if (c->tty.sy < ssy)
ssy = c->tty.sy;
s->attached++;
}
}
if (ssx == UINT_MAX || ssy == UINT_MAX) {
s->flags |= SESSION_UNATTACHED;
continue;
}
s->flags &= ~SESSION_UNATTACHED;
if (lines != 0 && ssy == 0)
ssy = lines;
if (s->sx == ssx && s->sy == ssy)
continue;
log_debug("session $%u size %u,%u (was %u,%u)", s->id, ssx, ssy,
s->sx, s->sy);
s->sx = ssx;
s->sy = ssy;
status_update_saved(s);
} }
/*
* Increment attached count and check the status line size for each
* client.
*/
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
if (c->tty.sy <= status_line_size(c))
c->flags |= CLIENT_STATUSOFF;
else
c->flags &= ~CLIENT_STATUSOFF;
c->session->attached++;
}
/* Walk each window and adjust the size. */
RB_FOREACH(w, windows, &windows) { RB_FOREACH(w, windows, &windows) {
if (w->active == NULL) if (w->active == NULL)
continue; continue;
flag = options_get_number(w->options, "aggressive-resize"); log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy);
ssx = ssy = UINT_MAX; type = options_get_number(w->options, "window-size");
RB_FOREACH(s, sessions, &sessions) { if (type == WINDOW_SIZE_MANUAL)
if (s->flags & SESSION_UNATTACHED) continue;
continue; current = options_get_number(w->options, "aggressive-resize");
if (flag)
has = s->curw->window == w; changed = 1;
else if (type == WINDOW_SIZE_LARGEST) {
has = session_has(s, w); sx = sy = 0;
if (has) { TAILQ_FOREACH(c, &clients, entry) {
if (s->sx < ssx) if (ignore_client_size(c))
ssx = s->sx; continue;
if (s->sy < ssy) s = c->session;
ssy = s->sy;
if (current)
has = (s->curw->window == w);
else
has = session_has(s, w);
if (!has)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx > sx)
sx = cx;
if (cy > sy)
sy = cy;
} }
if (sx == 0 || sy == 0)
changed = 0;
} else {
sx = sy = UINT_MAX;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
s = c->session;
if (current)
has = (s->curw->window == w);
else
has = session_has(s, w);
if (!has)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx < sx)
sx = cx;
if (cy < sy)
sy = cy;
}
if (sx == UINT_MAX || sy == UINT_MAX)
changed = 0;
} }
if (ssx == UINT_MAX || ssy == UINT_MAX) if (w->sx == sx && w->sy == sy)
changed = 0;
if (!changed) {
tty_update_window_offset(w);
continue; continue;
forced = 0;
limit = options_get_number(w->options, "force-width");
if (limit >= PANE_MINIMUM && ssx > limit) {
ssx = limit;
forced |= WINDOW_FORCEWIDTH;
} }
limit = options_get_number(w->options, "force-height"); log_debug("%s: @%u changed to %u,%u", __func__, w->id, sx, sy);
if (limit >= PANE_MINIMUM && ssy > limit) { resize_window(w, sx, sy);
ssy = limit;
forced |= WINDOW_FORCEHEIGHT;
}
if (w->sx == ssx && w->sy == ssy)
continue;
log_debug("window @%u size %u,%u (was %u,%u)", w->id, ssx, ssy,
w->sx, w->sy);
w->flags &= ~(WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
w->flags |= forced;
is_zoomed = w->flags & WINDOW_ZOOMED;
if (is_zoomed)
window_unzoom(w);
layout_resize(w, ssx, ssy);
window_resize(w, ssx, ssy);
if (is_zoomed && window_pane_visible(w->active))
window_zoom(w->active);
/*
* If the current pane is now not visible, move to the next
* that is.
*/
wp = w->active;
while (!window_pane_visible(w->active)) {
w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_LAST(&w->panes, window_panes);
if (w->active == wp)
break;
}
if (w->active == w->last)
w->last = NULL;
server_redraw_window(w);
notify_window("window-layout-changed", w);
} }
} }

View File

@@ -33,22 +33,15 @@ struct screen_redraw_ctx {
u_int sx; u_int sx;
u_int sy; u_int sy;
u_int ox;
u_int oy;
}; };
static int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
static int screen_redraw_cell_border(struct client *, u_int, u_int);
static int screen_redraw_check_cell(struct client *, u_int, u_int, int,
struct window_pane **);
static int screen_redraw_check_is(u_int, u_int, int, int, struct window *,
struct window_pane *, struct window_pane *);
static int screen_redraw_make_pane_status(struct client *, struct window *,
struct window_pane *);
static void screen_redraw_draw_pane_status(struct client *, int);
static void screen_redraw_draw_borders(struct screen_redraw_ctx *); static void screen_redraw_draw_borders(struct screen_redraw_ctx *);
static void screen_redraw_draw_panes(struct screen_redraw_ctx *); static void screen_redraw_draw_panes(struct screen_redraw_ctx *);
static void screen_redraw_draw_status(struct screen_redraw_ctx *); static void screen_redraw_draw_status(struct screen_redraw_ctx *);
static void screen_redraw_draw_pane(struct screen_redraw_ctx *,
struct window_pane *);
static void screen_redraw_draw_number(struct screen_redraw_ctx *, static void screen_redraw_draw_number(struct screen_redraw_ctx *,
struct window_pane *); struct window_pane *);
@@ -281,8 +274,8 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
struct grid_cell gc; struct grid_cell gc;
const char *fmt; const char *fmt;
struct format_tree *ft; struct format_tree *ft;
char *out; char *expanded;
size_t outlen; u_int width, i;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct screen old; struct screen old;
@@ -296,27 +289,30 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0); ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
format_defaults(ft, c, NULL, NULL, wp); format_defaults(ft, c, NULL, NULL, wp);
expanded = format_expand_time(ft, fmt);
if (wp->sx < 4)
wp->status_size = width = 0;
else
wp->status_size = width = wp->sx - 4;
memcpy(&old, &wp->status_screen, sizeof old); memcpy(&old, &wp->status_screen, sizeof old);
screen_init(&wp->status_screen, wp->sx, 1, 0); screen_init(&wp->status_screen, width, 1, 0);
wp->status_screen.mode = 0; wp->status_screen.mode = 0;
out = format_expand(ft, fmt);
outlen = screen_write_cstrlen("%s", out);
if (outlen > wp->sx - 4)
outlen = wp->sx - 4;
screen_resize(&wp->status_screen, outlen, 1, 0);
screen_write_start(&ctx, NULL, &wp->status_screen); screen_write_start(&ctx, NULL, &wp->status_screen);
screen_write_cursormove(&ctx, 0, 0);
screen_write_clearline(&ctx, 8); gc.attr |= GRID_ATTR_CHARSET;
screen_write_cnputs(&ctx, outlen, &gc, "%s", out); for (i = 0; i < width; i++)
screen_write_putc(&ctx, &gc, 'q');
gc.attr &= ~GRID_ATTR_CHARSET;
screen_write_cursormove(&ctx, 0, 0, 0);
format_draw(&ctx, &gc, width, expanded, NULL);
screen_write_stop(&ctx); screen_write_stop(&ctx);
free(out); free(expanded);
format_free(ft); format_free(ft);
wp->status_size = outlen;
if (grid_compare(wp->status_screen.grid, old.grid) == 0) { if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
screen_free(&old); screen_free(&old);
return (0); return (0);
@@ -327,35 +323,67 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
/* Draw pane status. */ /* Draw pane status. */
static void static void
screen_redraw_draw_pane_status(struct client *c, int pane_status) screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
{ {
struct client *c = ctx->c;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct options *oo = c->session->options;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
int spos; struct screen *s;
u_int yoff; u_int i, x, width, xoff, yoff, size;
log_debug("%s: %s @%u", __func__, c->name, w->id);
spos = options_get_number(oo, "status-position");
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
if (pane_status == CELL_STATUS_TOP) s = &wp->status_screen;
size = wp->status_size;
if (ctx->pane_status == CELL_STATUS_TOP)
yoff = wp->yoff - 1; yoff = wp->yoff - 1;
else else
yoff = wp->yoff + wp->sy; yoff = wp->yoff + wp->sy;
if (spos == 0) xoff = wp->xoff + 2;
yoff += 1;
tty_draw_line(tty, NULL, &wp->status_screen, 0, wp->xoff + 2, if (xoff + size <= ctx->ox ||
yoff); xoff >= ctx->ox + ctx->sx ||
yoff < ctx->oy ||
yoff >= ctx->oy + ctx->sy)
continue;
if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
/* All visible. */
i = 0;
x = xoff - ctx->ox;
width = size;
} else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
/* Both left and right not visible. */
i = ctx->ox;
x = 0;
width = ctx->sx;
} else if (xoff < ctx->ox) {
/* Left not visible. */
i = ctx->ox - xoff;
x = 0;
width = size - i;
} else {
/* Right not visible. */
i = 0;
x = xoff - ctx->ox;
width = size - x;
}
if (ctx->top)
yoff += ctx->lines;
tty_draw_line(tty, NULL, s, i, 0, width, x, yoff - ctx->oy);
} }
tty_cursor(tty, 0, 0); tty_cursor(tty, 0, 0);
} }
/* Update status line and change flags if unchanged. */ /* Update status line and change flags if unchanged. */
void static int
screen_redraw_update(struct client *c) screen_redraw_update(struct client *c, int flags)
{ {
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
@@ -368,8 +396,8 @@ screen_redraw_update(struct client *c)
redraw = status_prompt_redraw(c); redraw = status_prompt_redraw(c);
else else
redraw = status_redraw(c); redraw = status_redraw(c);
if (!redraw) if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
c->flags &= ~CLIENT_STATUS; flags &= ~CLIENT_REDRAWSTATUS;
if (options_get_number(wo, "pane-border-status") != CELL_STATUS_OFF) { if (options_get_number(wo, "pane-border-status") != CELL_STATUS_OFF) {
redraw = 0; redraw = 0;
@@ -378,99 +406,96 @@ screen_redraw_update(struct client *c)
redraw = 1; redraw = 1;
} }
if (redraw) if (redraw)
c->flags |= CLIENT_BORDERS; flags |= CLIENT_REDRAWBORDERS;
} }
return (flags);
}
/* Set up redraw context. */
static void
screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
{
struct session *s = c->session;
struct options *oo = s->options;
struct window *w = s->curw->window;
struct options *wo = w->options;
memset(ctx, 0, sizeof *ctx);
ctx->c = c;
ctx->lines = status_line_size(c);
if (c->message_string != NULL || c->prompt_string != NULL)
ctx->lines = (ctx->lines == 0) ? 1 : ctx->lines;
if (ctx->lines != 0 && options_get_number(oo, "status-position") == 0)
ctx->top = 1;
ctx->pane_status = options_get_number(wo, "pane-border-status");
tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->lines, ctx->top);
} }
/* Redraw entire screen. */ /* Redraw entire screen. */
void void
screen_redraw_screen(struct client *c, int draw_panes, int draw_status, screen_redraw_screen(struct client *c)
int draw_borders)
{ {
struct options *oo = c->session->options; struct screen_redraw_ctx ctx;
struct tty *tty = &c->tty; int flags;
struct window *w = c->session->curw->window;
struct options *wo = w->options;
struct screen_redraw_ctx ctx;
if (c->flags & CLIENT_SUSPENDED) if (c->flags & CLIENT_SUSPENDED)
return; return;
memset(&ctx, 0, sizeof ctx); flags = screen_redraw_update(c, c->flags);
ctx.c = c; screen_redraw_set_context(c, &ctx);
if (c->flags & CLIENT_STATUSOFF) if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
ctx.lines = 0;
else
ctx.lines = status_line_size(c->session);
if (c->message_string != NULL || c->prompt_string != NULL)
ctx.lines = (ctx.lines == 0) ? 1 : ctx.lines;
if (ctx.lines != 0 && options_get_number(oo, "status-position") == 0)
ctx.top = 1;
ctx.pane_status = options_get_number(wo, "pane-border-status");
ctx.sx = tty->sx;
ctx.sy = tty->sy - ctx.lines;
if (ctx.lines == 0)
draw_status = 0;
if (draw_borders) {
if (ctx.pane_status != CELL_STATUS_OFF) if (ctx.pane_status != CELL_STATUS_OFF)
screen_redraw_draw_pane_status(c, ctx.pane_status); screen_redraw_draw_pane_status(&ctx);
screen_redraw_draw_borders(&ctx); screen_redraw_draw_borders(&ctx);
} }
if (draw_panes) if (flags & CLIENT_REDRAWWINDOW)
screen_redraw_draw_panes(&ctx); screen_redraw_draw_panes(&ctx);
if (draw_status) if (ctx.lines != 0 &&
(flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS)))
screen_redraw_draw_status(&ctx); screen_redraw_draw_status(&ctx);
tty_reset(tty); tty_reset(&c->tty);
} }
/* Draw a single pane. */ /* Redraw a single pane. */
void void
screen_redraw_pane(struct client *c, struct window_pane *wp) screen_redraw_pane(struct client *c, struct window_pane *wp)
{ {
u_int i, yoff; struct screen_redraw_ctx ctx;
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
return; return;
yoff = wp->yoff; screen_redraw_set_context(c, &ctx);
if (status_at_line(c) == 0)
yoff += status_line_size(c->session);
log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id, screen_redraw_draw_pane(&ctx, wp);
wp->xoff, yoff);
for (i = 0; i < wp->sy; i++)
tty_draw_pane(&c->tty, wp, i, wp->xoff, yoff);
tty_reset(&c->tty); tty_reset(&c->tty);
} }
/* Draw a border cell. */ /* Draw a border cell. */
static void static void
screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y, screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j,
int small, u_int msgx, u_int msgy, struct grid_cell *m_active_gc, struct grid_cell *m_active_gc, struct grid_cell *active_gc,
struct grid_cell *active_gc, struct grid_cell *m_other_gc, struct grid_cell *m_other_gc, struct grid_cell *other_gc)
struct grid_cell *other_gc)
{ {
struct client *c = ctx->c; struct client *c = ctx->c;
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = s->curw->window;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
struct window_pane *active = w->active; struct window_pane *active = w->active;
struct window_pane *marked = marked_pane.wp; struct window_pane *marked = marked_pane.wp;
u_int type; u_int type, x = ctx->ox + i, y = ctx->oy + j;
int flag, pane_status = ctx->pane_status; int flag, pane_status = ctx->pane_status;
type = screen_redraw_check_cell(c, x, y, pane_status, &wp); type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
if (type == CELL_INSIDE) if (type == CELL_INSIDE)
return; return;
if (type == CELL_OUTSIDE && small && x > msgx && y == msgy)
return;
flag = screen_redraw_check_is(x, y, type, pane_status, w, active, wp); flag = screen_redraw_check_is(x, y, type, pane_status, w, active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) && if (server_is_marked(s, s->curw, marked_pane.wp) &&
@@ -484,9 +509,9 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y,
else else
tty_attributes(tty, other_gc, NULL); tty_attributes(tty, other_gc, NULL);
if (ctx->top) if (ctx->top)
tty_cursor(tty, x, ctx->lines + y); tty_cursor(tty, i, ctx->lines + j);
else else
tty_cursor(tty, x, y); tty_cursor(tty, i, j);
tty_putc(tty, CELL_BORDERS[type]); tty_putc(tty, CELL_BORDERS[type]);
} }
@@ -497,42 +522,12 @@ screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
struct client *c = ctx->c; struct client *c = ctx->c;
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = s->curw->window;
struct options *oo = w->options;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct options *oo = w->options;
struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc; struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
struct grid_cell msg_gc; u_int i, j;
u_int i, j, msgx = 0, msgy = 0;
int small, flags;
char msg[256];
const char *tmp;
size_t msglen = 0;
small = (ctx->sy + ctx->top > w->sy) || (ctx->sx > w->sx); log_debug("%s: %s @%u", __func__, c->name, w->id);
if (small) {
flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT))
tmp = "force-width, force-height";
else if (flags == WINDOW_FORCEWIDTH)
tmp = "force-width";
else if (flags == WINDOW_FORCEHEIGHT)
tmp = "force-height";
else if (c->flags & CLIENT_STATUSOFF)
tmp = "status line";
else
tmp = "a smaller client";
xsnprintf(msg, sizeof msg, "(size %ux%u from %s)",
w->sx, w->sy, tmp);
msglen = strlen(msg);
if (ctx->sy - 1 + ctx->top > w->sy && ctx->sx >= msglen) {
msgx = ctx->sx - msglen;
msgy = ctx->sy - 1 + ctx->top;
} else if (ctx->sx - w->sx > msglen) {
msgx = ctx->sx - msglen;
msgy = ctx->sy - 1 + ctx->top;
} else
small = 0;
}
style_apply(&other_gc, oo, "pane-border-style"); style_apply(&other_gc, oo, "pane-border-style");
style_apply(&active_gc, oo, "pane-active-border-style"); style_apply(&active_gc, oo, "pane-active-border-style");
@@ -543,20 +538,12 @@ screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
memcpy(&m_active_gc, &active_gc, sizeof m_active_gc); memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
m_active_gc.attr ^= GRID_ATTR_REVERSE; m_active_gc.attr ^= GRID_ATTR_REVERSE;
for (j = 0; j < ctx->sy; j++) { for (j = 0; j < tty->sy - ctx->lines; j++) {
for (i = 0; i < ctx->sx; i++) { for (i = 0; i < tty->sx; i++) {
screen_redraw_draw_borders_cell(ctx, i, j, small, screen_redraw_draw_borders_cell(ctx, i, j,
msgx, msgy, &m_active_gc, &active_gc, &m_other_gc, &m_active_gc, &active_gc, &m_other_gc, &other_gc);
&other_gc);
} }
} }
if (small) {
memcpy(&msg_gc, &grid_default_cell, sizeof msg_gc);
tty_attributes(tty, &msg_gc, NULL);
tty_cursor(tty, msgx, msgy);
tty_puts(tty, msg);
}
} }
/* Draw the panes. */ /* Draw the panes. */
@@ -565,19 +552,14 @@ screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
{ {
struct client *c = ctx->c; struct client *c = ctx->c;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
u_int i, y;
if (ctx->top) log_debug("%s: %s @%u", __func__, c->name, w->id);
y = ctx->lines;
else
y = 0;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
for (i = 0; i < wp->sy; i++) screen_redraw_draw_pane(ctx, wp);
tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff);
if (c->flags & CLIENT_IDENTIFY) if (c->flags & CLIENT_IDENTIFY)
screen_redraw_draw_number(ctx, wp); screen_redraw_draw_number(ctx, wp);
} }
@@ -588,15 +570,74 @@ static void
screen_redraw_draw_status(struct screen_redraw_ctx *ctx) screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
{ {
struct client *c = ctx->c; struct client *c = ctx->c;
struct window *w = c->session->curw->window;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct screen *s = c->status.active;
u_int i, y; u_int i, y;
log_debug("%s: %s @%u", __func__, c->name, w->id);
if (ctx->top) if (ctx->top)
y = 0; y = 0;
else else
y = ctx->sy; y = c->tty.sy - ctx->lines;
for (i = 0; i < ctx->lines; i++) for (i = 0; i < ctx->lines; i++)
tty_draw_line(tty, NULL, &c->status.status, i, 0, y); tty_draw_line(tty, NULL, s, 0, i, UINT_MAX, 0, y + i);
}
/* Draw one pane. */
static void
screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
{
struct client *c = ctx->c;
struct window *w = c->session->curw->window;
struct tty *tty = &c->tty;
struct screen *s;
u_int i, j, top, x, y, width;
log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
return;
if (ctx->top)
top = ctx->lines;
else
top = 0;
s = wp->screen;
for (j = 0; j < wp->sy; j++) {
if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
continue;
y = top + wp->yoff + j - ctx->oy;
if (wp->xoff >= ctx->ox &&
wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
/* All visible. */
i = 0;
x = wp->xoff - ctx->ox;
width = wp->sx;
} else if (wp->xoff < ctx->ox &&
wp->xoff + wp->sx > ctx->ox + ctx->sx) {
/* Both left and right not visible. */
i = ctx->ox;
x = 0;
width = ctx->sx;
} else if (wp->xoff < ctx->ox) {
/* Left not visible. */
i = ctx->ox - wp->xoff;
x = 0;
width = wp->sx - i;
} else {
/* Right not visible. */
i = 0;
x = wp->xoff - ctx->ox;
width = ctx->sx - x;
}
log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
__func__, c->name, wp->id, i, j, x, y, width);
tty_draw_line(tty, wp, s, i, j, width, x, y);
}
} }
/* Draw number on a pane. */ /* Draw number on a pane. */
@@ -609,27 +650,69 @@ screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
struct options *oo = s->options; struct options *oo = s->options;
struct window *w = wp->window; struct window *w = wp->window;
struct grid_cell gc; struct grid_cell gc;
u_int idx, px, py, i, j, xoff, yoff; u_int idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour; int colour, active_colour;
char buf[16], *ptr; char buf[16], *ptr;
size_t len; size_t len;
if (wp->xoff + wp->sx <= ctx->ox ||
wp->xoff >= ctx->ox + ctx->sx ||
wp->yoff + wp->sy <= ctx->oy ||
wp->yoff >= ctx->oy + ctx->sy)
return;
if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
/* All visible. */
xoff = wp->xoff - ctx->ox;
sx = wp->sx;
} else if (wp->xoff < ctx->ox &&
wp->xoff + wp->sx > ctx->ox + ctx->sx) {
/* Both left and right not visible. */
xoff = 0;
sx = ctx->sx;
} else if (wp->xoff < ctx->ox) {
/* Left not visible. */
xoff = 0;
sx = wp->sx - (ctx->ox - wp->xoff);
} else {
/* Right not visible. */
xoff = wp->xoff - ctx->ox;
sx = wp->sx - xoff;
}
if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
/* All visible. */
yoff = wp->yoff - ctx->oy;
sy = wp->sy;
} else if (wp->yoff < ctx->oy &&
wp->yoff + wp->sy > ctx->oy + ctx->sy) {
/* Both top and bottom not visible. */
yoff = 0;
sy = ctx->sy;
} else if (wp->yoff < ctx->oy) {
/* Top not visible. */
yoff = 0;
sy = wp->sy - (ctx->oy - wp->yoff);
} else {
/* Bottom not visible. */
yoff = wp->yoff - ctx->oy;
sy = wp->sy - yoff;
}
if (ctx->top)
yoff += ctx->lines;
px = sx / 2;
py = sy / 2;
if (window_pane_index(wp, &idx) != 0) if (window_pane_index(wp, &idx) != 0)
fatalx("index not found"); fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", idx); len = xsnprintf(buf, sizeof buf, "%u", idx);
if (wp->sx < len) if (sx < len)
return; return;
colour = options_get_number(oo, "display-panes-colour"); colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour"); active_colour = options_get_number(oo, "display-panes-active-colour");
px = wp->sx / 2; py = wp->sy / 2; if (sx < len * 6 || sy < 5) {
xoff = wp->xoff; yoff = wp->yoff;
if (ctx->top)
yoff += ctx->lines;
if (wp->sx < len * 6 || wp->sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py); tty_cursor(tty, xoff + px - len / 2, yoff + py);
goto draw_text; goto draw_text;
} }
@@ -661,9 +744,9 @@ screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
} }
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy); len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
if (wp->sx < len || wp->sy < 6) if (sx < len || sy < 6)
return; return;
tty_cursor(tty, xoff + wp->sx - len, yoff); tty_cursor(tty, xoff + sx - len, yoff);
draw_text: draw_text:
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);

View File

@@ -54,12 +54,53 @@ struct screen_write_collect_line {
TAILQ_HEAD(, screen_write_collect_item) items; TAILQ_HEAD(, screen_write_collect_item) items;
}; };
static void
screen_write_offset_timer(__unused int fd, __unused short events, void *data)
{
struct window *w = data;
tty_update_window_offset(w);
}
/* Set cursor position. */
static void
screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy)
{
struct window_pane *wp = ctx->wp;
struct window *w;
struct screen *s = ctx->s;
struct timeval tv = { .tv_usec = 10000 };
if (cx != -1 && (u_int)cx == s->cx && cy != -1 && (u_int)cy == s->cy)
return;
if (cx != -1) {
if ((u_int)cx > screen_size_x(s)) /* allow last column */
cx = screen_size_x(s) - 1;
s->cx = cx;
}
if (cy != -1) {
if ((u_int)cy > screen_size_y(s) - 1)
cy = screen_size_y(s) - 1;
s->cy = cy;
}
if (wp == NULL)
return;
w = wp->window;
if (!event_initialized(&w->offset_timer))
evtimer_set(&w->offset_timer, screen_write_offset_timer, w);
if (!evtimer_pending(&w->offset_timer, NULL))
evtimer_add(&w->offset_timer, &tv);
}
/* Initialize writing with a window. */ /* Initialize writing with a window. */
void void
screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
struct screen *s) struct screen *s)
{ {
char tmp[16]; char tmp[32];
u_int y; u_int y;
memset(ctx, 0, sizeof *ctx); memset(ctx, 0, sizeof *ctx);
@@ -78,8 +119,10 @@ screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
ctx->scrolled = 0; ctx->scrolled = 0;
ctx->bg = 8; ctx->bg = 8;
if (wp != NULL) if (wp != NULL) {
snprintf(tmp, sizeof tmp, "pane %%%u", wp->id); snprintf(tmp, sizeof tmp, "pane %%%u (at %u,%u)", wp->id,
wp->xoff, wp->yoff);
}
log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s), log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
screen_size_y(ctx->s), wp == NULL ? "no pane" : tmp); screen_size_y(ctx->s), wp == NULL ? "no pane" : tmp);
} }
@@ -107,11 +150,10 @@ screen_write_reset(struct screen_write_ctx *ctx)
screen_reset_tabs(s); screen_reset_tabs(s);
screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON); s->mode = MODE_CURSOR | MODE_WRAP;
s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
screen_write_clearscreen(ctx, 8); screen_write_clearscreen(ctx, 8);
screen_write_cursormove(ctx, 0, 0); screen_write_set_cursor(ctx, 0, 0);
} }
/* Write character. */ /* Write character. */
@@ -127,41 +169,6 @@ screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
screen_write_cell(ctx, &gc); screen_write_cell(ctx, &gc);
} }
/* Calculate string length, with embedded formatting. */
size_t
screen_write_cstrlen(const char *fmt, ...)
{
va_list ap;
char *msg, *msg2, *ptr, *ptr2;
size_t size;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
msg2 = xmalloc(strlen(msg) + 1);
ptr = msg;
ptr2 = msg2;
while (*ptr != '\0') {
if (ptr[0] == '#' && ptr[1] == '[') {
while (*ptr != ']' && *ptr != '\0')
ptr++;
if (*ptr == ']')
ptr++;
continue;
}
*ptr2++ = *ptr++;
}
*ptr2 = '\0';
size = screen_write_strlen("%s", msg2);
free(msg);
free(msg2);
return (size);
}
/* Calculate string length. */ /* Calculate string length. */
size_t size_t
screen_write_strlen(const char *fmt, ...) screen_write_strlen(const char *fmt, ...)
@@ -280,77 +287,6 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
free(msg); free(msg);
} }
/* Write string, similar to nputs, but with embedded formatting (#[]). */
void
screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
const struct grid_cell *gcp, const char *fmt, ...)
{
struct grid_cell gc;
struct utf8_data *ud = &gc.data;
va_list ap;
char *msg;
u_char *ptr, *last;
size_t left, size = 0;
enum utf8_state more;
memcpy(&gc, gcp, sizeof gc);
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
ptr = msg;
while (*ptr != '\0') {
if (ptr[0] == '#' && ptr[1] == '[') {
ptr += 2;
last = ptr + strcspn(ptr, "]");
if (*last == '\0') {
/* No ]. Not much point in doing anything. */
break;
}
*last = '\0';
style_parse(gcp, &gc, ptr);
ptr = last + 1;
continue;
}
if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
ptr++;
left = strlen(ptr);
if (left < (size_t)ud->size - 1)
break;
while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
ptr++;
ptr++;
if (more != UTF8_DONE)
continue;
if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
while (size < (size_t)maxlen) {
screen_write_putc(ctx, &gc, ' ');
size++;
}
break;
}
size += ud->width;
screen_write_cell(ctx, &gc);
} else {
if (maxlen > 0 && size + 1 > (size_t)maxlen)
break;
if (*ptr > 0x1f && *ptr < 0x7f) {
size++;
screen_write_putc(ctx, &gc, *ptr);
}
ptr++;
}
}
free(msg);
}
/* Copy from another screen. Assumes target region is big enough. */ /* Copy from another screen. Assumes target region is big enough. */
void void
screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px, screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
@@ -382,13 +318,13 @@ screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
screen_write_cell(ctx, &gc); screen_write_cell(ctx, &gc);
} }
cy++; cy++;
screen_write_cursormove(ctx, cx, cy); screen_write_set_cursor(ctx, cx, cy);
} }
} }
/* /*
* Copy from another screen but without the selection stuff. Also assumes the * Copy from another screen but without the selection stuff. Also assumes the
* target region is already big enough and already cleared. * target region is already big enough.
*/ */
void void
screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
@@ -413,8 +349,7 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
grid_get_cell(gd, xx, yy, &gc); grid_get_cell(gd, xx, yy, &gc);
if (xx + gc.data.width > px + nx) if (xx + gc.data.width > px + nx)
break; break;
if (!grid_cells_equal(&gc, &grid_default_cell)) grid_view_set_cell(ctx->s->grid, cx, cy, &gc);
grid_view_set_cell(ctx->s->grid, cx, cy, &gc);
cx++; cx++;
} }
cy++; cy++;
@@ -440,7 +375,7 @@ screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right)
screen_write_putc(ctx, &gc, 'q'); screen_write_putc(ctx, &gc, 'q');
screen_write_putc(ctx, &gc, right ? 'u' : 'q'); screen_write_putc(ctx, &gc, right ? 'u' : 'q');
screen_write_cursormove(ctx, cx, cy); screen_write_set_cursor(ctx, cx, cy);
} }
/* Draw a horizontal line on screen. */ /* Draw a horizontal line on screen. */
@@ -459,13 +394,13 @@ screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
screen_write_putc(ctx, &gc, top ? 'w' : 'x'); screen_write_putc(ctx, &gc, top ? 'w' : 'x');
for (i = 1; i < ny - 1; i++) { for (i = 1; i < ny - 1; i++) {
screen_write_cursormove(ctx, cx, cy + i); screen_write_set_cursor(ctx, cx, cy + i);
screen_write_putc(ctx, &gc, 'x'); screen_write_putc(ctx, &gc, 'x');
} }
screen_write_cursormove(ctx, cx, cy + ny - 1); screen_write_set_cursor(ctx, cx, cy + ny - 1);
screen_write_putc(ctx, &gc, bottom ? 'v' : 'x'); screen_write_putc(ctx, &gc, bottom ? 'v' : 'x');
screen_write_cursormove(ctx, cx, cy); screen_write_set_cursor(ctx, cx, cy);
} }
/* Draw a box on screen. */ /* Draw a box on screen. */
@@ -487,22 +422,22 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny)
screen_write_putc(ctx, &gc, 'q'); screen_write_putc(ctx, &gc, 'q');
screen_write_putc(ctx, &gc, 'k'); screen_write_putc(ctx, &gc, 'k');
screen_write_cursormove(ctx, cx, cy + ny - 1); screen_write_set_cursor(ctx, cx, cy + ny - 1);
screen_write_putc(ctx, &gc, 'm'); screen_write_putc(ctx, &gc, 'm');
for (i = 1; i < nx - 1; i++) for (i = 1; i < nx - 1; i++)
screen_write_putc(ctx, &gc, 'q'); screen_write_putc(ctx, &gc, 'q');
screen_write_putc(ctx, &gc, 'j'); screen_write_putc(ctx, &gc, 'j');
for (i = 1; i < ny - 1; i++) { for (i = 1; i < ny - 1; i++) {
screen_write_cursormove(ctx, cx, cy + i); screen_write_set_cursor(ctx, cx, cy + i);
screen_write_putc(ctx, &gc, 'x'); screen_write_putc(ctx, &gc, 'x');
} }
for (i = 1; i < ny - 1; i++) { for (i = 1; i < ny - 1; i++) {
screen_write_cursormove(ctx, cx + nx - 1, cy + i); screen_write_set_cursor(ctx, cx + nx - 1, cy + i);
screen_write_putc(ctx, &gc, 'x'); screen_write_putc(ctx, &gc, 'x');
} }
screen_write_cursormove(ctx, cx, cy); screen_write_set_cursor(ctx, cx, cy);
} }
/* /*
@@ -557,7 +492,7 @@ screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx,
if (src->mode & MODE_CURSOR) { if (src->mode & MODE_CURSOR) {
grid_view_get_cell(src->grid, src->cx, src->cy, &gc); grid_view_get_cell(src->grid, src->cx, src->cy, &gc);
gc.attr |= GRID_ATTR_REVERSE; gc.attr |= GRID_ATTR_REVERSE;
screen_write_cursormove(ctx, cx + (src->cx - px), screen_write_set_cursor(ctx, cx + (src->cx - px),
cy + (src->cy - py)); cy + (src->cy - py));
screen_write_cell(ctx, &gc); screen_write_cell(ctx, &gc);
} }
@@ -603,25 +538,26 @@ void
screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
u_int cx = s->cx, cy = s->cy;
if (ny == 0) if (ny == 0)
ny = 1; ny = 1;
if (s->cy < s->rupper) { if (cy < s->rupper) {
/* Above region. */ /* Above region. */
if (ny > s->cy) if (ny > cy)
ny = s->cy; ny = cy;
} else { } else {
/* Below region. */ /* Below region. */
if (ny > s->cy - s->rupper) if (ny > cy - s->rupper)
ny = s->cy - s->rupper; ny = cy - s->rupper;
} }
if (s->cx == screen_size_x(s)) if (cx == screen_size_x(s))
s->cx--; cx--;
if (ny == 0)
return;
s->cy -= ny; cy -= ny;
screen_write_set_cursor(ctx, cx, cy);
} }
/* Cursor down by ny. */ /* Cursor down by ny. */
@@ -629,25 +565,28 @@ void
screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
u_int cx = s->cx, cy = s->cy;
if (ny == 0) if (ny == 0)
ny = 1; ny = 1;
if (s->cy > s->rlower) { if (cy > s->rlower) {
/* Below region. */ /* Below region. */
if (ny > screen_size_y(s) - 1 - s->cy) if (ny > screen_size_y(s) - 1 - cy)
ny = screen_size_y(s) - 1 - s->cy; ny = screen_size_y(s) - 1 - cy;
} else { } else {
/* Above region. */ /* Above region. */
if (ny > s->rlower - s->cy) if (ny > s->rlower - cy)
ny = s->rlower - s->cy; ny = s->rlower - cy;
} }
if (s->cx == screen_size_x(s)) if (cx == screen_size_x(s))
s->cx--; cx--;
if (ny == 0) else if (ny == 0)
return; return;
s->cy += ny; cy += ny;
screen_write_set_cursor(ctx, cx, cy);
} }
/* Cursor right by nx. */ /* Cursor right by nx. */
@@ -655,16 +594,19 @@ void
screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx) screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
u_int cx = s->cx, cy = s->cy;
if (nx == 0) if (nx == 0)
nx = 1; nx = 1;
if (nx > screen_size_x(s) - 1 - s->cx) if (nx > screen_size_x(s) - 1 - cx)
nx = screen_size_x(s) - 1 - s->cx; nx = screen_size_x(s) - 1 - cx;
if (nx == 0) if (nx == 0)
return; return;
s->cx += nx; cx += nx;
screen_write_set_cursor(ctx, cx, cy);
} }
/* Cursor left by nx. */ /* Cursor left by nx. */
@@ -672,16 +614,19 @@ void
screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
u_int cx = s->cx, cy = s->cy;
if (nx == 0) if (nx == 0)
nx = 1; nx = 1;
if (nx > s->cx) if (nx > cx)
nx = s->cx; nx = cx;
if (nx == 0) if (nx == 0)
return; return;
s->cx -= nx; cx -= nx;
screen_write_set_cursor(ctx, cx, cy);
} }
/* Backspace; cursor left unless at start of wrapped line when can move up. */ /* Backspace; cursor left unless at start of wrapped line when can move up. */
@@ -690,17 +635,20 @@ screen_write_backspace(struct screen_write_ctx *ctx)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct grid_line *gl; struct grid_line *gl;
u_int cx = s->cx, cy = s->cy;
if (s->cx == 0) { if (cx == 0) {
if (s->cy == 0) if (cy == 0)
return; return;
gl = grid_get_line(s->grid, s->grid->hsize + s->cy - 1); gl = grid_get_line(s->grid, s->grid->hsize + cy - 1);
if (gl->flags & GRID_LINE_WRAPPED) { if (gl->flags & GRID_LINE_WRAPPED) {
s->cy--; cy--;
s->cx = screen_size_x(s) - 1; cx = screen_size_x(s) - 1;
} }
} else } else
s->cx--; cx--;
screen_write_set_cursor(ctx, cx, cy);
} }
/* VT100 alignment test. */ /* VT100 alignment test. */
@@ -712,8 +660,6 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
struct grid_cell gc; struct grid_cell gc;
u_int xx, yy; u_int xx, yy;
screen_write_initctx(ctx, &ttyctx);
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
utf8_set(&gc.data, 'E'); utf8_set(&gc.data, 'E');
@@ -722,12 +668,13 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
grid_view_set_cell(s->grid, xx, yy, &gc); grid_view_set_cell(s->grid, xx, yy, &gc);
} }
s->cx = 0; screen_write_set_cursor(ctx, 0, 0);
s->cy = 0;
s->rupper = 0; s->rupper = 0;
s->rlower = screen_size_y(s) - 1; s->rlower = screen_size_y(s) - 1;
screen_write_initctx(ctx, &ttyctx);
screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1); screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1);
tty_write(tty_cmd_alignmenttest, &ttyctx); tty_write(tty_cmd_alignmenttest, &ttyctx);
} }
@@ -918,7 +865,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
u_int sx = screen_size_x(s); u_int sx = screen_size_x(s);
gl = grid_get_line(s->grid, s->grid->hsize + s->cy); gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (gl->cellsize == 0 && bg == 8) if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
return; return;
screen_write_initctx(ctx, &ttyctx); screen_write_initctx(ctx, &ttyctx);
@@ -941,7 +888,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
u_int sx = screen_size_x(s); u_int sx = screen_size_x(s);
gl = grid_get_line(s->grid, s->grid->hsize + s->cy); gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8)) if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
return; return;
screen_write_initctx(ctx, &ttyctx); screen_write_initctx(ctx, &ttyctx);
@@ -979,17 +926,24 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
/* Move cursor to px,py. */ /* Move cursor to px,py. */
void void
screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py,
int origin)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
if (px > screen_size_x(s) - 1) if (origin && py != -1 && (s->mode & MODE_ORIGIN)) {
if ((u_int)py > s->rlower - s->rupper)
py = s->rlower;
else
py += s->rupper;
}
if (px != -1 && (u_int)px > screen_size_x(s) - 1)
px = screen_size_x(s) - 1; px = screen_size_x(s) - 1;
if (py > screen_size_y(s) - 1) if (py != -1 && (u_int)py > screen_size_y(s) - 1)
py = screen_size_y(s) - 1; py = screen_size_y(s) - 1;
s->cx = px; screen_write_set_cursor(ctx, px, py);
s->cy = py;
} }
/* Reverse index (up with scroll). */ /* Reverse index (up with scroll). */
@@ -1005,7 +959,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
if (s->cy == s->rupper) if (s->cy == s->rupper)
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg);
else if (s->cy > 0) else if (s->cy > 0)
s->cy--; screen_write_set_cursor(ctx, -1, s->cy - 1);
screen_write_collect_flush(ctx, 0); screen_write_collect_flush(ctx, 0);
tty_write(tty_cmd_reverseindex, &ttyctx); tty_write(tty_cmd_reverseindex, &ttyctx);
@@ -1028,8 +982,7 @@ screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
screen_write_collect_flush(ctx, 0); screen_write_collect_flush(ctx, 0);
/* Cursor moves to top-left. */ /* Cursor moves to top-left. */
s->cx = 0; screen_write_set_cursor(ctx, 0, 0);
s->cy = 0;
s->rupper = rupper; s->rupper = rupper;
s->rlower = rlower; s->rlower = rlower;
@@ -1062,7 +1015,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
screen_write_collect_scroll(ctx); screen_write_collect_scroll(ctx);
ctx->scrolled++; ctx->scrolled++;
} else if (s->cy < screen_size_y(s) - 1) } else if (s->cy < screen_size_y(s) - 1)
s->cy++; screen_write_set_cursor(ctx, -1, s->cy + 1);
} }
/* Scroll up. */ /* Scroll up. */
@@ -1094,9 +1047,7 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
void void
screen_write_carriagereturn(struct screen_write_ctx *ctx) screen_write_carriagereturn(struct screen_write_ctx *ctx)
{ {
struct screen *s = ctx->s; screen_write_set_cursor(ctx, 0, -1);
s->cx = 0;
} }
/* Clear to end of screen from cursor. */ /* Clear to end of screen from cursor. */
@@ -1251,7 +1202,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only)
cx = s->cx; cy = s->cy; cx = s->cx; cy = s->cy;
for (y = 0; y < screen_size_y(s); y++) { for (y = 0; y < screen_size_y(s); y++) {
TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) { TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) {
screen_write_cursormove(ctx, ci->x, y); screen_write_set_cursor(ctx, ci->x, y);
screen_write_initctx(ctx, &ttyctx); screen_write_initctx(ctx, &ttyctx);
ttyctx.cell = &ci->gc; ttyctx.cell = &ci->gc;
ttyctx.wrapped = ci->wrapped; ttyctx.wrapped = ci->wrapped;
@@ -1300,14 +1251,15 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
grid_view_set_cell(s->grid, xx, s->cy, grid_view_set_cell(s->grid, xx, s->cy,
&grid_default_cell); &grid_default_cell);
} }
if (gc.data.width > 1) if (gc.data.width > 1) {
grid_view_set_cell(s->grid, xx, s->cy, grid_view_set_cell(s->grid, xx, s->cy,
&grid_default_cell); &grid_default_cell);
}
} }
memcpy(&gc, &ci->gc, sizeof gc); memcpy(&gc, &ci->gc, sizeof gc);
grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used); grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used);
s->cx += ci->used; screen_write_set_cursor(ctx, s->cx + ci->used, -1);
for (xx = s->cx; xx < screen_size_x(s); xx++) { for (xx = s->cx; xx < screen_size_x(s); xx++) {
grid_view_get_cell(s->grid, xx, s->cy, &gc); grid_view_get_cell(s->grid, xx, s->cy, &gc);
@@ -1361,7 +1313,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
ci->wrapped = 1; ci->wrapped = 1;
screen_write_linefeed(ctx, 1, 8); screen_write_linefeed(ctx, 1, 8);
s->cx = 0; screen_write_set_cursor(ctx, 0, -1);
} }
if (ci->used == 0) if (ci->used == 0)
@@ -1395,7 +1347,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
screen_write_collect_flush(ctx, 0); screen_write_collect_flush(ctx, 0);
if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) { if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) {
cx = s->cx; cy = s->cy; cx = s->cx; cy = s->cy;
screen_write_cursormove(ctx, xx, s->cy); screen_write_set_cursor(ctx, xx, s->cy);
screen_write_initctx(ctx, &ttyctx); screen_write_initctx(ctx, &ttyctx);
ttyctx.cell = gc; ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx); tty_write(tty_cmd_cell, &ttyctx);
@@ -1423,7 +1375,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
if ((s->mode & MODE_WRAP) && s->cx > sx - width) { if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
screen_write_linefeed(ctx, 1, 8); screen_write_linefeed(ctx, 1, 8);
s->cx = 0; screen_write_set_cursor(ctx, 0, -1);
screen_write_collect_flush(ctx, 1); screen_write_collect_flush(ctx, 1);
} }
@@ -1496,9 +1448,9 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
*/ */
last = !(s->mode & MODE_WRAP); last = !(s->mode & MODE_WRAP);
if (s->cx <= sx - last - width) if (s->cx <= sx - last - width)
s->cx += width; screen_write_set_cursor(ctx, s->cx + width, -1);
else else
s->cx = sx - last; screen_write_set_cursor(ctx, sx - last, -1);
/* Create space for character in insert mode. */ /* Create space for character in insert mode. */
if (s->mode & MODE_INSERT) { if (s->mode & MODE_INSERT) {

View File

@@ -47,7 +47,6 @@ struct screen_title_entry {
}; };
TAILQ_HEAD(screen_titles, screen_title_entry); TAILQ_HEAD(screen_titles, screen_title_entry);
static void screen_resize_x(struct screen *, u_int);
static void screen_resize_y(struct screen *, u_int); static void screen_resize_y(struct screen *, u_int);
static void screen_reflow(struct screen *, u_int); static void screen_reflow(struct screen *, u_int);
@@ -206,13 +205,7 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
sy = 1; sy = 1;
if (sx != screen_size_x(s)) { if (sx != screen_size_x(s)) {
screen_resize_x(s, sx); s->grid->sx = sx;
/*
* It is unclear what should happen to tabs on resize. xterm
* seems to try and maintain them, rxvt resets them. Resetting
* is simpler and more reliable so let's do that.
*/
screen_reset_tabs(s); screen_reset_tabs(s);
} else } else
reflow = 0; reflow = 0;
@@ -224,28 +217,6 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
screen_reflow(s, sx); screen_reflow(s, sx);
} }
static void
screen_resize_x(struct screen *s, u_int sx)
{
struct grid *gd = s->grid;
if (sx == 0)
fatalx("zero size");
/*
* Treat resizing horizontally simply: just ensure the cursor is
* on-screen and change the size. Don't bother to truncate any lines -
* then the data should be accessible if the size is then increased.
*
* The only potential wrinkle is if UTF-8 double-width characters are
* left in the last column, but UTF-8 terminals should deal with this
* sanely.
*/
if (s->cx >= sx)
s->cx = sx - 1;
gd->sx = sx;
}
static void static void
screen_resize_y(struct screen *s, u_int sy) screen_resize_y(struct screen *s, u_int sy)
{ {
@@ -424,7 +395,11 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
if (py == sel->sy && px < sel->sx) if (py == sel->sy && px < sel->sx)
return (0); return (0);
if (py == sel->ey && px > sel->ex) if (sel->modekeys == MODEKEY_EMACS)
xx = (sel->ex == 0 ? 0 : sel->ex - 1);
else
xx = sel->ex;
if (py == sel->ey && px > xx)
return (0); return (0);
} else if (sel->sy > sel->ey) { } else if (sel->sy > sel->ey) {
/* starting line > ending line -- upward selection. */ /* starting line > ending line -- upward selection. */
@@ -455,7 +430,11 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
return (0); return (0);
} else { } else {
/* selection start (sx) is on the left */ /* selection start (sx) is on the left */
if (px < sel->sx || px > sel->ex) if (sel->modekeys == MODEKEY_EMACS)
xx = (sel->ex == 0 ? 0 : sel->ex - 1);
else
xx = sel->ex;
if (px < sel->sx || px > xx)
return (0); return (0);
} }
} }
@@ -484,5 +463,30 @@ screen_select_cell(struct screen *s, struct grid_cell *dst,
static void static void
screen_reflow(struct screen *s, u_int new_x) screen_reflow(struct screen *s, u_int new_x)
{ {
grid_reflow(s->grid, new_x, &s->cy); u_int cx = s->cx, cy = s->grid->hsize + s->cy, wx, wy;
struct timeval start, tv;
gettimeofday(&start, NULL);
grid_wrap_position(s->grid, cx, cy, &wx, &wy);
log_debug("%s: cursor %u,%u is %u,%u", __func__, cx, cy, wx, wy);
grid_reflow(s->grid, new_x);
grid_unwrap_position(s->grid, &cx, &cy, wx, wy);
log_debug("%s: new cursor is %u,%u", __func__, cx, cy);
if (cy >= s->grid->hsize) {
s->cx = cx;
s->cy = cy - s->grid->hsize;
} else {
s->cx = 0;
s->cy = 0;
}
gettimeofday(&tv, NULL);
timersub(&tv, &start, &tv);
log_debug("%s: reflow took %llu.%06u seconds", __func__,
(unsigned long long)tv.tv_sec, (u_int)tv.tv_usec);
} }

View File

@@ -184,18 +184,25 @@ server_client_create(int fd)
TAILQ_INIT(&c->queue); TAILQ_INIT(&c->queue);
c->stdin_data = evbuffer_new(); c->stdin_data = evbuffer_new();
if (c->stdin_data == NULL)
fatalx("out of memory");
c->stdout_data = evbuffer_new(); c->stdout_data = evbuffer_new();
if (c->stdout_data == NULL)
fatalx("out of memory");
c->stderr_data = evbuffer_new(); c->stderr_data = evbuffer_new();
if (c->stderr_data == NULL)
fatalx("out of memory");
c->tty.fd = -1; c->tty.fd = -1;
c->title = NULL; c->title = NULL;
c->session = NULL; c->session = NULL;
c->last_session = NULL; c->last_session = NULL;
c->tty.sx = 80; c->tty.sx = 80;
c->tty.sy = 24; c->tty.sy = 24;
screen_init(&c->status.status, c->tty.sx, 1, 0); status_init(c);
c->message_string = NULL; c->message_string = NULL;
TAILQ_INIT(&c->message_log); TAILQ_INIT(&c->message_log);
@@ -272,13 +279,7 @@ server_client_lost(struct client *c)
if (c->stderr_data != c->stdout_data) if (c->stderr_data != c->stdout_data)
evbuffer_free(c->stderr_data); evbuffer_free(c->stderr_data);
if (event_initialized(&c->status.timer)) status_free(c);
evtimer_del(&c->status.timer);
screen_free(&c->status.status);
if (c->status.old_status != NULL) {
screen_free(c->status.old_status);
free(c->status.old_status);
}
free(c->title); free(c->title);
free((void *)c->cwd); free((void *)c->cwd);
@@ -300,6 +301,7 @@ server_client_lost(struct client *c)
free(msg); free(msg);
} }
free(c->prompt_saved);
free(c->prompt_string); free(c->prompt_string);
free(c->prompt_buffer); free(c->prompt_buffer);
@@ -407,20 +409,21 @@ server_client_check_mouse(struct client *c)
{ {
struct session *s = c->session; struct session *s = c->session;
struct mouse_event *m = &c->tty.mouse; struct mouse_event *m = &c->tty.mouse;
struct window *w; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
u_int x, y, b; u_int x, y, b, sx, sy, px, py;
int flag; int flag;
key_code key; key_code key;
struct timeval tv; struct timeval tv;
struct style_range *sr;
enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type; enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type;
enum { NOWHERE, PANE, STATUS, BORDER } where; enum { NOWHERE, PANE, STATUS, STATUS_LEFT, STATUS_RIGHT, STATUS_DEFAULT, BORDER } where;
type = NOTYPE; type = NOTYPE;
where = NOWHERE; where = NOWHERE;
log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y, log_debug("%s mouse %02x at %u,%u (last %u,%u) (%d)", c->name, m->b,
m->lx, m->ly, c->tty.mouse_drag_flag); m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag);
/* What type of event is this? */ /* What type of event is this? */
if ((m->sgr_type != ' ' && if ((m->sgr_type != ' ' &&
@@ -439,7 +442,7 @@ server_client_check_mouse(struct client *c)
x = m->x, y = m->y, b = m->b; x = m->x, y = m->y, b = m->b;
log_debug("drag update at %u,%u", x, y); log_debug("drag update at %u,%u", x, y);
} else { } else {
x = m->lx, y = m->ly, b = m->lb; x = m->lx - m->ox, y = m->ly - m->oy, b = m->lb;
log_debug("drag start at %u,%u", x, y); log_debug("drag start at %u,%u", x, y);
} }
} else if (MOUSE_WHEEL(m->b)) { } else if (MOUSE_WHEEL(m->b)) {
@@ -493,48 +496,88 @@ have_event:
if (type == NOTYPE) if (type == NOTYPE)
return (KEYC_UNKNOWN); return (KEYC_UNKNOWN);
/* Always save the session. */ /* Save the session. */
m->s = s->id; m->s = s->id;
m->w = -1;
/* Is this on the status line? */ /* Is this on the status line? */
m->statusat = status_at_line(c); m->statusat = status_at_line(c);
if (m->statusat != -1 && y == (u_int)m->statusat) { if (m->statusat != -1 &&
w = status_get_window_at(c, x); y >= (u_int)m->statusat &&
if (w == NULL) y < m->statusat + status_line_size(c)) {
return (KEYC_UNKNOWN); sr = status_get_range(c, x, y - m->statusat);
m->w = w->id; if (sr == NULL) {
where = STATUS; where = STATUS_DEFAULT;
} else } else {
m->w = -1; switch (sr->type) {
case STYLE_RANGE_NONE:
return (KEYC_UNKNOWN);
case STYLE_RANGE_LEFT:
where = STATUS_LEFT;
break;
case STYLE_RANGE_RIGHT:
where = STATUS_RIGHT;
break;
case STYLE_RANGE_WINDOW:
wl = winlink_find_by_index(&s->windows, sr->argument);
if (wl == NULL)
return (KEYC_UNKNOWN);
m->w = wl->window->id;
where = STATUS;
break;
}
}
}
/* Not on status line. Adjust position and check for border or pane. */ /* Not on status line. Adjust position and check for border or pane. */
if (where == NOWHERE) { if (where == NOWHERE) {
px = x;
if (m->statusat == 0 && y > 0) if (m->statusat == 0 && y > 0)
y--; py = y - 1;
else if (m->statusat > 0 && y >= (u_int)m->statusat) else if (m->statusat > 0 && y >= (u_int)m->statusat)
y = m->statusat - 1; py = m->statusat - 1;
else
py = y;
TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { tty_window_offset(&c->tty, &m->ox, &m->oy, &sx, &sy);
if ((wp->xoff + wp->sx == x && log_debug("mouse window @%u at %u,%u (%ux%u)",
wp->yoff <= 1 + y && s->curw->window->id, m->ox, m->oy, sx, sy);
wp->yoff + wp->sy >= y) || if (px > sx || py > sy)
(wp->yoff + wp->sy == y && return (KEYC_UNKNOWN);
wp->xoff <= 1 + x && px = px + m->ox;
wp->xoff + wp->sx >= x)) py = py + m->oy;
break; m->x = x + m->ox;
} m->y = y + m->oy;
if (wp != NULL)
where = BORDER; /* Try the pane borders if not zoomed. */
else { if (~s->curw->window->flags & WINDOW_ZOOMED) {
wp = window_get_active_at(s->curw->window, x, y); TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
if (wp != NULL) { if ((wp->xoff + wp->sx == px &&
where = PANE; wp->yoff <= 1 + py &&
log_debug("mouse at %u,%u is on pane %%%u", wp->yoff + wp->sy >= py) ||
x, y, wp->id); (wp->yoff + wp->sy == py &&
wp->xoff <= 1 + px &&
wp->xoff + wp->sx >= px))
break;
} }
if (wp != NULL)
where = BORDER;
} }
/* Otherwise try inside the pane. */
if (where == NOWHERE) {
wp = window_get_active_at(s->curw->window, px, py);
if (wp != NULL)
where = PANE;
}
if (where == NOWHERE) if (where == NOWHERE)
return (KEYC_UNKNOWN); return (KEYC_UNKNOWN);
if (where == PANE)
log_debug("mouse %u,%u on pane %%%u", x, y, wp->id);
else if (where == BORDER)
log_debug("mouse on pane %%%u border", wp->id);
m->wp = wp->id; m->wp = wp->id;
m->w = wp->window->id; m->w = wp->window->id;
} else } else
@@ -558,6 +601,12 @@ have_event:
key = KEYC_MOUSEDRAGEND1_PANE; key = KEYC_MOUSEDRAGEND1_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDRAGEND1_STATUS; key = KEYC_MOUSEDRAGEND1_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND1_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND1_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND1_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAGEND1_BORDER; key = KEYC_MOUSEDRAGEND1_BORDER;
break; break;
@@ -566,6 +615,12 @@ have_event:
key = KEYC_MOUSEDRAGEND2_PANE; key = KEYC_MOUSEDRAGEND2_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDRAGEND2_STATUS; key = KEYC_MOUSEDRAGEND2_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND2_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND2_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND2_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAGEND2_BORDER; key = KEYC_MOUSEDRAGEND2_BORDER;
break; break;
@@ -574,6 +629,12 @@ have_event:
key = KEYC_MOUSEDRAGEND3_PANE; key = KEYC_MOUSEDRAGEND3_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDRAGEND3_STATUS; key = KEYC_MOUSEDRAGEND3_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND3_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND3_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND3_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAGEND3_BORDER; key = KEYC_MOUSEDRAGEND3_BORDER;
break; break;
@@ -596,6 +657,12 @@ have_event:
key = KEYC_MOUSEMOVE_PANE; key = KEYC_MOUSEMOVE_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEMOVE_STATUS; key = KEYC_MOUSEMOVE_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEMOVE_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEMOVE_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEMOVE_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEMOVE_BORDER; key = KEYC_MOUSEMOVE_BORDER;
break; break;
@@ -609,6 +676,12 @@ have_event:
key = KEYC_MOUSEDRAG1_PANE; key = KEYC_MOUSEDRAG1_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDRAG1_STATUS; key = KEYC_MOUSEDRAG1_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG1_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG1_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG1_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAG1_BORDER; key = KEYC_MOUSEDRAG1_BORDER;
break; break;
@@ -617,6 +690,12 @@ have_event:
key = KEYC_MOUSEDRAG2_PANE; key = KEYC_MOUSEDRAG2_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDRAG2_STATUS; key = KEYC_MOUSEDRAG2_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG2_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG2_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG2_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAG2_BORDER; key = KEYC_MOUSEDRAG2_BORDER;
break; break;
@@ -625,6 +704,12 @@ have_event:
key = KEYC_MOUSEDRAG3_PANE; key = KEYC_MOUSEDRAG3_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDRAG3_STATUS; key = KEYC_MOUSEDRAG3_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG3_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG3_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG3_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAG3_BORDER; key = KEYC_MOUSEDRAG3_BORDER;
break; break;
@@ -643,6 +728,12 @@ have_event:
key = KEYC_WHEELUP_PANE; key = KEYC_WHEELUP_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_WHEELUP_STATUS; key = KEYC_WHEELUP_STATUS;
if (where == STATUS_LEFT)
key = KEYC_WHEELUP_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_WHEELUP_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_WHEELUP_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_WHEELUP_BORDER; key = KEYC_WHEELUP_BORDER;
} else { } else {
@@ -650,6 +741,12 @@ have_event:
key = KEYC_WHEELDOWN_PANE; key = KEYC_WHEELDOWN_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_WHEELDOWN_STATUS; key = KEYC_WHEELDOWN_STATUS;
if (where == STATUS_LEFT)
key = KEYC_WHEELDOWN_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_WHEELDOWN_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_WHEELDOWN_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_WHEELDOWN_BORDER; key = KEYC_WHEELDOWN_BORDER;
} }
@@ -661,6 +758,12 @@ have_event:
key = KEYC_MOUSEUP1_PANE; key = KEYC_MOUSEUP1_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEUP1_STATUS; key = KEYC_MOUSEUP1_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP1_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP1_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP1_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEUP1_BORDER; key = KEYC_MOUSEUP1_BORDER;
break; break;
@@ -669,6 +772,12 @@ have_event:
key = KEYC_MOUSEUP2_PANE; key = KEYC_MOUSEUP2_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEUP2_STATUS; key = KEYC_MOUSEUP2_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP2_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP2_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP2_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEUP2_BORDER; key = KEYC_MOUSEUP2_BORDER;
break; break;
@@ -677,6 +786,12 @@ have_event:
key = KEYC_MOUSEUP3_PANE; key = KEYC_MOUSEUP3_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEUP3_STATUS; key = KEYC_MOUSEUP3_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP3_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP3_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP3_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEUP3_BORDER; key = KEYC_MOUSEUP3_BORDER;
break; break;
@@ -689,6 +804,12 @@ have_event:
key = KEYC_MOUSEDOWN1_PANE; key = KEYC_MOUSEDOWN1_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDOWN1_STATUS; key = KEYC_MOUSEDOWN1_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN1_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN1_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN1_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDOWN1_BORDER; key = KEYC_MOUSEDOWN1_BORDER;
break; break;
@@ -697,6 +818,12 @@ have_event:
key = KEYC_MOUSEDOWN2_PANE; key = KEYC_MOUSEDOWN2_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDOWN2_STATUS; key = KEYC_MOUSEDOWN2_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN2_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN2_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN2_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDOWN2_BORDER; key = KEYC_MOUSEDOWN2_BORDER;
break; break;
@@ -705,6 +832,12 @@ have_event:
key = KEYC_MOUSEDOWN3_PANE; key = KEYC_MOUSEDOWN3_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_MOUSEDOWN3_STATUS; key = KEYC_MOUSEDOWN3_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN3_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN3_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN3_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDOWN3_BORDER; key = KEYC_MOUSEDOWN3_BORDER;
break; break;
@@ -717,6 +850,12 @@ have_event:
key = KEYC_DOUBLECLICK1_PANE; key = KEYC_DOUBLECLICK1_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_DOUBLECLICK1_STATUS; key = KEYC_DOUBLECLICK1_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK1_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK1_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK1_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_DOUBLECLICK1_BORDER; key = KEYC_DOUBLECLICK1_BORDER;
break; break;
@@ -725,6 +864,12 @@ have_event:
key = KEYC_DOUBLECLICK2_PANE; key = KEYC_DOUBLECLICK2_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_DOUBLECLICK2_STATUS; key = KEYC_DOUBLECLICK2_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK2_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK2_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK2_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_DOUBLECLICK2_BORDER; key = KEYC_DOUBLECLICK2_BORDER;
break; break;
@@ -733,6 +878,12 @@ have_event:
key = KEYC_DOUBLECLICK3_PANE; key = KEYC_DOUBLECLICK3_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_DOUBLECLICK3_STATUS; key = KEYC_DOUBLECLICK3_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK3_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK3_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK3_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_DOUBLECLICK3_BORDER; key = KEYC_DOUBLECLICK3_BORDER;
break; break;
@@ -745,6 +896,12 @@ have_event:
key = KEYC_TRIPLECLICK1_PANE; key = KEYC_TRIPLECLICK1_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_TRIPLECLICK1_STATUS; key = KEYC_TRIPLECLICK1_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK1_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK1_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK1_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_TRIPLECLICK1_BORDER; key = KEYC_TRIPLECLICK1_BORDER;
break; break;
@@ -753,6 +910,12 @@ have_event:
key = KEYC_TRIPLECLICK2_PANE; key = KEYC_TRIPLECLICK2_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_TRIPLECLICK2_STATUS; key = KEYC_TRIPLECLICK2_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK2_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK2_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK2_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_TRIPLECLICK2_BORDER; key = KEYC_TRIPLECLICK2_BORDER;
break; break;
@@ -761,6 +924,12 @@ have_event:
key = KEYC_TRIPLECLICK3_PANE; key = KEYC_TRIPLECLICK3_PANE;
if (where == STATUS) if (where == STATUS)
key = KEYC_TRIPLECLICK3_STATUS; key = KEYC_TRIPLECLICK3_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK3_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK3_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK3_STATUS_DEFAULT;
if (where == BORDER) if (where == BORDER)
key = KEYC_TRIPLECLICK3_BORDER; key = KEYC_TRIPLECLICK3_BORDER;
break; break;
@@ -809,21 +978,24 @@ server_client_assume_paste(struct session *s)
void void
server_client_handle_key(struct client *c, key_code key) server_client_handle_key(struct client *c, key_code key)
{ {
struct mouse_event *m = &c->tty.mouse; struct mouse_event *m = &c->tty.mouse;
struct session *s = c->session; struct session *s = c->session;
struct window *w; struct winlink *wl;
struct window_pane *wp; struct window *w;
struct timeval tv; struct window_pane *wp;
struct key_table *table, *first; struct window_mode_entry *wme;
struct key_binding *bd; struct timeval tv;
int xtimeout, flags; struct key_table *table, *first;
struct cmd_find_state fs; struct key_binding *bd;
key_code key0; int xtimeout, flags;
struct cmd_find_state fs;
key_code key0;
/* Check the client is good to accept input. */ /* Check the client is good to accept input. */
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
return; return;
w = s->curw->window; wl = s->curw;
w = wl->window;
/* Update the activity timer. */ /* Update the activity timer. */
if (gettimeofday(&c->activity_time, NULL) != 0) if (gettimeofday(&c->activity_time, NULL) != 0)
@@ -836,8 +1008,6 @@ server_client_handle_key(struct client *c, key_code key)
return; return;
window_unzoom(w); window_unzoom(w);
wp = window_pane_at_index(w, key - '0'); wp = window_pane_at_index(w, key - '0');
if (wp != NULL && !window_pane_visible(wp))
wp = NULL;
server_client_clear_identify(c, wp); server_client_clear_identify(c, wp);
return; return;
} }
@@ -896,9 +1066,9 @@ server_client_handle_key(struct client *c, key_code key)
*/ */
if (server_client_is_default_key_table(c, c->keytable) && if (server_client_is_default_key_table(c, c->keytable) &&
wp != NULL && wp != NULL &&
wp->mode != NULL && (wme = TAILQ_FIRST(&wp->modes)) != NULL &&
wp->mode->key_table != NULL) wme->mode->key_table != NULL)
table = key_bindings_get_table(wp->mode->key_table(wp), 1); table = key_bindings_get_table(wme->mode->key_table(wme), 1);
else else
table = c->keytable; table = c->keytable;
first = table; first = table;
@@ -918,6 +1088,7 @@ table_changed:
} }
flags = c->flags; flags = c->flags;
try_again:
/* Log key table. */ /* Log key table. */
if (wp == NULL) if (wp == NULL)
log_debug("key table %s (no pane)", table->name); log_debug("key table %s (no pane)", table->name);
@@ -926,7 +1097,6 @@ table_changed:
if (c->flags & CLIENT_REPEAT) if (c->flags & CLIENT_REPEAT)
log_debug("currently repeating"); log_debug("currently repeating");
try_again:
/* Try to see if there is a key binding in the current table. */ /* Try to see if there is a key binding in the current table. */
bd = key_bindings_get(table, key0); bd = key_bindings_get(table, key0);
if (bd != NULL) { if (bd != NULL) {
@@ -937,10 +1107,12 @@ try_again:
*/ */
if ((c->flags & CLIENT_REPEAT) && if ((c->flags & CLIENT_REPEAT) &&
(~bd->flags & KEY_BINDING_REPEAT)) { (~bd->flags & KEY_BINDING_REPEAT)) {
log_debug("found in key table %s (not repeating)",
table->name);
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
first = table = c->keytable;
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
server_status_client(c); server_status_client(c);
table = c->keytable;
goto table_changed; goto table_changed;
} }
log_debug("found in key table %s", table->name); log_debug("found in key table %s", table->name);
@@ -990,10 +1162,13 @@ try_again:
log_debug("not found in key table %s", table->name); log_debug("not found in key table %s", table->name);
if (!server_client_is_default_key_table(c, table) || if (!server_client_is_default_key_table(c, table) ||
(c->flags & CLIENT_REPEAT)) { (c->flags & CLIENT_REPEAT)) {
log_debug("trying in root table");
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
table = c->keytable;
if (c->flags & CLIENT_REPEAT)
first = table;
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
server_status_client(c); server_status_client(c);
table = c->keytable;
goto table_changed; goto table_changed;
} }
@@ -1011,7 +1186,7 @@ forward_key:
if (c->flags & CLIENT_READONLY) if (c->flags & CLIENT_READONLY)
return; return;
if (wp != NULL) if (wp != NULL)
window_pane_key(wp, c, s, key, m); window_pane_key(wp, c, s, wl, key, m);
} }
/* Client functions that need to happen every loop. */ /* Client functions that need to happen every loop. */
@@ -1183,7 +1358,7 @@ server_client_check_focus(struct window_pane *wp)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || !(c->flags & CLIENT_FOCUSED)) if (c->session == NULL || !(c->flags & CLIENT_FOCUSED))
continue; continue;
if (c->session->flags & SESSION_UNATTACHED) if (c->session->attached == 0)
continue; continue;
if (c->session->curw->window == wp->window) if (c->session->curw->window == wp->window)
@@ -1224,28 +1399,37 @@ server_client_reset_state(struct client *c)
struct window_pane *wp = w->active, *loop; struct window_pane *wp = w->active, *loop;
struct screen *s = wp->screen; struct screen *s = wp->screen;
struct options *oo = c->session->options; struct options *oo = c->session->options;
int lines, mode; int mode, cursor = 0;
u_int cx = 0, cy = 0, ox, oy, sx, sy;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return; return;
mode = s->mode;
tty_region_off(&c->tty); tty_region_off(&c->tty);
tty_margin_off(&c->tty); tty_margin_off(&c->tty);
if (status_at_line(c) != 0) /* Move cursor to pane cursor and offset. */
lines = 0; cursor = 0;
else tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
lines = status_line_size(c->session); if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx &&
if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - lines) wp->yoff + s->cy >= oy && wp->yoff + s->cy <= oy + sy) {
tty_cursor(&c->tty, 0, 0); cursor = 1;
else
tty_cursor(&c->tty, wp->xoff + s->cx, lines + wp->yoff + s->cy); cx = wp->xoff + s->cx - ox;
cy = wp->yoff + s->cy - oy;
if (status_at_line(c) == 0)
cy += status_line_size(c);
}
if (!cursor)
mode &= ~MODE_CURSOR;
tty_cursor(&c->tty, cx, cy);
/* /*
* Set mouse mode if requested. To support dragging, always use button * Set mouse mode if requested. To support dragging, always use button
* mode. * mode.
*/ */
mode = s->mode;
if (options_get_number(oo, "mouse")) { if (options_get_number(oo, "mouse")) {
mode &= ~ALL_MOUSE_MODES; mode &= ~ALL_MOUSE_MODES;
TAILQ_FOREACH(loop, &w->panes, entry) { TAILQ_FOREACH(loop, &w->panes, entry) {
@@ -1322,13 +1506,19 @@ server_client_check_redraw(struct client *c)
struct session *s = c->session; struct session *s = c->session;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
int needed, flags, masked; int needed, flags;
struct timeval tv = { .tv_usec = 1000 }; struct timeval tv = { .tv_usec = 1000 };
static struct event ev; static struct event ev;
size_t left; size_t left;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return; return;
if (c->flags & CLIENT_ALLREDRAWFLAGS) {
log_debug("%s: redraw%s%s%s", c->name,
(c->flags & CLIENT_REDRAWWINDOW) ? " window" : "",
(c->flags & CLIENT_REDRAWSTATUS) ? " status" : "",
(c->flags & CLIENT_REDRAWBORDERS) ? " borders" : "");
}
/* /*
* If there is outstanding data, defer the redraw until it has been * If there is outstanding data, defer the redraw until it has been
@@ -1336,7 +1526,7 @@ server_client_check_redraw(struct client *c)
* end up back here. * end up back here.
*/ */
needed = 0; needed = 0;
if (c->flags & CLIENT_REDRAW) if (c->flags & CLIENT_ALLREDRAWFLAGS)
needed = 1; needed = 1;
else { else {
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
@@ -1359,25 +1549,19 @@ server_client_check_redraw(struct client *c)
* We may have got here for a single pane redraw, but force a * We may have got here for a single pane redraw, but force a
* full redraw next time in case other panes have been updated. * full redraw next time in case other panes have been updated.
*/ */
c->flags |= CLIENT_REDRAW; c->flags |= CLIENT_ALLREDRAWFLAGS;
return; return;
} else if (needed) } else if (needed)
log_debug("%s: redraw needed", c->name); log_debug("%s: redraw needed", c->name);
if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
if (options_get_number(s->options, "set-titles"))
server_client_set_title(c);
screen_redraw_update(c); /* will adjust flags */
}
flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR); flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR);
tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE)) | TTY_NOCURSOR; tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE)) | TTY_NOCURSOR;
if (c->flags & CLIENT_REDRAW) { if (~c->flags & CLIENT_REDRAWWINDOW) {
tty_update_mode(tty, tty->mode, NULL); /*
screen_redraw_screen(c, 1, 1, 1); * If not redrawing the entire window, check whether each pane
c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); * needs to be redrawn.
} else { */
TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
if (wp->flags & PANE_REDRAW) { if (wp->flags & PANE_REDRAW) {
tty_update_mode(tty, tty->mode, NULL); tty_update_mode(tty, tty->mode, NULL);
@@ -1386,21 +1570,16 @@ server_client_check_redraw(struct client *c)
} }
} }
masked = c->flags & (CLIENT_BORDERS|CLIENT_STATUS); if (c->flags & CLIENT_ALLREDRAWFLAGS) {
if (masked != 0) if (options_get_number(s->options, "set-titles"))
tty_update_mode(tty, tty->mode, NULL); server_client_set_title(c);
if (masked == CLIENT_BORDERS) screen_redraw_screen(c);
screen_redraw_screen(c, 0, 0, 1); }
else if (masked == CLIENT_STATUS)
screen_redraw_screen(c, 0, 1, 0);
else if (masked != 0)
screen_redraw_screen(c, 0, 1, 1);
tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags; tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags;
tty_update_mode(tty, tty->mode, NULL); tty_update_mode(tty, tty->mode, NULL);
c->flags &= ~(CLIENT_REDRAW|CLIENT_BORDERS|CLIENT_STATUS| c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_STATUSFORCE);
CLIENT_STATUSFORCE);
if (needed) { if (needed) {
/* /*
@@ -1427,7 +1606,7 @@ server_client_set_title(struct client *c)
ft = format_create(c, NULL, FORMAT_NONE, 0); ft = format_create(c, NULL, FORMAT_NONE, 0);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
title = format_expand_time(ft, template, time(NULL)); title = format_expand_time(ft, template);
if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title == NULL || strcmp(title, c->title) != 0) {
free(c->title); free(c->title);
c->title = xstrdup(title); c->title = xstrdup(title);
@@ -1877,6 +2056,8 @@ server_client_get_cwd(struct client *c, struct session *s)
{ {
const char *home; const char *home;
if (!cfg_finished && cfg_client != NULL)
return (cfg_client->cwd);
if (c != NULL && c->session == NULL && c->cwd != NULL) if (c != NULL && c->session == NULL && c->cwd != NULL)
return (c->cwd); return (c->cwd);
if (s != NULL && s->cwd != NULL) if (s != NULL && s->cwd != NULL)

View File

@@ -33,13 +33,13 @@ static void server_destroy_session_group(struct session *);
void void
server_redraw_client(struct client *c) server_redraw_client(struct client *c)
{ {
c->flags |= CLIENT_REDRAW; c->flags |= CLIENT_ALLREDRAWFLAGS;
} }
void void
server_status_client(struct client *c) server_status_client(struct client *c)
{ {
c->flags |= CLIENT_STATUS; c->flags |= CLIENT_REDRAWSTATUS;
} }
void void
@@ -108,7 +108,7 @@ server_redraw_window_borders(struct window *w)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && c->session->curw->window == w) if (c->session != NULL && c->session->curw->window == w)
c->flags |= CLIENT_BORDERS; c->flags |= CLIENT_REDRAWBORDERS;
} }
} }
@@ -303,6 +303,7 @@ server_destroy_pane(struct window_pane *wp, int notify)
utempter_remove_record(wp->fd); utempter_remove_record(wp->fd);
#endif #endif
bufferevent_free(wp->event); bufferevent_free(wp->event);
wp->event = NULL;
close(wp->fd); close(wp->fd);
wp->fd = -1; wp->fd = -1;
} }
@@ -320,7 +321,7 @@ server_destroy_pane(struct window_pane *wp, int notify)
screen_write_start(&ctx, wp, &wp->base); screen_write_start(&ctx, wp, &wp->base);
screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1); screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1);
screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1); screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1, 0);
screen_write_linefeed(&ctx, 1, 8); screen_write_linefeed(&ctx, 1, 8);
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
@@ -410,6 +411,7 @@ server_destroy_session(struct session *s)
c->last_session = NULL; c->last_session = NULL;
c->session = s_new; c->session = s_new;
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
notify_client("client-session-changed", c); notify_client("client-session-changed", c);
session_update_activity(s_new, NULL); session_update_activity(s_new, NULL);
@@ -431,7 +433,7 @@ server_check_unattached(void)
* set, collect them. * set, collect them.
*/ */
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
if (!(s->flags & SESSION_UNATTACHED)) if (s->attached != 0)
continue; continue;
if (options_get_number (s->options, "destroy-unattached")) if (options_get_number (s->options, "destroy-unattached"))
session_destroy(s, __func__); session_destroy(s, __func__);

View File

@@ -161,7 +161,6 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
char *lockfile) char *lockfile)
{ {
int pair[2]; int pair[2];
struct job *job;
sigset_t set, oldset; sigset_t set, oldset;
struct client *c; struct client *c;
char *cause = NULL; char *cause = NULL;
@@ -222,17 +221,13 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
} }
start_cfg(); start_cfg();
server_add_accept(0); server_add_accept(0);
proc_loop(server_proc, server_loop); proc_loop(server_proc, server_loop);
LIST_FOREACH(job, &all_jobs, entry) { job_kill_all();
if (job->pid != -1)
kill(job->pid, SIGTERM);
}
status_prompt_save_history(); status_prompt_save_history();
exit(0); exit(0);
} }
@@ -242,7 +237,6 @@ server_loop(void)
{ {
struct client *c; struct client *c;
u_int items; u_int items;
struct job *job;
do { do {
items = cmdq_next(NULL); items = cmdq_next(NULL);
@@ -275,10 +269,8 @@ server_loop(void)
if (!TAILQ_EMPTY(&clients)) if (!TAILQ_EMPTY(&clients))
return (0); return (0);
LIST_FOREACH(job, &all_jobs, entry) { if (job_still_running())
if ((~job->flags & JOB_NOWAIT) && job->state == JOB_RUNNING) return (0);
return (0);
}
return (1); return (1);
} }
@@ -318,7 +310,7 @@ server_update_socket(void)
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
if (!(s->flags & SESSION_UNATTACHED)) { if (s->attached != 0) {
n++; n++;
break; break;
} }
@@ -456,7 +448,6 @@ server_child_exited(pid_t pid, int status)
{ {
struct window *w, *w1; struct window *w, *w1;
struct window_pane *wp; struct window_pane *wp;
struct job *job;
RB_FOREACH_SAFE(w, windows, &windows, w1) { RB_FOREACH_SAFE(w, windows, &windows, w1) {
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
@@ -473,13 +464,7 @@ server_child_exited(pid_t pid, int status)
} }
} }
} }
job_check_died(pid, status);
LIST_FOREACH(job, &all_jobs, entry) {
if (pid == job->pid) {
job_died(job, status); /* might free job */
break;
}
}
} }
/* Handle stopped children. */ /* Handle stopped children. */

View File

@@ -112,8 +112,8 @@ session_find_by_id(u_int id)
/* Create a new session. */ /* Create a new session. */
struct session * struct session *
session_create(const char *prefix, const char *name, int argc, char **argv, session_create(const char *prefix, const char *name, int argc, char **argv,
const char *path, const char *cwd, struct environ *env, struct termios *tio, const char *path, const char *cwd, struct environ *env, struct options *oo,
int idx, u_int sx, u_int sy, char **cause) struct termios *tio, int idx, char **cause)
{ {
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
@@ -132,10 +132,10 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
if (env != NULL) if (env != NULL)
environ_copy(env, s->environ); environ_copy(env, s->environ);
s->options = options_create(global_s_options); s->options = oo;
s->hooks = hooks_create(global_hooks); s->hooks = hooks_create(global_hooks);
status_update_saved(s); status_update_cache(s);
s->tio = NULL; s->tio = NULL;
if (tio != NULL) { if (tio != NULL) {
@@ -143,9 +143,6 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
memcpy(s->tio, tio, sizeof *s->tio); memcpy(s->tio, tio, sizeof *s->tio);
} }
s->sx = sx;
s->sy = sy;
if (name != NULL) { if (name != NULL) {
s->name = xstrdup(name); s->name = xstrdup(name);
s->id = next_session_id++; s->id = next_session_id++;
@@ -265,7 +262,7 @@ session_lock_timer(__unused int fd, __unused short events, void *arg)
{ {
struct session *s = arg; struct session *s = arg;
if (s->flags & SESSION_UNATTACHED) if (s->attached == 0)
return; return;
log_debug("session %s locked, activity time %lld", s->name, log_debug("session %s locked, activity time %lld", s->name,
@@ -298,7 +295,7 @@ session_update_activity(struct session *s, struct timeval *from)
else else
evtimer_set(&s->lock_timer, session_lock_timer, s); evtimer_set(&s->lock_timer, session_lock_timer, s);
if (~s->flags & SESSION_UNATTACHED) { if (s->attached != 0) {
timerclear(&tv); timerclear(&tv);
tv.tv_sec = options_get_number(s->options, "lock-after-time"); tv.tv_sec = options_get_number(s->options, "lock-after-time");
if (tv.tv_sec != 0) if (tv.tv_sec != 0)
@@ -349,7 +346,7 @@ session_new(struct session *s, const char *name, int argc, char **argv,
struct winlink *wl; struct winlink *wl;
struct environ *env; struct environ *env;
const char *shell; const char *shell;
u_int hlimit; u_int hlimit, sx, sy;
if ((wl = winlink_add(&s->windows, idx)) == NULL) { if ((wl = winlink_add(&s->windows, idx)) == NULL) {
xasprintf(cause, "index in use: %d", idx); xasprintf(cause, "index in use: %d", idx);
@@ -361,10 +358,11 @@ session_new(struct session *s, const char *name, int argc, char **argv,
if (*shell == '\0' || areshell(shell)) if (*shell == '\0' || areshell(shell))
shell = _PATH_BSHELL; shell = _PATH_BSHELL;
default_window_size(s, NULL, &sx, &sy, -1);
hlimit = options_get_number(s->options, "history-limit"); hlimit = options_get_number(s->options, "history-limit");
env = environ_for_session(s, 0); env = environ_for_session(s, 0);
w = window_create_spawn(name, argc, argv, path, shell, cwd, env, s->tio, w = window_create_spawn(name, argc, argv, path, shell, cwd, env, s->tio,
s->sx, s->sy, hlimit, cause); sx, sy, hlimit, cause);
if (w == NULL) { if (w == NULL) {
winlink_remove(&s->windows, wl); winlink_remove(&s->windows, wl);
environ_free(env); environ_free(env);
@@ -547,6 +545,7 @@ session_set_current(struct session *s, struct winlink *wl)
s->curw = wl; s->curw = wl;
winlink_clear_flags(wl); winlink_clear_flags(wl);
window_update_activity(wl->window); window_update_activity(wl->window);
tty_update_window_offset(wl->window);
notify_session("session-window-changed", s); notify_session("session-window-changed", s);
return (0); return (0);
} }

733
status.c

File diff suppressed because it is too large Load Diff

277
style.c
View File

@@ -19,32 +19,51 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "tmux.h" #include "tmux.h"
/* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */ /* Mask for bits not included in style. */
#define STYLE_ATTR_MASK (~GRID_ATTR_CHARSET)
/* Default style. */
static struct style style_default = {
{ 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } },
STYLE_ALIGN_DEFAULT,
STYLE_LIST_OFF,
STYLE_RANGE_NONE, 0
};
/*
* Parse an embedded style of the form "fg=colour,bg=colour,bright,...".
* Note that this adds onto the given style, so it must have been initialized
* alredy.
*/
int int
style_parse(const struct grid_cell *defgc, struct grid_cell *gc, style_parse(struct style *sy, const struct grid_cell *base, const char *in)
const char *in)
{ {
struct grid_cell savedgc; struct style saved;
const char delimiters[] = " ,"; const char delimiters[] = " ,", *cp;
char tmp[32]; char tmp[256], *found;
int val, fg, bg, attr, flags; int value;
size_t end; size_t end;
if (*in == '\0') if (*in == '\0')
return (0); return (0);
if (strchr(delimiters, in[strlen(in) - 1]) != NULL) style_copy(&saved, sy);
return (-1);
memcpy(&savedgc, gc, sizeof savedgc);
fg = gc->fg;
bg = gc->bg;
attr = gc->attr;
flags = gc->flags;
do { do {
while (*in != '\0' && strchr(delimiters, *in) != NULL) {
in++;
end--;
}
if (*in == '\0')
break;
end = strcspn(in, delimiters); end = strcspn(in, delimiters);
if (end > (sizeof tmp) - 1) if (end > (sizeof tmp) - 1)
goto error; goto error;
@@ -52,74 +71,164 @@ style_parse(const struct grid_cell *defgc, struct grid_cell *gc,
tmp[end] = '\0'; tmp[end] = '\0';
if (strcasecmp(tmp, "default") == 0) { if (strcasecmp(tmp, "default") == 0) {
fg = defgc->fg; sy->gc.fg = base->fg;
bg = defgc->bg; sy->gc.bg = base->bg;
attr = defgc->attr; sy->gc.attr = base->attr;
flags = defgc->flags; sy->gc.flags = base->flags;
} else if (strcasecmp(tmp, "nolist") == 0)
sy->list = STYLE_LIST_OFF;
else if (strncasecmp(tmp, "list=", 5) == 0) {
if (strcasecmp(tmp + 5, "on") == 0)
sy->list = STYLE_LIST_ON;
else if (strcasecmp(tmp + 5, "focus") == 0)
sy->list = STYLE_LIST_FOCUS;
else if (strcasecmp(tmp + 5, "left-marker") == 0)
sy->list = STYLE_LIST_LEFT_MARKER;
else if (strcasecmp(tmp + 5, "right-marker") == 0)
sy->list = STYLE_LIST_RIGHT_MARKER;
else
goto error;
} else if (strcasecmp(tmp, "norange") == 0) {
sy->range_type = style_default.range_type;
sy->range_argument = style_default.range_type;
} else if (end > 6 && strncasecmp(tmp, "range=", 6) == 0) {
found = strchr(tmp + 6, '|');
if (found != NULL) {
*found++ = '\0';
if (*found == '\0')
goto error;
for (cp = found; *cp != '\0'; cp++) {
if (!isdigit((u_char)*cp))
goto error;
}
}
if (strcasecmp(tmp + 6, "left") == 0) {
if (found != NULL)
goto error;
sy->range_type = STYLE_RANGE_LEFT;
sy->range_argument = 0;
} else if (strcasecmp(tmp + 6, "right") == 0) {
if (found != NULL)
goto error;
sy->range_type = STYLE_RANGE_RIGHT;
sy->range_argument = 0;
} else if (strcasecmp(tmp + 6, "window") == 0) {
if (found == NULL)
goto error;
sy->range_type = STYLE_RANGE_WINDOW;
sy->range_argument = atoi(found);
}
} else if (strcasecmp(tmp, "noalign") == 0)
sy->align = style_default.align;
else if (end > 6 && strncasecmp(tmp, "align=", 6) == 0) {
if (strcasecmp(tmp + 6, "left") == 0)
sy->align = STYLE_ALIGN_LEFT;
else if (strcasecmp(tmp + 6, "centre") == 0)
sy->align = STYLE_ALIGN_CENTRE;
else if (strcasecmp(tmp + 6, "right") == 0)
sy->align = STYLE_ALIGN_RIGHT;
else
goto error;
} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) { } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
if ((val = colour_fromstring(tmp + 3)) == -1) if ((value = colour_fromstring(tmp + 3)) == -1)
goto error; goto error;
if (*in == 'f' || *in == 'F') { if (*in == 'f' || *in == 'F') {
if (val != 8) if (value != 8)
fg = val; sy->gc.fg = value;
else else
fg = defgc->fg; sy->gc.fg = base->fg;
} else if (*in == 'b' || *in == 'B') { } else if (*in == 'b' || *in == 'B') {
if (val != 8) if (value != 8)
bg = val; sy->gc.bg = value;
else else
bg = defgc->bg; sy->gc.bg = base->bg;
} else } else
goto error; goto error;
} else if (strcasecmp(tmp, "none") == 0) } else if (strcasecmp(tmp, "none") == 0)
attr = 0; sy->gc.attr = 0;
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
if ((val = attributes_fromstring(tmp + 2)) == -1) if ((value = attributes_fromstring(tmp + 2)) == -1)
goto error; goto error;
attr &= ~val; sy->gc.attr &= ~value;
} else { } else {
if ((val = attributes_fromstring(tmp)) == -1) if ((value = attributes_fromstring(tmp)) == -1)
goto error; goto error;
attr |= val; sy->gc.attr |= value;
} }
in += end + strspn(in + end, delimiters); in += end + strspn(in + end, delimiters);
} while (*in != '\0'); } while (*in != '\0');
gc->fg = fg;
gc->bg = bg;
gc->attr = attr;
gc->flags = flags;
return (0); return (0);
error: error:
memcpy(gc, &savedgc, sizeof *gc); style_copy(sy, &saved);
return (-1); return (-1);
} }
/* Convert style to a string. */ /* Convert style to a string. */
const char * const char *
style_tostring(struct grid_cell *gc) style_tostring(struct style *sy)
{ {
int off = 0, comma = 0; struct grid_cell *gc = &sy->gc;
static char s[256]; int off = 0;
const char *comma = "", *tmp;
static char s[256];
char b[16];
*s = '\0'; *s = '\0';
if (sy->list != STYLE_LIST_OFF) {
if (sy->list == STYLE_LIST_ON)
tmp = "on";
else if (sy->list == STYLE_LIST_FOCUS)
tmp = "focus";
else if (sy->list == STYLE_LIST_LEFT_MARKER)
tmp = "left-marker";
else if (sy->list == STYLE_LIST_RIGHT_MARKER)
tmp = "right-marker";
off += xsnprintf(s + off, sizeof s - off, "%slist=%s", comma,
tmp);
comma = ",";
}
if (sy->range_type != STYLE_RANGE_NONE) {
if (sy->range_type == STYLE_RANGE_LEFT)
tmp = "left";
else if (sy->range_type == STYLE_RANGE_RIGHT)
tmp = "right";
else if (sy->range_type == STYLE_RANGE_WINDOW) {
snprintf(b, sizeof b, "window|%u", sy->range_argument);
tmp = b;
}
off += xsnprintf(s + off, sizeof s - off, "%srange=%s", comma,
tmp);
comma = ",";
}
if (sy->align != STYLE_ALIGN_DEFAULT) {
if (sy->align == STYLE_ALIGN_LEFT)
tmp = "left";
else if (sy->align == STYLE_ALIGN_CENTRE)
tmp = "centre";
else if (sy->align == STYLE_ALIGN_RIGHT)
tmp = "right";
off += xsnprintf(s + off, sizeof s - off, "%salign=%s", comma,
tmp);
comma = ",";
}
if (gc->fg != 8) { if (gc->fg != 8) {
off += xsnprintf(s, sizeof s, "fg=%s", colour_tostring(gc->fg)); off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma,
comma = 1; colour_tostring(gc->fg));
comma = ",";
} }
if (gc->bg != 8) { if (gc->bg != 8) {
off += xsnprintf(s + off, sizeof s - off, "%sbg=%s", off += xsnprintf(s + off, sizeof s - off, "%sbg=%s", comma,
comma ? "," : "", colour_tostring(gc->bg)); colour_tostring(gc->bg));
comma = 1; comma = ",";
} }
if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) { if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) {
xsnprintf(s + off, sizeof s - off, "%s%s", xsnprintf(s + off, sizeof s - off, "%s%s", comma,
comma ? "," : "", attributes_tostring(gc->attr)); attributes_tostring(gc->attr));
comma = ",";
} }
if (*s == '\0') if (*s == '\0')
@@ -131,38 +240,66 @@ style_tostring(struct grid_cell *gc)
void void
style_apply(struct grid_cell *gc, struct options *oo, const char *name) style_apply(struct grid_cell *gc, struct options *oo, const char *name)
{ {
const struct grid_cell *gcp; struct style *sy;
memcpy(gc, &grid_default_cell, sizeof *gc); memcpy(gc, &grid_default_cell, sizeof *gc);
gcp = options_get_style(oo, name); sy = options_get_style(oo, name);
gc->fg = gcp->fg; gc->fg = sy->gc.fg;
gc->bg = gcp->bg; gc->bg = sy->gc.bg;
gc->attr |= gcp->attr; gc->attr |= sy->gc.attr;
} }
/* Apply a style, updating if default. */ /* Apply a style, updating if default. */
void void
style_apply_update(struct grid_cell *gc, struct options *oo, const char *name) style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
{ {
const struct grid_cell *gcp; struct style *sy;
gcp = options_get_style(oo, name); sy = options_get_style(oo, name);
if (gcp->fg != 8) if (sy->gc.fg != 8)
gc->fg = gcp->fg; gc->fg = sy->gc.fg;
if (gcp->bg != 8) if (sy->gc.bg != 8)
gc->bg = gcp->bg; gc->bg = sy->gc.bg;
if (gcp->attr != 0) if (sy->gc.attr != 0)
gc->attr |= gcp->attr; gc->attr |= sy->gc.attr;
} }
/* Check if two styles are the same. */ /* Initialize style from cell. */
int void
style_equal(const struct grid_cell *gc1, const struct grid_cell *gc2) style_set(struct style *sy, const struct grid_cell *gc)
{ {
return (gc1->fg == gc2->fg && memcpy(sy, &style_default, sizeof *sy);
gc1->bg == gc2->bg && memcpy(&sy->gc, gc, sizeof sy->gc);
(gc1->flags & ~GRID_FLAG_PADDING) == }
(gc2->flags & ~GRID_FLAG_PADDING) &&
(gc1->attr & ~GRID_ATTR_CHARSET) == /* Copy style. */
(gc2->attr & ~GRID_ATTR_CHARSET)); void
style_copy(struct style *dst, struct style *src)
{
memcpy(dst, src, sizeof *dst);
}
/* Check if two styles are (visibly) the same. */
int
style_equal(struct style *sy1, struct style *sy2)
{
struct grid_cell *gc1 = &sy1->gc;
struct grid_cell *gc2 = &sy2->gc;
if (gc1->fg != gc2->fg)
return (0);
if (gc1->bg != gc2->bg)
return (0);
if ((gc1->attr & STYLE_ATTR_MASK) != (gc2->attr & STYLE_ATTR_MASK))
return (0);
if (sy1->align != sy2->align)
return (0);
return (1);
}
/* Is this style default? */
int
style_is_default(struct style *sy)
{
return (style_equal(sy, &style_default));
} }

549
tmux.1
View File

@@ -234,7 +234,7 @@ If no commands are specified, the
.Ic new-session .Ic new-session
command is assumed. command is assumed.
.El .El
.Sh KEY BINDINGS .Sh DEFAULT KEY BINDINGS
.Nm .Nm
may be controlled from an attached client by using a key combination of a may be controlled from an attached client by using a key combination of a
prefix key, prefix key,
@@ -255,6 +255,7 @@ client.
.It ! .It !
Break the current pane out of the window. Break the current pane out of the window.
.It \&" .It \&"
.\" "
Split the current pane into two, top and bottom. Split the current pane into two, top and bottom.
.It # .It #
List all paste buffers. List all paste buffers.
@@ -628,13 +629,13 @@ refers to a
.Nm .Nm
command, passed with the command and arguments separately, for example: command, passed with the command and arguments separately, for example:
.Bd -literal -offset indent .Bd -literal -offset indent
bind-key F1 set-window-option force-width 81 bind-key F1 set-option status off
.Ed .Ed
.Pp .Pp
Or if using Or if using
.Xr sh 1 : .Xr sh 1 :
.Bd -literal -offset indent .Bd -literal -offset indent
$ tmux bind-key F1 set-window-option force-width 81 $ tmux bind-key F1 set-option status off
.Ed .Ed
.Pp .Pp
Multiple commands may be specified together as part of a Multiple commands may be specified together as part of a
@@ -850,13 +851,22 @@ and
are the name of and shell command to execute in the initial window. are the name of and shell command to execute in the initial window.
With With
.Fl d , .Fl d ,
the initial size is 80 x 24; the initial size comes from the global
.Ar default-size
option;
.Fl x .Fl x
and and
.Fl y .Fl y
can be used to specify a different size. can be used to specify a different size.
.Ql - .Ql -
uses the size of the current client if any. uses the size of the current client if any.
If
.Fl x
or
.Fl y
is given, the
.Ar default-size
option is set for the session.
.Pp .Pp
If run from a terminal, any If run from a terminal, any
.Xr termios 4 .Xr termios 4
@@ -921,9 +931,10 @@ is used, the
.Ic update-environment .Ic update-environment
option will not be applied. option will not be applied.
.It Xo Ic refresh-client .It Xo Ic refresh-client
.Op Fl cDlLRSU
.Op Fl C Ar width,height .Op Fl C Ar width,height
.Op Fl S
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Op Ar adjustment
.Xc .Xc
.D1 (alias: Ic refresh ) .D1 (alias: Ic refresh )
Refresh the current client if bound to a key, or a single client if one is given Refresh the current client if bound to a key, or a single client if one is given
@@ -933,8 +944,57 @@ If
.Fl S .Fl S
is specified, only update the client's status line. is specified, only update the client's status line.
.Pp .Pp
The
.Fl U ,
.Fl D ,
.Fl L
.Fl R ,
and
.Fl c
flags allow the visible portion of a window which is larger than the client
to be changed.
.Fl U
moves the visible part up by
.Ar adjustment
rows and
.Fl D
down,
.Fl L
left by
.Ar adjustment
columns and
.Fl R
right.
.Fl c
returns to tracking the cursor automatically.
If
.Ar adjustment
is omitted, 1 is used.
Note that the visible position is a property of the client not of the
window, changing the current window in the attached session will reset
it.
.Pp
.Fl C .Fl C
sets the width and height of a control client. sets the width and height of a control client.
.Fl l
requests the clipboard from the client using the
.Xr xterm 1
escape sequence and stores it in a new paste buffer.
.Pp
.Fl L ,
.Fl R ,
.Fl U
and
.Fl D
move the visible portion of the window left, right, up or down
by
.Ar adjustment ,
if the window is larger than the client.
.Fl c
resets so that the position follows the cursor.
See the
.Ic window-size
option.
.It Xo Ic rename-session .It Xo Ic rename-session
.Op Fl t Ar target-session .Op Fl t Ar target-session
.Ar new-name .Ar new-name
@@ -1510,6 +1570,7 @@ first.
This command works only if at least one client is attached. This command works only if at least one client is attached.
.It Xo .It Xo
.Ic display-panes .Ic display-panes
.Op Fl b
.Op Fl d Ar duration .Op Fl d Ar duration
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Op Ar template .Op Ar template
@@ -1543,8 +1604,11 @@ substituted by the pane ID.
The default The default
.Ar template .Ar template
is "select-pane -t '%%'". is "select-pane -t '%%'".
With
.Fl b ,
other commands are not blocked from running until the indicator is closed.
.It Xo Ic find-window .It Xo Ic find-window
.Op Fl CNT .Op Fl CNTZ
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
.Ar match-string .Ar match-string
.Xc .Xc
@@ -1563,6 +1627,8 @@ matches only the window name and
matches only the window title. matches only the window title.
The default is The default is
.Fl CNT . .Fl CNT .
.Fl Z
zooms the pane.
.Pp .Pp
This command works only if at least one client is attached. This command works only if at least one client is attached.
.It Xo Ic join-pane .It Xo Ic join-pane
@@ -1916,6 +1982,38 @@ and unzoomed (its normal position in the layout).
.Fl M .Fl M
begins mouse resizing (only valid if bound to a mouse key binding, see begins mouse resizing (only valid if bound to a mouse key binding, see
.Sx MOUSE SUPPORT ) . .Sx MOUSE SUPPORT ) .
.It Xo Ic resize-window
.Op Fl aADLRU
.Op Fl t Ar target-window
.Op Fl x Ar width
.Op Fl y Ar height
.Op Ar adjustment
.Xc
.D1 (alias: Ic resizew )
Resize a window, up, down, left or right by
.Ar adjustment
with
.Fl U ,
.Fl D ,
.Fl L
or
.Fl R ,
or
to an absolute size
with
.Fl x
or
.Fl y .
The
.Ar adjustment
is given in lines or cells (the default is 1).
.Fl A
sets the size of the largest session containing the window;
.Fl a
the size of the smallest.
This command will automatically set
.Ic window-size
to manual in the window options.
.It Xo Ic respawn-pane .It Xo Ic respawn-pane
.Op Fl c Ar start-directory .Op Fl c Ar start-directory
.Op Fl k .Op Fl k
@@ -2659,6 +2757,16 @@ The default is an empty string, which instructs
to create a login shell using the value of the to create a login shell using the value of the
.Ic default-shell .Ic default-shell
option. option.
.It Ic default-size Ar XxY
Set the default size of new windows when the
.Ar window-size
option is set to manual or when a session is created with
.Ic new-session
.Fl d .
The value is the width and height separated by an
.Ql x
character.
The default is 80x24.
.It Ic default-shell Ar path .It Ic default-shell Ar path
Specify the default shell. Specify the default shell.
This is used as the login shell for new windows when the This is used as the login shell for new windows when the
@@ -2675,6 +2783,10 @@ or
This option should be configured when This option should be configured when
.Nm .Nm
is used as a login shell. is used as a login shell.
.It Ic default-size Ar XxY
Set the default size of windows when the size is not set or the
.Ic window-size
option is manual.
.It Xo Ic destroy-unattached .It Xo Ic destroy-unattached
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -2728,73 +2840,19 @@ The default is to run
with with
.Fl np . .Fl np .
.It Ic message-command-style Ar style .It Ic message-command-style Ar style
Set status line message command style, where Set status line message command style.
.Ar style For how to specify
is a comma-separated list of characteristics to be specified. .Ar style ,
.Pp see the
These may be .Sx STYLES
.Ql bg=colour section.
to set the background colour,
.Ql fg=colour
to set the foreground colour, and a list of attributes as specified below.
.Pp
The colour is one of:
.Ic black ,
.Ic red ,
.Ic green ,
.Ic yellow ,
.Ic blue ,
.Ic magenta ,
.Ic cyan ,
.Ic white ,
aixterm bright variants (if supported:
.Ic brightred ,
.Ic brightgreen ,
and so on),
.Ic colour0
to
.Ic colour255
from the 256-colour set,
.Ic default ,
or a hexadecimal RGB string such as
.Ql #ffffff .
.Pp
The attributes is either
.Ic none
or a comma-delimited list of one or more of:
.Ic bright
(or
.Ic bold ) ,
.Ic dim ,
.Ic underscore ,
.Ic blink ,
.Ic reverse ,
.Ic hidden ,
.Ic italics ,
or
.Ic strikethrough
to turn an attribute on, or an attribute prefixed with
.Ql no
to turn one off.
.Pp
Examples are:
.Bd -literal -offset indent
fg=yellow,bold,underscore,blink
bg=black,fg=default,noreverse
.Ed
.Pp
With the
.Fl a
flag to the
.Ic set-option
command the new style is added otherwise the existing style is replaced.
.It Ic message-style Ar style .It Ic message-style Ar style
Set status line message style. Set status line message style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Xo Ic mouse .It Xo Ic mouse
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -2870,9 +2928,22 @@ is on.
The values are the same as those for The values are the same as those for
.Ic activity-action . .Ic activity-action .
.It Xo Ic status .It Xo Ic status
.Op Ic on | off .Op Ic off | on | 2 | 3 | 4 | 5
.Xc .Xc
Show or hide the status line. Show or hide the status line or specify its size.
Using
.Ic on
gives a status line one row in height;
.Ic 2 ,
.Ic 3 ,
.Ic 4
or
.Ic 5
more rows.
.It Ic status-format[] Ar format
Specify the format to be used for each line of the status line.
The default builds the top status line from the various individual status
options below.
.It Ic status-interval Ar interval .It Ic status-interval Ar interval
Update the status line every Update the status line every
.Ar interval .Ar interval
@@ -2901,17 +2972,12 @@ Display
(by default the session name) to the left of the status line. (by default the session name) to the left of the status line.
.Ar string .Ar string
will be passed through will be passed through
.Xr strftime 3 .Xr strftime 3 .
and formats (see Also see the
.Sx FORMATS ) .Sx FORMATS
will be expanded. and
It may also contain the special character sequence #[] to change the colour .Sx STYLES
or attributes, for example sections.
.Ql #[fg=red,bright]
to set a bright red foreground.
See the
.Ic message-command-style
option for a description of colours and attributes.
.Pp .Pp
For details on how the names and titles can be set see the For details on how the names and titles can be set see the
.Sx "NAMES AND TITLES" .Sx "NAMES AND TITLES"
@@ -2935,8 +3001,8 @@ Set the style of the left part of the status line.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Xo Ic status-position .It Xo Ic status-position
.Op Ic top | bottom .Op Ic top | bottom
.Xc .Xc
@@ -2963,15 +3029,15 @@ Set the style of the right part of the status line.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Ic status-style Ar style .It Ic status-style Ar style
Set status line style. Set status line style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Ic update-environment[] Ar variable .It Ic update-environment[] Ar variable
Set list of environment variables to be copied into the session environment Set list of environment variables to be copied into the session environment
when a new session is created or an existing session is attached. when a new session is created or an existing session is attached.
@@ -3055,10 +3121,13 @@ Supported window options are:
Aggressively resize the chosen window. Aggressively resize the chosen window.
This means that This means that
.Nm .Nm
will resize the window to the size of the smallest session for which it is the will resize the window to the size of the smallest or largest session
current window, rather than the smallest session to which it is attached. (see the
The window may resize when the current window is changed on another sessions; .Ic window-size
this option is good for full-screen programs which support option) for which it is the current window, rather than the session to
which it is attached.
The window may resize when the current window is changed on another
session; this option is good for full-screen programs which support
.Dv SIGWINCH .Dv SIGWINCH
and poor for interactive programs such as shells. and poor for interactive programs such as shells.
.Pp .Pp
@@ -3121,16 +3190,6 @@ Set clock colour.
.Xc .Xc
Set clock hour format. Set clock hour format.
.Pp .Pp
.It Ic force-height Ar height
.It Ic force-width Ar width
Prevent
.Nm
from resizing a window to greater than
.Ar width
or
.Ar height .
A value of zero restores the default unlimited setting.
.Pp
.It Ic main-pane-height Ar height .It Ic main-pane-height Ar height
.It Ic main-pane-width Ar width .It Ic main-pane-width Ar width
Set the width or height of the main (left or top) pane in the Set the width or height of the main (left or top) pane in the
@@ -3155,8 +3214,8 @@ Set window modes style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Xo Ic monitor-activity .It Xo Ic monitor-activity
.Op Ic on | off .Op Ic on | off
@@ -3204,8 +3263,8 @@ Set the pane border style for the currently active pane.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
Attributes are ignored. Attributes are ignored.
.Pp .Pp
.It Ic pane-base-index Ar index .It Ic pane-base-index Ar index
@@ -3226,8 +3285,8 @@ Set the pane border style for panes aside from the active pane.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
Attributes are ignored. Attributes are ignored.
.Pp .Pp
.It Xo Ic remain-on-exit .It Xo Ic remain-on-exit
@@ -3250,24 +3309,24 @@ Set the style for the window's active pane.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-activity-style Ar style .It Ic window-status-activity-style Ar style
Set status line style for windows with an activity alert. Set status line style for windows with an activity alert.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-bell-style Ar style .It Ic window-status-bell-style Ar style
Set status line style for windows with a bell alert. Set status line style for windows with a bell alert.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-current-format Ar string .It Ic window-status-current-format Ar string
Like Like
@@ -3279,24 +3338,24 @@ Set status line style for the currently active window.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-format Ar string .It Ic window-status-format Ar string
Set the format in which the window is displayed in the status line window list. Set the format in which the window is displayed in the status line window list.
See the See the
.Ar status-left .Sx FORMATS
option for details of special character sequences available. and
The default is .Sx STYLES
.Ql #I:#W#F . sections.
.Pp .Pp
.It Ic window-status-last-style Ar style .It Ic window-status-last-style Ar style
Set status line style for the last active window. Set status line style for the last active window.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-separator Ar string .It Ic window-status-separator Ar string
Sets the separator drawn between windows in the status line. Sets the separator drawn between windows in the status line.
@@ -3307,7 +3366,29 @@ Set status line style for a single window.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
section.
.Pp
.It Xo Ic Ic window-size
.Ar largest | Ar smallest | Ar manual
.Xc
Configure how
.Nm
determines the window size.
If set to
.Ar largest ,
the size of the largest attached session is used; if
.Ar smallest ,
the size of the smallest.
If
.Ar manual ,
the size of a new window is set from the
.Ic default-size
option and windows are resized automatically.
See also the
.Ic resize-window
command and the
.Ic aggressive-resize
option. option.
.Pp .Pp
.It Ic window-style Ar style .It Ic window-style Ar style
@@ -3315,8 +3396,23 @@ Set the default window style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp
.It Xo Ic window-size
.Op Ic smallest | largest | manual
.Xc
Tell
.Nm
how to automatically size windows either the size of the smallest session
containing the window, the size of the largest, or manual size.
See also the
.Ic resize-window
command and the
.Ic default-size
and
.Ic aggressive-resize
options.
.Pp .Pp
.It Xo Ic wrap-search .It Xo Ic wrap-search
.Op Ic on | off .Op Ic on | off
@@ -3501,13 +3597,16 @@ option is on (the default is off),
allows mouse events to be bound as keys. allows mouse events to be bound as keys.
The name of each key is made up of a mouse event (such as The name of each key is made up of a mouse event (such as
.Ql MouseUp1 ) .Ql MouseUp1 )
and a location suffix (one of and a location suffix, one of the following:
.Ql Pane .Bl -column "XXXXXXXXXXXXX" -offset indent
for the contents of a pane, .It Li "Pane" Ta "the contents of a pane"
.Ql Border .It Li "Border" Ta "a pane border"
for a pane border or .It Li "Status" Ta "the status line window list"
.Ql Status .It Li "StatusLeft" Ta "the left part of the status line"
for the status line). .It Li "StatusRight" Ta "the right part of the status line"
.It Li "StatusDefault" Ta "any other part of the status line"
.El
.Pp
The following mouse events are available: The following mouse events are available:
.Bl -column "MouseDown1" "MouseDrag1" "WheelDown" -offset indent .Bl -column "MouseDown1" "MouseDrag1" "WheelDown" -offset indent
.It Li "WheelUp" Ta "WheelDown" Ta "" .It Li "WheelUp" Ta "WheelDown" Ta ""
@@ -3675,6 +3774,35 @@ prefixes are
and and
.Xr dirname 3 .Xr dirname 3
of the variable respectively. of the variable respectively.
.Ql q:
will escape
.Xr sh 1
special characters.
.Ql E:
will expand the format twice, for example
.Ql #{E:status-left}
is the result of expanding the content of the
.Ic status-left
option rather than the content itself.
.Ql T:
is like
.Ql E:
but also expands
.Xr strftime 3
specifiers.
.Ql S: ,
.Ql W:
or
.Ql P:
will loop over each session, window or pane and insert the format once
for each.
For windows and panes, two comma-separated formats may be given:
the second is used for the current window or active pane.
For example, to get a list of windows formatted like the status line:
.Bd -literal -offset indent
#{W:#{E:window-status-format} ,#{E:window-status-current-format} }
.Ed
.Pp
A prefix of the form A prefix of the form
.Ql s/foo/bar/: .Ql s/foo/bar/:
will substitute will substitute
@@ -3735,6 +3863,7 @@ The following variables are available, where appropriate:
.It Li "command_list_alias" Ta "" Ta "Command alias if listing commands" .It Li "command_list_alias" Ta "" Ta "Command alias if listing commands"
.It Li "command_list_usage" Ta "" Ta "Command usage if listing commands" .It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag" .It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
.It Li "cursor_character" Ta "" Ta "Character at cursor in pane"
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane" .It Li "cursor_x" Ta "" Ta "Cursor X position in pane"
.It Li "cursor_y" Ta "" Ta "Cursor Y position in pane" .It Li "cursor_y" Ta "" Ta "Cursor Y position in pane"
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history" .It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
@@ -3801,12 +3930,10 @@ The following variables are available, where appropriate:
.It Li "session_group_size" Ta "" Ta "Size of session group" .It Li "session_group_size" Ta "" Ta "Size of session group"
.It Li "session_group_list" Ta "" Ta "List of sessions in group" .It Li "session_group_list" Ta "" Ta "List of sessions in group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group" .It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_height" Ta "" Ta "Height of session"
.It Li "session_id" Ta "" Ta "Unique session ID" .It Li "session_id" Ta "" Ta "Unique session ID"
.It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached" .It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached"
.It Li "session_name" Ta "#S" Ta "Name of session" .It Li "session_name" Ta "#S" Ta "Name of session"
.It Li "session_stack" Ta "" Ta "Window indexes in most recent order" .It Li "session_stack" Ta "" Ta "Window indexes in most recent order"
.It Li "session_width" Ta "" Ta "Width of session"
.It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" Ta "Server socket path" .It Li "socket_path" Ta "" Ta "Server socket path"
.It Li "start_time" Ta "" Ta "Server start time" .It Li "start_time" Ta "" Ta "Server start time"
@@ -3815,6 +3942,8 @@ The following variables are available, where appropriate:
.It Li "window_activity_flag" Ta "" Ta "1 if window has activity" .It Li "window_activity_flag" Ta "" Ta "1 if window has activity"
.It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell" .It Li "window_bell_flag" Ta "" Ta "1 if window has bell"
.It Li "window_bigger" Ta "" Ta "1 if window is larger than client"
.It Li "window_end_flag" Ta "" Ta "1 if window has the highest index"
.It Li "window_flags" Ta "#F" Ta "Window flags" .It Li "window_flags" Ta "#F" Ta "Window flags"
.It Li "window_format" Ta "" Ta "1 if format is for a window (not assuming the current)" .It Li "window_format" Ta "" Ta "1 if format is for a window (not assuming the current)"
.It Li "window_height" Ta "" Ta "Height of window" .It Li "window_height" Ta "" Ta "Height of window"
@@ -3824,14 +3953,137 @@ The following variables are available, where appropriate:
.It Li "window_layout" Ta "" Ta "Window layout description, ignoring zoomed window panes" .It Li "window_layout" Ta "" Ta "Window layout description, ignoring zoomed window panes"
.It Li "window_linked" Ta "" Ta "1 if window is linked across sessions" .It Li "window_linked" Ta "" Ta "1 if window is linked across sessions"
.It Li "window_name" Ta "#W" Ta "Name of window" .It Li "window_name" Ta "#W" Ta "Name of window"
.It Li "window_offset_x" Ta "" Ta "X offset into window if larger than client"
.It Li "window_offset_y" Ta "" Ta "Y offset into window if larger than client"
.It Li "window_panes" Ta "" Ta "Number of panes in window" .It Li "window_panes" Ta "" Ta "Number of panes in window"
.It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert" .It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert"
.It Li "window_stack_index" Ta "" Ta "Index in session most recent stack" .It Li "window_stack_index" Ta "" Ta "Index in session most recent stack"
.It Li "window_start_flag" Ta "" Ta "1 if window has the lowest index"
.It Li "window_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes" .It Li "window_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes"
.It Li "window_width" Ta "" Ta "Width of window" .It Li "window_width" Ta "" Ta "Width of window"
.It Li "window_zoomed_flag" Ta "" Ta "1 if window is zoomed" .It Li "window_zoomed_flag" Ta "" Ta "1 if window is zoomed"
.It Li "wrap_flag" Ta "" Ta "Pane wrap flag" .It Li "wrap_flag" Ta "" Ta "Pane wrap flag"
.El .El
.Sh STYLES
.Nm
offers various options to specify the colour and attributes of aspects of the
interface, for example
.Ic status-style
for the status line.
In addition, embedded styles may be specified in format options, such as
.Ic status-left-format ,
by enclosing them in
.Ql #[
and
.Ql ] .
.Pp
A style may be the single term
.Ql default
to specify the default style (which may inherit from another option) or a space
or comma separated list of the following:
.Bl -tag -width Ds
.It Ic fg=colour
Set the foreground colour.
The colour is one of:
.Ic black ,
.Ic red ,
.Ic green ,
.Ic yellow ,
.Ic blue ,
.Ic magenta ,
.Ic cyan ,
.Ic white ;
if supported the bright variants
.Ic brightred ,
.Ic brightgreen ,
.Ic brightyellow ;
.Ic colour0
to
.Ic colour255
from the 256-colour set;
.Ic default
for the default colour;
.Ic terminal
for the terminal default colour; or a hexadecimal RGB string such as
.Ql #ffffff .
.It Ic bg=colour
Set the background colour.
.It Ic none
Set no attributes (turn off any active attributes).
.It Xo Ic bright
(or
.Ic bold ) ,
.Ic dim ,
.Ic underscore ,
.Ic blink ,
.Ic reverse ,
.Ic hidden ,
.Ic italics ,
.Ic strikethrough ,
.Ic double-underscore ,
.Ic curly-underscore ,
.Ic dotted-underscore ,
.Ic dashed-underscore
.Xc
Set an attribute.
Any of the attributes may be prefixed with
.Ql no
to unset.
.It Xo Ic align=left
(or
.Ic noalign ) ,
.Ic align=centre ,
.Ic align=right
.Xc
Align text to the left, centre or right of the available space if appropriate.
.It Xo Ic list=on ,
.Ic list=focus ,
.Ic list=left-marker ,
.Ic list=right=marker ,
.Ic nolist
.Xc
Mark the position of the various window list components in the
.Ic status-format
option:
.Ic list=on
marks the start of the list;
.Ic list=focus
is the part of the list that should be kept in focus if the entire list won't fit
in the available space (typically the current window);
.Ic list=left-marker
and
.Ic list=right-marker
mark the text to be used to mark that text has been trimmed from the left or
right of the list if there is not enough space.
.It Xo Ic range=left ,
.Ic range=right ,
.Ic range=window|X ,
.Ic norange
.Xc
Mark a range in the
. Ic status-format
option.
.Ic range=left
and
.Ic range=right
are the text used for the
.Ql StatusLeft
and
.Ql StatusRight
mouse keys.
.Ic range=window|X
is the range for a window passed to the
.Ql Status
mouse key, where
.Ql X
is a window index.
.El
.Pp
Examples are:
.Bd -literal -offset indent
fg=yellow bold underscore blink
bg=black,fg=default,noreverse
.Ed
.Sh NAMES AND TITLES .Sh NAMES AND TITLES
.Nm .Nm
distinguishes between names and titles. distinguishes between names and titles.
@@ -3883,7 +4135,7 @@ option.
.El .El
.Pp .Pp
When a pane is first created, its title is the hostname. When a pane is first created, its title is the hostname.
A pane's title can be set via the OSC title setting sequence, for example: A pane's title can be set via the title setting escape sequence, for example:
.Bd -literal -offset indent .Bd -literal -offset indent
$ printf '\e033]2;My Title\e033\e\e' $ printf '\e033]2;My Title\e033\e\e'
.Ed .Ed
@@ -3959,15 +4211,20 @@ is used, the output is formatted as a set of Bourne shell commands.
.Nm .Nm
includes an optional status line which is displayed in the bottom line of each includes an optional status line which is displayed in the bottom line of each
terminal. terminal.
By default, the status line is enabled (it may be disabled with the .Pp
By default, the status line is enabled and one line in height (it may be
disabled or made multiple lines with the
.Ic status .Ic status
session option) and contains, from left-to-right: the name of the current session option) and contains, from left-to-right: the name of the current
session in square brackets; the window list; the title of the active pane session in square brackets; the window list; the title of the active pane
in double quotes; and the time and date. in double quotes; and the time and date.
.Pp .Pp
The status line is made of three parts: configurable left and right sections Each line of the status line is configured with the
(which may contain dynamic content such as the time or output from a shell .Ic status-format
command, see the option.
The default is made of three parts: configurable left and right sections (which
may contain dynamic content such as the time or output from a shell command,
see the
.Ic status-left , .Ic status-left ,
.Ic status-left-length , .Ic status-left-length ,
.Ic status-right , .Ic status-right ,
@@ -4112,7 +4369,7 @@ option.
This command works only from inside This command works only from inside
.Nm . .Nm .
.It Xo Ic display-message .It Xo Ic display-message
.Op Fl p .Op Fl apv
.Op Fl c Ar target-client .Op Fl c Ar target-client
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
.Op Ar message .Op Ar message
@@ -4134,6 +4391,11 @@ if
.Fl t .Fl t
is given, otherwise the active pane for the session attached to is given, otherwise the active pane for the session attached to
.Ar target-client . .Ar target-client .
.Pp
.Fl v
prints verbose logging as the format is parsed and
.Fl a
lists the format variables and their values.
.El .El
.Sh BUFFERS .Sh BUFFERS
.Nm .Nm
@@ -4398,8 +4660,6 @@ is used, the channel is locked and any clients that try to lock the same
channel are made to wait until the channel is unlocked with channel are made to wait until the channel is unlocked with
.Ic wait-for .Ic wait-for
.Fl U . .Fl U .
This command only works from outside
.Nm .
.El .El
.Sh TERMINFO EXTENSIONS .Sh TERMINFO EXTENSIONS
.Nm .Nm
@@ -4416,6 +4676,11 @@ to change the cursor colour from inside
.Bd -literal -offset indent .Bd -literal -offset indent
$ printf '\e033]12;red\e033\e\e' $ printf '\e033]12;red\e033\e\e'
.Ed .Ed
.It Em \&Smulx
Set a styled underline.
The single parameter is one of: 0 for no underline, 1 for normal
underline, 2 for double underline, 3 for curly underline, 4 for dotted
underline and 5 for dashed underline.
.It Em \&Ss , Se .It Em \&Ss , Se
Set or reset the cursor style. Set or reset the cursor style.
If set, a sequence such as this may be used If set, a sequence such as this may be used
@@ -4432,7 +4697,7 @@ Indicate that the terminal supports the
.Ql direct colour .Ql direct colour
RGB escape sequence (for example, \ee[38;2;255;255;255m). RGB escape sequence (for example, \ee[38;2;255;255;255m).
.Pp .Pp
If supported, this is used for the OSC initialize colour escape sequence (which If supported, this is used for the initialize colour escape sequence (which
may be enabled by adding the may be enabled by adding the
.Ql initc .Ql initc
and and

29
tmux.c
View File

@@ -163,6 +163,31 @@ setblocking(int fd, int state)
} }
} }
const char *
find_cwd(void)
{
char resolved1[PATH_MAX], resolved2[PATH_MAX];
static char cwd[PATH_MAX];
const char *pwd;
if (getcwd(cwd, sizeof cwd) == NULL)
return (NULL);
if ((pwd = getenv("PWD")) == NULL || *pwd == '\0')
return (cwd);
/*
* We want to use PWD so that symbolic links are maintained,
* but only if it matches the actual working directory.
*/
if (realpath(pwd, resolved1) == NULL)
return (cwd);
if (realpath(cwd, resolved2) == NULL)
return (cwd);
if (strcmp(resolved1, resolved2) != 0)
return (cwd);
return (pwd);
}
const char * const char *
find_home(void) find_home(void)
{ {
@@ -188,7 +213,6 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
char *path, *label, *cause, **var; char *path, *label, *cause, **var;
char tmp[PATH_MAX];
const char *s, *shell, *cwd; const char *s, *shell, *cwd;
int opt, flags, keys; int opt, flags, keys;
const struct options_table_entry *oe; const struct options_table_entry *oe;
@@ -293,8 +317,7 @@ main(int argc, char **argv)
global_environ = environ_create(); global_environ = environ_create();
for (var = environ; *var != NULL; var++) for (var = environ; *var != NULL; var++)
environ_put(global_environ, *var); environ_put(global_environ, *var);
if ((cwd = getenv("PWD")) == NULL && if ((cwd = find_cwd()) != NULL)
(cwd = getcwd(tmp, sizeof tmp)) != NULL)
environ_set(global_environ, "PWD", "%s", cwd); environ_set(global_environ, "PWD", "%s", cwd);
global_options = options_create(NULL); global_options = options_create(NULL);

379
tmux.h
View File

@@ -45,14 +45,18 @@ struct cmdq_item;
struct cmdq_list; struct cmdq_list;
struct environ; struct environ;
struct format_job_tree; struct format_job_tree;
struct format_tree;
struct input_ctx; struct input_ctx;
struct job;
struct mode_tree_data; struct mode_tree_data;
struct mouse_event; struct mouse_event;
struct options; struct options;
struct options_entry; struct options_entry;
struct options_array_item;
struct session; struct session;
struct tmuxpeer; struct tmuxpeer;
struct tmuxproc; struct tmuxproc;
struct winlink;
/* Client-server protocol version. */ /* Client-server protocol version. */
#define PROTOCOL_VERSION 8 #define PROTOCOL_VERSION 8
@@ -62,11 +66,12 @@ struct tmuxproc;
#define TMUX_CONF "/etc/tmux.conf" #define TMUX_CONF "/etc/tmux.conf"
#endif #endif
/* /* Minimum layout cell size, NOT including border lines. */
* Minimum layout cell size, NOT including separator line. The scroll region #define PANE_MINIMUM 1
* cannot be one line in height so this must be at least two.
*/ /* Minimum and maximum window size. */
#define PANE_MINIMUM 2 #define WINDOW_MINIMUM PANE_MINIMUM
#define WINDOW_MAXIMUM 10000
/* Automatic name refresh interval, in microseconds. Must be < 1 second. */ /* Automatic name refresh interval, in microseconds. Must be < 1 second. */
#define NAME_INTERVAL 500000 #define NAME_INTERVAL 500000
@@ -120,13 +125,19 @@ struct tmuxproc;
#define KEYC_CLICK_TIMEOUT 300 #define KEYC_CLICK_TIMEOUT 300
/* Mouse key codes. */ /* Mouse key codes. */
#define KEYC_MOUSE_KEY(name) \ #define KEYC_MOUSE_KEY(name) \
KEYC_ ## name ## _PANE, \ KEYC_ ## name ## _PANE, \
KEYC_ ## name ## _STATUS, \ KEYC_ ## name ## _STATUS, \
KEYC_ ## name ## _STATUS_LEFT, \
KEYC_ ## name ## _STATUS_RIGHT, \
KEYC_ ## name ## _STATUS_DEFAULT, \
KEYC_ ## name ## _BORDER KEYC_ ## name ## _BORDER
#define KEYC_MOUSE_STRING(name, s) \ #define KEYC_MOUSE_STRING(name, s) \
{ #s "Pane", KEYC_ ## name ## _PANE }, \ { #s "Pane", KEYC_ ## name ## _PANE }, \
{ #s "Status", KEYC_ ## name ## _STATUS }, \ { #s "Status", KEYC_ ## name ## _STATUS }, \
{ #s "StatusLeft", KEYC_ ## name ## _STATUS_LEFT }, \
{ #s "StatusRight", KEYC_ ## name ## _STATUS_RIGHT }, \
{ #s "StatusDefault", KEYC_ ## name ## _STATUS_DEFAULT }, \
{ #s "Border", KEYC_ ## name ## _BORDER } { #s "Border", KEYC_ ## name ## _BORDER }
/* /*
@@ -423,6 +434,7 @@ enum tty_code_code {
TTYC_SMCUP, TTYC_SMCUP,
TTYC_SMKX, TTYC_SMKX,
TTYC_SMSO, TTYC_SMSO,
TTYC_SMULX,
TTYC_SMUL, TTYC_SMUL,
TTYC_SMXX, TTYC_SMXX,
TTYC_SS, TTYC_SS,
@@ -510,6 +522,7 @@ struct msg_stderr_data {
#define MODE_BRACKETPASTE 0x400 #define MODE_BRACKETPASTE 0x400
#define MODE_FOCUSON 0x800 #define MODE_FOCUSON 0x800
#define MODE_MOUSE_ALL 0x1000 #define MODE_MOUSE_ALL 0x1000
#define MODE_ORIGIN 0x2000
#define ALL_MODES 0xffffff #define ALL_MODES 0xffffff
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
@@ -538,6 +551,9 @@ enum utf8_state {
#define COLOUR_FLAG_256 0x01000000 #define COLOUR_FLAG_256 0x01000000
#define COLOUR_FLAG_RGB 0x02000000 #define COLOUR_FLAG_RGB 0x02000000
/* Special colours. */
#define COLOUR_DEFAULT(c) ((c) == 8 || (c) == 9)
/* Grid attributes. Anything above 0xff is stored in an extended cell. */ /* Grid attributes. Anything above 0xff is stored in an extended cell. */
#define GRID_ATTR_BRIGHT 0x1 #define GRID_ATTR_BRIGHT 0x1
#define GRID_ATTR_DIM 0x2 #define GRID_ATTR_DIM 0x2
@@ -548,6 +564,18 @@ enum utf8_state {
#define GRID_ATTR_ITALICS 0x40 #define GRID_ATTR_ITALICS 0x40
#define GRID_ATTR_CHARSET 0x80 /* alternative character set */ #define GRID_ATTR_CHARSET 0x80 /* alternative character set */
#define GRID_ATTR_STRIKETHROUGH 0x100 #define GRID_ATTR_STRIKETHROUGH 0x100
#define GRID_ATTR_UNDERSCORE_2 0x200
#define GRID_ATTR_UNDERSCORE_3 0x400
#define GRID_ATTR_UNDERSCORE_4 0x800
#define GRID_ATTR_UNDERSCORE_5 0x1000
/* All underscore attributes. */
#define GRID_ATTR_ALL_UNDERSCORE \
(GRID_ATTR_UNDERSCORE| \
GRID_ATTR_UNDERSCORE_2| \
GRID_ATTR_UNDERSCORE_3| \
GRID_ATTR_UNDERSCORE_4| \
GRID_ATTR_UNDERSCORE_5)
/* Grid flags. */ /* Grid flags. */
#define GRID_FLAG_FG256 0x1 #define GRID_FLAG_FG256 0x1
@@ -556,6 +584,7 @@ enum utf8_state {
#define GRID_FLAG_EXTENDED 0x8 #define GRID_FLAG_EXTENDED 0x8
#define GRID_FLAG_SELECTED 0x10 #define GRID_FLAG_SELECTED 0x10
#define GRID_FLAG_NOPALETTE 0x20 #define GRID_FLAG_NOPALETTE 0x20
#define GRID_FLAG_CLEARED 0x40
/* Grid line flags. */ /* Grid line flags. */
#define GRID_LINE_WRAPPED 0x1 #define GRID_LINE_WRAPPED 0x1
@@ -610,6 +639,52 @@ struct grid {
struct grid_line *linedata; struct grid_line *linedata;
}; };
/* Style alignment. */
enum style_align {
STYLE_ALIGN_DEFAULT,
STYLE_ALIGN_LEFT,
STYLE_ALIGN_CENTRE,
STYLE_ALIGN_RIGHT
};
/* Style list. */
enum style_list {
STYLE_LIST_OFF,
STYLE_LIST_ON,
STYLE_LIST_FOCUS,
STYLE_LIST_LEFT_MARKER,
STYLE_LIST_RIGHT_MARKER,
};
/* Style range. */
enum style_range_type {
STYLE_RANGE_NONE,
STYLE_RANGE_LEFT,
STYLE_RANGE_RIGHT,
STYLE_RANGE_WINDOW
};
struct style_range {
enum style_range_type type;
u_int argument;
u_int start;
u_int end; /* not included */
TAILQ_ENTRY(style_range) entry;
};
TAILQ_HEAD(style_ranges, style_range);
/* Style option. */
struct style {
struct grid_cell gc;
enum style_align align;
enum style_list list;
enum style_range_type range_type;
u_int range_argument;
};
/* Hook data structures. */ /* Hook data structures. */
struct hook { struct hook {
const char *name; const char *name;
@@ -619,37 +694,6 @@ struct hook {
RB_ENTRY(hook) entry; RB_ENTRY(hook) entry;
}; };
/* Scheduled job. */
struct job;
typedef void (*job_update_cb) (struct job *);
typedef void (*job_complete_cb) (struct job *);
typedef void (*job_free_cb) (void *);
struct job {
enum {
JOB_RUNNING,
JOB_DEAD,
JOB_CLOSED
} state;
int flags;
#define JOB_NOWAIT 0x1
char *cmd;
pid_t pid;
int status;
int fd;
struct bufferevent *event;
job_update_cb updatecb;
job_complete_cb completecb;
job_free_cb freecb;
void *data;
LIST_ENTRY(job) entry;
};
LIST_HEAD(joblist, job);
/* Virtual screen. */ /* Virtual screen. */
struct screen_sel; struct screen_sel;
struct screen_titles; struct screen_titles;
@@ -702,23 +746,41 @@ struct screen_write_ctx {
* Window mode. Windows can be in several modes and this is used to call the * Window mode. Windows can be in several modes and this is used to call the
* right function to handle input and output. * right function to handle input and output.
*/ */
struct window_mode_entry;
struct window_mode { struct window_mode {
const char *name; const char *name;
const char *default_format;
struct screen *(*init)(struct window_pane *, struct cmd_find_state *, struct screen *(*init)(struct window_mode_entry *,
struct args *); struct cmd_find_state *, struct args *);
void (*free)(struct window_pane *); void (*free)(struct window_mode_entry *);
void (*resize)(struct window_pane *, u_int, u_int); void (*resize)(struct window_mode_entry *, u_int, u_int);
void (*key)(struct window_pane *, struct client *, void (*key)(struct window_mode_entry *, struct client *,
struct session *, key_code, struct mouse_event *); struct session *, struct winlink *, key_code,
const char *(*key_table)(struct window_pane *);
void (*command)(struct window_pane *, struct client *,
struct session *, struct args *,
struct mouse_event *); struct mouse_event *);
const char *(*key_table)(struct window_mode_entry *);
void (*command)(struct window_mode_entry *, struct client *,
struct session *, struct winlink *, struct args *,
struct mouse_event *);
void (*formats)(struct window_mode_entry *,
struct format_tree *);
}; };
#define WINDOW_MODE_TIMEOUT 180 #define WINDOW_MODE_TIMEOUT 180
/* Active window mode. */
struct window_mode_entry {
struct window_pane *wp;
const struct window_mode *mode;
void *data;
struct screen *screen;
u_int prefix;
TAILQ_ENTRY (window_mode_entry) entry;
};
/* Child window structure. */ /* Child window structure. */
struct window_pane { struct window_pane {
u_int id; u_int id;
@@ -762,13 +824,13 @@ struct window_pane {
int fd; int fd;
struct bufferevent *event; struct bufferevent *event;
u_int disabled;
struct event resize_timer; struct event resize_timer;
struct input_ctx *ictx; struct input_ctx *ictx;
struct grid_cell colgc; struct style style;
int *palette; int *palette;
int pipe_fd; int pipe_fd;
@@ -787,11 +849,9 @@ struct window_pane {
struct grid *saved_grid; struct grid *saved_grid;
struct grid_cell saved_cell; struct grid_cell saved_cell;
const struct window_mode *mode; TAILQ_HEAD (, window_mode_entry) modes;
void *modedata;
struct event modetimer; struct event modetimer;
time_t modelast; time_t modelast;
u_int modeprefix;
char *searchstr; char *searchstr;
TAILQ_ENTRY(window_pane) entry; TAILQ_ENTRY(window_pane) entry;
@@ -809,6 +869,7 @@ struct window {
struct timeval name_time; struct timeval name_time;
struct event alerts_timer; struct event alerts_timer;
struct event offset_timer;
struct timeval activity_time; struct timeval activity_time;
@@ -829,9 +890,7 @@ struct window {
#define WINDOW_ACTIVITY 0x2 #define WINDOW_ACTIVITY 0x2
#define WINDOW_SILENCE 0x4 #define WINDOW_SILENCE 0x4
#define WINDOW_ZOOMED 0x8 #define WINDOW_ZOOMED 0x8
#define WINDOW_FORCEWIDTH 0x10 #define WINDOW_STYLECHANGED 0x10
#define WINDOW_FORCEHEIGHT 0x20
#define WINDOW_STYLECHANGED 0x40
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
int alerts_queued; int alerts_queued;
@@ -839,8 +898,8 @@ struct window {
struct options *options; struct options *options;
struct grid_cell style; struct style style;
struct grid_cell active_style; struct style active_style;
u_int references; u_int references;
TAILQ_HEAD(, winlink) winlinks; TAILQ_HEAD(, winlink) winlinks;
@@ -855,10 +914,6 @@ struct winlink {
struct session *session; struct session *session;
struct window *window; struct window *window;
size_t status_width;
struct grid_cell status_cell;
char *status_text;
int flags; int flags;
#define WINLINK_BELL 0x1 #define WINLINK_BELL 0x1
#define WINLINK_ACTIVITY 0x2 #define WINLINK_ACTIVITY 0x2
@@ -872,6 +927,11 @@ struct winlink {
RB_HEAD(winlinks, winlink); RB_HEAD(winlinks, winlink);
TAILQ_HEAD(winlink_stack, winlink); TAILQ_HEAD(winlink_stack, winlink);
/* Window size option. */
#define WINDOW_SIZE_LARGEST 0
#define WINDOW_SIZE_SMALLEST 1
#define WINDOW_SIZE_MANUAL 2
/* Layout direction. */ /* Layout direction. */
enum layout_type { enum layout_type {
LAYOUT_LEFTRIGHT, LAYOUT_LEFTRIGHT,
@@ -930,21 +990,18 @@ struct session {
struct event lock_timer; struct event lock_timer;
u_int sx;
u_int sy;
struct winlink *curw; struct winlink *curw;
struct winlink_stack lastw; struct winlink_stack lastw;
struct winlinks windows; struct winlinks windows;
int statusat; int statusat;
u_int statuslines;
struct hooks *hooks; struct hooks *hooks;
struct options *options; struct options *options;
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */ #define SESSION_PASTING 0x1
#define SESSION_PASTING 0x2 #define SESSION_ALERTED 0x2
#define SESSION_ALERTED 0x4
int flags; int flags;
u_int attached; u_int attached;
@@ -970,7 +1027,7 @@ RB_HEAD(sessions, session);
/* Mouse wheel states. */ /* Mouse wheel states. */
#define MOUSE_WHEEL_UP 0 #define MOUSE_WHEEL_UP 0
#define MOUSE_WHEEL_DOWN 64 #define MOUSE_WHEEL_DOWN 1
/* Mouse helpers. */ /* Mouse helpers. */
#define MOUSE_BUTTONS(b) ((b) & MOUSE_MASK_BUTTONS) #define MOUSE_BUTTONS(b) ((b) & MOUSE_MASK_BUTTONS)
@@ -983,7 +1040,9 @@ struct mouse_event {
int valid; int valid;
key_code key; key_code key;
int statusat; int statusat;
u_int statuslines;
u_int x; u_int x;
u_int y; u_int y;
@@ -993,6 +1052,9 @@ struct mouse_event {
u_int ly; u_int ly;
u_int lb; u_int lb;
u_int ox;
u_int oy;
int s; int s;
int w; int w;
int wp; int wp;
@@ -1040,6 +1102,12 @@ struct tty {
u_int cstyle; u_int cstyle;
char *ccolour; char *ccolour;
int oflag;
u_int oox;
u_int ooy;
u_int osx;
u_int osy;
int mode; int mode;
u_int rlower; u_int rlower;
@@ -1120,11 +1188,19 @@ struct tty_ctx {
u_int orupper; u_int orupper;
u_int orlower; u_int orlower;
/* Pane offset. */
u_int xoff; u_int xoff;
u_int yoff; u_int yoff;
/* The background colour used for clearing (erasing). */ /* The background colour used for clearing (erasing). */
u_int bg; u_int bg;
/* Window offset and size. */
int bigger;
u_int ox;
u_int oy;
u_int sx;
u_int sy;
}; };
/* Saved message entry. */ /* Saved message entry. */
@@ -1281,10 +1357,20 @@ struct cmd_entry {
}; };
/* Status line. */ /* Status line. */
#define STATUS_LINES_LIMIT 5
struct status_line_entry {
char *expanded;
struct style_ranges ranges;
};
struct status_line { struct status_line {
struct event timer; struct event timer;
struct screen status;
struct screen *old_status; struct screen screen;
struct screen *active;
int references;
struct grid_cell style;
struct status_line_entry entries[STATUS_LINES_LIMIT];
}; };
/* Client connection. */ /* Client connection. */
@@ -1334,14 +1420,14 @@ struct client {
#define CLIENT_TERMINAL 0x1 #define CLIENT_TERMINAL 0x1
#define CLIENT_LOGIN 0x2 #define CLIENT_LOGIN 0x2
#define CLIENT_EXIT 0x4 #define CLIENT_EXIT 0x4
#define CLIENT_REDRAW 0x8 #define CLIENT_REDRAWWINDOW 0x8
#define CLIENT_STATUS 0x10 #define CLIENT_REDRAWSTATUS 0x10
#define CLIENT_REPEAT 0x20 #define CLIENT_REPEAT 0x20
#define CLIENT_SUSPENDED 0x40 #define CLIENT_SUSPENDED 0x40
#define CLIENT_ATTACHED 0x80 #define CLIENT_ATTACHED 0x80
#define CLIENT_IDENTIFY 0x100 #define CLIENT_IDENTIFY 0x100
#define CLIENT_DEAD 0x200 #define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400 #define CLIENT_REDRAWBORDERS 0x400
#define CLIENT_READONLY 0x800 #define CLIENT_READONLY 0x800
#define CLIENT_DETACHING 0x1000 #define CLIENT_DETACHING 0x1000
#define CLIENT_CONTROL 0x2000 #define CLIENT_CONTROL 0x2000
@@ -1355,6 +1441,16 @@ struct client {
#define CLIENT_TRIPLECLICK 0x200000 #define CLIENT_TRIPLECLICK 0x200000
#define CLIENT_SIZECHANGED 0x400000 #define CLIENT_SIZECHANGED 0x400000
#define CLIENT_STATUSOFF 0x800000 #define CLIENT_STATUSOFF 0x800000
#define CLIENT_REDRAWSTATUSALWAYS 0x1000000
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \
CLIENT_REDRAWSTATUSALWAYS| \
CLIENT_REDRAWBORDERS)
#define CLIENT_NOSIZEFLAGS \
(CLIENT_DEAD| \
CLIENT_SUSPENDED| \
CLIENT_DETACHING)
int flags; int flags;
struct key_table *keytable; struct key_table *keytable;
@@ -1377,6 +1473,7 @@ struct client {
void *prompt_data; void *prompt_data;
u_int prompt_hindex; u_int prompt_hindex;
enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode; enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode;
struct utf8_data *prompt_saved;
#define PROMPT_SINGLE 0x1 #define PROMPT_SINGLE 0x1
#define PROMPT_NUMERIC 0x2 #define PROMPT_NUMERIC 0x2
@@ -1387,10 +1484,12 @@ struct client {
struct session *session; struct session *session;
struct session *last_session; struct session *last_session;
int wlmouse;
int references; int references;
void *pan_window;
u_int pan_ox;
u_int pan_oy;
TAILQ_ENTRY(client) entry; TAILQ_ENTRY(client) entry;
}; };
TAILQ_HEAD(clients, client); TAILQ_HEAD(clients, client);
@@ -1423,7 +1522,6 @@ enum options_table_type {
OPTIONS_TABLE_NUMBER, OPTIONS_TABLE_NUMBER,
OPTIONS_TABLE_KEY, OPTIONS_TABLE_KEY,
OPTIONS_TABLE_COLOUR, OPTIONS_TABLE_COLOUR,
OPTIONS_TABLE_ATTRIBUTES,
OPTIONS_TABLE_FLAG, OPTIONS_TABLE_FLAG,
OPTIONS_TABLE_CHOICE, OPTIONS_TABLE_CHOICE,
OPTIONS_TABLE_STYLE, OPTIONS_TABLE_STYLE,
@@ -1448,9 +1546,10 @@ struct options_table_entry {
const char *default_str; const char *default_str;
long long default_num; long long default_num;
const char **default_arr;
const char *separator; const char *separator;
const char *style; const char *pattern;
}; };
/* Common command usages. */ /* Common command usages. */
@@ -1477,6 +1576,7 @@ extern int ptm_fd;
extern const char *shell_command; extern const char *shell_command;
int areshell(const char *); int areshell(const char *);
void setblocking(int, int); void setblocking(int, int);
const char *find_cwd(void);
const char *find_home(void); const char *find_home(void);
/* proc.c */ /* proc.c */
@@ -1495,6 +1595,7 @@ void proc_toggle_log(struct tmuxproc *);
/* cfg.c */ /* cfg.c */
extern int cfg_finished; extern int cfg_finished;
extern struct client *cfg_client;
void start_cfg(void); void start_cfg(void);
int load_cfg(const char *, struct client *, struct cmdq_item *, int); int load_cfg(const char *, struct client *, struct cmdq_item *, int);
void set_cfg_file(const char *); void set_cfg_file(const char *);
@@ -1521,17 +1622,21 @@ char *paste_make_sample(struct paste_buffer *);
#define FORMAT_STATUS 0x1 #define FORMAT_STATUS 0x1
#define FORMAT_FORCE 0x2 #define FORMAT_FORCE 0x2
#define FORMAT_NOJOBS 0x4 #define FORMAT_NOJOBS 0x4
#define FORMAT_VERBOSE 0x8
#define FORMAT_NONE 0 #define FORMAT_NONE 0
#define FORMAT_PANE 0x80000000U #define FORMAT_PANE 0x80000000U
#define FORMAT_WINDOW 0x40000000U #define FORMAT_WINDOW 0x40000000U
struct format_tree; struct format_tree;
const char *format_skip(const char *s, const char *end);
int format_true(const char *); int format_true(const char *);
struct format_tree *format_create(struct client *, struct cmdq_item *, int, struct format_tree *format_create(struct client *, struct cmdq_item *, int,
int); int);
void format_free(struct format_tree *); void format_free(struct format_tree *);
void printflike(3, 4) format_add(struct format_tree *, const char *, void printflike(3, 4) format_add(struct format_tree *, const char *,
const char *, ...); const char *, ...);
char *format_expand_time(struct format_tree *, const char *, time_t); void format_each(struct format_tree *, void (*)(const char *,
const char *, void *), void *);
char *format_expand_time(struct format_tree *, const char *);
char *format_expand(struct format_tree *, const char *); char *format_expand(struct format_tree *, const char *);
char *format_single(struct cmdq_item *, const char *, char *format_single(struct cmdq_item *, const char *,
struct client *, struct session *, struct winlink *, struct client *, struct session *, struct winlink *,
@@ -1545,6 +1650,14 @@ void format_defaults_paste_buffer(struct format_tree *,
struct paste_buffer *); struct paste_buffer *);
void format_lost_client(struct client *); void format_lost_client(struct client *);
/* format-draw.c */
void format_draw(struct screen_write_ctx *,
const struct grid_cell *, u_int, const char *,
struct style_ranges *);
u_int format_width(const char *);
char *format_trim_left(const char *, u_int);
char *format_trim_right(const char *, u_int);
/* hooks.c */ /* hooks.c */
struct hook; struct hook;
struct hooks *hooks_get(struct session *); struct hooks *hooks_get(struct session *);
@@ -1587,8 +1700,12 @@ void options_array_clear(struct options_entry *);
const char *options_array_get(struct options_entry *, u_int); const char *options_array_get(struct options_entry *, u_int);
int options_array_set(struct options_entry *, u_int, const char *, int options_array_set(struct options_entry *, u_int, const char *,
int); int);
int options_array_size(struct options_entry *, u_int *);
void options_array_assign(struct options_entry *, const char *); void options_array_assign(struct options_entry *, const char *);
struct options_array_item *options_array_first(struct options_entry *);
struct options_array_item *options_array_next(struct options_array_item *);
u_int options_array_item_index(struct options_array_item *);
const char *options_array_item_value(struct options_array_item *);
int options_isarray(struct options_entry *);
int options_isstring(struct options_entry *); int options_isstring(struct options_entry *);
const char *options_tostring(struct options_entry *, int, int); const char *options_tostring(struct options_entry *, int, int);
char *options_parse(const char *, int *); char *options_parse(const char *, int *);
@@ -1599,7 +1716,7 @@ struct options_entry *options_match_get(struct options *, const char *, int *,
int, int *); int, int *);
const char *options_get_string(struct options *, const char *); const char *options_get_string(struct options *, const char *);
long long options_get_number(struct options *, const char *); long long options_get_number(struct options *, const char *);
const struct grid_cell *options_get_style(struct options *, const char *); struct style *options_get_style(struct options *, const char *);
struct options_entry * printflike(4, 5) options_set_string(struct options *, struct options_entry * printflike(4, 5) options_set_string(struct options *,
const char *, int, const char *, ...); const char *, int, const char *, ...);
struct options_entry *options_set_number(struct options *, const char *, struct options_entry *options_set_number(struct options *, const char *,
@@ -1608,20 +1725,25 @@ struct options_entry *options_set_style(struct options *, const char *, int,
const char *); const char *);
enum options_table_scope options_scope_from_flags(struct args *, int, enum options_table_scope options_scope_from_flags(struct args *, int,
struct cmd_find_state *, struct options **, char **); struct cmd_find_state *, struct options **, char **);
void options_style_update_new(struct options *,
struct options_entry *);
void options_style_update_old(struct options *,
struct options_entry *);
/* options-table.c */ /* options-table.c */
extern const struct options_table_entry options_table[]; extern const struct options_table_entry options_table[];
/* job.c */ /* job.c */
extern struct joblist all_jobs; typedef void (*job_update_cb) (struct job *);
typedef void (*job_complete_cb) (struct job *);
typedef void (*job_free_cb) (void *);
#define JOB_NOWAIT 0x1
struct job *job_run(const char *, struct session *, const char *, struct job *job_run(const char *, struct session *, const char *,
job_update_cb, job_complete_cb, job_free_cb, void *, int); job_update_cb, job_complete_cb, job_free_cb, void *, int);
void job_free(struct job *); void job_free(struct job *);
void job_died(struct job *, int); void job_check_died(pid_t, int);
int job_get_status(struct job *);
void *job_get_data(struct job *);
struct bufferevent *job_get_event(struct job *);
void job_kill_all(void);
int job_still_running(void);
void job_print_summary(struct cmdq_item *, int);
/* environ.c */ /* environ.c */
struct environ *environ_create(void); struct environ *environ_create(void);
@@ -1642,9 +1764,13 @@ struct environ *environ_for_session(struct session *, int);
/* tty.c */ /* tty.c */
void tty_create_log(void); void tty_create_log(void);
int tty_window_bigger(struct tty *);
int tty_window_offset(struct tty *, u_int *, u_int *, u_int *, u_int *);
void tty_update_window_offset(struct window *);
void tty_update_client_offset(struct client *);
void tty_raw(struct tty *, const char *); void tty_raw(struct tty *, const char *);
void tty_attributes(struct tty *, const struct grid_cell *, void tty_attributes(struct tty *, const struct grid_cell *,
const struct window_pane *); struct window_pane *);
void tty_reset(struct tty *); void tty_reset(struct tty *);
void tty_region_off(struct tty *); void tty_region_off(struct tty *);
void tty_margin_off(struct tty *); void tty_margin_off(struct tty *);
@@ -1666,10 +1792,8 @@ void tty_start_tty(struct tty *);
void tty_stop_tty(struct tty *); void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *); void tty_set_title(struct tty *, const char *);
void tty_update_mode(struct tty *, int, struct screen *); void tty_update_mode(struct tty *, int, struct screen *);
void tty_draw_pane(struct tty *, const struct window_pane *, u_int, u_int, void tty_draw_line(struct tty *, struct window_pane *, struct screen *,
u_int); u_int, u_int, u_int, u_int, u_int);
void tty_draw_line(struct tty *, const struct window_pane *, struct screen *,
u_int, u_int, u_int);
int tty_open(struct tty *, char **); int tty_open(struct tty *, char **);
void tty_close(struct tty *); void tty_close(struct tty *);
void tty_free(struct tty *); void tty_free(struct tty *);
@@ -1902,10 +2026,12 @@ void server_unzoom_window(struct window *);
/* status.c */ /* status.c */
void status_timer_start(struct client *); void status_timer_start(struct client *);
void status_timer_start_all(void); void status_timer_start_all(void);
void status_update_saved(struct session *s); void status_update_cache(struct session *);
int status_at_line(struct client *); int status_at_line(struct client *);
u_int status_line_size(struct session *); u_int status_line_size(struct client *);
struct window *status_get_window_at(struct client *, u_int); struct style_range *status_get_range(struct client *, u_int, u_int);
void status_init(struct client *);
void status_free(struct client *);
int status_redraw(struct client *); int status_redraw(struct client *);
void printflike(2, 3) status_message_set(struct client *, const char *, ...); void printflike(2, 3) status_message_set(struct client *, const char *, ...);
void status_message_clear(struct client *); void status_message_clear(struct client *);
@@ -1920,6 +2046,9 @@ void status_prompt_load_history(void);
void status_prompt_save_history(void); void status_prompt_save_history(void);
/* resize.c */ /* resize.c */
void resize_window(struct window *, u_int, u_int);
void default_window_size(struct session *, struct window *, u_int *,
u_int *, int);
void recalculate_sizes(void); void recalculate_sizes(void);
/* input.c */ /* input.c */
@@ -1963,6 +2092,8 @@ void grid_get_cell(struct grid *, u_int, u_int, struct grid_cell *);
void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *);
void grid_set_cells(struct grid *, u_int, u_int, const struct grid_cell *, void grid_set_cells(struct grid *, u_int, u_int, const struct grid_cell *,
const char *, size_t); const char *, size_t);
struct grid_line *grid_get_line(struct grid *, u_int);
void grid_adjust_lines(struct grid *, u_int);
void grid_clear(struct grid *, u_int, u_int, u_int, u_int, u_int); void grid_clear(struct grid *, u_int, u_int, u_int, u_int, u_int);
void grid_clear_lines(struct grid *, u_int, u_int, u_int); void grid_clear_lines(struct grid *, u_int, u_int, u_int);
void grid_move_lines(struct grid *, u_int, u_int, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int, u_int);
@@ -1971,9 +2102,9 @@ char *grid_string_cells(struct grid *, u_int, u_int, u_int,
struct grid_cell **, int, int, int); struct grid_cell **, int, int, int);
void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int, void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int,
u_int); u_int);
void grid_reflow(struct grid *, u_int, u_int *); void grid_reflow(struct grid *, u_int);
struct grid_line *grid_get_line(struct grid *, u_int); void grid_wrap_position(struct grid *, u_int, u_int, u_int *, u_int *);
void grid_adjust_lines(struct grid *, u_int); void grid_unwrap_position(struct grid *, u_int *, u_int *, u_int, u_int);
/* grid-view.c */ /* grid-view.c */
void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *); void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *);
@@ -1987,10 +2118,10 @@ void grid_view_scroll_region_up(struct grid *, u_int, u_int, u_int);
void grid_view_scroll_region_down(struct grid *, u_int, u_int, u_int); void grid_view_scroll_region_down(struct grid *, u_int, u_int, u_int);
void grid_view_insert_lines(struct grid *, u_int, u_int, u_int); void grid_view_insert_lines(struct grid *, u_int, u_int, u_int);
void grid_view_insert_lines_region(struct grid *, u_int, u_int, u_int, void grid_view_insert_lines_region(struct grid *, u_int, u_int, u_int,
u_int); u_int);
void grid_view_delete_lines(struct grid *, u_int, u_int, u_int); void grid_view_delete_lines(struct grid *, u_int, u_int, u_int);
void grid_view_delete_lines_region(struct grid *, u_int, u_int, u_int, void grid_view_delete_lines_region(struct grid *, u_int, u_int, u_int,
u_int); u_int);
void grid_view_insert_cells(struct grid *, u_int, u_int, u_int, u_int); void grid_view_insert_cells(struct grid *, u_int, u_int, u_int, u_int);
void grid_view_delete_cells(struct grid *, u_int, u_int, u_int, u_int); void grid_view_delete_cells(struct grid *, u_int, u_int, u_int, u_int);
char *grid_view_string_cells(struct grid *, u_int, u_int, u_int); char *grid_view_string_cells(struct grid *, u_int, u_int, u_int);
@@ -2000,9 +2131,6 @@ void screen_write_start(struct screen_write_ctx *, struct window_pane *,
struct screen *); struct screen *);
void screen_write_stop(struct screen_write_ctx *); void screen_write_stop(struct screen_write_ctx *);
void screen_write_reset(struct screen_write_ctx *); void screen_write_reset(struct screen_write_ctx *);
size_t printflike(1, 2) screen_write_cstrlen(const char *, ...);
void printflike(4, 5) screen_write_cnputs(struct screen_write_ctx *,
ssize_t, const struct grid_cell *, const char *, ...);
size_t printflike(1, 2) screen_write_strlen(const char *, ...); size_t printflike(1, 2) screen_write_strlen(const char *, ...);
void printflike(3, 4) screen_write_puts(struct screen_write_ctx *, void printflike(3, 4) screen_write_puts(struct screen_write_ctx *,
const struct grid_cell *, const char *, ...); const struct grid_cell *, const char *, ...);
@@ -2037,7 +2165,7 @@ void screen_write_deleteline(struct screen_write_ctx *, u_int, u_int);
void screen_write_clearline(struct screen_write_ctx *, u_int); void screen_write_clearline(struct screen_write_ctx *, u_int);
void screen_write_clearendofline(struct screen_write_ctx *, u_int); void screen_write_clearendofline(struct screen_write_ctx *, u_int);
void screen_write_clearstartofline(struct screen_write_ctx *, u_int); void screen_write_clearstartofline(struct screen_write_ctx *, u_int);
void screen_write_cursormove(struct screen_write_ctx *, u_int, u_int); void screen_write_cursormove(struct screen_write_ctx *, int, int, int);
void screen_write_reverseindex(struct screen_write_ctx *, u_int); void screen_write_reverseindex(struct screen_write_ctx *, u_int);
void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int);
void screen_write_linefeed(struct screen_write_ctx *, int, u_int); void screen_write_linefeed(struct screen_write_ctx *, int, u_int);
@@ -2055,8 +2183,7 @@ void screen_write_setselection(struct screen_write_ctx *, u_char *, u_int);
void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int); void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int);
/* screen-redraw.c */ /* screen-redraw.c */
void screen_redraw_update(struct client *); void screen_redraw_screen(struct client *);
void screen_redraw_screen(struct client *, int, int, int);
void screen_redraw_pane(struct client *, struct window_pane *); void screen_redraw_pane(struct client *, struct window_pane *);
/* screen.c */ /* screen.c */
@@ -2081,6 +2208,7 @@ void screen_select_cell(struct screen *, struct grid_cell *,
/* window.c */ /* window.c */
extern struct windows windows; extern struct windows windows;
extern struct window_pane_tree all_window_panes; extern struct window_pane_tree all_window_panes;
extern const struct window_mode *all_window_modes[];
int window_cmp(struct window *, struct window *); int window_cmp(struct window *, struct window *);
RB_PROTOTYPE(windows, window, entry, window_cmp); RB_PROTOTYPE(windows, window, entry, window_cmp);
int winlink_cmp(struct winlink *, struct winlink *); int winlink_cmp(struct winlink *, struct winlink *);
@@ -2144,13 +2272,15 @@ void window_pane_alternate_off(struct window_pane *,
void window_pane_set_palette(struct window_pane *, u_int, int); void window_pane_set_palette(struct window_pane *, u_int, int);
void window_pane_unset_palette(struct window_pane *, u_int); void window_pane_unset_palette(struct window_pane *, u_int);
void window_pane_reset_palette(struct window_pane *); void window_pane_reset_palette(struct window_pane *);
int window_pane_get_palette(const struct window_pane *, int); int window_pane_get_palette(struct window_pane *, int);
int window_pane_set_mode(struct window_pane *, int window_pane_set_mode(struct window_pane *,
const struct window_mode *, struct cmd_find_state *, const struct window_mode *, struct cmd_find_state *,
struct args *); struct args *);
void window_pane_reset_mode(struct window_pane *); void window_pane_reset_mode(struct window_pane *);
void window_pane_reset_mode_all(struct window_pane *);
void window_pane_key(struct window_pane *, struct client *, void window_pane_key(struct window_pane *, struct client *,
struct session *, key_code, struct mouse_event *); struct session *, struct winlink *, key_code,
struct mouse_event *);
int window_pane_visible(struct window_pane *); int window_pane_visible(struct window_pane *);
u_int window_pane_search(struct window_pane *, const char *); u_int window_pane_search(struct window_pane *, const char *);
const char *window_printable_flags(struct winlink *); const char *window_printable_flags(struct winlink *);
@@ -2179,7 +2309,7 @@ void layout_set_size(struct layout_cell *, u_int, u_int, u_int,
void layout_make_leaf(struct layout_cell *, struct window_pane *); void layout_make_leaf(struct layout_cell *, struct window_pane *);
void layout_make_node(struct layout_cell *, enum layout_type); void layout_make_node(struct layout_cell *, enum layout_type);
void layout_fix_offsets(struct layout_cell *); void layout_fix_offsets(struct layout_cell *);
void layout_fix_panes(struct window *, u_int, u_int); void layout_fix_panes(struct window *);
void layout_resize_adjust(struct window *, struct layout_cell *, void layout_resize_adjust(struct window *, struct layout_cell *,
enum layout_type, int); enum layout_type, int);
void layout_init(struct window *, struct window_pane *); void layout_init(struct window *, struct window_pane *);
@@ -2251,14 +2381,11 @@ extern const struct window_mode window_client_mode;
/* window-copy.c */ /* window-copy.c */
extern const struct window_mode window_copy_mode; extern const struct window_mode window_copy_mode;
void window_copy_init_from_pane(struct window_pane *, int); extern const struct window_mode window_view_mode;
void window_copy_init_for_output(struct window_pane *);
void printflike(2, 3) window_copy_add(struct window_pane *, const char *, ...); void printflike(2, 3) window_copy_add(struct window_pane *, const char *, ...);
void window_copy_vadd(struct window_pane *, const char *, va_list); void window_copy_vadd(struct window_pane *, const char *, va_list);
void window_copy_pageup(struct window_pane *, int); void window_copy_pageup(struct window_pane *, int);
void window_copy_start_drag(struct client *, struct mouse_event *); void window_copy_start_drag(struct client *, struct mouse_event *);
void window_copy_add_formats(struct window_pane *,
struct format_tree *);
/* names.c */ /* names.c */
void check_window_name(struct window *); void check_window_name(struct window *);
@@ -2295,7 +2422,7 @@ struct session *session_find_by_id_str(const char *);
struct session *session_find_by_id(u_int); struct session *session_find_by_id(u_int);
struct session *session_create(const char *, const char *, int, char **, struct session *session_create(const char *, const char *, int, char **,
const char *, const char *, struct environ *, const char *, const char *, struct environ *,
struct termios *, int, u_int, u_int, char **); struct options *, struct termios *, int, char **);
void session_destroy(struct session *, const char *); void session_destroy(struct session *, const char *);
void session_add_ref(struct session *, const char *); void session_add_ref(struct session *, const char *);
void session_remove_ref(struct session *, const char *); void session_remove_ref(struct session *, const char *);
@@ -2340,8 +2467,6 @@ u_int utf8_strwidth(const struct utf8_data *, ssize_t);
struct utf8_data *utf8_fromcstr(const char *); struct utf8_data *utf8_fromcstr(const char *);
char *utf8_tocstr(struct utf8_data *); char *utf8_tocstr(struct utf8_data *);
u_int utf8_cstrwidth(const char *); u_int utf8_cstrwidth(const char *);
char *utf8_rtrimcstr(const char *, u_int);
char *utf8_trimcstr(const char *, u_int);
char *utf8_padcstr(const char *, u_int); char *utf8_padcstr(const char *, u_int);
/* osdep-*.c */ /* osdep-*.c */
@@ -2360,14 +2485,16 @@ __dead void printflike(1, 2) fatal(const char *, ...);
__dead void printflike(1, 2) fatalx(const char *, ...); __dead void printflike(1, 2) fatalx(const char *, ...);
/* style.c */ /* style.c */
int style_parse(const struct grid_cell *, int style_parse(struct style *,const struct grid_cell *,
struct grid_cell *, const char *); const char *);
const char *style_tostring(struct grid_cell *); const char *style_tostring(struct style *);
void style_apply(struct grid_cell *, struct options *, void style_apply(struct grid_cell *, struct options *,
const char *); const char *);
void style_apply_update(struct grid_cell *, struct options *, void style_apply_update(struct grid_cell *, struct options *,
const char *); const char *);
int style_equal(const struct grid_cell *, int style_equal(struct style *, struct style *);
const struct grid_cell *); void style_set(struct style *, const struct grid_cell *);
void style_copy(struct style *, struct style *);
int style_is_default(struct style *);
#endif /* TMUX_H */ #endif /* TMUX_H */

View File

@@ -14,7 +14,7 @@
# https://github.com/gnachman/iTerm2/blob/master/LICENSE # https://github.com/gnachman/iTerm2/blob/master/LICENSE
# #
if which gseq >/dev/null if which gseq >/dev/null 2>&1
then then
SEQ=gseq SEQ=gseq
else else

View File

@@ -19,7 +19,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <netinet/in.h>
#include <limits.h> #include <limits.h>
#include <resolv.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
@@ -44,6 +47,8 @@ static int tty_keys_next1(struct tty *, const char *, size_t, key_code *,
size_t *, int); size_t *, int);
static void tty_keys_callback(int, short, void *); static void tty_keys_callback(int, short, void *);
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *);
static int tty_keys_clipboard(struct tty *, const char *, size_t,
size_t *);
static int tty_keys_device_attributes(struct tty *, const char *, size_t, static int tty_keys_device_attributes(struct tty *, const char *, size_t,
size_t *); size_t *);
@@ -393,9 +398,10 @@ tty_keys_build(struct tty *tty)
{ {
const struct tty_default_key_raw *tdkr; const struct tty_default_key_raw *tdkr;
const struct tty_default_key_code *tdkc; const struct tty_default_key_code *tdkc;
u_int i, size; u_int i;
const char *s, *value; const char *s, *value;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a;
if (tty->key_tree != NULL) if (tty->key_tree != NULL)
tty_keys_free(tty); tty_keys_free(tty);
@@ -418,11 +424,13 @@ tty_keys_build(struct tty *tty)
} }
o = options_get(global_options, "user-keys"); o = options_get(global_options, "user-keys");
if (o != NULL && options_array_size(o, &size) != -1) { if (o != NULL) {
for (i = 0; i < size; i++) { a = options_array_first(o);
value = options_array_get(o, i); while (a != NULL) {
value = options_array_item_value(a);
if (value != NULL) if (value != NULL)
tty_keys_add(tty, value, KEYC_USER + i); tty_keys_add(tty, value, KEYC_USER + i);
a = options_array_next(a);
} }
} }
} }
@@ -459,6 +467,10 @@ tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size)
static struct tty_key * static struct tty_key *
tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
{ {
/* If no data, no match. */
if (len == 0)
return (NULL);
/* If the node is NULL, this is the end of the tree. No match. */ /* If the node is NULL, this is the end of the tree. No match. */
if (tk == NULL) if (tk == NULL)
return (NULL); return (NULL);
@@ -571,6 +583,17 @@ tty_keys_next(struct tty *tty)
return (0); return (0);
log_debug("%s: keys are %zu (%.*s)", c->name, len, (int)len, buf); log_debug("%s: keys are %zu (%.*s)", c->name, len, (int)len, buf);
/* Is this a clipboard response? */
switch (tty_keys_clipboard(tty, buf, len, &size)) {
case 0: /* yes */
key = KEYC_UNKNOWN;
goto complete_key;
case -1: /* no, or not valid */
break;
case 1: /* partial */
goto partial_key;
}
/* Is this a device attributes response? */ /* Is this a device attributes response? */
switch (tty_keys_device_attributes(tty, buf, len, &size)) { switch (tty_keys_device_attributes(tty, buf, len, &size)) {
case 0: /* yes */ case 0: /* yes */
@@ -608,7 +631,7 @@ first_key:
* If not a complete key, look for key with an escape prefix (meta * If not a complete key, look for key with an escape prefix (meta
* modifier). * modifier).
*/ */
if (*buf == '\033') { if (*buf == '\033' && len > 1) {
/* Look for a key without the escape. */ /* Look for a key without the escape. */
n = tty_keys_next1(tty, buf + 1, len - 1, &key, &size, expired); n = tty_keys_next1(tty, buf + 1, len - 1, &key, &size, expired);
if (n == 0) { /* found */ if (n == 0) { /* found */
@@ -871,6 +894,93 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
return (0); return (0);
} }
/*
* Handle OSC 52 clipboard input. Returns 0 for success, -1 for failure, 1 for
* partial.
*/
static int
tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len,
size_t *size)
{
size_t end, terminator, needed;
char *copy, *out;
int outlen;
*size = 0;
/* First three bytes are always \033]52;. */
if (buf[0] != '\033')
return (-1);
if (len == 1)
return (1);
if (buf[1] != ']')
return (-1);
if (len == 2)
return (1);
if (buf[2] != '5')
return (-1);
if (len == 3)
return (1);
if (buf[3] != '2')
return (-1);
if (len == 4)
return (1);
if (buf[4] != ';')
return (-1);
if (len == 5)
return (1);
/* Find the terminator if any. */
for (end = 5; end < len; end++) {
if (buf[end] == '\007') {
terminator = 1;
break;
}
if (end > 5 && buf[end - 1] == '\033' && buf[end] == '\\') {
terminator = 2;
break;
}
}
if (end == len)
return (1);
*size = end + terminator;
/* Skip the initial part. */
buf += 5;
end -= 5;
/* Get the second argument. */
while (end != 0 && *buf != ';') {
buf++;
end--;
}
if (end == 0 || end == 1)
return (0);
buf++;
end--;
/* It has to be a string so copy it. */
copy = xmalloc(end + 1);
memcpy(copy, buf, end);
copy[end] = '\0';
/* Convert from base64. */
needed = (end / 4) * 3;
out = xmalloc(needed);
if ((outlen = b64_pton(copy, out, len)) == -1) {
free(out);
free(copy);
return (0);
}
free(copy);
/* Create a new paste buffer. */
log_debug("%s: %.*s", __func__, outlen, out);
paste_add(out, outlen);
return (0);
}
/* /*
* Handle device attributes input. Returns 0 for success, -1 for failure, 1 for * Handle device attributes input. Returns 0 for success, -1 for failure, 1 for
* partial. * partial.

View File

@@ -256,6 +256,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_SMCUP] = { TTYCODE_STRING, "smcup" }, [TTYC_SMCUP] = { TTYCODE_STRING, "smcup" },
[TTYC_SMKX] = { TTYCODE_STRING, "smkx" }, [TTYC_SMKX] = { TTYCODE_STRING, "smkx" },
[TTYC_SMSO] = { TTYCODE_STRING, "smso" }, [TTYC_SMSO] = { TTYCODE_STRING, "smso" },
[TTYC_SMULX] = { TTYCODE_STRING, "Smulx" },
[TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SMUL] = { TTYCODE_STRING, "smul" },
[TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, [TTYC_SMXX] = { TTYCODE_STRING, "smxx" },
[TTYC_SS] = { TTYCODE_STRING, "Ss" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" },
@@ -302,25 +303,53 @@ tty_term_strip(const char *s)
return (xstrdup(buf)); return (xstrdup(buf));
} }
static char *
tty_term_override_next(const char *s, size_t *offset)
{
static char value[BUFSIZ];
size_t n = 0, at = *offset;
if (s[at] == '\0')
return (NULL);
while (s[at] != '\0') {
if (s[at] == ':') {
if (s[at + 1] == ':') {
value[n++] = ':';
at += 2;
} else
break;
} else {
value[n++] = s[at];
at++;
}
if (n == (sizeof value) - 1)
return (NULL);
}
if (s[at] != '\0')
*offset = at + 1;
else
*offset = at;
value[n] = '\0';
return (value);
}
static void static void
tty_term_override(struct tty_term *term, const char *override) tty_term_override(struct tty_term *term, const char *override)
{ {
const struct tty_term_code_entry *ent; const struct tty_term_code_entry *ent;
struct tty_code *code; struct tty_code *code;
char *next, *s, *copy, *cp, *value; size_t offset = 0;
char *cp, *value, *s;
const char *errstr; const char *errstr;
u_int i; u_int i;
int n, remove; int n, remove;
copy = next = xstrdup(override); s = tty_term_override_next(override, &offset);
if (s == NULL || fnmatch(s, term->name, 0) != 0)
s = strsep(&next, ":");
if (s == NULL || next == NULL || fnmatch(s, term->name, 0) != 0) {
free(copy);
return; return;
}
while ((s = strsep(&next, ":")) != NULL) { while ((s = tty_term_override_next(override, &offset)) != NULL) {
if (*s == '\0') if (*s == '\0')
continue; continue;
value = NULL; value = NULL;
@@ -341,6 +370,8 @@ tty_term_override(struct tty_term *term, const char *override)
if (remove) if (remove)
log_debug("%s override: %s@", term->name, s); log_debug("%s override: %s@", term->name, s);
else if (*value == '\0')
log_debug("%s override: %s", term->name, s);
else else
log_debug("%s override: %s=%s", term->name, s, value); log_debug("%s override: %s=%s", term->name, s, value);
@@ -379,7 +410,6 @@ tty_term_override(struct tty_term *term, const char *override)
free(value); free(value);
} }
free(s);
} }
struct tty_term * struct tty_term *
@@ -389,7 +419,8 @@ tty_term_find(char *name, int fd, char **cause)
const struct tty_term_code_entry *ent; const struct tty_term_code_entry *ent;
struct tty_code *code; struct tty_code *code;
struct options_entry *o; struct options_entry *o;
u_int size, i; struct options_array_item *a;
u_int i;
int n, error; int n, error;
const char *s, *acs; const char *s, *acs;
@@ -464,12 +495,12 @@ tty_term_find(char *name, int fd, char **cause)
/* Apply terminal overrides. */ /* Apply terminal overrides. */
o = options_get_only(global_options, "terminal-overrides"); o = options_get_only(global_options, "terminal-overrides");
if (options_array_size(o, &size) != -1) { a = options_array_first(o);
for (i = 0; i < size; i++) { while (a != NULL) {
s = options_array_get(o, i); s = options_array_item_value(a);
if (s != NULL) if (s != NULL)
tty_term_override(term, s); tty_term_override(term, s);
} a = options_array_next(a);
} }
/* Delete curses data. */ /* Delete curses data. */
@@ -616,14 +647,14 @@ tty_term_string3(struct tty_term *term, enum tty_code_code code, int a, int b, i
const char * const char *
tty_term_ptr1(struct tty_term *term, enum tty_code_code code, const void *a) tty_term_ptr1(struct tty_term *term, enum tty_code_code code, const void *a)
{ {
return (tparm((char *) tty_term_string(term, code), a, 0, 0, 0, 0, 0, 0, 0, 0)); return (tparm((char *) tty_term_string(term, code), (long)a, 0, 0, 0, 0, 0, 0, 0, 0));
} }
const char * const char *
tty_term_ptr2(struct tty_term *term, enum tty_code_code code, const void *a, tty_term_ptr2(struct tty_term *term, enum tty_code_code code, const void *a,
const void *b) const void *b)
{ {
return (tparm((char *) tty_term_string(term, code), a, b, 0, 0, 0, 0, 0, 0, 0)); return (tparm((char *) tty_term_string(term, code), (long)a, (long)b, 0, 0, 0, 0, 0, 0, 0));
} }
int int

696
tty.c

File diff suppressed because it is too large Load Diff

60
utf8.c
View File

@@ -408,66 +408,6 @@ utf8_cstrwidth(const char *s)
return (width); return (width);
} }
/* Trim UTF-8 string to width. Caller frees. */
char *
utf8_trimcstr(const char *s, u_int width)
{
struct utf8_data *tmp, *next;
char *out;
u_int at;
tmp = utf8_fromcstr(s);
at = 0;
for (next = tmp; next->size != 0; next++) {
if (at + next->width > width) {
next->size = 0;
break;
}
at += next->width;
}
out = utf8_tocstr(tmp);
free(tmp);
return (out);
}
/* Trim UTF-8 string to width. Caller frees. */
char *
utf8_rtrimcstr(const char *s, u_int width)
{
struct utf8_data *tmp, *next, *end;
char *out;
u_int at;
tmp = utf8_fromcstr(s);
for (end = tmp; end->size != 0; end++)
/* nothing */;
if (end == tmp) {
free(tmp);
return (xstrdup(""));
}
next = end - 1;
at = 0;
for (;;) {
if (at + next->width > width) {
next++;
break;
}
at += next->width;
if (next == tmp)
break;
next--;
}
out = utf8_tocstr(next);
free(tmp);
return (out);
}
/* Pad UTF-8 string to width. Caller frees. */ /* Pad UTF-8 string to width. Caller frees. */
char * char *
utf8_padcstr(const char *s, u_int width) utf8_padcstr(const char *s, u_int width)

View File

@@ -24,14 +24,14 @@
#include "tmux.h" #include "tmux.h"
static struct screen *window_buffer_init(struct window_pane *, static struct screen *window_buffer_init(struct window_mode_entry *,
struct cmd_find_state *, struct args *); struct cmd_find_state *, struct args *);
static void window_buffer_free(struct window_pane *); static void window_buffer_free(struct window_mode_entry *);
static void window_buffer_resize(struct window_pane *, u_int, static void window_buffer_resize(struct window_mode_entry *, u_int,
u_int); u_int);
static void window_buffer_key(struct window_pane *, static void window_buffer_key(struct window_mode_entry *,
struct client *, struct session *, key_code, struct client *, struct session *,
struct mouse_event *); struct winlink *, key_code, struct mouse_event *);
#define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -b '%%'" #define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -b '%%'"
@@ -40,6 +40,7 @@ static void window_buffer_key(struct window_pane *,
const struct window_mode window_buffer_mode = { const struct window_mode window_buffer_mode = {
.name = "buffer-mode", .name = "buffer-mode",
.default_format = WINDOW_BUFFER_DEFAULT_FORMAT,
.init = window_buffer_init, .init = window_buffer_init,
.free = window_buffer_free, .free = window_buffer_free,
@@ -225,7 +226,7 @@ window_buffer_draw(__unused void *modedata, void *itemdata,
line[at] = '\0'; line[at] = '\0';
if (*line != '\0') { if (*line != '\0') {
screen_write_cursormove(ctx, cx, cy + i); screen_write_cursormove(ctx, cx, cy + i, 0);
screen_write_puts(ctx, &grid_default_cell, "%s", line); screen_write_puts(ctx, &grid_default_cell, "%s", line);
} }
@@ -252,13 +253,14 @@ window_buffer_search(__unused void *modedata, void *itemdata, const char *ss)
} }
static struct screen * static struct screen *
window_buffer_init(struct window_pane *wp, __unused struct cmd_find_state *fs, window_buffer_init(struct window_mode_entry *wme,
struct args *args) __unused struct cmd_find_state *fs, struct args *args)
{ {
struct window_pane *wp = wme->wp;
struct window_buffer_modedata *data; struct window_buffer_modedata *data;
struct screen *s; struct screen *s;
wp->modedata = data = xcalloc(1, sizeof *data); wme->data = data = xcalloc(1, sizeof *data);
if (args == NULL || !args_has(args, 'F')) if (args == NULL || !args_has(args, 'F'))
data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT); data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT);
@@ -281,9 +283,9 @@ window_buffer_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
} }
static void static void
window_buffer_free(struct window_pane *wp) window_buffer_free(struct window_mode_entry *wme)
{ {
struct window_buffer_modedata *data = wp->modedata; struct window_buffer_modedata *data = wme->data;
u_int i; u_int i;
if (data == NULL) if (data == NULL)
@@ -302,9 +304,9 @@ window_buffer_free(struct window_pane *wp)
} }
static void static void
window_buffer_resize(struct window_pane *wp, u_int sx, u_int sy) window_buffer_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
{ {
struct window_buffer_modedata *data = wp->modedata; struct window_buffer_modedata *data = wme->data;
mode_tree_resize(data->data, sx, sy); mode_tree_resize(data->data, sx, sy);
} }
@@ -336,10 +338,12 @@ window_buffer_do_paste(void* modedata, void *itemdata, struct client *c,
} }
static void static void
window_buffer_key(struct window_pane *wp, struct client *c, window_buffer_key(struct window_mode_entry *wme, struct client *c,
__unused struct session *s, key_code key, struct mouse_event *m) __unused struct session *s, __unused struct winlink *wl, key_code key,
struct mouse_event *m)
{ {
struct window_buffer_modedata *data = wp->modedata; struct window_pane *wp = wme->wp;
struct window_buffer_modedata *data = wme->data;
struct mode_tree_data *mtd = data->data; struct mode_tree_data *mtd = data->data;
struct window_buffer_itemdata *item; struct window_buffer_itemdata *item;
int finished; int finished;

View File

@@ -25,14 +25,14 @@
#include "tmux.h" #include "tmux.h"
static struct screen *window_client_init(struct window_pane *, static struct screen *window_client_init(struct window_mode_entry *,
struct cmd_find_state *, struct args *); struct cmd_find_state *, struct args *);
static void window_client_free(struct window_pane *); static void window_client_free(struct window_mode_entry *);
static void window_client_resize(struct window_pane *, u_int, static void window_client_resize(struct window_mode_entry *, u_int,
u_int); u_int);
static void window_client_key(struct window_pane *, static void window_client_key(struct window_mode_entry *,
struct client *, struct session *, key_code, struct client *, struct session *,
struct mouse_event *); struct winlink *, key_code, struct mouse_event *);
#define WINDOW_CLIENT_DEFAULT_COMMAND "detach-client -t '%%'" #define WINDOW_CLIENT_DEFAULT_COMMAND "detach-client -t '%%'"
@@ -42,6 +42,7 @@ static void window_client_key(struct window_pane *,
const struct window_mode window_client_mode = { const struct window_mode window_client_mode = {
.name = "client-mode", .name = "client-mode",
.default_format = WINDOW_CLIENT_DEFAULT_FORMAT,
.init = window_client_init, .init = window_client_init,
.free = window_client_free, .free = window_client_free,
@@ -216,33 +217,47 @@ window_client_draw(__unused void *modedata, void *itemdata,
{ {
struct window_client_itemdata *item = itemdata; struct window_client_itemdata *item = itemdata;
struct client *c = item->c; struct client *c = item->c;
struct screen *s = ctx->s;
struct window_pane *wp; struct window_pane *wp;
u_int cx = ctx->s->cx, cy = ctx->s->cy; u_int cx = s->cx, cy = s->cy, lines, at;
if (c->session == NULL || (c->flags & (CLIENT_DEAD|CLIENT_DETACHING))) if (c->session == NULL || (c->flags & (CLIENT_DEAD|CLIENT_DETACHING)))
return; return;
wp = c->session->curw->window->active; wp = c->session->curw->window->active;
screen_write_preview(ctx, &wp->base, sx, sy - 3); lines = status_line_size(c);
if (lines >= sy)
lines = 0;
if (status_at_line(c) == 0)
at = lines;
else
at = 0;
screen_write_cursormove(ctx, cx, cy + sy - 2); screen_write_cursormove(ctx, cx, cy + at, 0);
screen_write_preview(ctx, &wp->base, sx, sy - 2 - lines);
if (at != 0)
screen_write_cursormove(ctx, cx, cy + 2, 0);
else
screen_write_cursormove(ctx, cx, cy + sy - 1 - lines, 0);
screen_write_hline(ctx, sx, 0, 0); screen_write_hline(ctx, sx, 0, 0);
screen_write_cursormove(ctx, cx, cy + sy - 1); if (at != 0)
if (c->status.old_status != NULL) screen_write_cursormove(ctx, cx, cy, 0);
screen_write_fast_copy(ctx, c->status.old_status, 0, 0, sx, 1);
else else
screen_write_fast_copy(ctx, &c->status.status, 0, 0, sx, 1); screen_write_cursormove(ctx, cx, cy + sy - lines, 0);
screen_write_fast_copy(ctx, &c->status.screen, 0, 0, sx, lines);
} }
static struct screen * static struct screen *
window_client_init(struct window_pane *wp, __unused struct cmd_find_state *fs, window_client_init(struct window_mode_entry *wme,
struct args *args) __unused struct cmd_find_state *fs, struct args *args)
{ {
struct window_pane *wp = wme->wp;
struct window_client_modedata *data; struct window_client_modedata *data;
struct screen *s; struct screen *s;
wp->modedata = data = xcalloc(1, sizeof *data); wme->data = data = xcalloc(1, sizeof *data);
if (args == NULL || !args_has(args, 'F')) if (args == NULL || !args_has(args, 'F'))
data->format = xstrdup(WINDOW_CLIENT_DEFAULT_FORMAT); data->format = xstrdup(WINDOW_CLIENT_DEFAULT_FORMAT);
@@ -265,9 +280,9 @@ window_client_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
} }
static void static void
window_client_free(struct window_pane *wp) window_client_free(struct window_mode_entry *wme)
{ {
struct window_client_modedata *data = wp->modedata; struct window_client_modedata *data = wme->data;
u_int i; u_int i;
if (data == NULL) if (data == NULL)
@@ -286,9 +301,9 @@ window_client_free(struct window_pane *wp)
} }
static void static void
window_client_resize(struct window_pane *wp, u_int sx, u_int sy) window_client_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
{ {
struct window_client_modedata *data = wp->modedata; struct window_client_modedata *data = wme->data;
mode_tree_resize(data->data, sx, sy); mode_tree_resize(data->data, sx, sy);
} }
@@ -311,10 +326,12 @@ window_client_do_detach(void* modedata, void *itemdata,
} }
static void static void
window_client_key(struct window_pane *wp, struct client *c, window_client_key(struct window_mode_entry *wme, struct client *c,
__unused struct session *s, key_code key, struct mouse_event *m) __unused struct session *s, __unused struct winlink *wl, key_code key,
struct mouse_event *m)
{ {
struct window_client_modedata *data = wp->modedata; struct window_pane *wp = wme->wp;
struct window_client_modedata *data = wme->data;
struct mode_tree_data *mtd = data->data; struct mode_tree_data *mtd = data->data;
struct window_client_itemdata *item; struct window_client_itemdata *item;
int finished; int finished;

View File

@@ -24,15 +24,16 @@
#include "tmux.h" #include "tmux.h"
static struct screen *window_clock_init(struct window_pane *, static struct screen *window_clock_init(struct window_mode_entry *,
struct cmd_find_state *, struct args *); struct cmd_find_state *, struct args *);
static void window_clock_free(struct window_pane *); static void window_clock_free(struct window_mode_entry *);
static void window_clock_resize(struct window_pane *, u_int, u_int); static void window_clock_resize(struct window_mode_entry *, u_int, u_int);
static void window_clock_key(struct window_pane *, struct client *, static void window_clock_key(struct window_mode_entry *, struct client *,
struct session *, key_code, struct mouse_event *); struct session *, struct winlink *, key_code,
struct mouse_event *);
static void window_clock_timer_callback(int, short, void *); static void window_clock_timer_callback(int, short, void *);
static void window_clock_draw_screen(struct window_pane *); static void window_clock_draw_screen(struct window_mode_entry *);
const struct window_mode window_clock_mode = { const struct window_mode window_clock_mode = {
.name = "clock-mode", .name = "clock-mode",
@@ -125,8 +126,9 @@ const char window_clock_table[14][5][5] = {
static void static void
window_clock_timer_callback(__unused int fd, __unused short events, void *arg) window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
{ {
struct window_pane *wp = arg; struct window_mode_entry *wme = arg;
struct window_clock_mode_data *data = wp->modedata; struct window_pane *wp = wme->wp;
struct window_clock_mode_data *data = wme->data;
struct tm now, then; struct tm now, then;
time_t t; time_t t;
struct timeval tv = { .tv_sec = 1 }; struct timeval tv = { .tv_sec = 1 };
@@ -134,6 +136,9 @@ window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
evtimer_del(&data->timer); evtimer_del(&data->timer);
evtimer_add(&data->timer, &tv); evtimer_add(&data->timer, &tv);
if (TAILQ_FIRST(&wp->modes) != wme)
return;
t = time(NULL); t = time(NULL);
gmtime_r(&t, &now); gmtime_r(&t, &now);
gmtime_r(&data->tim, &then); gmtime_r(&data->tim, &then);
@@ -141,37 +146,38 @@ window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
return; return;
data->tim = t; data->tim = t;
window_clock_draw_screen(wp); window_clock_draw_screen(wme);
server_redraw_window(wp->window); wp->flags |= PANE_REDRAW;
} }
static struct screen * static struct screen *
window_clock_init(struct window_pane *wp, __unused struct cmd_find_state *fs, window_clock_init(struct window_mode_entry *wme,
__unused struct args *args) __unused struct cmd_find_state *fs, __unused struct args *args)
{ {
struct window_pane *wp = wme->wp;
struct window_clock_mode_data *data; struct window_clock_mode_data *data;
struct screen *s; struct screen *s;
struct timeval tv = { .tv_sec = 1 }; struct timeval tv = { .tv_sec = 1 };
wp->modedata = data = xmalloc(sizeof *data); wme->data = data = xmalloc(sizeof *data);
data->tim = time(NULL); data->tim = time(NULL);
evtimer_set(&data->timer, window_clock_timer_callback, wp); evtimer_set(&data->timer, window_clock_timer_callback, wme);
evtimer_add(&data->timer, &tv); evtimer_add(&data->timer, &tv);
s = &data->screen; s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
s->mode &= ~MODE_CURSOR; s->mode &= ~MODE_CURSOR;
window_clock_draw_screen(wp); window_clock_draw_screen(wme);
return (s); return (s);
} }
static void static void
window_clock_free(struct window_pane *wp) window_clock_free(struct window_mode_entry *wme)
{ {
struct window_clock_mode_data *data = wp->modedata; struct window_clock_mode_data *data = wme->data;
evtimer_del(&data->timer); evtimer_del(&data->timer);
screen_free(&data->screen); screen_free(&data->screen);
@@ -179,27 +185,28 @@ window_clock_free(struct window_pane *wp)
} }
static void static void
window_clock_resize(struct window_pane *wp, u_int sx, u_int sy) window_clock_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
{ {
struct window_clock_mode_data *data = wp->modedata; struct window_clock_mode_data *data = wme->data;
struct screen *s = &data->screen; struct screen *s = &data->screen;
screen_resize(s, sx, sy, 0); screen_resize(s, sx, sy, 0);
window_clock_draw_screen(wp); window_clock_draw_screen(wme);
} }
static void static void
window_clock_key(struct window_pane *wp, __unused struct client *c, window_clock_key(struct window_mode_entry *wme, __unused struct client *c,
__unused struct session *sess, __unused key_code key, __unused struct session *s, __unused struct winlink *wl,
__unused struct mouse_event *m) __unused key_code key, __unused struct mouse_event *m)
{ {
window_pane_reset_mode(wp); window_pane_reset_mode(wme->wp);
} }
static void static void
window_clock_draw_screen(struct window_pane *wp) window_clock_draw_screen(struct window_mode_entry *wme)
{ {
struct window_clock_mode_data *data = wp->modedata; struct window_pane *wp = wme->wp;
struct window_clock_mode_data *data = wme->data;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
int colour, style; int colour, style;
struct screen *s = &data->screen; struct screen *s = &data->screen;
@@ -231,7 +238,7 @@ window_clock_draw_screen(struct window_pane *wp)
if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) { if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) {
x = (screen_size_x(s) / 2) - (strlen(tim) / 2); x = (screen_size_x(s) / 2) - (strlen(tim) / 2);
y = screen_size_y(s) / 2; y = screen_size_y(s) / 2;
screen_write_cursormove(&ctx, x, y); screen_write_cursormove(&ctx, x, y, 0);
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
gc.flags |= GRID_FLAG_NOPALETTE; gc.flags |= GRID_FLAG_NOPALETTE;
@@ -267,7 +274,7 @@ window_clock_draw_screen(struct window_pane *wp)
for (j = 0; j < 5; j++) { for (j = 0; j < 5; j++) {
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
screen_write_cursormove(&ctx, x + i, y + j); screen_write_cursormove(&ctx, x + i, y + j, 0);
if (window_clock_table[idx][j][i]) if (window_clock_table[idx][j][i])
screen_write_putc(&ctx, &gc, ' '); screen_write_putc(&ctx, &gc, ' ');
} }

File diff suppressed because it is too large Load Diff

View File

@@ -24,13 +24,14 @@
#include "tmux.h" #include "tmux.h"
static struct screen *window_tree_init(struct window_pane *, static struct screen *window_tree_init(struct window_mode_entry *,
struct cmd_find_state *, struct args *); struct cmd_find_state *, struct args *);
static void window_tree_free(struct window_pane *); static void window_tree_free(struct window_mode_entry *);
static void window_tree_resize(struct window_pane *, u_int, u_int); static void window_tree_resize(struct window_mode_entry *, u_int,
static void window_tree_key(struct window_pane *, u_int);
struct client *, struct session *, key_code, static void window_tree_key(struct window_mode_entry *,
struct mouse_event *); struct client *, struct session *,
struct winlink *, key_code, struct mouse_event *);
#define WINDOW_TREE_DEFAULT_COMMAND "switch-client -t '%%'" #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -t '%%'"
@@ -54,6 +55,7 @@ static void window_tree_key(struct window_pane *,
const struct window_mode window_tree_mode = { const struct window_mode window_tree_mode = {
.name = "tree-mode", .name = "tree-mode",
.default_format = WINDOW_TREE_DEFAULT_FORMAT,
.init = window_tree_init, .init = window_tree_init,
.free = window_tree_free, .free = window_tree_free,
@@ -461,7 +463,6 @@ window_tree_build(void *modedata, u_int sort_type, uint64_t *tag,
} }
} }
static void static void
window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py, window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
u_int sx, u_int sy, const struct grid_cell *gc, const char *label) u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
@@ -476,10 +477,10 @@ window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
oy = (sy + 1) / 2; oy = (sy + 1) / 2;
if (ox > 1 && ox + len < sx - 1 && sy >= 3) { if (ox > 1 && ox + len < sx - 1 && sy >= 3) {
screen_write_cursormove(ctx, px + ox - 1, py + oy - 1); screen_write_cursormove(ctx, px + ox - 1, py + oy - 1, 0);
screen_write_box(ctx, len + 2, 3); screen_write_box(ctx, len + 2, 3);
} }
screen_write_cursormove(ctx, px + ox, py + oy); screen_write_cursormove(ctx, px + ox, py + oy, 0);
screen_write_puts(ctx, gc, "%s", label); screen_write_puts(ctx, gc, "%s", label);
} }
@@ -554,17 +555,17 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
if (left) { if (left) {
data->left = cx + 2; data->left = cx + 2;
screen_write_cursormove(ctx, cx + 2, cy); screen_write_cursormove(ctx, cx + 2, cy, 0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, cx, cy + sy / 2); screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
screen_write_puts(ctx, &grid_default_cell, "<"); screen_write_puts(ctx, &grid_default_cell, "<");
} else } else
data->left = -1; data->left = -1;
if (right) { if (right) {
data->right = cx + sx - 3; data->right = cx + sx - 3;
screen_write_cursormove(ctx, cx + sx - 3, cy); screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2); screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
screen_write_puts(ctx, &grid_default_cell, ">"); screen_write_puts(ctx, &grid_default_cell, ">");
} else } else
data->right = -1; data->right = -1;
@@ -597,7 +598,7 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
else else
width = each - 1; width = each - 1;
screen_write_cursormove(ctx, cx + offset, cy); screen_write_cursormove(ctx, cx + offset, cy, 0);
screen_write_preview(ctx, &w->active->base, width, sy); screen_write_preview(ctx, &w->active->base, width, sy);
xasprintf(&label, " %u:%s ", wl->idx, w->name); xasprintf(&label, " %u:%s ", wl->idx, w->name);
@@ -608,7 +609,7 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
free(label); free(label);
if (loop != end - 1) { if (loop != end - 1) {
screen_write_cursormove(ctx, cx + offset + width, cy); screen_write_cursormove(ctx, cx + offset + width, cy, 0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
} }
loop++; loop++;
@@ -687,17 +688,17 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
if (left) { if (left) {
data->left = cx + 2; data->left = cx + 2;
screen_write_cursormove(ctx, cx + 2, cy); screen_write_cursormove(ctx, cx + 2, cy, 0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, cx, cy + sy / 2); screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
screen_write_puts(ctx, &grid_default_cell, "<"); screen_write_puts(ctx, &grid_default_cell, "<");
} else } else
data->left = -1; data->left = -1;
if (right) { if (right) {
data->right = cx + sx - 3; data->right = cx + sx - 3;
screen_write_cursormove(ctx, cx + sx - 3, cy); screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2); screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
screen_write_puts(ctx, &grid_default_cell, ">"); screen_write_puts(ctx, &grid_default_cell, ">");
} else } else
data->right = -1; data->right = -1;
@@ -729,7 +730,7 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
else else
width = each - 1; width = each - 1;
screen_write_cursormove(ctx, cx + offset, cy); screen_write_cursormove(ctx, cx + offset, cy, 0);
screen_write_preview(ctx, &wp->base, width, sy); screen_write_preview(ctx, &wp->base, width, sy);
if (window_pane_index(wp, &pane_idx) != 0) if (window_pane_index(wp, &pane_idx) != 0)
@@ -740,7 +741,7 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
free(label); free(label);
if (loop != end - 1) { if (loop != end - 1) {
screen_write_cursormove(ctx, cx + offset + width, cy); screen_write_cursormove(ctx, cx + offset + width, cy, 0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
} }
loop++; loop++;
@@ -811,13 +812,14 @@ window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
} }
static struct screen * static struct screen *
window_tree_init(struct window_pane *wp, struct cmd_find_state *fs, window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
struct args *args) struct args *args)
{ {
struct window_pane *wp = wme->wp;
struct window_tree_modedata *data; struct window_tree_modedata *data;
struct screen *s; struct screen *s;
wp->modedata = data = xcalloc(1, sizeof *data); wme->data = data = xcalloc(1, sizeof *data);
if (args_has(args, 's')) if (args_has(args, 's'))
data->type = WINDOW_TREE_SESSION; data->type = WINDOW_TREE_SESSION;
@@ -872,9 +874,9 @@ window_tree_destroy(struct window_tree_modedata *data)
} }
static void static void
window_tree_free(struct window_pane *wp) window_tree_free(struct window_mode_entry *wme)
{ {
struct window_tree_modedata *data = wp->modedata; struct window_tree_modedata *data = wme->data;
if (data == NULL) if (data == NULL)
return; return;
@@ -885,9 +887,9 @@ window_tree_free(struct window_pane *wp)
} }
static void static void
window_tree_resize(struct window_pane *wp, u_int sx, u_int sy) window_tree_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
{ {
struct window_tree_modedata *data = wp->modedata; struct window_tree_modedata *data = wme->data;
mode_tree_resize(data->data, sx, sy); mode_tree_resize(data->data, sx, sy);
} }
@@ -1120,10 +1122,12 @@ window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x,
} }
static void static void
window_tree_key(struct window_pane *wp, struct client *c, window_tree_key(struct window_mode_entry *wme, struct client *c,
__unused struct session *s, key_code key, struct mouse_event *m) __unused struct session *s, __unused struct winlink *wl, key_code key,
struct mouse_event *m)
{ {
struct window_tree_modedata *data = wp->modedata; struct window_pane *wp = wme->wp;
struct window_tree_modedata *data = wme->data;
struct window_tree_itemdata *item, *new_item; struct window_tree_itemdata *item, *new_item;
char *name, *prompt = NULL; char *name, *prompt = NULL;
struct cmd_find_state fs; struct cmd_find_state fs;

193
window.c
View File

@@ -60,6 +60,17 @@ static u_int next_window_pane_id;
static u_int next_window_id; static u_int next_window_id;
static u_int next_active_point; static u_int next_active_point;
/* List of window modes. */
const struct window_mode *all_window_modes[] = {
&window_buffer_mode,
&window_client_mode,
&window_clock_mode,
&window_copy_mode,
&window_tree_mode,
&window_view_mode,
NULL
};
static void window_destroy(struct window *); static void window_destroy(struct window *);
static struct window_pane *window_pane_create(struct window *, u_int, u_int, static struct window_pane *window_pane_create(struct window *, u_int, u_int,
@@ -204,7 +215,6 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl)
} }
RB_REMOVE(winlinks, wwl, wl); RB_REMOVE(winlinks, wwl, wl);
free(wl->status_text);
free(wl); free(wl);
} }
@@ -378,6 +388,8 @@ window_destroy(struct window *w)
if (event_initialized(&w->alerts_timer)) if (event_initialized(&w->alerts_timer))
evtimer_del(&w->alerts_timer); evtimer_del(&w->alerts_timer);
if (event_initialized(&w->offset_timer))
event_del(&w->offset_timer);
options_free(w->options); options_free(w->options);
@@ -456,17 +468,9 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
return (0); return (0);
w->last = w->active; w->last = w->active;
w->active = wp; w->active = wp;
while (!window_pane_visible(w->active)) {
w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_LAST(&w->panes, window_panes);
if (w->active == wp) {
notify_window("window-pane-changed", w);
return (1);
}
}
w->active->active_point = next_active_point++; w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED; w->active->flags |= PANE_CHANGED;
tty_update_window_offset(w);
notify_window("window-pane-changed", w); notify_window("window-pane-changed", w);
return (1); return (1);
} }
@@ -474,7 +478,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
void void
window_redraw_active_switch(struct window *w, struct window_pane *wp) window_redraw_active_switch(struct window *w, struct window_pane *wp)
{ {
const struct grid_cell *gc; struct style *sy;
if (wp == w->active) if (wp == w->active)
return; return;
@@ -483,21 +487,21 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
* If window-style and window-active-style are the same, we don't need * If window-style and window-active-style are the same, we don't need
* to redraw panes when switching active panes. * to redraw panes when switching active panes.
*/ */
gc = options_get_style(w->options, "window-active-style"); sy = options_get_style(w->options, "window-active-style");
if (style_equal(gc, options_get_style(w->options, "window-style"))) if (style_equal(sy, options_get_style(w->options, "window-style")))
return; return;
/* /*
* If the now active or inactive pane do not have a custom style or if * If the now active or inactive pane do not have a custom style or if
* the palette is different, they need to be redrawn. * the palette is different, they need to be redrawn.
*/ */
if (window_pane_get_palette(w->active, w->active->colgc.fg) != -1 || if (window_pane_get_palette(w->active, w->active->style.gc.fg) != -1 ||
window_pane_get_palette(w->active, w->active->colgc.bg) != -1 || window_pane_get_palette(w->active, w->active->style.gc.bg) != -1 ||
style_equal(&grid_default_cell, &w->active->colgc)) style_is_default(&w->active->style))
w->active->flags |= PANE_REDRAW; w->active->flags |= PANE_REDRAW;
if (window_pane_get_palette(wp, wp->colgc.fg) != -1 || if (window_pane_get_palette(wp, wp->style.gc.fg) != -1 ||
window_pane_get_palette(wp, wp->colgc.bg) != -1 || window_pane_get_palette(wp, wp->style.gc.bg) != -1 ||
style_equal(&grid_default_cell, &wp->colgc)) style_is_default(&wp->style))
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
} }
@@ -561,9 +565,6 @@ window_zoom(struct window_pane *wp)
if (w->flags & WINDOW_ZOOMED) if (w->flags & WINDOW_ZOOMED)
return (-1); return (-1);
if (!window_pane_visible(wp))
return (-1);
if (window_count_panes(w) == 1) if (window_count_panes(w) == 1)
return (-1); return (-1);
@@ -600,7 +601,7 @@ window_unzoom(struct window *w)
wp->layout_cell = wp->saved_layout_cell; wp->layout_cell = wp->saved_layout_cell;
wp->saved_layout_cell = NULL; wp->saved_layout_cell = NULL;
} }
layout_fix_panes(w, w->sx, w->sy); layout_fix_panes(w);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
return (0); return (0);
@@ -817,8 +818,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->fd = -1; wp->fd = -1;
wp->event = NULL; wp->event = NULL;
wp->mode = NULL; TAILQ_INIT(&wp->modes);
wp->modeprefix = 1;
wp->layout_cell = NULL; wp->layout_cell = NULL;
@@ -834,7 +834,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->saved_grid = NULL; wp->saved_grid = NULL;
memcpy(&wp->colgc, &grid_default_cell, sizeof wp->colgc); style_set(&wp->style, &grid_default_cell);
screen_init(&wp->base, sx, sy, hlimit); screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base; wp->screen = &wp->base;
@@ -852,7 +852,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
static void static void
window_pane_destroy(struct window_pane *wp) window_pane_destroy(struct window_pane *wp)
{ {
window_pane_reset_mode(wp); window_pane_reset_mode_all(wp);
free(wp->searchstr); free(wp->searchstr);
if (wp->fd != -1) { if (wp->fd != -1) {
@@ -865,6 +865,8 @@ window_pane_destroy(struct window_pane *wp)
input_free(wp); input_free(wp);
screen_free(&wp->status_screen);
screen_free(&wp->base); screen_free(&wp->base);
if (wp->saved_grid != NULL) if (wp->saved_grid != NULL)
grid_destroy(wp->saved_grid); grid_destroy(wp->saved_grid);
@@ -898,7 +900,6 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
#ifdef HAVE_UTEMPTER #ifdef HAVE_UTEMPTER
char s[32]; char s[32];
#endif #endif
int i;
sigset_t set, oldset; sigset_t set, oldset;
if (wp->fd != -1) { if (wp->fd != -1) {
@@ -935,6 +936,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
sigprocmask(SIG_BLOCK, &set, &oldset); sigprocmask(SIG_BLOCK, &set, &oldset);
switch (wp->pid = fdforkpty(ptm_fd, &wp->fd, wp->tty, NULL, &ws)) { switch (wp->pid = fdforkpty(ptm_fd, &wp->fd, wp->tty, NULL, &ws)) {
case -1: case -1:
wp->event = NULL;
wp->fd = -1; wp->fd = -1;
xasprintf(cause, "%s: %s", cmd, strerror(errno)); xasprintf(cause, "%s: %s", cmd, strerror(errno));
@@ -1020,6 +1022,11 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL, wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
window_pane_error_callback, wp); window_pane_error_callback, wp);
if (wp->event == NULL)
fatalx("out of memory");
wp->pipe_off = 0;
wp->flags &= ~PANE_EXITED;
bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE); bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
bufferevent_enable(wp->event, EV_READ|EV_WRITE); bufferevent_enable(wp->event, EV_READ|EV_WRITE);
@@ -1065,14 +1072,18 @@ window_pane_error_callback(__unused struct bufferevent *bufev,
void void
window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{ {
struct window_mode_entry *wme;
if (sx == wp->sx && sy == wp->sy) if (sx == wp->sx && sy == wp->sy)
return; return;
wp->sx = sx; wp->sx = sx;
wp->sy = sy; wp->sy = sy;
screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL); screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL);
if (wp->mode != NULL)
wp->mode->resize(wp, sx, sy); wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->resize != NULL)
wme->mode->resize(wme, sx, sy);
wp->flags |= PANE_RESIZE; wp->flags |= PANE_RESIZE;
} }
@@ -1193,7 +1204,7 @@ window_pane_reset_palette(struct window_pane *wp)
} }
int int
window_pane_get_palette(const struct window_pane *wp, int c) window_pane_get_palette(struct window_pane *wp, int c)
{ {
int new; int new;
@@ -1226,7 +1237,7 @@ window_pane_mode_timer(__unused int fd, __unused short events, void *arg)
if (wp->modelast < time(NULL) - WINDOW_MODE_TIMEOUT) { if (wp->modelast < time(NULL) - WINDOW_MODE_TIMEOUT) {
if (ioctl(wp->fd, FIONREAD, &n) == -1 || n > 0) if (ioctl(wp->fd, FIONREAD, &n) == -1 || n > 0)
window_pane_reset_mode(wp); window_pane_reset_mode_all(wp);
} }
} }
@@ -1234,39 +1245,67 @@ int
window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode, window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode,
struct cmd_find_state *fs, struct args *args) struct cmd_find_state *fs, struct args *args)
{ {
struct screen *s; struct timeval tv = { .tv_sec = 10 };
struct timeval tv = { .tv_sec = 10 }; struct window_mode_entry *wme;
if (wp->mode != NULL) if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode)
return (1); return (1);
wp->mode = mode;
wp->modelast = time(NULL); wp->modelast = time(NULL);
evtimer_set(&wp->modetimer, window_pane_mode_timer, wp); if (TAILQ_EMPTY(&wp->modes)) {
evtimer_add(&wp->modetimer, &tv); evtimer_set(&wp->modetimer, window_pane_mode_timer, wp);
evtimer_add(&wp->modetimer, &tv);
}
if ((s = wp->mode->init(wp, fs, args)) != NULL) TAILQ_FOREACH(wme, &wp->modes, entry) {
wp->screen = s; if (wme->mode == mode)
break;
}
if (wme != NULL) {
TAILQ_REMOVE(&wp->modes, wme, entry);
TAILQ_INSERT_HEAD(&wp->modes, wme, entry);
} else {
wme = xcalloc(1, sizeof *wme);
wme->wp = wp;
wme->mode = mode;
wme->prefix = 1;
TAILQ_INSERT_HEAD(&wp->modes, wme, entry);
wme->screen = wme->mode->init(wme, fs, args);
}
wp->screen = wme->screen;
wp->flags |= (PANE_REDRAW|PANE_CHANGED); wp->flags |= (PANE_REDRAW|PANE_CHANGED);
server_status_window(wp->window); server_status_window(wp->window);
notify_pane("pane-mode-changed", wp); notify_pane("pane-mode-changed", wp);
return (0); return (0);
} }
void void
window_pane_reset_mode(struct window_pane *wp) window_pane_reset_mode(struct window_pane *wp)
{ {
if (wp->mode == NULL) struct window_mode_entry *wme, *next;
if (TAILQ_EMPTY(&wp->modes))
return; return;
evtimer_del(&wp->modetimer); wme = TAILQ_FIRST(&wp->modes);
TAILQ_REMOVE(&wp->modes, wme, entry);
wme->mode->free(wme);
free(wme);
wp->mode->free(wp); next = TAILQ_FIRST(&wp->modes);
wp->mode = NULL; if (next == NULL) {
wp->modeprefix = 1; log_debug("%s: no next mode", __func__);
evtimer_del(&wp->modetimer);
wp->screen = &wp->base; wp->screen = &wp->base;
} else {
log_debug("%s: next mode is %s", __func__, next->mode->name);
wp->screen = next->screen;
if (next != NULL && next->mode->resize != NULL)
next->mode->resize(next, wp->sx, wp->sy);
}
wp->flags |= (PANE_REDRAW|PANE_CHANGED); wp->flags |= (PANE_REDRAW|PANE_CHANGED);
server_status_window(wp->window); server_status_window(wp->window);
@@ -1274,18 +1313,27 @@ window_pane_reset_mode(struct window_pane *wp)
} }
void void
window_pane_key(struct window_pane *wp, struct client *c, struct session *s, window_pane_reset_mode_all(struct window_pane *wp)
key_code key, struct mouse_event *m)
{ {
struct window_pane *wp2; while (!TAILQ_EMPTY(&wp->modes))
window_pane_reset_mode(wp);
}
void
window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
struct winlink *wl, key_code key, struct mouse_event *m)
{
struct window_mode_entry *wme;
struct window_pane *wp2;
if (KEYC_IS_MOUSE(key) && m == NULL) if (KEYC_IS_MOUSE(key) && m == NULL)
return; return;
if (wp->mode != NULL) { wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL) {
wp->modelast = time(NULL); wp->modelast = time(NULL);
if (wp->mode->key != NULL) if (wme->mode->key != NULL)
wp->mode->key(wp, c, s, (key & ~KEYC_XTERM), m); wme->mode->key(wme, c, s, wl, (key & ~KEYC_XTERM), m);
return; return;
} }
@@ -1298,11 +1346,11 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
return; return;
if (options_get_number(wp->window->options, "synchronize-panes")) { if (options_get_number(wp->window->options, "synchronize-panes")) {
TAILQ_FOREACH(wp2, &wp->window->panes, entry) { TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (wp2 == wp || wp2->mode != NULL) if (wp2 != wp &&
continue; TAILQ_EMPTY(&wp2->modes) &&
if (wp2->fd == -1 || wp2->flags & PANE_INPUTOFF) wp2->fd != -1 &&
continue; (~wp2->flags & PANE_INPUTOFF) &&
if (window_pane_visible(wp2)) window_pane_visible(wp2))
input_key(wp2, key, NULL); input_key(wp2, key, NULL);
} }
} }
@@ -1311,16 +1359,9 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
int int
window_pane_visible(struct window_pane *wp) window_pane_visible(struct window_pane *wp)
{ {
struct window *w = wp->window; if (~wp->window->flags & WINDOW_ZOOMED)
return (1);
if (wp->layout_cell == NULL) return (wp == wp->window->active);
return (0);
if (wp->xoff >= w->sx || wp->yoff >= w->sy)
return (0);
if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
return (0);
return (1);
} }
u_int u_int
@@ -1377,7 +1418,7 @@ window_pane_find_up(struct window_pane *wp)
u_int edge, left, right, end, size; u_int edge, left, right, end, size;
int status, found; int status, found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL)
return (NULL); return (NULL);
status = options_get_number(wp->window->options, "pane-border-status"); status = options_get_number(wp->window->options, "pane-border-status");
@@ -1392,7 +1433,7 @@ window_pane_find_up(struct window_pane *wp)
right = wp->xoff + wp->sx; right = wp->xoff + wp->sx;
TAILQ_FOREACH(next, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (next == wp || !window_pane_visible(next)) if (next == wp)
continue; continue;
if (next->yoff + next->sy + 1 != edge) if (next->yoff + next->sy + 1 != edge)
continue; continue;
@@ -1424,7 +1465,7 @@ window_pane_find_down(struct window_pane *wp)
u_int edge, left, right, end, size; u_int edge, left, right, end, size;
int status, found; int status, found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL)
return (NULL); return (NULL);
status = options_get_number(wp->window->options, "pane-border-status"); status = options_get_number(wp->window->options, "pane-border-status");
@@ -1439,7 +1480,7 @@ window_pane_find_down(struct window_pane *wp)
right = wp->xoff + wp->sx; right = wp->xoff + wp->sx;
TAILQ_FOREACH(next, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (next == wp || !window_pane_visible(next)) if (next == wp)
continue; continue;
if (next->yoff != edge) if (next->yoff != edge)
continue; continue;
@@ -1471,7 +1512,7 @@ window_pane_find_left(struct window_pane *wp)
u_int edge, top, bottom, end, size; u_int edge, top, bottom, end, size;
int found; int found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL)
return (NULL); return (NULL);
list = NULL; list = NULL;
@@ -1485,7 +1526,7 @@ window_pane_find_left(struct window_pane *wp)
bottom = wp->yoff + wp->sy; bottom = wp->yoff + wp->sy;
TAILQ_FOREACH(next, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (next == wp || !window_pane_visible(next)) if (next == wp)
continue; continue;
if (next->xoff + next->sx + 1 != edge) if (next->xoff + next->sx + 1 != edge)
continue; continue;
@@ -1517,7 +1558,7 @@ window_pane_find_right(struct window_pane *wp)
u_int edge, top, bottom, end, size; u_int edge, top, bottom, end, size;
int found; int found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL)
return (NULL); return (NULL);
list = NULL; list = NULL;
@@ -1531,7 +1572,7 @@ window_pane_find_right(struct window_pane *wp)
bottom = wp->yoff + wp->sy; bottom = wp->yoff + wp->sy;
TAILQ_FOREACH(next, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (next == wp || !window_pane_visible(next)) if (next == wp)
continue; continue;
if (next->xoff != edge) if (next->xoff != edge)
continue; continue;