mirror of
https://github.com/tmux/tmux.git
synced 2024-12-25 02:48:47 +00:00
Allow control mode clients to set a hard limit on the window width and
height, GitHub issue 2594.
This commit is contained in:
parent
24636be42b
commit
fd756a150b
@ -77,6 +77,58 @@ out:
|
|||||||
free(copy);
|
free(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
|
||||||
|
{
|
||||||
|
struct args *args = cmd_get_args(self);
|
||||||
|
struct client *tc = cmdq_get_target_client(item);
|
||||||
|
const char *size = args_get(args, 'C');
|
||||||
|
u_int w, x, y;
|
||||||
|
struct client_window *cw;
|
||||||
|
|
||||||
|
if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) {
|
||||||
|
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
|
||||||
|
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
|
||||||
|
cmdq_error(item, "size too small or too big");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
log_debug("%s: client %s window @%u: size %ux%u", __func__,
|
||||||
|
tc->name, w, x, y);
|
||||||
|
cw = server_client_add_client_window(tc, w);
|
||||||
|
cw->sx = x;
|
||||||
|
cw->sy = y;
|
||||||
|
tc->flags |= CLIENT_WINDOWSIZECHANGED;
|
||||||
|
recalculate_sizes_now(1);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
if (sscanf(size, "@%u:", &w) == 1) {
|
||||||
|
cw = server_client_get_client_window(tc, w);
|
||||||
|
if (cw != NULL) {
|
||||||
|
log_debug("%s: client %s window @%u: no size", __func__,
|
||||||
|
tc->name, w);
|
||||||
|
cw->sx = 0;
|
||||||
|
cw->sy = 0;
|
||||||
|
recalculate_sizes_now(1);
|
||||||
|
}
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
|
||||||
|
sscanf(size, "%ux%u", &x, &y) != 2) {
|
||||||
|
cmdq_error(item, "bad size argument");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
|
||||||
|
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
|
||||||
|
cmdq_error(item, "size too small or too big");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
tty_set_size(&tc->tty, x, y, 0, 0);
|
||||||
|
tc->flags |= CLIENT_SIZECHANGED;
|
||||||
|
recalculate_sizes_now(1);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_refresh_client_update_offset(struct client *tc, const char *value)
|
cmd_refresh_client_update_offset(struct client *tc, const char *value)
|
||||||
{
|
{
|
||||||
@ -117,8 +169,8 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct client *tc = cmdq_get_target_client(item);
|
struct client *tc = cmdq_get_target_client(item);
|
||||||
struct tty *tty = &tc->tty;
|
struct tty *tty = &tc->tty;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
const char *size, *errstr;
|
const char *errstr;
|
||||||
u_int x, y, adjust;
|
u_int adjust;
|
||||||
struct args_value *av;
|
struct args_value *av;
|
||||||
|
|
||||||
if (args_has(args, 'c') ||
|
if (args_has(args, 'c') ||
|
||||||
@ -205,21 +257,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(args, 'C')) {
|
if (args_has(args, 'C')) {
|
||||||
if (~tc->flags & CLIENT_CONTROL)
|
if (~tc->flags & CLIENT_CONTROL)
|
||||||
goto not_control_client;
|
goto not_control_client;
|
||||||
size = args_get(args, 'C');
|
return (cmd_refresh_client_control_client_size(self, item));
|
||||||
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
|
|
||||||
sscanf(size, "%ux%u", &x, &y) != 2) {
|
|
||||||
cmdq_error(item, "bad size argument");
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
|
|
||||||
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
|
|
||||||
cmdq_error(item, "size too small or too big");
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
tty_set_size(&tc->tty, x, y, 0, 0);
|
|
||||||
tc->flags |= CLIENT_SIZECHANGED;
|
|
||||||
recalculate_sizes_now(1);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'S')) {
|
if (args_has(args, 'S')) {
|
||||||
|
@ -108,7 +108,9 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
|
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
|
||||||
resize_window(w, sx, sy, xpixel, ypixel);
|
w->manual_sx = sx;
|
||||||
|
w->manual_sy = sy;
|
||||||
|
recalculate_size(w, 1);
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
85
resize.c
85
resize.c
@ -87,7 +87,9 @@ ignore_client_size(struct client *c)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED))
|
if ((c->flags & CLIENT_CONTROL) &&
|
||||||
|
(~c->flags & CLIENT_SIZECHANGED) &&
|
||||||
|
(~c->flags & CLIENT_WINDOWSIZECHANGED))
|
||||||
return (1);
|
return (1);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -114,22 +116,24 @@ clients_calculate_size(int type, int current, struct client *c,
|
|||||||
u_int *xpixel, u_int *ypixel)
|
u_int *xpixel, u_int *ypixel)
|
||||||
{
|
{
|
||||||
struct client *loop;
|
struct client *loop;
|
||||||
|
struct client_window *cw;
|
||||||
u_int cx, cy, n = 0;
|
u_int cx, cy, n = 0;
|
||||||
|
|
||||||
/* Manual windows do not have their size changed based on a client. */
|
|
||||||
if (type == WINDOW_SIZE_MANUAL) {
|
|
||||||
log_debug("%s: type is manual", __func__);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start comparing with 0 for largest and UINT_MAX for smallest or
|
* Start comparing with 0 for largest and UINT_MAX for smallest or
|
||||||
* latest.
|
* latest.
|
||||||
*/
|
*/
|
||||||
if (type == WINDOW_SIZE_LARGEST)
|
if (type == WINDOW_SIZE_LARGEST) {
|
||||||
*sx = *sy = 0;
|
*sx = 0;
|
||||||
else
|
*sy = 0;
|
||||||
*sx = *sy = UINT_MAX;
|
} else if (type == WINDOW_SIZE_MANUAL) {
|
||||||
|
*sx = w->manual_sx;
|
||||||
|
*sy = w->manual_sy;
|
||||||
|
log_debug("%s: manual size %ux%u", __func__, *sx, *sy);
|
||||||
|
} else {
|
||||||
|
*sx = UINT_MAX;
|
||||||
|
*sy = UINT_MAX;
|
||||||
|
}
|
||||||
*xpixel = *ypixel = 0;
|
*xpixel = *ypixel = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -139,14 +143,18 @@ clients_calculate_size(int type, int current, struct client *c,
|
|||||||
if (type == WINDOW_SIZE_LATEST && w != NULL)
|
if (type == WINDOW_SIZE_LATEST && w != NULL)
|
||||||
n = clients_with_window(w);
|
n = clients_with_window(w);
|
||||||
|
|
||||||
|
/* Skip setting the size if manual */
|
||||||
|
if (type == WINDOW_SIZE_MANUAL)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
/* Loop over the clients and work out the size. */
|
/* Loop over the clients and work out the size. */
|
||||||
TAILQ_FOREACH(loop, &clients, entry) {
|
TAILQ_FOREACH(loop, &clients, entry) {
|
||||||
if (loop != c && ignore_client_size(loop)) {
|
if (loop != c && ignore_client_size(loop)) {
|
||||||
log_debug("%s: ignoring %s", __func__, loop->name);
|
log_debug("%s: ignoring %s (1)", __func__, loop->name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (loop != c && skip_client(loop, type, current, s, w)) {
|
if (loop != c && skip_client(loop, type, current, s, w)) {
|
||||||
log_debug("%s: skipping %s", __func__, loop->name);
|
log_debug("%s: skipping %s (1)", __func__, loop->name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,9 +168,23 @@ clients_calculate_size(int type, int current, struct client *c,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the client has a per-window size, use this instead if it is
|
||||||
|
* smaller.
|
||||||
|
*/
|
||||||
|
if (w != NULL)
|
||||||
|
cw = server_client_get_client_window(loop, w->id);
|
||||||
|
else
|
||||||
|
cw = NULL;
|
||||||
|
|
||||||
/* Work out this client's size. */
|
/* Work out this client's size. */
|
||||||
|
if (cw != NULL) {
|
||||||
|
cx = cw->sx;
|
||||||
|
cy = cw->sy;
|
||||||
|
} else {
|
||||||
cx = loop->tty.sx;
|
cx = loop->tty.sx;
|
||||||
cy = loop->tty.sy - status_line_size(loop);
|
cy = loop->tty.sy - status_line_size(loop);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it is larger or smaller than the best so far, update the
|
* If it is larger or smaller than the best so far, update the
|
||||||
@ -191,7 +213,44 @@ clients_calculate_size(int type, int current, struct client *c,
|
|||||||
else
|
else
|
||||||
log_debug("%s: no calculated size", __func__);
|
log_debug("%s: no calculated size", __func__);
|
||||||
|
|
||||||
|
skip:
|
||||||
|
/*
|
||||||
|
* Do not allow any size to be larger than the per-client window size
|
||||||
|
* if one exists.
|
||||||
|
*/
|
||||||
|
if (w != NULL) {
|
||||||
|
TAILQ_FOREACH(loop, &clients, entry) {
|
||||||
|
if (loop != c && ignore_client_size(loop))
|
||||||
|
continue;
|
||||||
|
if (loop != c && skip_client(loop, type, current, s, w))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Look up per-window size if any. */
|
||||||
|
if (~loop->flags & CLIENT_WINDOWSIZECHANGED)
|
||||||
|
continue;
|
||||||
|
cw = server_client_get_client_window(loop, w->id);
|
||||||
|
if (cw == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Clamp the size. */
|
||||||
|
log_debug("%s: %s size for @%u is %ux%u", __func__,
|
||||||
|
loop->name, w->id, cw->sx, cw->sy);
|
||||||
|
if (cw->sx != 0 && *sx > cw->sx)
|
||||||
|
*sx = cw->sx;
|
||||||
|
if (cw->sy != 0 && *sy > cw->sy)
|
||||||
|
*sy = cw->sy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*sx != UINT_MAX && *sy != UINT_MAX)
|
||||||
|
log_debug("%s: calculated size %ux%u", __func__, *sx, *sy);
|
||||||
|
else
|
||||||
|
log_debug("%s: no calculated size", __func__);
|
||||||
|
|
||||||
/* Return whether a suitable size was found. */
|
/* Return whether a suitable size was found. */
|
||||||
|
if (type == WINDOW_SIZE_MANUAL) {
|
||||||
|
log_debug("%s: type is manual", __func__);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
if (type == WINDOW_SIZE_LARGEST) {
|
if (type == WINDOW_SIZE_LARGEST) {
|
||||||
log_debug("%s: type is largest", __func__);
|
log_debug("%s: type is largest", __func__);
|
||||||
return (*sx != 0 && *sy != 0);
|
return (*sx != 0 && *sy != 0);
|
||||||
|
@ -2443,7 +2443,7 @@ server_client_get_flags(struct client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get client window. */
|
/* Get client window. */
|
||||||
static struct client_window *
|
struct client_window *
|
||||||
server_client_get_client_window(struct client *c, u_int id)
|
server_client_get_client_window(struct client *c, u_int id)
|
||||||
{
|
{
|
||||||
struct client_window cw = { .window = id };
|
struct client_window cw = { .window = id };
|
||||||
@ -2451,6 +2451,21 @@ server_client_get_client_window(struct client *c, u_int id)
|
|||||||
return (RB_FIND(client_windows, &c->windows, &cw));
|
return (RB_FIND(client_windows, &c->windows, &cw));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add client window. */
|
||||||
|
struct client_window *
|
||||||
|
server_client_add_client_window(struct client *c, u_int id)
|
||||||
|
{
|
||||||
|
struct client_window *cw;
|
||||||
|
|
||||||
|
cw = server_client_get_client_window(c, id);
|
||||||
|
if (cw == NULL) {
|
||||||
|
cw = xcalloc(1, sizeof *cw);
|
||||||
|
cw->window = id;
|
||||||
|
RB_INSERT(client_windows, &c->windows, cw);
|
||||||
|
}
|
||||||
|
return cw;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get client active pane. */
|
/* Get client active pane. */
|
||||||
struct window_pane *
|
struct window_pane *
|
||||||
server_client_get_pane(struct client *c)
|
server_client_get_pane(struct client *c)
|
||||||
@ -2479,12 +2494,7 @@ server_client_set_pane(struct client *c, struct window_pane *wp)
|
|||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cw = server_client_get_client_window(c, s->curw->window->id);
|
cw = server_client_add_client_window(c, s->curw->window->id);
|
||||||
if (cw == NULL) {
|
|
||||||
cw = xcalloc(1, sizeof *cw);
|
|
||||||
cw->window = s->curw->window->id;
|
|
||||||
RB_INSERT(client_windows, &c->windows, cw);
|
|
||||||
}
|
|
||||||
cw->pane = wp;
|
cw->pane = wp;
|
||||||
log_debug("%s pane now %%%u", c->name, wp->id);
|
log_debug("%s pane now %%%u", c->name, wp->id);
|
||||||
}
|
}
|
||||||
|
14
tmux.1
14
tmux.1
@ -1331,7 +1331,7 @@ specified multiple times.
|
|||||||
.Op Fl cDlLRSU
|
.Op Fl cDlLRSU
|
||||||
.Op Fl A Ar pane:state
|
.Op Fl A Ar pane:state
|
||||||
.Op Fl B Ar name:what:format
|
.Op Fl B Ar name:what:format
|
||||||
.Op Fl C Ar XxY
|
.Op Fl C Ar size
|
||||||
.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
|
||||||
@ -1375,7 +1375,17 @@ 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 mode client.
|
sets the width and height of a control mode client or of a window for a
|
||||||
|
control mode client,
|
||||||
|
.Ar size
|
||||||
|
must be one of
|
||||||
|
.Ql widthxheight
|
||||||
|
or
|
||||||
|
.Ql window ID:widthxheight ,
|
||||||
|
for example
|
||||||
|
.Ql 80x24
|
||||||
|
or
|
||||||
|
.Ql @0:80x24 .
|
||||||
.Fl A
|
.Fl A
|
||||||
allows a control mode client to trigger actions on a pane.
|
allows a control mode client to trigger actions on a pane.
|
||||||
The argument is a pane ID (with leading
|
The argument is a pane ID (with leading
|
||||||
|
9
tmux.h
9
tmux.h
@ -998,6 +998,8 @@ struct window {
|
|||||||
|
|
||||||
u_int sx;
|
u_int sx;
|
||||||
u_int sy;
|
u_int sy;
|
||||||
|
u_int manual_sx;
|
||||||
|
u_int manual_sy;
|
||||||
u_int xpixel;
|
u_int xpixel;
|
||||||
u_int ypixel;
|
u_int ypixel;
|
||||||
|
|
||||||
@ -1555,6 +1557,10 @@ RB_HEAD(client_files, client_file);
|
|||||||
struct client_window {
|
struct client_window {
|
||||||
u_int window;
|
u_int window;
|
||||||
struct window_pane *pane;
|
struct window_pane *pane;
|
||||||
|
|
||||||
|
u_int sx;
|
||||||
|
u_int sy;
|
||||||
|
|
||||||
RB_ENTRY(client_window) entry;
|
RB_ENTRY(client_window) entry;
|
||||||
};
|
};
|
||||||
RB_HEAD(client_windows, client_window);
|
RB_HEAD(client_windows, client_window);
|
||||||
@ -1650,6 +1656,7 @@ struct client {
|
|||||||
#define CLIENT_ACTIVEPANE 0x80000000ULL
|
#define CLIENT_ACTIVEPANE 0x80000000ULL
|
||||||
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
|
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
|
||||||
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
|
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
|
||||||
|
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
||||||
#define CLIENT_ALLREDRAWFLAGS \
|
#define CLIENT_ALLREDRAWFLAGS \
|
||||||
(CLIENT_REDRAWWINDOW| \
|
(CLIENT_REDRAWWINDOW| \
|
||||||
CLIENT_REDRAWSTATUS| \
|
CLIENT_REDRAWSTATUS| \
|
||||||
@ -2465,6 +2472,8 @@ void server_client_push_stderr(struct client *);
|
|||||||
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 *);
|
void server_client_set_flags(struct client *, const char *);
|
||||||
const char *server_client_get_flags(struct client *);
|
const char *server_client_get_flags(struct client *);
|
||||||
|
struct client_window *server_client_get_client_window(struct client *, u_int);
|
||||||
|
struct client_window *server_client_add_client_window(struct client *, u_int);
|
||||||
struct window_pane *server_client_get_pane(struct client *);
|
struct window_pane *server_client_get_pane(struct client *);
|
||||||
void server_client_set_pane(struct client *, struct window_pane *);
|
void server_client_set_pane(struct client *, struct window_pane *);
|
||||||
void server_client_remove_pane(struct window_pane *);
|
void server_client_remove_pane(struct window_pane *);
|
||||||
|
Loading…
Reference in New Issue
Block a user