mirror of
https://github.com/tmux/tmux.git
synced 2026-03-07 00:05:33 +00:00
Merge branch 'master' into floating_panes
This commit is contained in:
@@ -57,30 +57,30 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct paste_buffer *pb;
|
||||
char *bufdata, *cause;
|
||||
const char *bufname, *olddata;
|
||||
size_t bufsize, newsize;
|
||||
struct paste_buffer *pb = NULL;
|
||||
char *bufname = NULL, *bufdata = NULL, *cause = NULL;
|
||||
const char *olddata;
|
||||
size_t bufsize = 0, newsize;
|
||||
|
||||
bufname = args_get(args, 'b');
|
||||
if (bufname == NULL)
|
||||
pb = NULL;
|
||||
else
|
||||
if (args_get(args, 'b') != NULL) {
|
||||
bufname = xstrdup(args_get(args, 'b'));
|
||||
pb = paste_get_name(bufname);
|
||||
}
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
|
||||
if (pb == NULL) {
|
||||
if (bufname != NULL) {
|
||||
cmdq_error(item, "unknown buffer: %s", bufname);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
pb = paste_get_top(&bufname);
|
||||
}
|
||||
if (pb == NULL) {
|
||||
cmdq_error(item, "no buffer");
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
paste_free(pb);
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -88,32 +88,28 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (pb == NULL) {
|
||||
if (bufname != NULL) {
|
||||
cmdq_error(item, "unknown buffer: %s", bufname);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
pb = paste_get_top(&bufname);
|
||||
}
|
||||
if (pb == NULL) {
|
||||
cmdq_error(item, "no buffer");
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_count(args) != 1) {
|
||||
cmdq_error(item, "no data specified");
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if ((newsize = strlen(args_string(args, 0))) == 0)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
bufsize = 0;
|
||||
bufdata = NULL;
|
||||
|
||||
if (args_has(args, 'a') && pb != NULL) {
|
||||
olddata = paste_buffer_data(pb, &bufsize);
|
||||
bufdata = xmalloc(bufsize);
|
||||
@@ -126,12 +122,16 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(bufdata);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
if (args_has(args, 'w') && tc != NULL)
|
||||
tty_set_selection(&tc->tty, "", bufdata, bufsize);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(bufdata);
|
||||
free(bufname);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -51,29 +51,24 @@ control_notify_window_layout_changed(struct window *w)
|
||||
template = "%layout-change #{window_id} #{window_layout} "
|
||||
"#{window_visible_layout} #{window_raw_flags}";
|
||||
|
||||
/*
|
||||
* When the last pane in a window is closed it won't have a layout root
|
||||
* and we don't need to inform the client about the layout change
|
||||
* because the whole window will go away soon.
|
||||
*/
|
||||
wl = TAILQ_FIRST(&w->winlinks);
|
||||
if (wl == NULL || w->layout_root == NULL)
|
||||
return;
|
||||
cp = format_single(NULL, template, NULL, NULL, wl, NULL);
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
s = c->session;
|
||||
|
||||
if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* When the last pane in a window is closed it won't have a
|
||||
* layout root and we don't need to inform the client about the
|
||||
* layout change because the whole window will go away soon.
|
||||
*/
|
||||
if (w->layout_root == NULL)
|
||||
continue;
|
||||
|
||||
wl = winlink_find_by_window(&s->windows, w);
|
||||
if (wl != NULL) {
|
||||
cp = format_single(NULL, template, c, NULL, wl, NULL);
|
||||
if (winlink_find_by_window_id(&s->windows, w->id) != NULL)
|
||||
control_write(c, "%s", cp);
|
||||
free(cp);
|
||||
}
|
||||
}
|
||||
free(cp);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
204
control.c
204
control.c
@@ -610,7 +610,7 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
||||
struct evbuffer *message, struct window_pane *wp, size_t size)
|
||||
{
|
||||
u_char *new_data;
|
||||
size_t new_size;
|
||||
size_t new_size, start;
|
||||
u_int i;
|
||||
|
||||
if (message == NULL) {
|
||||
@@ -629,10 +629,16 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
||||
if (new_size < size)
|
||||
fatalx("not enough data: %zu < %zu", new_size, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (new_data[i] < ' ' || new_data[i] == '\\')
|
||||
if (new_data[i] < ' ' || new_data[i] == '\\') {
|
||||
evbuffer_add_printf(message, "\\%03o", new_data[i]);
|
||||
else
|
||||
evbuffer_add_printf(message, "%c", new_data[i]);
|
||||
} else {
|
||||
start = i;
|
||||
while (i + 1 < size &&
|
||||
new_data[i + 1] >= ' ' &&
|
||||
new_data[i + 1] != '\\')
|
||||
i++;
|
||||
evbuffer_add(message, new_data + start, i - start + 1);
|
||||
}
|
||||
}
|
||||
window_pane_update_used_data(wp, &cp->offset, size);
|
||||
return (message);
|
||||
@@ -840,15 +846,13 @@ control_stop(struct client *c)
|
||||
|
||||
/* Check session subscription. */
|
||||
static void
|
||||
control_check_subs_session(struct client *c, struct control_sub *csub)
|
||||
control_check_subs_session(struct client *c, struct control_sub *csub,
|
||||
struct format_tree *ft)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct format_tree *ft;
|
||||
char *value;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, NULL, NULL);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
|
||||
if (csub->last != NULL && strcmp(value, csub->last) == 0) {
|
||||
free(value);
|
||||
@@ -909,48 +913,38 @@ control_check_subs_pane(struct client *c, struct control_sub *csub)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all panes subscription. */
|
||||
/* Check all-panes subscription for a pane. */
|
||||
static void
|
||||
control_check_subs_all_panes(struct client *c, struct control_sub *csub)
|
||||
control_check_subs_all_panes_one(struct client *c, struct control_sub *csub,
|
||||
struct format_tree *ft, struct winlink *wl, struct window_pane *wp)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window_pane *wp;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
struct window *w = wl->window;
|
||||
char *value;
|
||||
struct control_sub_pane *csp, find;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
w = wl->window;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
value = format_expand(ft, csub->format);
|
||||
|
||||
find.pane = wp->id;
|
||||
find.idx = wl->idx;
|
||||
find.pane = wp->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
||||
if (csp == NULL) {
|
||||
csp = xcalloc(1, sizeof *csp);
|
||||
csp->pane = wp->id;
|
||||
csp->idx = wl->idx;
|
||||
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
||||
}
|
||||
|
||||
if (csp->last != NULL &&
|
||||
strcmp(value, csp->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
||||
free(csp->last);
|
||||
csp->last = value;
|
||||
}
|
||||
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
||||
if (csp == NULL) {
|
||||
csp = xcalloc(1, sizeof *csp);
|
||||
csp->pane = wp->id;
|
||||
csp->idx = wl->idx;
|
||||
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
||||
}
|
||||
|
||||
if (csp->last != NULL && strcmp(value, csp->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
||||
free(csp->last);
|
||||
csp->last = value;
|
||||
}
|
||||
|
||||
/* Check window subscription. */
|
||||
@@ -999,45 +993,38 @@ control_check_subs_window(struct client *c, struct control_sub *csub)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all windows subscription. */
|
||||
/* Check all-windows subscription for a window. */
|
||||
static void
|
||||
control_check_subs_all_windows(struct client *c, struct control_sub *csub)
|
||||
control_check_subs_all_windows_one(struct client *c, struct control_sub *csub,
|
||||
struct format_tree *ft, struct winlink *wl)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
struct window *w = wl->window;
|
||||
char *value;
|
||||
struct control_sub_window *csw, find;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
w = wl->window;
|
||||
value = format_expand(ft, csub->format);
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
value = format_expand(ft, csub->format);
|
||||
format_free(ft);
|
||||
find.window = w->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
find.window = w->id;
|
||||
find.idx = wl->idx;
|
||||
|
||||
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
||||
if (csw == NULL) {
|
||||
csw = xcalloc(1, sizeof *csw);
|
||||
csw->window = w->id;
|
||||
csw->idx = wl->idx;
|
||||
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
||||
}
|
||||
|
||||
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||
csub->name, s->id, w->id, wl->idx, value);
|
||||
free(csw->last);
|
||||
csw->last = value;
|
||||
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
||||
if (csw == NULL) {
|
||||
csw = xcalloc(1, sizeof *csw);
|
||||
csw->window = w->id;
|
||||
csw->idx = wl->idx;
|
||||
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
||||
}
|
||||
|
||||
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
control_write(c,
|
||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||
csub->name, s->id, w->id, wl->idx, value);
|
||||
free(csw->last);
|
||||
csw->last = value;
|
||||
}
|
||||
|
||||
/* Check subscriptions timer. */
|
||||
@@ -1047,30 +1034,91 @@ control_check_subs_timer(__unused int fd, __unused short events, void *data)
|
||||
struct client *c = data;
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_sub *csub, *csub1;
|
||||
struct session *s = c->session;
|
||||
struct format_tree *ft;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
int have_session = 0, have_all_panes = 0;
|
||||
int have_all_windows = 0;
|
||||
|
||||
log_debug("%s: timer fired", __func__);
|
||||
evtimer_add(&cs->subs_timer, &tv);
|
||||
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||
/* Find which subscription types are present. */
|
||||
RB_FOREACH(csub, control_subs, &cs->subs) {
|
||||
switch (csub->type) {
|
||||
case CONTROL_SUB_SESSION:
|
||||
control_check_subs_session(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_PANE:
|
||||
control_check_subs_pane(c, csub);
|
||||
have_session = 1;
|
||||
break;
|
||||
case CONTROL_SUB_ALL_PANES:
|
||||
control_check_subs_all_panes(c, csub);
|
||||
have_all_panes = 1;
|
||||
break;
|
||||
case CONTROL_SUB_ALL_WINDOWS:
|
||||
have_all_windows = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check session subscriptions. */
|
||||
if (have_session) {
|
||||
ft = format_create_defaults(NULL, c, s, NULL, NULL);
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||
if (csub->type == CONTROL_SUB_SESSION)
|
||||
control_check_subs_session(c, csub, ft);
|
||||
}
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
/* Check pane and window subscriptions. */
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||
switch (csub->type) {
|
||||
case CONTROL_SUB_PANE:
|
||||
control_check_subs_pane(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_WINDOW:
|
||||
control_check_subs_window(c, csub);
|
||||
break;
|
||||
case CONTROL_SUB_SESSION:
|
||||
case CONTROL_SUB_ALL_PANES:
|
||||
case CONTROL_SUB_ALL_WINDOWS:
|
||||
control_check_subs_all_windows(c, csub);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all-panes subscriptions. */
|
||||
if (have_all_panes) {
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs,
|
||||
csub1) {
|
||||
if (csub->type != CONTROL_SUB_ALL_PANES)
|
||||
continue;
|
||||
control_check_subs_all_panes_one(c,
|
||||
csub, ft, wl, wp);
|
||||
}
|
||||
format_free(ft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all-windows subscriptions. */
|
||||
if (have_all_windows) {
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs,
|
||||
csub1) {
|
||||
if (csub->type != CONTROL_SUB_ALL_WINDOWS)
|
||||
continue;
|
||||
control_check_subs_all_windows_one(c, csub, ft,
|
||||
wl);
|
||||
}
|
||||
format_free(ft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a subscription. */
|
||||
|
||||
6
format.c
6
format.c
@@ -2012,8 +2012,10 @@ format_cb_pane_bottom(struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_pane_dead(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL) {
|
||||
if (ft->wp->fd == -1)
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL) {
|
||||
if (wp->fd == -1 && (wp->flags & PANE_STATUSREADY))
|
||||
return (xstrdup("1"));
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
|
||||
14
grid.c
14
grid.c
@@ -205,11 +205,17 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
|
||||
struct grid_line *gl = &gd->linedata[py];
|
||||
struct grid_cell_entry *gce = &gl->celldata[px];
|
||||
struct grid_extd_entry *gee;
|
||||
u_int old_offset = gce->offset;
|
||||
int had_extd = (gce->flags & GRID_FLAG_EXTENDED);
|
||||
|
||||
memcpy(gce, &grid_cleared_entry, sizeof *gce);
|
||||
if (bg != 8) {
|
||||
if (bg & COLOUR_FLAG_RGB) {
|
||||
grid_get_extended_cell(gl, gce, gce->flags);
|
||||
if (had_extd && old_offset < gl->extdsize) {
|
||||
gce->flags |= GRID_FLAG_EXTENDED;
|
||||
gce->offset = old_offset;
|
||||
} else
|
||||
grid_get_extended_cell(gl, gce, gce->flags);
|
||||
gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
|
||||
gee->bg = bg;
|
||||
} else {
|
||||
@@ -1089,12 +1095,16 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
|
||||
off = 0;
|
||||
|
||||
gl = grid_peek_line(gd, py);
|
||||
if (gl == NULL) {
|
||||
buf[0] = '\0';
|
||||
return (buf);
|
||||
}
|
||||
if (flags & GRID_STRING_EMPTY_CELLS)
|
||||
end = gl->cellsize;
|
||||
else
|
||||
end = gl->cellused;
|
||||
for (xx = px; xx < px + nx; xx++) {
|
||||
if (gl == NULL || xx >= end)
|
||||
if (xx >= end)
|
||||
break;
|
||||
grid_get_cell(gd, xx, py, &gc);
|
||||
if (gc.flags & GRID_FLAG_PADDING)
|
||||
|
||||
91
input.c
91
input.c
@@ -101,6 +101,7 @@ struct input_ctx {
|
||||
struct bufferevent *event;
|
||||
struct screen_write_ctx ctx;
|
||||
struct colour_palette *palette;
|
||||
struct client *c;
|
||||
|
||||
struct input_cell cell;
|
||||
struct input_cell old_cell;
|
||||
@@ -854,7 +855,7 @@ input_restore_state(struct input_ctx *ictx)
|
||||
/* Initialise input parser. */
|
||||
struct input_ctx *
|
||||
input_init(struct window_pane *wp, struct bufferevent *bev,
|
||||
struct colour_palette *palette)
|
||||
struct colour_palette *palette, struct client *c)
|
||||
{
|
||||
struct input_ctx *ictx;
|
||||
|
||||
@@ -862,6 +863,7 @@ input_init(struct window_pane *wp, struct bufferevent *bev,
|
||||
ictx->wp = wp;
|
||||
ictx->event = bev;
|
||||
ictx->palette = palette;
|
||||
ictx->c = c;
|
||||
|
||||
ictx->input_space = INPUT_BUF_START;
|
||||
ictx->input_buf = xmalloc(INPUT_BUF_START);
|
||||
@@ -3110,31 +3112,28 @@ input_osc_52_reply(struct input_ctx *ictx)
|
||||
input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end);
|
||||
}
|
||||
|
||||
/* Handle the OSC 52 sequence for setting the clipboard. */
|
||||
static void
|
||||
input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
/*
|
||||
* Parse and decode OSC 52 clipboard data. Returns 0 on failure or if handled
|
||||
* as a query. On success, returns 1 and sets *out, *outlen, and *flags (caller
|
||||
* must free *out).
|
||||
*/
|
||||
static int
|
||||
input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
|
||||
int *outlen, char *flags)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
size_t len;
|
||||
char *end;
|
||||
u_char *out;
|
||||
int outlen, state;
|
||||
struct screen_write_ctx ctx;
|
||||
const char* allow = "cpqs01234567";
|
||||
char flags[sizeof "cpqs01234567"] = "";
|
||||
u_int i, j = 0;
|
||||
char *end;
|
||||
size_t len;
|
||||
const char *allow = "cpqs01234567";
|
||||
u_int i, j = 0;
|
||||
|
||||
if (wp == NULL)
|
||||
return;
|
||||
state = options_get_number(global_options, "set-clipboard");
|
||||
if (state != 2)
|
||||
return;
|
||||
if (options_get_number(global_options, "set-clipboard") != 2)
|
||||
return (0);
|
||||
|
||||
if ((end = strchr(p, ';')) == NULL)
|
||||
return;
|
||||
return (0);
|
||||
end++;
|
||||
if (*end == '\0')
|
||||
return;
|
||||
return (0);
|
||||
log_debug("%s: %s", __func__, end);
|
||||
|
||||
for (i = 0; p + i != end; i++) {
|
||||
@@ -3145,25 +3144,53 @@ input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
|
||||
if (strcmp(end, "?") == 0) {
|
||||
input_osc_52_reply(ictx);
|
||||
return;
|
||||
return (0);
|
||||
}
|
||||
|
||||
len = (strlen(end) / 4) * 3;
|
||||
if (len == 0)
|
||||
return;
|
||||
return (0);
|
||||
|
||||
out = xmalloc(len);
|
||||
if ((outlen = b64_pton(end, out, len)) == -1) {
|
||||
free(out);
|
||||
return;
|
||||
*out = xmalloc(len);
|
||||
if ((*outlen = b64_pton(end, *out, len)) == -1) {
|
||||
free(*out);
|
||||
*out = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_setselection(&ctx, flags, out, outlen);
|
||||
screen_write_stop(&ctx);
|
||||
notify_pane("pane-set-clipboard", wp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
paste_add(NULL, out, outlen);
|
||||
/* Handle the OSC 52 sequence for setting the clipboard. */
|
||||
static void
|
||||
input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct screen_write_ctx ctx;
|
||||
u_char *out;
|
||||
int outlen;
|
||||
char flags[sizeof "cpqs01234567"] = "";
|
||||
|
||||
if (!input_osc_52_parse(ictx, p, &out, &outlen, flags))
|
||||
return;
|
||||
|
||||
if (wp == NULL) {
|
||||
/* Popup window. */
|
||||
if (ictx->c == NULL) {
|
||||
free(out);
|
||||
return;
|
||||
}
|
||||
tty_set_selection(&ictx->c->tty, flags, out, outlen);
|
||||
paste_add(NULL, out, outlen);
|
||||
} else {
|
||||
/* Normal window. */
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_setselection(&ctx, flags, out, outlen);
|
||||
screen_write_stop(&ctx);
|
||||
notify_pane("pane-set-clipboard", wp);
|
||||
paste_add(NULL, out, outlen);
|
||||
}
|
||||
free(out);
|
||||
}
|
||||
|
||||
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
|
||||
@@ -3434,7 +3461,7 @@ input_cancel_requests(struct client *c)
|
||||
{
|
||||
struct input_request *ir, *ir1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(ir, &c->input_requests, entry, ir1)
|
||||
TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1)
|
||||
input_free_request(ir);
|
||||
}
|
||||
|
||||
|
||||
@@ -297,12 +297,12 @@ key_bindings_remove_table(const char *name)
|
||||
table = key_bindings_get_table(name, 0);
|
||||
if (table != NULL) {
|
||||
RB_REMOVE(key_tables, &key_tables, table);
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->keytable == table)
|
||||
server_client_set_key_table(c, NULL);
|
||||
}
|
||||
key_bindings_unref_table(table);
|
||||
}
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->keytable == table)
|
||||
server_client_set_key_table(c, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
4
paste.c
4
paste.c
@@ -106,7 +106,7 @@ paste_is_empty(void)
|
||||
|
||||
/* Get the most recent automatic buffer. */
|
||||
struct paste_buffer *
|
||||
paste_get_top(const char **name)
|
||||
paste_get_top(char **name)
|
||||
{
|
||||
struct paste_buffer *pb;
|
||||
|
||||
@@ -116,7 +116,7 @@ paste_get_top(const char **name)
|
||||
if (pb == NULL)
|
||||
return (NULL);
|
||||
if (name != NULL)
|
||||
*name = pb->name;
|
||||
*name = xstrdup(pb->name);
|
||||
return (pb);
|
||||
}
|
||||
|
||||
|
||||
2
popup.c
2
popup.c
@@ -850,7 +850,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
||||
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
|
||||
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
|
||||
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
|
||||
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette);
|
||||
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette, c);
|
||||
|
||||
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
||||
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
|
||||
|
||||
2
resize.c
2
resize.c
@@ -250,7 +250,7 @@ skip:
|
||||
/* Return whether a suitable size was found. */
|
||||
if (type == WINDOW_SIZE_MANUAL) {
|
||||
log_debug("%s: type is manual", __func__);
|
||||
return (1);
|
||||
return (w != NULL);
|
||||
}
|
||||
if (type == WINDOW_SIZE_LARGEST) {
|
||||
log_debug("%s: type is largest", __func__);
|
||||
|
||||
@@ -2743,18 +2743,31 @@ server_client_handle_key(struct client *c, struct key_event *event)
|
||||
void
|
||||
server_client_loop(void)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct client *c;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct window_mode_entry *wme;
|
||||
|
||||
/* Check for window resize. This is done before redrawing. */
|
||||
RB_FOREACH(w, windows, &windows)
|
||||
server_client_check_window_resize(w);
|
||||
|
||||
/* Notify modes that pane styles may have changed. */
|
||||
RB_FOREACH(w, windows, &windows) {
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->flags & PANE_STYLECHANGED) {
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme != NULL &&
|
||||
wme->mode->style_changed != NULL)
|
||||
wme->mode->style_changed(wme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check clients. */
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
server_client_check_exit(c);
|
||||
if (c->session != NULL) {
|
||||
if (c->session != NULL && c->session->curw != NULL) {
|
||||
server_client_check_modes(c);
|
||||
server_client_check_redraw(c);
|
||||
server_client_reset_state(c);
|
||||
|
||||
40
sort.c
40
sort.c
@@ -197,23 +197,25 @@ sort_pane_cmp(const void *a0, const void *b0)
|
||||
case SORT_CREATION:
|
||||
result = a->id - b->id;
|
||||
break;
|
||||
case SORT_INDEX:
|
||||
case SORT_NAME:
|
||||
case SORT_ORDER:
|
||||
case SORT_SIZE:
|
||||
case SORT_END:
|
||||
result = a->sx * a->sy - b->sx * b->sy;
|
||||
break;
|
||||
}
|
||||
if (result == 0) {
|
||||
/*
|
||||
* Panes don't have names, so use number order for any other
|
||||
* sort field.
|
||||
*/
|
||||
case SORT_INDEX:
|
||||
window_pane_index(a, &ai);
|
||||
window_pane_index(b, &bi);
|
||||
result = ai - bi;
|
||||
break;
|
||||
case SORT_NAME:
|
||||
result = strcmp(a->screen->title, b->screen->title);
|
||||
break;
|
||||
case SORT_ORDER:
|
||||
case SORT_END:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
result = strcmp(a->screen->title, b->screen->title);
|
||||
|
||||
if (sort_crit->reversed)
|
||||
result = -result;
|
||||
return (result);
|
||||
@@ -235,6 +237,16 @@ sort_winlink_cmp(const void *a0, const void *b0)
|
||||
case SORT_INDEX:
|
||||
result = wla->idx - wlb->idx;
|
||||
break;
|
||||
case SORT_CREATION:
|
||||
if (timercmp(&wa->creation_time, &wb->creation_time, >)) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
if (timercmp(&wa->creation_time, &wb->creation_time, <)) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SORT_ACTIVITY:
|
||||
if (timercmp(&wa->activity_time, &wb->activity_time, >)) {
|
||||
result = -1;
|
||||
@@ -248,9 +260,10 @@ sort_winlink_cmp(const void *a0, const void *b0)
|
||||
case SORT_NAME:
|
||||
result = strcmp(wa->name, wb->name);
|
||||
break;
|
||||
case SORT_CREATION:
|
||||
case SORT_ORDER:
|
||||
case SORT_SIZE:
|
||||
result = wa->sx * wa->sy - wb->sx * wb->sy;
|
||||
break;
|
||||
case SORT_ORDER:
|
||||
case SORT_END:
|
||||
break;
|
||||
}
|
||||
@@ -295,7 +308,8 @@ sort_order_from_string(const char* order)
|
||||
return (SORT_CREATION);
|
||||
if (strcasecmp(order, "index") == 0)
|
||||
return (SORT_INDEX);
|
||||
if (strcasecmp(order, "name") == 0)
|
||||
if (strcasecmp(order, "name") == 0 ||
|
||||
strcasecmp(order, "title") == 0)
|
||||
return (SORT_NAME);
|
||||
if (strcasecmp(order, "order") == 0)
|
||||
return (SORT_ORDER);
|
||||
|
||||
10
tmux.1
10
tmux.1
@@ -3092,7 +3092,11 @@ See the
|
||||
section.
|
||||
.Fl O
|
||||
specifies the sort order: one of
|
||||
.Ql name ,
|
||||
.Ql name
|
||||
(title),
|
||||
.Ql index ,
|
||||
.Ql size
|
||||
(area),
|
||||
.Ql creation
|
||||
(time), or
|
||||
.Ql activity
|
||||
@@ -3125,6 +3129,10 @@ section.
|
||||
specifies the sort order: one of
|
||||
.Ql index ,
|
||||
.Ql name ,
|
||||
.Ql size
|
||||
(area),
|
||||
.Ql creation
|
||||
(time),
|
||||
or
|
||||
.Ql activity
|
||||
(time).
|
||||
|
||||
6
tmux.h
6
tmux.h
@@ -1101,6 +1101,7 @@ struct window_mode {
|
||||
void (*free)(struct window_mode_entry *);
|
||||
void (*resize)(struct window_mode_entry *, u_int, u_int);
|
||||
void (*update)(struct window_mode_entry *);
|
||||
void (*style_changed)(struct window_mode_entry *);
|
||||
void (*key)(struct window_mode_entry *, struct client *,
|
||||
struct session *, struct winlink *, key_code,
|
||||
struct mouse_event *);
|
||||
@@ -1305,6 +1306,7 @@ struct window {
|
||||
struct event offset_timer;
|
||||
|
||||
struct timeval activity_time;
|
||||
struct timeval creation_time;
|
||||
|
||||
struct window_pane *active;
|
||||
struct window_panes last_panes;
|
||||
@@ -2363,7 +2365,7 @@ time_t paste_buffer_created(struct paste_buffer *);
|
||||
const char *paste_buffer_data(struct paste_buffer *, size_t *);
|
||||
struct paste_buffer *paste_walk(struct paste_buffer *);
|
||||
int paste_is_empty(void);
|
||||
struct paste_buffer *paste_get_top(const char **);
|
||||
struct paste_buffer *paste_get_top(char **);
|
||||
struct paste_buffer *paste_get_name(const char *);
|
||||
void paste_free(struct paste_buffer *);
|
||||
void paste_add(const char *, char *, size_t);
|
||||
@@ -3065,7 +3067,7 @@ void recalculate_sizes_now(int);
|
||||
/* input.c */
|
||||
#define INPUT_BUF_DEFAULT_SIZE 1048576
|
||||
struct input_ctx *input_init(struct window_pane *, struct bufferevent *,
|
||||
struct colour_palette *);
|
||||
struct colour_palette *, struct client *);
|
||||
void input_free(struct input_ctx *);
|
||||
void input_reset(struct input_ctx *, int);
|
||||
struct evbuffer *input_pending(struct input_ctx *);
|
||||
|
||||
10
tty-draw.c
10
tty-draw.c
@@ -262,10 +262,12 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
else
|
||||
next_state = TTY_DRAW_LINE_NEW1;
|
||||
}
|
||||
log_debug("%s: cell %u empty %u, bg %u; state: current %s, "
|
||||
"next %s", __func__, px + i, empty, gcp->bg,
|
||||
tty_draw_line_states[current_state],
|
||||
tty_draw_line_states[next_state]);
|
||||
if (log_get_level() != 0) {
|
||||
log_debug("%s: cell %u empty %u, bg %u; state: "
|
||||
"current %s, next %s", __func__, px + i, empty,
|
||||
gcp->bg, tty_draw_line_states[current_state],
|
||||
tty_draw_line_states[next_state]);
|
||||
}
|
||||
|
||||
/* If the state has changed, flush any collected data. */
|
||||
if (next_state != current_state) {
|
||||
|
||||
16
tty-keys.c
16
tty-keys.c
@@ -1377,6 +1377,10 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
|
||||
|
||||
/* Convert from base64. */
|
||||
needed = (end / 4) * 3;
|
||||
if (needed == 0) {
|
||||
free(copy);
|
||||
return (0);
|
||||
}
|
||||
out = xmalloc(needed);
|
||||
if ((outlen = b64_pton(copy, out, len)) == -1) {
|
||||
free(out);
|
||||
@@ -1612,8 +1616,10 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
||||
}
|
||||
if (i == (sizeof tmp) - 1)
|
||||
return (-1);
|
||||
tmp[i - 1] = '\0';
|
||||
*size = 5 + i;
|
||||
if (i == 0)
|
||||
return (0);
|
||||
tmp[i - 1] = '\0';
|
||||
|
||||
/* Add terminal features. */
|
||||
if (strncmp(tmp, "iTerm2 ", 7) == 0)
|
||||
@@ -1686,11 +1692,13 @@ tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size,
|
||||
}
|
||||
if (i == (sizeof tmp) - 1)
|
||||
return (-1);
|
||||
*size = 6 + i;
|
||||
if (i == 0)
|
||||
return (0);
|
||||
if (tmp[i - 1] == '\033')
|
||||
tmp[i - 1] = '\0';
|
||||
else
|
||||
tmp[i] = '\0';
|
||||
*size = 6 + i;
|
||||
|
||||
/* Work out the colour. */
|
||||
n = colour_parseX11(tmp);
|
||||
@@ -1755,11 +1763,13 @@ tty_keys_palette(struct tty *tty, const char *buf, size_t len, size_t *size)
|
||||
}
|
||||
if (i == (sizeof tmp) - 1)
|
||||
return (-1);
|
||||
*size = 5 + i;
|
||||
if (i == 0)
|
||||
return (0);
|
||||
if (tmp[i - 1] == '\033')
|
||||
tmp[i - 1] = '\0';
|
||||
else
|
||||
tmp[i] = '\0';
|
||||
*size = 5 + i;
|
||||
|
||||
/* Parse index. */
|
||||
idx = strtol(tmp, &endptr, 10);
|
||||
|
||||
4
tty.c
4
tty.c
@@ -633,7 +633,8 @@ tty_add(struct tty *tty, const char *buf, size_t len)
|
||||
|
||||
if (tty_log_fd != -1)
|
||||
write(tty_log_fd, buf, len);
|
||||
if (tty->flags & TTY_STARTED)
|
||||
if ((tty->flags & TTY_STARTED) &&
|
||||
!event_pending(&tty->event_out, EV_WRITE, NULL))
|
||||
event_add(&tty->event_out, NULL);
|
||||
}
|
||||
|
||||
@@ -2289,7 +2290,6 @@ tty_cell(struct tty *tty, const struct grid_cell *gc,
|
||||
|
||||
/* If it is a single character, write with putc to handle ACS. */
|
||||
if (gcp->data.size == 1) {
|
||||
tty_attributes(tty, gcp, defaults, palette, hl);
|
||||
if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f)
|
||||
return;
|
||||
tty_putc(tty, *gcp->data.data);
|
||||
|
||||
@@ -51,6 +51,7 @@ static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
|
||||
static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
|
||||
u_int);
|
||||
static void window_copy_redraw_screen(struct window_mode_entry *);
|
||||
static void window_copy_style_changed(struct window_mode_entry *);
|
||||
static void window_copy_write_line(struct window_mode_entry *,
|
||||
struct screen_write_ctx *, u_int);
|
||||
static void window_copy_write_lines(struct window_mode_entry *,
|
||||
@@ -158,6 +159,7 @@ const struct window_mode window_copy_mode = {
|
||||
.init = window_copy_init,
|
||||
.free = window_copy_free,
|
||||
.resize = window_copy_resize,
|
||||
.style_changed = window_copy_style_changed,
|
||||
.key_table = window_copy_key_table,
|
||||
.command = window_copy_command,
|
||||
.formats = window_copy_formats,
|
||||
@@ -170,6 +172,7 @@ const struct window_mode window_view_mode = {
|
||||
.init = window_copy_view_init,
|
||||
.free = window_copy_free,
|
||||
.resize = window_copy_resize,
|
||||
.style_changed = window_copy_style_changed,
|
||||
.key_table = window_copy_key_table,
|
||||
.command = window_copy_command,
|
||||
.formats = window_copy_formats,
|
||||
@@ -352,7 +355,7 @@ window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
|
||||
if (trim) {
|
||||
while (sy > screen_hsize(src)) {
|
||||
gl = grid_peek_line(src->grid, sy - 1);
|
||||
if (gl->cellused != 0)
|
||||
if (gl == NULL || gl->cellused != 0)
|
||||
break;
|
||||
sy--;
|
||||
}
|
||||
@@ -491,7 +494,7 @@ window_copy_view_init(struct window_mode_entry *wme,
|
||||
|
||||
data->backing = xmalloc(sizeof *data->backing);
|
||||
screen_init(data->backing, sx, screen_size_y(base), UINT_MAX);
|
||||
data->ictx = input_init(NULL, NULL, NULL);
|
||||
data->ictx = input_init(NULL, NULL, NULL, NULL);
|
||||
data->mx = data->cx;
|
||||
data->my = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
data->showmark = 0;
|
||||
@@ -3622,6 +3625,10 @@ window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
|
||||
buf = xrealloc(buf, bufsize);
|
||||
|
||||
gl = grid_peek_line(gd, py);
|
||||
if (gl == NULL) {
|
||||
buf[*size - 1] = '\0';
|
||||
return (buf);
|
||||
}
|
||||
bx = *size - 1;
|
||||
for (ax = first; ax < last; ax++) {
|
||||
d = window_copy_cellstring(gl, ax, &dlen, &allocated);
|
||||
@@ -3667,6 +3674,10 @@ window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
|
||||
px = *ppx;
|
||||
pywrap = *ppy;
|
||||
gl = grid_peek_line(gd, pywrap);
|
||||
if (gl == NULL) {
|
||||
free(cells);
|
||||
return;
|
||||
}
|
||||
while (cell < ncells) {
|
||||
cells[cell].d = window_copy_cellstring(gl, px,
|
||||
&cells[cell].dlen, &cells[cell].allocated);
|
||||
@@ -3676,6 +3687,8 @@ window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
|
||||
px = 0;
|
||||
pywrap++;
|
||||
gl = grid_peek_line(gd, pywrap);
|
||||
if (gl == NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4077,7 +4090,7 @@ window_copy_visible_lines(struct window_copy_mode_data *data, u_int *start,
|
||||
|
||||
for (*start = gd->hsize - data->oy; *start > 0; (*start)--) {
|
||||
gl = grid_peek_line(gd, (*start) - 1);
|
||||
if (~gl->flags & GRID_LINE_WRAPPED)
|
||||
if (gl == NULL || ~gl->flags & GRID_LINE_WRAPPED)
|
||||
break;
|
||||
}
|
||||
*end = gd->hsize - data->oy + gd->sy;
|
||||
@@ -4268,6 +4281,9 @@ window_copy_clear_marks(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
|
||||
data->searchcount = -1;
|
||||
data->searchmore = 0;
|
||||
|
||||
free(data->searchmark);
|
||||
data->searchmark = NULL;
|
||||
}
|
||||
@@ -4595,6 +4611,16 @@ window_copy_redraw_screen(struct window_mode_entry *wme)
|
||||
window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen));
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_style_changed(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
|
||||
if (data->screen.sel != NULL)
|
||||
window_copy_set_selection(wme, 0, 1);
|
||||
window_copy_redraw_screen(wme);
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin,
|
||||
int no_reset)
|
||||
@@ -5036,9 +5062,9 @@ static void
|
||||
window_copy_append_selection(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_pane *wp = wme->wp;
|
||||
char *buf;
|
||||
char *buf, *bufname = NULL;
|
||||
struct paste_buffer *pb;
|
||||
const char *bufdata, *bufname = NULL;
|
||||
const char *bufdata;
|
||||
size_t len, bufsize;
|
||||
struct screen_write_ctx ctx;
|
||||
|
||||
@@ -5063,6 +5089,7 @@ window_copy_append_selection(struct window_mode_entry *wme)
|
||||
}
|
||||
if (paste_set(buf, len, bufname, NULL) != 0)
|
||||
free(buf);
|
||||
free(bufname);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
5
window.c
5
window.c
@@ -329,6 +329,9 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel)
|
||||
RB_INSERT(windows, &windows, w);
|
||||
|
||||
window_set_fill_character(w);
|
||||
|
||||
if (gettimeofday(&w->creation_time, NULL) != 0)
|
||||
fatal("gettimeofday failed");
|
||||
window_update_activity(w);
|
||||
|
||||
log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy,
|
||||
@@ -1171,7 +1174,7 @@ window_pane_set_event(struct window_pane *wp)
|
||||
NULL, window_pane_error_callback, wp);
|
||||
if (wp->event == NULL)
|
||||
fatalx("out of memory");
|
||||
wp->ictx = input_init(wp, wp->event, &wp->palette);
|
||||
wp->ictx = input_init(wp, wp->event, &wp->palette, NULL);
|
||||
|
||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user