The attached patch adds control mode and is up to date with the latest
changes.
Index: tmux.h
===================================================================
--- tmux.h (revision 2749)
+++ tmux.h (working copy)
@@ -402,6 +402,7 @@
#define IDENTIFY_UTF8 0x1
#define IDENTIFY_256COLOURS 0x2
#define IDENTIFY_88COLOURS 0x4
+#define IDENTIFY_CONTROL 0x8
int flags;
};
@@ -743,6 +744,16 @@
#define screen_hsize(s) ((s)->grid->hsize)
#define screen_hlimit(s) ((s)->grid->hlimit)
+/* dstring is a dynamic string. It is null terminated. It allocates memory as
+ * needed and has an amortized O(n) cost of appending. */
+struct dstring {
+ char *buffer; /* always points at the current buffer. */
+ int used; /* this does not include the trailing nul. */
+ int available; /* amount of allocated space in buffer. */
+#define DSTRING_STATIC_BUFFER_SIZE 1024
+ char staticbuffer[DSTRING_STATIC_BUFFER_SIZE];
+};
+
/* Input parser context. */
struct input_ctx {
struct window_pane *wp;
@@ -773,6 +784,11 @@
#define INPUT_DISCARD 0x1
const struct input_state *state;
+
+ /* All input received since we were last in the ground state. Sent to
+ * control clients on connection so their vt100 state can be the same as
+ * ours. */
+ struct dstring input_since_ground;
};
/*
@@ -948,6 +964,7 @@
struct session {
u_int idx;
+ u_int id;
char *name;
char *cwd;
@@ -964,7 +981,8 @@
struct options options;
-#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
+#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
+#define SESSION_RENAMED 0x2 /* notify control clients */
int flags;
struct termios *tio;
@@ -1167,7 +1185,11 @@
#define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800
#define CLIENT_REDRAWWINDOW 0x1000
- int flags;
+#define CLIENT_CONTROL 0x2000 /* is a control client */
+#define CLIENT_CONTROL_READY 0x4000 /* control client ready for messages */
+#define CLIENT_SESSION_CHANGED 0x8000 /* needs session-changed notification */
+#define CLIENT_SESSION_HANDSHAKE 0x10000 /* has sent handshake */
+ int flags;
struct event identify_timer;
@@ -1591,6 +1613,7 @@
extern const struct cmd_entry cmd_display_message_entry;
extern const struct cmd_entry cmd_display_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry;
+extern const struct cmd_entry cmd_control_entry;
extern const struct cmd_entry cmd_find_window_entry;
extern const struct cmd_entry cmd_has_session_entry;
extern const struct cmd_entry cmd_if_shell_entry;
@@ -1639,6 +1662,7 @@
extern const struct cmd_entry cmd_send_prefix_entry;
extern const struct cmd_entry cmd_server_info_entry;
extern const struct cmd_entry cmd_set_buffer_entry;
+extern const struct cmd_entry cmd_set_control_client_attr_entry;
extern const struct cmd_entry cmd_set_environment_entry;
extern const struct cmd_entry cmd_set_option_entry;
extern const struct cmd_entry cmd_set_window_option_entry;
@@ -1670,6 +1694,46 @@
/* client.c */
int client_main(int, char **, int);
+/* cmd-join-pane.c */
+int join_pane(
+ struct cmd *self, struct cmd_ctx *ctx, int require_diff_windows);
+
+/* control.c */
+void control_init(void);
+void control_start(struct client *);
+void control_write(struct client *, const char *, int);
+void control_write_str(struct client*, const char*);
+void control_write_printf(struct client*, const char*, ...);
+void control_write_window(struct client *, struct window *);
+void control_write_window_pane(struct client *, struct window_pane *);
+void control_write_input(struct client *, struct window_pane *,
+ const u_char *, int);
+void control_broadcast_input(struct window_pane *, const u_char *,
+ size_t);
+void control_set_spontaneous_messages_allowed(int);
+void control_notify_layout_change(struct window *);
+void control_notify_window_added(struct window *w);
+void control_notify_window_removed(struct window *);
+void control_broadcast_queue(void);
+void control_handshake(struct client *);
+void control_print_session_layouts(struct session *session,
+ struct cmd_ctx *);
+void control_set_kvp(const char *, const char *);
+char *control_get_kvp_value(const char *);
+void control_notify_attached_session_changed(struct client *);
+void control_notify_session_closed(struct session *);
+void control_notify_session_created(struct session *);
+void control_notify_session_renamed(struct session *);
+void control_notify_window_renamed(struct window *w);
+
+/* dstring.c */
+void ds_init(struct dstring *ds);
+void ds_free(struct dstring *ds);
+void ds_appendf(struct dstring *ds, const char *fmt, ...);
+void ds_append(struct dstring *ds, const char *str);
+void ds_appendl(struct dstring *ds, const char *str, int len);
+void ds_truncate(struct dstring *ds, int new_length);
+
/* key-bindings.c */
extern struct key_bindings key_bindings;
int key_bindings_cmp(struct key_binding *, struct key_binding *);
Index: cmd-new-session.c
===================================================================
--- cmd-new-session.c (revision 2749)
+++ cmd-new-session.c (working copy)
@@ -64,7 +64,7 @@
struct passwd *pw;
const char *newname, *target, *update, *cwd, *errstr;
char *overrides, *cmd, *cause;
- int detached, idx;
+ int detached, idx, hastty;
u_int sx, sy, i;
newname = args_get(args, 's');
@@ -110,6 +110,14 @@
if (ctx->cmdclient == NULL && ctx->curclient == NULL)
detached = 1;
+ /* Control clients don't have a tty, so avoid doing tty-ish things in
+ * that case. */
+ if ((ctx->cmdclient && (ctx->cmdclient->flags & CLIENT_CONTROL)) ||
+ (ctx->curclient && (ctx->curclient->flags & CLIENT_CONTROL)))
+ hastty = 0;
+ else
+ hastty = 1;
+
/*
* Save the termios settings, part of which is used for new windows in
* this session.
@@ -127,7 +135,7 @@
tiop = NULL;
/* Open the terminal if necessary. */
- if (!detached && ctx->cmdclient != NULL) {
+ if (hastty && !detached && ctx->cmdclient != NULL) {
if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
ctx->error(ctx, "not a terminal");
return (-1);
Index: cmd-list.c
===================================================================
--- cmd-list.c (revision 2749)
+++ cmd-list.c (working copy)
@@ -83,11 +83,29 @@
{
struct cmd *cmd;
int n, retval;
+ struct client *c;
+ int print_guards;
+ c = ctx->curclient;
+ /* print %begin...%end guards around command output only if the client
+ * is a control client that has an attached session. The requirement
+ * for an attached session exists because the local client may issue an
+ * attach-session or new-session command on startup that the remote
+ * client is unaware of. Only after attaching to a session does the
+ * remote client take charge.*/
+ print_guards = c && (c->flags & CLIENT_CONTROL) && c->session;
retval = 0;
+ control_set_spontaneous_messages_allowed(0);
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
- if ((n = cmd_exec(cmd, ctx)) == -1)
+ if (print_guards)
+ ctx->print(ctx, "%%begin");
+ if ((n = cmd_exec(cmd, ctx)) == -1) {
+ if (print_guards)
+ ctx->print(ctx, "%%end");
return (-1);
+ }
+ if (print_guards)
+ ctx->print(ctx, "%%end");
/*
* A 1 return value means the command client is being attached
@@ -111,6 +129,7 @@
}
}
}
+ control_set_spontaneous_messages_allowed(1);
return (retval);
}
Index: session.c
===================================================================
--- session.c (revision 2749)
+++ session.c (working copy)
@@ -34,6 +34,7 @@
struct winlink *session_next_alert(struct winlink *);
struct winlink *session_previous_alert(struct winlink *);
+u_int next_session_id = 0;
RB_GENERATE(sessions, session, entry, session_cmp);
@@ -91,6 +92,7 @@
struct session *s;
s = xmalloc(sizeof *s);
+ s->id = next_session_id++;
s->references = 0;
s->flags = 0;
Index: Makefile.am
===================================================================
--- Makefile.am (revision 2749)
+++ Makefile.am (working copy)
@@ -60,6 +60,7 @@
cfg.c \
client.c \
clock.c \
+ control.c \
cmd-attach-session.c \
cmd-bind-key.c \
cmd-break-pane.c \
@@ -72,6 +73,7 @@
cmd-clock-mode.c \
cmd-command-prompt.c \
cmd-confirm-before.c \
+ cmd-control.c \
cmd-copy-mode.c \
cmd-delete-buffer.c \
cmd-detach-client.c \
@@ -135,6 +137,7 @@
cmd-unlink-window.c \
cmd.c \
colour.c \
+ dstring.c \
environ.c \
format.c \
grid-utf8.c \
Index: server-client.c
===================================================================
--- server-client.c (revision 2749)
+++ server-client.c (working copy)
@@ -508,6 +508,9 @@
if (c->flags & CLIENT_SUSPENDED)
return;
+ if (c->flags & CLIENT_CONTROL)
+ return;
+
tty_region(&c->tty, 0, c->tty.sy - 1);
status = options_get_number(oo, "status");
@@ -602,6 +605,9 @@
struct window_pane *wp;
int flags, redraw;
+ if (c->flags & CLIENT_CONTROL)
+ return;
+
flags = c->tty.flags & TTY_FREEZE;
c->tty.flags &= ~TTY_FREEZE;
@@ -797,7 +803,8 @@
if (datalen != 0)
fatalx("bad MSG_RESIZE size");
- if (tty_resize(&c->tty)) {
+ if (!(c->flags & CLIENT_CONTROL) &&
+ tty_resize(&c->tty)) {
recalculate_sizes();
server_redraw_client(c);
}
@@ -948,13 +955,24 @@
server_client_msg_identify(
struct client *c, struct msg_identify_data *data, int fd)
{
- int tty_fd;
+ int tty_fd;
+ struct termios dummy_termios;
c->cwd = NULL;
data->cwd[(sizeof data->cwd) - 1] = '\0';
if (*data->cwd != '\0')
c->cwd = xstrdup(data->cwd);
+ /*
+ * If this is a control client, mark the client, and initiate the
+ * control events.
+ */
+ if (data->flags & IDENTIFY_CONTROL) {
+ c->flags |= CLIENT_CONTROL;
+ tty_init_termios(fd, &dummy_termios, NULL);
+ control_start(c);
+ }
+
if (!isatty(fd))
return;
if ((tty_fd = dup(fd)) == -1)
@@ -972,7 +990,8 @@
tty_resize(&c->tty);
- c->flags |= CLIENT_TERMINAL;
+ if (!(data->flags & IDENTIFY_CONTROL))
+ c->flags |= CLIENT_TERMINAL;
}
/* Handle shell message. */
Index: resize.c
===================================================================
--- resize.c (revision 2749)
+++ resize.c (working copy)
@@ -49,10 +49,13 @@
struct client *c;
struct window *w;
struct window_pane *wp;
- u_int i, j, ssx, ssy, has, limit;
- int flag;
+ u_int i, j, ssx, ssy, has, limit;
+ int flag;
+ int session_has_status;
+ u_int ssy_ex_status;
RB_FOREACH(s, sessions, &sessions) {
+ session_has_status = options_get_number(&s->options, "status");
ssx = ssy = UINT_MAX;
for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j);
@@ -61,8 +64,16 @@
if (c->session == s) {
if (c->tty.sx < ssx)
ssx = c->tty.sx;
- if (c->tty.sy < ssy)
- ssy = c->tty.sy;
+ /* Reserve one line for status if the session
+ * wants it, the client supports it, and there
+ * is room. */
+ ssy_ex_status = c->tty.sy;
+ if (session_has_status &&
+ !(c->flags & CLIENT_CONTROL) &&
+ ssy_ex_status > 1)
+ --ssy_ex_status;
+ if (ssy_ex_status < ssy)
+ ssy = ssy_ex_status;
}
}
if (ssx == UINT_MAX || ssy == UINT_MAX) {
@@ -71,12 +82,9 @@
}
s->flags &= ~SESSION_UNATTACHED;
- if (options_get_number(&s->options, "status")) {
- if (ssy == 0)
- ssy = 1;
- else
- ssy--;
- }
+ if (session_has_status && ssy == 0)
+ ssy = 1;
+
if (s->sx == ssx && s->sy == ssy)
continue;
Index: server-fn.c
===================================================================
--- server-fn.c (revision 2749)
+++ server-fn.c (working copy)
@@ -226,6 +226,11 @@
size_t cmdlen;
struct msg_lock_data lockdata;
+ /* Control clients aren't able to lock, but just in case the command
+ * gets sent, do nothing because it doesn't have a tty. */
+ if (!(c->flags & CLIENT_CONTROL))
+ return;
+
if (c->flags & CLIENT_SUSPENDED)
return;
Index: tmux.1
===================================================================
--- tmux.1 (revision 2749)
+++ tmux.1 (working copy)
@@ -23,7 +23,7 @@
.Sh SYNOPSIS
.Nm tmux
.Bk -words
-.Op Fl 28lquvV
+.Op Fl 28ClquvV
.Op Fl c Ar shell-command
.Op Fl f Ar file
.Op Fl L Ar socket-name
@@ -116,6 +116,10 @@
when
.Nm
is used as a login shell.
+.It Fl C
+Operate in
+.Ic control mode ,
+which allows compatible terminal emulators to offer a native user interface
for tmux.
.It Fl f Ar file
Specify an alternative configuration file.
By default,
Index: server-window.c
===================================================================
--- server-window.c (revision 2749)
+++ server-window.c (working copy)
@@ -85,7 +85,7 @@
visual = options_get_number(&s->options, "visual-bell");
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session != s)
+ if (c == NULL || c->session != s || (c->flags &
CLIENT_CONTROL))
continue;
if (!visual) {
tty_bell(&c->tty);
@@ -105,7 +105,7 @@
visual = options_get_number(&s->options, "visual-bell");
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session != s)
+ if (c == NULL || c->session != s || (c->flags &
CLIENT_CONTROL))
continue;
if (c->session->curw->window != w)
continue;
@@ -255,7 +255,7 @@
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (c != NULL && c->session == s)
+ if (c != NULL && c->session == s && !(c->flags &
CLIENT_CONTROL))
tty_bell(&c->tty);
}
}
Index: client.c
===================================================================
--- client.c (revision 2749)
+++ client.c (working copy)
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <termios.h>
#include "tmux.h"
@@ -38,6 +39,7 @@
int client_exitval;
enum msgtype client_exittype;
int client_attached;
+static int is_control_client;
int client_get_lock(char *);
int client_connect(char *, int);
@@ -120,10 +122,34 @@
return (-1);
}
+/* Sleep and then read any pending input. This tries to handle a problem
+ * in control mode where the client is unexpectedly detached while commands it
+ * has sent are on the wire. We'd like to read those commands and throw them
+ * away rather than have them sent to the shell after tmux quits.
+ */
+static void
+read_stray_input(int fd)
+{
+ int saved_flags;
+ int n;
+ char buffer[100];
+
+ sleep(2);
+ saved_flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, saved_flags | O_NONBLOCK);
+ do {
+ n = read(fd, buffer, sizeof(buffer));
+ if (n == -1 && errno != EINTR) {
+ break;
+ }
+ } while (n > 0);
+}
+
/* Client main loop. */
int
client_main(int argc, char **argv, int flags)
{
+ struct termios saved_termios;
struct cmd *cmd;
struct cmd_list *cmdlist;
struct msg_command_data cmddata;
@@ -181,6 +207,17 @@
log_warn("failed to connect to server");
return (1);
}
+ if (flags & IDENTIFY_CONTROL) {
+ if (!isatty(fileno(stdout))) {
+ /* This test must be performed earlier for control
clients because
+ * the CLIENT_TERMINAL flag is used for more than
detecting the presence
+ * of a terminal and control mode is completely useless
without a tty
+ * because echo can't be disabled. */
+ log_fatalx("not a terminal");
+ return (1);
+ }
+ is_control_client = 1;
+ }
/* Set process title, log and signals now this is the client. */
#ifdef HAVE_SETPROCTITLE
@@ -200,6 +237,14 @@
client_send_environ();
client_send_identify(flags);
+ if (is_control_client) {
+ /* Save termios and restore it on exit. Can't count on the
+ * server to do that because it might crash. */
+ struct termios tio;
+ tcgetattr(fileno(stdout), &tio);
+ saved_termios = tio;
+ }
+
/* Send first command. */
if (msg == MSG_COMMAND) {
/* Fill in command line arguments. */
@@ -224,13 +269,25 @@
/* Print the exit message, if any, and exit. */
if (client_attached) {
- if (client_exitmsg != NULL && !login_shell)
- printf("[%s]\n", client_exitmsg);
+ if (client_exitmsg != NULL && !login_shell) {
+ if (flags & IDENTIFY_CONTROL) {
+ printf("%%exit %s\n", client_exitmsg);
+ /* Exit messages other than "detached" are
+ * not client-initiated. */
+ if (strcmp("detached", client_exitmsg))
+ read_stray_input(fileno(stdin));
+ } else
+ printf("[%s]\n", client_exitmsg);
+ }
ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
}
+ if (is_control_client)
+ /* Turn off echo in control mode (we only get here if stdout is
+ * a tty so it's ok to do). */
+ tcsetattr(fileno(stdout), TCSANOW, &saved_termios);
return (client_exitval);
}
@@ -252,11 +309,6 @@
strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
*data.term = '\0';
- if ((fd = dup(STDIN_FILENO)) == -1)
- fatal("dup failed");
- imsg_compose(&client_ibuf,
- MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
-
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
@@ -266,6 +318,12 @@
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
+
+ if ((fd = dup(STDIN_FILENO)) == -1)
+ fatal("dup failed");
+ /* For control clients, this has to be the last message. */
+ imsg_compose(&client_ibuf,
+ MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
}
/* Forward entire environment to server. */
Index: input.c
===================================================================
--- input.c (revision 2749)
+++ input.c (working copy)
@@ -692,12 +692,17 @@
ictx->state = &input_state_ground;
ictx->flags = 0;
+
+ ds_init(&ictx->input_since_ground);
}
/* Destroy input parser. */
void
input_free(unused struct window_pane *wp)
{
+ if (wp) {
+ ds_free(&wp->ictx.input_since_ground);
+ }
}
/* Parse input. */
@@ -728,6 +733,8 @@
buf = EVBUFFER_DATA(evb);
len = EVBUFFER_LENGTH(evb);
+
+ control_broadcast_input(wp, buf, len);
off = 0;
/* Parse the input. */
@@ -758,10 +765,19 @@
if (itr->state != NULL) {
if (ictx->state->exit != NULL)
ictx->state->exit(ictx);
+ if (ictx->state != &input_state_ground &&
+ itr->state == &input_state_ground) {
+ /* Entering ground state. */
+ ds_truncate(&ictx->input_since_ground, 0);
+ }
ictx->state = itr->state;
if (ictx->state->enter != NULL)
ictx->state->enter(ictx);
}
+ if (ictx->state != &input_state_ground) {
+ /* Not in ground state, so save input. */
+ ds_appendl(&ictx->input_since_ground, (const char *)
&ictx->ch, 1);
+ }
}
/* Close the screen. */
Index: cmd.c
===================================================================
--- cmd.c (revision 2749)
+++ cmd.c (working copy)
@@ -39,6 +39,7 @@
&cmd_clear_history_entry,
&cmd_clock_mode_entry,
&cmd_command_prompt_entry,
+ &cmd_control_entry,
&cmd_confirm_before_entry,
&cmd_copy_mode_entry,
&cmd_delete_buffer_entry,
Index: server.c
===================================================================
--- server.c (revision 2749)
+++ server.c (working copy)
@@ -152,6 +152,7 @@
mode_key_init_trees();
key_bindings_init();
utf8_build();
+ control_init();
start_time = time(NULL);
log_debug("socket path %s", socket_path);
Index: notify.c
===================================================================
--- notify.c (revision 2749)
+++ notify.c (working copy)
@@ -21,39 +21,50 @@
void
notify_window_layout_changed(unused struct window *w)
{
+ control_notify_layout_change(w);
}
void
notify_window_unlinked(unused struct session *s, unused struct window *w)
{
+ control_notify_window_removed(w);
}
void
notify_window_linked(unused struct session *s, unused struct window *w)
{
+ control_notify_window_added(w);
}
void
notify_window_renamed(unused struct window *w)
{
+ control_notify_window_renamed(w);
}
void
notify_attached_session_changed(unused struct client *c)
{
+ if (c->flags & CLIENT_CONTROL) {
+ control_handshake(c);
+ control_notify_attached_session_changed(c);
+ }
}
void
notify_session_renamed(unused struct session *s)
{
+ control_notify_session_renamed(s);
}
void
notify_session_created(unused struct session *s)
{
+ control_notify_session_created(s);
}
void
notify_session_closed(unused struct session *s)
{
+ control_notify_session_closed(s);
}
Index: cmd-attach-session.c
===================================================================
--- cmd-attach-session.c (revision 2749)
+++ cmd-attach-session.c (working copy)
@@ -79,17 +79,20 @@
server_redraw_client(ctx->curclient);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
} else {
- if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
+ if (!(ctx->cmdclient->flags & CLIENT_CONTROL) &&
+ !(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
ctx->error(ctx, "not a terminal");
return (-1);
}
- overrides =
- options_get_string(&s->options, "terminal-overrides");
- if (tty_open(&ctx->cmdclient->tty, overrides, &cause) != 0) {
- ctx->error(ctx, "terminal open failed: %s", cause);
- xfree(cause);
- return (-1);
+ if (!(ctx->cmdclient->flags & CLIENT_CONTROL)) {
+ overrides =
+ options_get_string(&s->options,
"terminal-overrides");
+ if (tty_open(&ctx->cmdclient->tty, overrides, &cause)
!= 0) {
+ ctx->error(ctx, "terminal open failed: %s",
cause);
+ xfree(cause);
+ return (-1);
+ }
}
if (args_has(self->args, 'r'))
Index: tmux.c
===================================================================
--- tmux.c (revision 2749)
+++ tmux.c (working copy)
@@ -62,7 +62,7 @@
usage(void)
{
fprintf(stderr,
- "usage: %s [-28lquvV] [-c shell-command] [-f file] [-L
socket-name]\n"
+ "usage: %s [-28ClquvV] [-c shell-command] [-f file] [-L
socket-name]\n"
" [-S socket-path] [command [flags]]\n",
__progname);
exit(1);
@@ -245,7 +245,7 @@
quiet = flags = 0;
label = path = NULL;
login_shell = (**argv == '-');
- while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUvV")) != -1) {
+ while ((opt = getopt(argc, argv, "28Cc:df:lL:qS:uUvV")) != -1) {
switch (opt) {
case '2':
flags |= IDENTIFY_256COLOURS;
@@ -255,6 +255,9 @@
flags |= IDENTIFY_88COLOURS;
flags &= ~IDENTIFY_256COLOURS;
break;
+ case 'C':
+ flags |= IDENTIFY_CONTROL;
+ break;
case 'c':
if (shell_cmd != NULL)
xfree(shell_cmd);
------------------------------------------------------------------------------
This SF email is sponsosred by:
Try Windows Azure free for 90 days Click Here
http://p.sf.net/sfu/sfd2d-msazure
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users