Change the existing client flags for control mode to apply for any client, use

the same mechanism for the read-only flag and add an ignore-size flag.

refresh-client -F has become -f (-F stays for backwards compatibility) and
attach-session and switch-client now have -f flags also. A new format
"client_flags" lists the flags and is shown by list-clients by default.

This separates the read-only flag from "ignore size" behaviour (new
ignore-size) flag - both behaviours are useful in different circumstances.

attach -r and switchc -r remain and set or toggle both flags together.
This commit is contained in:
Nicholas Marriott 2020-05-05 15:42:20 +01:00
parent deacfedc65
commit 2f89d2e7d8
10 changed files with 136 additions and 50 deletions

View File

@ -37,8 +37,9 @@ const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session", .name = "attach-session",
.alias = "attach", .alias = "attach",
.args = { "c:dErt:x", 0, 0 }, .args = { "c:dEf:rt:x", 0, 0 },
.usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE, .usage = "[-dErx] [-c working-directory] [-f flags] "
CMD_TARGET_SESSION_USAGE,
/* -t is special */ /* -t is special */
@ -48,7 +49,7 @@ const struct cmd_entry cmd_attach_session_entry = {
enum cmd_retval enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int xflag, int rflag, const char *cflag, int Eflag) int xflag, int rflag, const char *cflag, int Eflag, const char *fflag)
{ {
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state target; struct cmd_find_state target;
@ -101,6 +102,10 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
free((void *)s->cwd); free((void *)s->cwd);
s->cwd = format_single(item, cflag, c, s, wl, wp); s->cwd = format_single(item, cflag, c, s, wl, wp);
} }
if (fflag)
server_client_set_flags(c, fflag);
if (rflag)
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
c->last_session = c->session; c->last_session = c->session;
if (c->session != NULL) { if (c->session != NULL) {
@ -135,8 +140,6 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag || xflag) { if (dflag || xflag) {
if (xflag) if (xflag)
@ -182,5 +185,5 @@ cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
return (cmd_attach_session(item, args_get(args, 't'), return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'), args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
args_get(args, 'c'), args_has(args, 'E'))); args_get(args, 'c'), args_has(args, 'E'), args_get(args, 'f')));
} }

View File

@ -31,7 +31,7 @@
#define LIST_CLIENTS_TEMPLATE \ #define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \ "#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}] " \ "[#{client_width}x#{client_height} #{client_termname}] " \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),}" "#{?client_flags,(,}#{client_flags}#{?client_flags,),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);

View File

