diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 8c30c767..38d9c024 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -37,8 +37,9 @@ const struct cmd_entry cmd_attach_session_entry = { .name = "attach-session", .alias = "attach", - .args = { "c:dErt:x", 0, 0 }, - .usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE, + .args = { "c:dEf:rt:x", 0, 0 }, + .usage = "[-dErx] [-c working-directory] [-f flags] " + CMD_TARGET_SESSION_USAGE, /* -t is special */ @@ -48,7 +49,7 @@ const struct cmd_entry cmd_attach_session_entry = { enum cmd_retval 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 target; @@ -101,6 +102,10 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, free((void *)s->cwd); 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; if (c->session != NULL) { @@ -135,8 +140,6 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, free(cause); return (CMD_RETURN_ERROR); } - if (rflag) - c->flags |= CLIENT_READONLY; if (dflag || 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'), 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'))); } diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 75118c8e..d450f017 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -28,10 +28,10 @@ * List all clients. */ -#define LIST_CLIENTS_TEMPLATE \ - "#{client_name}: #{session_name} " \ - "[#{client_width}x#{client_height} #{client_termname}]" \ - "#{?client_utf8, (utf8),} #{?client_readonly, (ro),}" +#define LIST_CLIENTS_TEMPLATE \ + "#{client_name}: #{session_name} " \ + "[#{client_width}x#{client_height} #{client_termname}] " \ + "#{?client_flags,(,}#{client_flags}#{?client_flags,),}" static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *); diff --git a/cmd-new-session.c b/cmd-new-session.c index 9815e1e1..a9a0376b 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -39,9 +39,9 @@ const struct cmd_entry cmd_new_session_entry = { .name = "new-session", .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] " - "[-n window-name] [-s session-name] " + "[-f flags] [-n window-name] [-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", .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) { retval = cmd_attach_session(item, as->name, args_has(args, 'D'), args_has(args, 'X'), 0, NULL, - args_has(args, 'E')); + args_has(args, 'E'), args_get(args, 'f')); free(newname); 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. */ if (!detached) { + if (args_has(args, 'f')) + server_client_set_flags(c, args_get(args, 'f')); if (!already_attached) { if (~c->flags & CLIENT_CONTROL) proc_send(c->peer, MSG_READY, -1, NULL, 0); diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 5514ff73..c53a6a78 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -34,8 +34,8 @@ const struct cmd_entry cmd_refresh_client_entry = { .name = "refresh-client", .alias = "refresh", - .args = { "cC:DF:lLRSt:U", 0, 1 }, - .usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE + .args = { "cC:Df:F:lLRSt:U", 0, 1 }, + .usage = "[-cDlLRSU] [-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE " [adjustment]", .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 window *w; const char *size, *errstr; - char *copy, *next, *s; u_int x, y, adjust; if (args_has(args, 'c') || @@ -108,7 +107,12 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) 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 (!(tc->flags & CLIENT_CONTROL)) { 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; 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); } diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 82510ce6..d062b946 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -34,7 +34,7 @@ const struct cmd_entry cmd_switch_client_entry = { .name = "switch-client", .alias = "switchc", - .args = { "lc:Enpt:rT:Z", 0, 0 }, + .args = { "lc:EFnpt:rT:Z", 0, 0 }, .usage = "[-ElnprZ] [-c target-client] [-t target-session] " "[-T key-table]", @@ -74,8 +74,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) wl = target.wl; wp = target.wp; - if (args_has(args, 'r')) - tc->flags ^= CLIENT_READONLY; + if (args_has(args, 'r')) { + if (tc->flags & CLIENT_READONLY) + tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE); + else + tc->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE); + } tablename = args_get(args, 'T'); if (tablename != NULL) { diff --git a/format.c b/format.c index a2b2822f..3b9af626 100644 --- a/format.c +++ b/format.c @@ -2678,11 +2678,11 @@ format_defaults_client(struct format_tree *ft, struct client *c) format_add(ft, "client_utf8", "%d", 1); else format_add(ft, "client_utf8", "%d", 0); - if (c->flags & CLIENT_READONLY) format_add(ft, "client_readonly", "%d", 1); else format_add(ft, "client_readonly", "%d", 0); + format_add(ft, "client_flags", "%s", server_client_get_flags(c)); s = c->session; if (s != NULL) diff --git a/resize.c b/resize.c index 96d733f0..15d146d8 100644 --- a/resize.c +++ b/resize.c @@ -72,17 +72,17 @@ ignore_client_size(struct client *c) return (1); if (c->flags & CLIENT_NOSIZEFLAGS) return (1); - if (c->flags & CLIENT_READONLY) { + if (c->flags & CLIENT_IGNORESIZE) { /* - * Ignore readonly clients if there are any attached clients - * that aren't readonly. + * Ignore flagged clients if there are any attached clients + * that aren't flagged. */ TAILQ_FOREACH (loop, &clients, entry) { if (loop->session == NULL) continue; if (loop->flags & CLIENT_NOSIZEFLAGS) continue; - if (~loop->flags & CLIENT_READONLY) + if (~loop->flags & CLIENT_IGNORESIZE) return (1); } } diff --git a/server-client.c b/server-client.c index a45e9812..86b7a1b8 100644 --- a/server-client.c +++ b/server-client.c @@ -2253,3 +2253,61 @@ server_client_get_cwd(struct client *c, struct session *s) return (home); 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); +} diff --git a/tmux.1 b/tmux.1 index eafa3751..97d57d5b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -947,6 +947,7 @@ The following commands are available to manage clients and sessions: .It Xo Ic attach-session .Op Fl dErx .Op Fl c Ar working-directory +.Op Fl f Ar flags .Op Fl t Ar target-session .Xc .D1 (alias: Ic attach ) @@ -964,12 +965,30 @@ is given, send .Dv SIGHUP to the parent process of the client as well as 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 -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 or .Ic switch-client -commands have any effect) +commands have any effect. .Pp If no server is started, .Ic attach-session @@ -1095,6 +1114,7 @@ Lock all clients attached to .Op Fl AdDEPX .Op Fl c Ar start-directory .Op Fl e Ar environment +.Op Fl f Ar flags .Op Fl F Ar format .Op Fl n Ar window-name .Op Fl s Ar session-name @@ -1132,6 +1152,9 @@ or is given, the .Ic default-size option is set for the session. +.Fl f +sets a comma-separated list of client flags (see +.Ic attach-session ) . .Pp If run from a terminal, any .Xr termios 4 @@ -1209,7 +1232,7 @@ specified multiple times. .It Xo Ic refresh-client .Op Fl cDlLRSU .Op Fl C Ar XxY -.Op Fl F Ar flags +.Op Fl f Ar flags .Op Fl t Ar target-client .Op Ar adjustment .Xc @@ -1252,12 +1275,10 @@ window, changing the current window in the attached session will reset it. .Pp .Fl C -sets the width and height of a control client and -.Fl F -sets a comma-separated list of flags. -Currently the only flag available is -.Ql no-output -to disable receiving pane output. +sets the width and height of a control client. +.Fl f +sets a comma-separated list of client flags, see +.Ic attach-session . .Pp .Fl l 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 respectively. .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 command). .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_created" Ta "" Ta "Time client created" .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_key_table" Ta "" Ta "Current key table" .It Li "client_last_session" Ta "" Ta "Name of the client's last session" diff --git a/tmux.h b/tmux.h index 811b5fb6..7a687c09 100644 --- a/tmux.h +++ b/tmux.h @@ -1568,7 +1568,7 @@ struct client { #define CLIENT_CONTROLCONTROL 0x4000 #define CLIENT_FOCUSED 0x8000 #define CLIENT_UTF8 0x10000 -/* 0x20000 unused */ +#define CLIENT_IGNORESIZE 0x20000 #define CLIENT_IDENTIFIED 0x40000 #define CLIENT_STATUSFORCE 0x80000 #define CLIENT_DOUBLECLICK 0x100000 @@ -2163,7 +2163,7 @@ char *cmd_template_replace(const char *, const char *, int); /* cmd-attach-session.c */ 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 */ void cmd_parse_empty(struct cmd_parse_input *); @@ -2302,6 +2302,8 @@ void server_client_push_stderr(struct client *); void printflike(2, 3) server_client_add_message(struct client *, const char *, ...); 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 */ void server_redraw_client(struct client *);