@ -39,9 +39,9 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session", .name = "new-session",
.alias = "new", .alias = "new",
.args = { "Ac:dDe:EF:n:Ps:t:x:Xy:", 0, -1 }, .args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1 },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] " .usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] [-s session-name] " "[-f flags] [-n window-name] [-s session-name] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@ -112,7 +112,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (as != NULL) { if (as != NULL) {
retval = cmd_attach_session(item, as->name, retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL, args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
args_has(args, 'E')); args_has(args, 'E'), args_get(args, 'f'));
free(newname); free(newname);
return (retval); return (retval);
} }
@ -306,6 +306,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* taking this session and needs to get MSG_READY and stay around. * taking this session and needs to get MSG_READY and stay around.
*/ */
if (!detached) { if (!detached) {
if (args_has(args, 'f'))
server_client_set_flags(c, args_get(args, 'f'));
if (!already_attached) { if (!already_attached) {
if (~c->flags & CLIENT_CONTROL) if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0); proc_send(c->peer, MSG_READY, -1, NULL, 0);

View File

@ -34,8 +34,8 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", .name = "refresh-client",
.alias = "refresh", .alias = "refresh",
.args = { "cC:DF:lLRSt:U", 0, 1 }, .args = { "cC:Df:F:lLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE .usage = "[-cDlLRSU] [-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE
" [adjustment]", " [adjustment]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
@ -50,7 +50,6 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
struct tty *tty = &tc->tty; struct tty *tty = &tc->tty;
struct window *w; struct window *w;
const char *size, *errstr; const char *size, *errstr;
char *copy, *next, *s;
u_int x, y, adjust; u_int x, y, adjust;
if (args_has(args, 'c') || if (args_has(args, 'c') ||
@ -108,7 +107,12 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'C') || args_has(args, 'F')) { if (args_has(args, 'F')) /* -F is an alias for -f */
server_client_set_flags(tc, args_get(args, 'F'));
if (args_has(args, 'f'))
server_client_set_flags(tc, args_get(args, 'f'));
if (args_has(args, 'C')) {
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
if (!(tc->flags & CLIENT_CONTROL)) { if (!(tc->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client"); cmdq_error(item, "not a control client");
@ -129,19 +133,6 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
tc->flags |= CLIENT_SIZECHANGED; tc->flags |= CLIENT_SIZECHANGED;
recalculate_sizes(); recalculate_sizes();
} }
if (args_has(args, 'F')) {
if (!(tc->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
s = copy = xstrdup(args_get(args, 'F'));
while ((next = strsep(&s, ",")) != NULL) {
/* Unknown flags are ignored. */
if (strcmp(next, "no-output") == 0)
tc->flags |= CLIENT_CONTROL_NOOUTPUT;
}
free(copy);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -34,7 +34,7 @@ const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client", .name = "switch-client",
.alias = "switchc", .alias = "switchc",
.args = { "lc:Enpt:rT:Z", 0, 0 }, .args = { "lc:EFnpt:rT:Z", 0, 0 },
.usage = "[-ElnprZ] [-c target-client] [-t target-session] " .usage = "[-ElnprZ] [-c target-client] [-t target-session] "
"[-T key-table]", "[-T key-table]",
@ -74,8 +74,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
wl = target.wl; wl = target.wl;
wp = target.wp; wp = target.wp;
if (args_has(args, 'r')) if (args_has(args, 'r')) {
tc->flags ^= CLIENT_READONLY; if (tc->flags & CLIENT_READONLY)
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
else
tc->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
}
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename != NULL) { if (tablename != NULL) {

View File

@ -2671,11 +2671,11 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_utf8", "%d", 1); format_add(ft, "client_utf8", "%d", 1);
else else
format_add(ft, "client_utf8", "%d", 0); format_add(ft, "client_utf8", "%d", 0);
if (c->flags & CLIENT_READONLY) if (c->flags & CLIENT_READONLY)
format_add(ft, "client_readonly", "%d", 1); format_add(ft, "client_readonly", "%d", 1);
else else
format_add(ft, "client_readonly", "%d", 0); format_add(ft, "client_readonly", "%d", 0);
format_add(ft, "client_flags", "%s", server_client_get_flags(c));
s = c->session; s = c->session;
if (s != NULL) if (s != NULL)

View File

@ -72,17 +72,17 @@ ignore_client_size(struct client *c)
return (1); return (1);
if (c->flags & CLIENT_NOSIZEFLAGS) if (c->flags & CLIENT_NOSIZEFLAGS)
return (1); return (1);
if (c->flags & CLIENT_READONLY) { if (c->flags & CLIENT_IGNORESIZE) {
/* /*
* Ignore readonly clients if there are any attached clients * Ignore flagged clients if there are any attached clients
* that aren't readonly. * that aren't flagged.
*/ */
TAILQ_FOREACH (loop, &clients, entry) { TAILQ_FOREACH (loop, &clients, entry) {
if (loop->session == NULL) if (loop->session == NULL)
continue; continue;
if (loop->flags & CLIENT_NOSIZEFLAGS) if (loop->flags & CLIENT_NOSIZEFLAGS)
continue; continue;
if (~loop->flags & CLIENT_READONLY) if (~loop->flags & CLIENT_IGNORESIZE)
return (1); return (1);
} }
} }

View File

@ -2255,3 +2255,61 @@ server_client_get_cwd(struct client *c, struct session *s)
return (home); return (home);
return ("/"); return ("/");
} }
/* Set client flags. */
void
server_client_set_flags(struct client *c, const char *flags)
{
char *s, *copy, *next;
int flag, not;
s = copy = xstrdup (flags);
while ((next = strsep(&s, ",")) != NULL) {
not = (*next == '!');
if (not)
next++;
if (strcmp(next, "no-output") == 0)
flag = CLIENT_CONTROL_NOOUTPUT;
else if (strcmp(next, "read-only") == 0)
flag = CLIENT_READONLY;
else if (strcmp(next, "ignore-size") == 0)
flag = CLIENT_IGNORESIZE;
else
continue;
log_debug("client %s set flag %s", c->name, next);
if (not)
c->flags &= ~flag;
else
c->flags |= flag;
}
free(copy);
}
/*Get client flags. This is only flags useful to show to users. */
const char *
server_client_get_flags(struct client *c)
{
static char s[256];
*s = '\0';
if (c->flags & CLIENT_ATTACHED)
strlcat(s, "attached,", sizeof s);
if (c->flags & CLIENT_CONTROL)
strlcat(s, "control-mode,", sizeof s);
if (c->flags & CLIENT_IGNORESIZE)
strlcat(s, "ignore-size,", sizeof s);
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
strlcat(s, "no-output,", sizeof s);
if (c->flags & CLIENT_READONLY)
strlcat(s, "read-only,", sizeof s);
if (c->flags & CLIENT_SUSPENDED)
strlcat(s, "suspended,", sizeof s);
if (c->flags & CLIENT_UTF8)
strlcat(s, "UTF-8,", sizeof s);
if (*s != '\0')
s[strlen(s) - 1] = '\0';
return (s);
}

46
tmux.1
View File

@ -947,6 +947,7 @@ The following commands are available to manage clients and sessions:
.It Xo Ic attach-session .It Xo Ic attach-session
.Op Fl dErx .Op Fl dErx
.Op Fl c Ar working-directory .Op Fl c Ar working-directory
.Op Fl f Ar flags
.Op Fl t Ar target-session .Op Fl t Ar target-session
.Xc .Xc
.D1 (alias: Ic attach ) .D1 (alias: Ic attach )
@ -964,12 +965,30 @@ is given, send
.Dv SIGHUP .Dv SIGHUP
to the parent process of the client as well as to the parent process of the client as well as
detaching the client, typically causing it to exit. detaching the client, typically causing it to exit.
.Fl f
sets a comma-separated list of client flags.
The flags are:
.Bl -tag -width Ds
.It read-only
the client is read-only
.It ignore-size
the client does not affect the size of other clients
.It no-output
the client does not receive pane output in control mode
.El
.Pp
A leading
.Ql !
turns a flag off if the client is already attached.
.Fl r .Fl r
signifies the client is read-only (only keys bound to the is an alias for
.Fl f
.Ar read-only,ignore-size .
When a client is read-only, only keys bound to the
.Ic detach-client .Ic detach-client
or or
.Ic switch-client .Ic switch-client
commands have any effect) commands have any effect.
.Pp .Pp
If no server is started, If no server is started,
.Ic attach-session .Ic attach-session
@ -1095,6 +1114,7 @@ Lock all clients attached to
.Op Fl AdDEPX .Op Fl AdDEPX
.Op Fl c Ar start-directory .Op Fl c Ar start-directory
.Op Fl e Ar environment .Op Fl e Ar environment
.Op Fl f Ar flags
.Op Fl F Ar format .Op Fl F Ar format
.Op Fl n Ar window-name .Op Fl n Ar window-name
.Op Fl s Ar session-name .Op Fl s Ar session-name
@ -1132,6 +1152,9 @@ or
is given, the is given, the
.Ic default-size .Ic default-size
option is set for the session. option is set for the session.
.Fl f
sets a comma-separated list of client flags (see
.Ic attach-session ) .
.Pp .Pp
If run from a terminal, any If run from a terminal, any
.Xr termios 4 .Xr termios 4
@ -1209,7 +1232,7 @@ specified multiple times.
.It Xo Ic refresh-client .It Xo Ic refresh-client
.Op Fl cDlLRSU .Op Fl cDlLRSU
.Op Fl C Ar XxY .Op Fl C Ar XxY
.Op Fl F Ar flags .Op Fl f Ar flags
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Op Ar adjustment .Op Ar adjustment
.Xc .Xc
@ -1252,12 +1275,10 @@ window, changing the current window in the attached session will reset
it. it.
.Pp .Pp
.Fl C .Fl C
sets the width and height of a control client and sets the width and height of a control client.
.Fl F .Fl f
sets a comma-separated list of flags. sets a comma-separated list of client flags, see
Currently the only flag available is .Ic attach-session .
.Ql no-output
to disable receiving pane output.
.Pp .Pp
.Fl l .Fl l
requests the clipboard from the client using the requests the clipboard from the client using the
@ -1377,7 +1398,11 @@ or
is used, the client is moved to the last, next or previous session is used, the client is moved to the last, next or previous session
respectively. respectively.
.Fl r .Fl r
toggles whether a client is read-only (see the toggles the client
.Ic read-only
and
.Ic ignore-size
flags (see the
.Ic attach-session .Ic attach-session
command). command).
.Pp .Pp
@ -4480,6 +4505,7 @@ The following variables are available, where appropriate:
.It Li "client_control_mode" Ta "" Ta "1 if client is in control mode" .It Li "client_control_mode" Ta "" Ta "1 if client is in control mode"
.It Li "client_created" Ta "" Ta "Time client created" .It Li "client_created" Ta "" Ta "Time client created"
.It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind" .It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind"
.It Li "client_flags" Ta "" Ta "List of client flags"
.It Li "client_height" Ta "" Ta "Height of client" .It Li "client_height" Ta "" Ta "Height of client"
.It Li "client_key_table" Ta "" Ta "Current key table" .It Li "client_key_table" Ta "" Ta "Current key table"
.It Li "client_last_session" Ta "" Ta "Name of the client's last session" .It Li "client_last_session" Ta "" Ta "Name of the client's last session"

6
tmux.h
View File

@ -1570,7 +1570,7 @@ struct client {
#define CLIENT_CONTROLCONTROL 0x4000 #define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000 #define CLIENT_FOCUSED 0x8000
#define CLIENT_UTF8 0x10000 #define CLIENT_UTF8 0x10000
/* 0x20000 unused */ #define CLIENT_IGNORESIZE 0x20000
#define CLIENT_IDENTIFIED 0x40000 #define CLIENT_IDENTIFIED 0x40000
#define CLIENT_STATUSFORCE 0x80000 #define CLIENT_STATUSFORCE 0x80000
#define CLIENT_DOUBLECLICK 0x100000 #define CLIENT_DOUBLECLICK 0x100000
@ -2165,7 +2165,7 @@ char *cmd_template_replace(const char *, const char *, int);
/* cmd-attach-session.c */ /* cmd-attach-session.c */
enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int, enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int,
int, const char *, int); int, const char *, int, const char *);
/* cmd-parse.c */ /* cmd-parse.c */
void cmd_parse_empty(struct cmd_parse_input *); void cmd_parse_empty(struct cmd_parse_input *);
@ -2304,6 +2304,8 @@ void server_client_push_stderr(struct client *);
void printflike(2, 3) server_client_add_message(struct client *, const char *, void printflike(2, 3) server_client_add_message(struct client *, const char *,
...); ...);
const char *server_client_get_cwd(struct client *, struct session *); const char *server_client_get_cwd(struct client *, struct session *);
void server_client_set_flags(struct client *, const char *);
const char *server_client_get_flags(struct client *);
/* server-fn.c */ /* server-fn.c */
void server_redraw_client(struct client *); void server_redraw_client(struct client *);