Merge branch 'master' into floating_panes

This commit is contained in:
Dane Jensen
2026-06-10 12:47:50 -07:00
19 changed files with 451 additions and 173 deletions

View File

@@ -84,7 +84,7 @@ cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx,
struct client *c = ctx->c;
struct tty *tty = &c->tty;
struct session *s = c->session;
struct screen screen;
struct screen *sc = wp->screen, screen;
struct screen_write_ctx sctx;
struct visible_ranges *r;
struct visible_range *ri;
@@ -97,6 +97,8 @@ cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx,
screen_init(&screen, sx, 1, 0);
screen_write_start(&sctx, &screen);
screen_write_fast_copy(&sctx, sc, 0, sc->grid->hsize, sx, 1);
screen_write_cursormove(&sctx, 0, 0, 0);
format_draw(&sctx, gc, sx, expanded, NULL, 0);
screen_write_stop(&sctx);
free(expanded);
@@ -105,7 +107,7 @@ cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx,
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
tty_draw_line(tty, &screen, ri->px - px, 0, ri->nx,
ri->px - ctx->ox, yoff, gc, NULL);
ri->px - ctx->ox, yoff, NULL);
}
screen_free(&screen);
}
@@ -199,7 +201,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
llen = 0;
if (sx < len * 6 || sy < 5) {
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
tty_attributes(tty, &fgc, NULL);
if (sx >= len + llen + 1) {
len += llen + 1;
cx = xoff + px - len / 2;
@@ -220,7 +222,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px -= len * 3;
py -= 2;
tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL);
tty_attributes(tty, &bgc, NULL);
for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9')
continue;
@@ -242,7 +244,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
goto out;
cmd_display_panes_draw_format(ctx, wp, xoff, yoff, sx, &fgc);
if (llen != 0) {
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
tty_attributes(tty, &fgc, NULL);
cx = xoff + sx / 2 + len * 3 - llen - 1;
cy = yoff + py + 5;
cmd_display_panes_put(ctx, wp, cx, cy, lbuf, llen);

View File

@@ -147,6 +147,18 @@ cmd_find_session_better(struct session *s, struct session *than, int flags)
return (timercmp(&s->activity_time, &than->activity_time, >));
}
/* Can this session be usefully targeted? */
static int
cmd_find_session_valid(struct session *s)
{
if (!session_alive(s) ||
s->curw == NULL ||
s->curw->window == NULL ||
s->curw->window->active == NULL)
return (0);
return (1);
}
/* Find best session from a list, or all if list is NULL. */
static struct session *
cmd_find_best_session(struct session **slist, u_int ssize, int flags)
@@ -159,11 +171,15 @@ cmd_find_best_session(struct session **slist, u_int ssize, int flags)
s = NULL;
if (slist != NULL) {
for (i = 0; i < ssize; i++) {
if (!cmd_find_session_valid(slist[i]))
continue;
if (cmd_find_session_better(slist[i], s, flags))
s = slist[i];
}
} else {
RB_FOREACH(s_loop, sessions, &sessions) {
if (!cmd_find_session_valid(s_loop))
continue;
if (cmd_find_session_better(s_loop, s, flags))
s = s_loop;
}

View File

@@ -50,8 +50,6 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
const char *filter = args_get(args, 'f');

View File

@@ -237,7 +237,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
cmd_list_keys_format_add_key_binding(ft, l[i], prefix);
line = format_expand(ft, template);
if ((single && tc != NULL) || n == 1)
if (single && tc != NULL && (~tc->flags & CLIENT_CONTROL))
status_message_set(tc, -1, 1, 0, 0, "%s", line);
else if (*line != '\0')
cmdq_print(item, "%s", line);

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_new_pane_entry = {
.name = "new-pane",
.alias = "newp",
.args = { "bBc:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vx:X:y:Y:Z", 0, -1, NULL },
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
.args = { "bc:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
.usage = "[-bdefhIklPvWZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] [-m message] [-p percentage] "
"[-s style] [-S active-border-style] "
"[-R inactive-border-style] [-T title] [-x width] [-y height] "
@@ -56,8 +56,8 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window",
.alias = "splitw",
.args = { "bBc:de:EfF:hIkl:m:p:PR:s:S:t:T:vZ", 0, -1, NULL },
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
.args = { "bc:de:EfF:hIkl:m:p:PR:s:S:t:T:vWZ", 0, -1, NULL },
.usage = "[-bdefhIklPvWZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] [-m message] [-p percentage] "
"[-s style] [-S active-border-style] "
"[-R inactive-border-style] [-T title] " CMD_TARGET_PANE_USAGE " "
@@ -245,13 +245,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (input)
return (CMD_RETURN_WAIT);
if (args_has(args, 'B')) {
if (args_has(args, 'W')) {
/*
* With -B, block this command queue item until the pane's
* command exits; window_pane_block_finish will be called to
* With -W, block this command queue item until the pane's
* command exits; window_pane_wait_finish will be called to
* continue it.
*/
new_wp->block_item = item;
new_wp->wait_item = item;
return (CMD_RETURN_WAIT);
}
return (CMD_RETURN_NORMAL);

11
grid.c
View File

@@ -292,7 +292,7 @@ grid_free_line(struct grid *gd, u_int py)
}
/* Free several lines. */
static void
void
grid_free_lines(struct grid *gd, u_int py, u_int ny)
{
u_int yy;
@@ -320,6 +320,10 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
gd->hsize = 0;
gd->hlimit = hlimit;
gd->scroll_added = 0;
gd->scroll_collected = 0;
gd->scroll_generation = 0;
if (gd->sy != 0)
gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
else
@@ -405,6 +409,7 @@ grid_collect_history(struct grid *gd, int all)
grid_trim_history(gd, ny);
gd->hsize -= ny;
gd->scroll_collected += ny;
if (gd->hscrolled > gd->hsize)
gd->hscrolled = gd->hsize;
}
@@ -442,6 +447,7 @@ grid_scroll_history(struct grid *gd, u_int bg)
grid_compact_line(&gd->linedata[gd->hsize]);
gd->linedata[gd->hsize].time = current_time;
gd->hsize++;
gd->scroll_added++;
}
/* Clear the history. */
@@ -452,6 +458,7 @@ grid_clear_history(struct grid *gd)
gd->hscrolled = 0;
gd->hsize = 0;
gd->scroll_generation++;
gd->linedata = xreallocarray(gd->linedata, gd->sy,
sizeof *gd->linedata);
@@ -489,6 +496,7 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
/* Move the history offset down over the line. */
gd->hscrolled++;
gd->hsize++;
gd->scroll_added++;
}
/* Expand line to fit to cell. */
@@ -1510,6 +1518,7 @@ grid_reflow(struct grid *gd, u_int sx)
free(gd->linedata);
gd->linedata = target->linedata;
free(target);
gd->scroll_generation++;
}
/* Convert to position based on wrapped lines. */

View File

@@ -533,7 +533,7 @@ key_bindings_init(void)
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
"bind -Tcopy-mode n { send -X search-again }",
"bind -Tcopy-mode q { send -X cancel }",
"bind -Tcopy-mode r { send -X refresh-from-pane }",
"bind -Tcopy-mode r { send -X refresh-toggle }",
"bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
"bind -Tcopy-mode Home { send -X start-of-line }",
"bind -Tcopy-mode End { send -X end-of-line }",
@@ -641,7 +641,7 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi n { send -X search-again }",
"bind -Tcopy-mode-vi o { send -X other-end }",
"bind -Tcopy-mode-vi q { send -X cancel }",
"bind -Tcopy-mode-vi r { send -X refresh-from-pane }",
"bind -Tcopy-mode-vi r { send -X refresh-toggle }",
"bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
"bind -Tcopy-mode-vi w { send -X next-word }",

6
menu.c
View File

@@ -281,10 +281,8 @@ menu_draw_cb(struct client *c, void *data,
&md->style_gc, &md->border_style_gc, &md->selected_style_gc);
screen_write_stop(&ctx);
for (i = 0; i < screen_size_y(&md->s); i++) {
tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i,
&grid_default_cell, NULL);
}
for (i = 0; i < screen_size_y(&md->s); i++)
tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i, NULL);
}
void

View File

@@ -738,7 +738,7 @@ const struct options_table_entry options_table[] = {
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the command prompt when in command mode, if "
"'mode-keys' is set to 'vi'."
"'status-keys' is set to 'vi'."
},
{ .name = "message-format",

18
popup.c
View File

@@ -208,7 +208,8 @@ popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
memcpy(&ttyctx->defaults, &pd->defaults, sizeof ttyctx->defaults);
ttyctx->flags &= ~TTY_CTX_WINDOW_BIGGER;
ttyctx->palette = &pd->palette;
ttyctx->style_ctx.defaults = &ttyctx->defaults;
ttyctx->style_ctx.palette = &pd->palette;
ttyctx->redraw_cb = popup_redraw_cb;
ttyctx->set_client_cb = popup_set_client_cb;
ttyctx->arg = pd;
@@ -294,8 +295,8 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
struct screen s;
struct screen_write_ctx ctx;
u_int i, px = pd->px, py = pd->py;
struct colour_palette *palette = &pd->palette;
struct grid_cell defaults;
struct tty_style_ctx style_ctx;
popup_reapply_styles(pd);
@@ -321,9 +322,12 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
memcpy(&defaults, &pd->defaults, sizeof defaults);
if (defaults.fg == 8)
defaults.fg = palette->fg;
defaults.fg = pd->palette.fg;
if (defaults.bg == 8)
defaults.bg = palette->bg;
defaults.bg = pd->palette.bg;
style_ctx.defaults = &defaults;
style_ctx.palette = &pd->palette;
style_ctx.hyperlinks = s.hyperlinks;
if (pd->md != NULL) {
c->overlay_check = menu_check_cb;
@@ -332,10 +336,8 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
c->overlay_check = NULL;
c->overlay_data = NULL;
}
for (i = 0; i < pd->sy; i++) {
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults,
palette);
}
for (i = 0; i < pd->sy; i++)
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &style_ctx);
screen_free(&s);
if (pd->md != NULL) {
c->overlay_check = NULL;

View File

@@ -715,7 +715,7 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
/* Right not visible. */
l = 0;
x = xoff - ctx->ox;
width = size - x;
width = ctx->sx - x;
}
r = tty_check_overlay_range(tty, x, yoff, width);
@@ -727,8 +727,7 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
if (ri->nx == 0)
continue;
tty_draw_line(tty, s, l + (ri->px - x), 0, ri->nx,
ri->px, yoff - ctx->oy,
&grid_default_cell, NULL);
ri->px, yoff - ctx->oy, NULL);
}
}
tty_cursor(tty, 0, 0);
@@ -1046,7 +1045,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
screen_redraw_draw_border_arrows(ctx, i, j, cell_type, wp, active, &gc);
tty_cell(tty, &gc, &grid_default_cell, NULL, NULL);
tty_cell(tty, &gc, NULL);
if (isolates)
tty_puts(tty, START_ISOLATE);
}
@@ -1106,10 +1105,8 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
y = 0;
else
y = c->tty.sy - ctx->statuslines;
for (i = 0; i < ctx->statuslines; i++) {
tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
&grid_default_cell, NULL);
}
for (i = 0; i < ctx->statuslines; i++)
tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i, NULL);
}
/*
@@ -1304,6 +1301,7 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
struct screen *s = wp->screen;
struct colour_palette *palette = &wp->palette;
struct grid_cell defaults;
struct tty_style_ctx style_ctx;
u_int j, k, woy, wx, wy, py, width;
struct visible_ranges *r;
struct visible_range *ri;
@@ -1378,10 +1376,15 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
width = ctx->sx - wx;
}
/* Set up the default style. */
tty_default_colours(&defaults, wp);
style_ctx.defaults = &defaults;
style_ctx.palette = palette;
style_ctx.hyperlinks = s->hyperlinks;
/* Get visible ranges of line before we draw it. */
r = tty_check_overlay_range(tty, wx, wy, width);
r = screen_redraw_get_visible_ranges(wp, wx, wy, width, r);
tty_default_colours(&defaults, wp);
for (k = 0; k < r->used; k++) {
ri = &r->ranges[k];
if (ri->nx == 0)
@@ -1392,7 +1395,7 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
ri->px + (int)ctx->ox - wp->xoff, j, ri->nx,
ri->px, py, ri->nx);
tty_draw_line(tty, s, ri->px + (int)ctx->ox - wp->xoff,
j, ri->nx, ri->px, py, &defaults, palette);
j, ri->nx, ri->px, py, &style_ctx);
}
}
@@ -1569,16 +1572,14 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
if ((sb_pos == PANE_SCROLLBARS_LEFT &&
i >= sb_w && i < sb_w + sb_pad) ||
(sb_pos == PANE_SCROLLBARS_RIGHT &&
i < sb_pad)) {
tty_cell(tty, &grid_default_cell,
&grid_default_cell, NULL, NULL);
} else {
i < sb_pad))
tty_cell(tty, &grid_default_cell, NULL);
else {
if (j >= slider_y && j < slider_y + slider_h)
gcp = &slgc;
else
gcp = &gc;
tty_cell(tty, gcp, &grid_default_cell, NULL,
NULL);
tty_cell(tty, gcp, NULL);
}
}
}

View File

@@ -222,7 +222,8 @@ static void
screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
int is_sync, int check_obscured)
{
struct screen *s = ctx->s;
struct screen *s = ctx->s;
struct colour_palette *palette = NULL;
memset(ttyctx, 0, sizeof *ttyctx);
@@ -239,19 +240,23 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
ttyctx->flags |= TTY_CTX_PANE_OBSCURED;
memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults);
ttyctx->style_ctx.defaults = &ttyctx->defaults;
ttyctx->style_ctx.hyperlinks = ctx->s->hyperlinks;
if (ctx->init_ctx_cb != NULL) {
ctx->init_ctx_cb(ctx, ttyctx);
if (ttyctx->palette != NULL) {
if (ttyctx->style_ctx.palette != NULL) {
palette = ttyctx->style_ctx.palette;
if (ttyctx->defaults.fg == 8)
ttyctx->defaults.fg = ttyctx->palette->fg;
ttyctx->defaults.fg = palette->fg;
if (ttyctx->defaults.bg == 8)
ttyctx->defaults.bg = ttyctx->palette->bg;
ttyctx->defaults.bg = palette->bg;
}
} else {
ttyctx->redraw_cb = screen_write_redraw_cb;
if (ctx->wp != NULL) {
tty_default_colours(&ttyctx->defaults, ctx->wp);
ttyctx->palette = &ctx->wp->palette;
ttyctx->style_ctx.palette = &ctx->wp->palette;
ttyctx->set_client_cb = screen_write_set_client_cb;
ttyctx->arg = ctx->wp;
}

View File

@@ -497,7 +497,7 @@ server_child_exited(pid_t pid, int status)
log_debug("%%%u exited", wp->id);
wp->flags |= PANE_EXITED;
window_pane_block_finish(wp);
window_pane_wait_finish(wp);
if (window_pane_destroy_ready(wp))
server_destroy_pane(wp, 1);

23
tmux.1
View File

@@ -2297,11 +2297,22 @@ Toggle rectangle selection mode.
.Xc
Cycles the current line between centre, top, and bottom.
.It Xo
.Ic refresh\-from\-pane
.Ic refresh\-on
.Xc
Turn on automatic refresh of the content from the pane, so that new output
appears while in copy mode.
Automatic refresh is off by default; it will scroll only while the cursor is at
the bottom and is paused while a selection is in progress.
.It Xo
.Ic refresh\-off
.Xc
Turn off automatic refresh of the content from the pane.
.It Xo
.Ic refresh\-toggle
(vi: r)
(emacs: r)
.Xc
Refresh the content from the pane.
Toggle automatic refresh of the content from the pane.
.It Xo
.Ic scroll\-bottom
.Xc
@@ -3457,7 +3468,7 @@ but a different format may be specified with
.Fl F .
.Tg newp
.It Xo Ic new\-pane
.Op Fl bBdefhIkPvZ
.Op Fl bdefhIkPvWZ
.Op Fl c Ar start\-directory
.Op Fl e Ar environment
.Op Fl F Ar format
@@ -3533,13 +3544,13 @@ but also sets the
option for this pane to
.Ar message .
.Pp
.Fl B
blocks until
.Fl W
Waits until
.Ar shell\-command
exits, then returns its exit status.
For example:
.Bd -literal -offset indent
$ tmux new-pane -B 'vi afile'
$ tmux new-pane -W 'vi afile'
$ echo $?
0
.Ed

42
tmux.h
View File

@@ -871,6 +871,10 @@ struct grid {
u_int hsize;
u_int hlimit;
u_int scroll_added;
u_int scroll_collected;
u_int scroll_generation;
struct grid_line *linedata;
};
@@ -1305,7 +1309,7 @@ struct window_pane {
char tty[TTY_NAME_MAX];
int status;
struct timeval dead_time;
struct cmdq_item *block_item; /* new-pane -B: waiting for pane exit */
struct cmdq_item *wait_item; /* new-pane -W: waiting for pane exit */
int fd;
struct bufferevent *event;
@@ -1654,6 +1658,13 @@ struct tty_term {
};
LIST_HEAD(tty_terms, tty_term);
/* Terminal style context. */
struct tty_style_ctx {
const struct grid_cell *defaults;
struct colour_palette *palette;
struct hyperlinks *hyperlinks;
};
/* Client terminal. */
struct tty {
struct client *client;
@@ -1804,7 +1815,7 @@ struct tty_ctx {
/* The default colours and palette. */
struct grid_cell defaults;
struct colour_palette *palette;
struct tty_style_ctx style_ctx;
/* Containing region (usually window) offset and size. */
u_int wox;
@@ -2672,6 +2683,10 @@ void environ_push(struct environ *);
void printflike(2, 3) environ_log(struct environ *, const char *, ...);
struct environ *environ_for_session(struct session *, int);
/* tty-draw.c */
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
u_int, u_int, const struct tty_style_ctx *);
/* tty.c */
void tty_create_log(void);
int tty_window_bigger(struct tty *);
@@ -2680,8 +2695,7 @@ void tty_update_window_offset(struct window *);
void tty_update_client_offset(struct client *);
void tty_raw(struct tty *, const char *);
void tty_attributes(struct tty *, const struct grid_cell *,
const struct grid_cell *, struct colour_palette *,
struct hyperlinks *);
const struct tty_style_ctx *);
void tty_reset(struct tty *);
void tty_region_off(struct tty *);
void tty_margin_off(struct tty *);
@@ -2700,8 +2714,7 @@ void tty_puts(struct tty *, const char *);
void tty_putc(struct tty *, u_char);
void tty_putn(struct tty *, const void *, size_t, u_int);
void tty_cell(struct tty *, const struct grid_cell *,
const struct grid_cell *, struct colour_palette *,
struct hyperlinks *);
const struct tty_style_ctx *);
int tty_init(struct tty *, struct client *);
void tty_resize(struct tty *);
void tty_set_size(struct tty *, u_int, u_int, u_int, u_int);
@@ -2713,22 +2726,13 @@ void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *);
void tty_set_path(struct tty *, const char *);
void tty_set_progress_bar(struct tty *, struct progress_bar *);
void tty_default_attributes(struct tty *, const struct grid_cell *,
struct colour_palette *, u_int, struct hyperlinks *);
void tty_default_attributes(struct tty *, u_int,
const struct tty_style_ctx *);
void tty_update_mode(struct tty *, int, struct screen *);
const struct grid_cell *tty_check_codeset(struct tty *,
const struct grid_cell *);
struct visible_ranges *tty_check_overlay_range(struct tty *, u_int, u_int,
u_int);
/* tty-draw.c */
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
u_int, u_int, const struct grid_cell *, struct colour_palette *);
#ifdef ENABLE_SIXEL
void tty_draw_images(struct client *, struct window_pane *, struct screen *);
#endif
void tty_sync_start(struct tty *);
void tty_sync_end(struct tty *);
int tty_open(struct tty *, char **);
@@ -2760,6 +2764,7 @@ void tty_cmd_setselection(struct tty *, const struct tty_ctx *);
void tty_cmd_rawstring(struct tty *, const struct tty_ctx *);
#ifdef ENABLE_SIXEL
void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
void tty_draw_images(struct client *, struct window_pane *, struct screen *);
#endif
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
void tty_default_colours(struct grid_cell *, struct window_pane *);
@@ -3222,6 +3227,7 @@ int grid_cells_look_equal(const struct grid_cell *,
const struct grid_cell *);
struct grid *grid_create(u_int, u_int, u_int);
void grid_destroy(struct grid *);
void grid_free_lines(struct grid *, u_int, u_int);
int grid_compare(struct grid *, struct grid *);
void grid_collect_history(struct grid *, int);
void grid_remove_history(struct grid *, u_int );
@@ -3436,7 +3442,7 @@ struct window *window_find_by_id(u_int);
void window_update_activity(struct window *);
struct window *window_create(u_int, u_int, u_int, u_int);
void window_pane_set_event(struct window_pane *);
void window_pane_block_finish(struct window_pane *);
void window_pane_wait_finish(struct window_pane *);
struct window_pane *window_get_active_at(struct window *, u_int, u_int);
struct window_pane *window_find_string(struct window *, const char *);
int window_has_floating_panes(struct window *);

View File

@@ -22,6 +22,7 @@
#include "tmux.h"
/* Current state when drawing line. */
enum tty_draw_line_state {
TTY_DRAW_LINE_FIRST,
TTY_DRAW_LINE_FLUSH,
@@ -91,8 +92,7 @@ tty_draw_line_clear(struct tty *tty, u_int px, u_int py, u_int nx,
/* Draw a line from screen to tty. */
void
tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
u_int atx, u_int aty, const struct grid_cell *defaults,
struct colour_palette *palette)
u_int atx, u_int aty, const struct tty_style_ctx *style_ctx)
{
struct grid *gd = s->grid;
const struct grid_cell *gcp;
@@ -104,6 +104,14 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
char buf[1000];
size_t len;
enum tty_draw_line_state current_state, next_state;
struct tty_style_ctx default_style_ctx = { 0 };
if (style_ctx == NULL) {
default_style_ctx.defaults = &grid_default_cell;
default_style_ctx.hyperlinks = s->hyperlinks;
style_ctx = &default_style_ctx;
}
/*
* py is the line in the screen to draw. px is the start x and nx is
@@ -130,8 +138,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
else
ex = screen_size_x(s);
log_debug("%s: drawing %u-%u,%u (end %u) at %u,%u; defaults: fg=%d, "
"bg=%d", __func__, px, px + nx, py, ex, atx, aty, defaults->fg,
defaults->bg);
"bg=%d", __func__, px, px + nx, py, ex, atx, aty,
style_ctx->defaults->fg, style_ctx->defaults->bg);
/* Turn off cursor while redrawing and reset region and margins. */
flags = (tty->flags & TTY_NOCURSOR);
@@ -142,8 +150,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
/* Start with the default cell as the last cell. */
memcpy(&last, &grid_default_cell, sizeof last);
last.bg = defaults->bg;
tty_default_attributes(tty, defaults, palette, 8, s->hyperlinks);
last.bg = style_ctx->defaults->bg;
tty_default_attributes(tty, 8, style_ctx);
/*
* If there is padding at the start, we must have truncated a wide
@@ -164,7 +172,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
break;
}
if (i == 0)
bg = defaults->bg;
bg = style_ctx->defaults->bg;
else {
bg = gc.bg;
if (gc.flags & GRID_FLAG_SELECTED) {
@@ -173,9 +181,9 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
bg = ngc.bg;
}
}
tty_attributes(tty, &last, defaults, palette, s->hyperlinks);
tty_attributes(tty, &last, style_ctx);
log_debug("%s: clearing %u padding cells", __func__, cx);
tty_draw_line_clear(tty, atx, aty, cx, defaults, bg, 0);
tty_draw_line_clear(tty, atx, aty, cx, style_ctx->defaults, bg, 0);
if (cx == ex)
goto out;
atx += cx;
@@ -274,15 +282,14 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
/* If the state has changed, flush any collected data. */
if (next_state != current_state) {
if (current_state == TTY_DRAW_LINE_EMPTY) {
tty_attributes(tty, &last, defaults, palette,
s->hyperlinks);
tty_attributes(tty, &last, style_ctx);
tty_draw_line_clear(tty, atx + last_i, aty,
i - last_i, defaults, last.bg, wrapped);
i - last_i, style_ctx->defaults, last.bg,
wrapped);
wrapped = 0;
} else if (next_state != TTY_DRAW_LINE_SAME &&
len != 0) {
tty_attributes(tty, &last, defaults, palette,
s->hyperlinks);
tty_attributes(tty, &last, style_ctx);
if (atx + i - width != 0 || !wrapped)
tty_cursor(tty, atx + i - width, aty);
if (~last.attr & GRID_ATTR_CHARSET)
@@ -322,4 +329,3 @@ out:
tty->flags = (tty->flags & ~TTY_NOCURSOR)|flags;
tty_update_mode(tty, tty->mode, s);
}

99
tty.c
View File

@@ -84,6 +84,10 @@ static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *),
#define TTY_QUERY_TIMEOUT 5
#define TTY_REQUEST_LIMIT 30
static struct tty_style_ctx tty_default_style_ctx = {
&grid_default_cell, NULL, NULL
};
void
tty_create_log(void)
{
@@ -1415,7 +1419,7 @@ tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
if (rr->nx == 0)
continue;
tty_draw_line(tty, s, rr->px - ctx->xoff, py, rr->nx,
rr->px, ctx->yoff + py, &ctx->defaults, ctx->palette);
rr->px, ctx->yoff + py, &ctx->style_ctx);
}
return;
}
@@ -1426,7 +1430,7 @@ tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
if (rr->nx == 0)
continue;
tty_draw_line(tty, s, i + rr->px - x, py, rr->nx,
rr->px, ry, &ctx->defaults, ctx->palette);
rr->px, ry, &ctx->style_ctx);
}
}
}
@@ -1650,8 +1654,7 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
@@ -1673,8 +1676,7 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
@@ -1684,8 +1686,7 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
{
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, ctx->n, ctx->bg);
}
@@ -1707,8 +1708,7 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_off(tty);
@@ -1735,8 +1735,7 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_off(tty);
@@ -1749,8 +1748,7 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx)
{
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->sx, ctx->bg);
}
@@ -1760,8 +1758,7 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
{
u_int nx = ctx->sx - ctx->ocx;
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, nx, ctx->bg);
}
@@ -1769,8 +1766,7 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
{
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->ocx + 1, ctx->bg);
}
@@ -1796,8 +1792,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1828,8 +1823,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1869,8 +1863,7 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1910,8 +1903,7 @@ tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
tty_margin_pane(tty, ctx);
@@ -1930,8 +1922,7 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
{
u_int px, py, nx, ny;
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
@@ -1955,8 +1946,7 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
{
u_int px, py, nx, ny;
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
@@ -1980,8 +1970,7 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
{
u_int px, py, nx, ny;
tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
ctx->s->hyperlinks);
tty_default_attributes(tty, ctx->bg, &ctx->style_ctx);
tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
@@ -2006,8 +1995,7 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
return;
}
tty_attributes(tty, &grid_default_cell, &ctx->defaults, ctx->palette,
ctx->s->hyperlinks);
tty_attributes(tty, &grid_default_cell, &ctx->style_ctx);
tty_region_pane(tty, ctx, 0, ctx->sy - 1);
tty_margin_off(tty);
@@ -2040,7 +2028,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
vis += r->ranges[i].nx;
if (vis < gcp->data.width) {
tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width,
px, py, &ctx->defaults, ctx->palette);
px, py, &ctx->style_ctx);
return;
}
}
@@ -2055,8 +2043,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
tty_invalidate(tty);
tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
tty_cell(tty, ctx->cell, &ctx->defaults, ctx->palette,
ctx->s->hyperlinks);
tty_cell(tty, ctx->cell, &ctx->style_ctx);
if (ctx->flags & TTY_CTX_CELL_INVALIDATE)
tty_invalidate(tty);
@@ -2092,8 +2079,7 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
tty_margin_off(tty);
tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette,
ctx->s->hyperlinks);
tty_attributes(tty, ctx->cell, &ctx->style_ctx);
/* Get tty position from pane position for overlay check. */
px = ctx->xoff + ctx->ocx - ctx->wox;
@@ -2361,8 +2347,7 @@ tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cell(struct tty *tty, const struct grid_cell *gc,
const struct grid_cell *defaults, struct colour_palette *palette,
struct hyperlinks *hl)
const struct tty_style_ctx *style_ctx)
{
const struct grid_cell *gcp;
@@ -2382,7 +2367,7 @@ tty_cell(struct tty *tty, const struct grid_cell *gc,
/* Check the output codeset and apply attributes. */
gcp = tty_check_codeset(tty, gc);
tty_attributes(tty, gcp, defaults, palette, hl);
tty_attributes(tty, gcp, style_ctx);
/* If it is a single character, write with putc to handle ACS. */
if (gcp->data.size == 1) {
@@ -2727,19 +2712,22 @@ tty_hyperlink(struct tty *tty, const struct grid_cell *gc,
void
tty_attributes(struct tty *tty, const struct grid_cell *gc,
const struct grid_cell *defaults, struct colour_palette *palette,
struct hyperlinks *hl)
const struct tty_style_ctx *style_ctx)
{
struct grid_cell *tc = &tty->cell, gc2;
int changed;
/* Use default style if not given. */
if (style_ctx == NULL)
style_ctx = &tty_default_style_ctx;
/* Copy cell and update default colours. */
memcpy(&gc2, gc, sizeof gc2);
if (~gc->flags & GRID_FLAG_NOPALETTE) {
if (gc2.fg == 8)
gc2.fg = defaults->fg;
gc2.fg = style_ctx->defaults->fg;
if (gc2.bg == 8)
gc2.bg = defaults->bg;
gc2.bg = style_ctx->defaults->bg;
}
/* Ignore cell if it is the same as the last one. */
@@ -2766,9 +2754,9 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
}
/* Fix up the colours if necessary. */
tty_check_fg(tty, palette, &gc2);
tty_check_bg(tty, palette, &gc2);
tty_check_us(tty, palette, &gc2);
tty_check_fg(tty, style_ctx->palette, &gc2);
tty_check_bg(tty, style_ctx->palette, &gc2);
tty_check_us(tty, style_ctx->palette, &gc2);
/*
* If any bits are being cleared or the underline colour is now default,
@@ -2824,7 +2812,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
tty_putcode(tty, TTYC_SMACS);
/* Set hyperlink if any. */
tty_hyperlink(tty, gc, hl);
tty_hyperlink(tty, gc, style_ctx->hyperlinks);
memcpy(&tty->last_cell, &gc2, sizeof tty->last_cell);
}
@@ -2846,8 +2834,9 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
*/
if (COLOUR_DEFAULT(gc->fg) || COLOUR_DEFAULT(gc->bg)) {
/*
* If don't have AX, send sgr0. This resets both colours to default.
* Otherwise, try to set the default colour only as needed.
* If don't have AX, send sgr0. This resets both colours to
* default. Otherwise, try to set the default colour only as
* needed.
*/
if (!tty_term_flag(tty->term, TTYC_AX))
tty_reset(tty);
@@ -3217,14 +3206,14 @@ tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
}
void
tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
struct colour_palette *palette, u_int bg, struct hyperlinks *hl)
tty_default_attributes(struct tty *tty, u_int bg,
const struct tty_style_ctx *style_ctx)
{
struct grid_cell gc;
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.bg = bg;
tty_attributes(tty, &gc, defaults, palette, hl);
tty_attributes(tty, &gc, style_ctx);
}
static void

View File

@@ -51,6 +51,11 @@ 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_do_refresh(struct window_mode_entry *, int);
static void window_copy_refresh_timer(int, short, void *);
static void window_copy_refresh_arm(struct window_mode_entry *);
static void window_copy_refresh_start(struct window_mode_entry *);
static void window_copy_refresh_stop(struct window_mode_entry *);
static void window_copy_style_changed(struct window_mode_entry *);
static int window_copy_line_number_mode(struct window_mode_entry *);
static int window_copy_line_number_is_absolute(struct window_mode_entry *);
@@ -255,6 +260,10 @@ struct window_copy_mode_data {
int backing_written; /* backing display started */
struct input_ctx *ictx;
u_int sync_added; /* snapshot of backing grid counters */
u_int sync_collected;
u_int sync_generation;
int viewmode; /* view mode entered */
u_int oy; /* number of lines scrolled up */
@@ -338,6 +347,10 @@ struct window_copy_mode_data {
struct event dragtimer;
#define WINDOW_COPY_DRAG_REPEAT_TIME 50000
struct event refresh_timer;
#define WINDOW_COPY_REFRESH_INTERVAL 50000
int refresh_active;
};
static void
@@ -424,6 +437,116 @@ window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
return (dst);
}
/*
* Snapshot the source grid's monotonic scroll counters so the next incremental
* sync can tell how much history was added or collected since this point.
*/
static void
window_copy_sync_snapshot(struct window_copy_mode_data *data, struct grid *src)
{
data->sync_added = src->scroll_added;
data->sync_collected = src->scroll_collected;
data->sync_generation = src->scroll_generation;
}
/*
* Reconcile the backing screen with the live pane grid in place, copying only
* the history that scrolled in or was collected since the last snapshot rather
* than cloning the whole scrollback. The result is identical to a fresh
* window_copy_clone_screen, so the caller repositions and redraws the same way
* for both paths. Returns 1 on success, or 0 if the caller must fall back to a
* full clone (different source pane, geometry or generation change, or counter
* deltas that do not add up).
*/
static int
window_copy_sync_backing(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
struct window_pane *wp = wme->swp;
struct screen *src = &wp->base;
struct screen *dst = data->backing;
struct grid *sg = src->grid;
struct grid *dg = dst->grid;
u_int sy = sg->sy;
u_int old_hsize = dg->hsize;
u_int new_hsize = sg->hsize;
u_int added, collected, kept;
/*
* Only a pane's own live grid is tracked incrementally. A different
* source pane (copy-mode -s) goes through clone_screen, which also
* trims trailing blank lines that this path does not.
*/
if (data->viewmode || wme->swp != wme->wp)
return (0);
/* Indices only line up at the same size and generation. */
if (sg->sx != dg->sx || sg->sy != dg->sy ||
sg->scroll_generation != data->sync_generation)
return (0);
added = sg->scroll_added - data->sync_added;
collected = sg->scroll_collected - data->sync_collected;
/*
* Reject anything that does not balance: counter wrap, a history-limit
* change that collected past the snapshot, or arithmetic that does not
* reproduce the new history size.
*/
if (added > (u_int)INT_MAX || collected > (u_int)INT_MAX ||
collected > old_hsize || old_hsize + added < collected ||
old_hsize + added - collected != new_hsize)
return (0);
kept = old_hsize - collected;
if (added == 0 && collected == 0) {
/* History is unchanged; only the viewport can have mutated. */
grid_duplicate_lines(dg, dg->hsize, sg, sg->hsize, sy);
} else {
/* Drop the oldest lines and shift the rest down. */
if (collected > 0) {
grid_free_lines(dg, 0, collected);
memmove(&dg->linedata[0], &dg->linedata[collected],
(old_hsize + sy - collected) * sizeof *dg->linedata);
memset(&dg->linedata[old_hsize + sy - collected], 0,
collected * sizeof *dg->linedata);
}
/* Resize linedata to the new history plus viewport. */
if (new_hsize + sy != old_hsize + sy - collected) {
dg->linedata = xreallocarray(dg->linedata,
new_hsize + sy, sizeof *dg->linedata);
memset(&dg->linedata[old_hsize + sy - collected], 0,
(new_hsize - kept) * sizeof *dg->linedata);
}
/*
* Set hsize before copying so grid_duplicate_lines does not
* clamp the count to the old, smaller grid size.
*/
dg->hsize = new_hsize;
/* Copy the newly scrolled history, then refresh the viewport. */
if (added > 0)
grid_duplicate_lines(dg, kept, sg, kept, added);
grid_duplicate_lines(dg, new_hsize, sg, new_hsize, sy);
}
dg->hscrolled = sg->hscrolled;
/* Match clone_screen's backing cursor placement. */
if (src->cy > dg->sy - 1) {
dst->cx = 0;
dst->cy = dg->sy - 1;
} else {
dst->cx = src->cx;
dst->cy = src->cy;
}
return (1);
}
static struct window_copy_mode_data *
window_copy_common_init(struct window_mode_entry *wme)
{
@@ -458,6 +581,7 @@ window_copy_common_init(struct window_mode_entry *wme)
data->modekeys = options_get_number(wp->window->options, "mode-keys");
evtimer_set(&data->dragtimer, window_copy_scroll_timer, wme);
evtimer_set(&data->refresh_timer, window_copy_refresh_timer, wme);
return (data);
}
@@ -475,6 +599,7 @@ window_copy_init(struct window_mode_entry *wme,
data = window_copy_common_init(wme);
data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy,
wme->swp != wme->wp);
window_copy_sync_snapshot(data, base->grid);
data->cx = cx;
if (cy < screen_hsize(data->backing)) {
@@ -541,6 +666,7 @@ window_copy_free(struct window_mode_entry *wme)
struct window_copy_mode_data *data = wme->data;
evtimer_del(&data->dragtimer);
evtimer_del(&data->refresh_timer);
free(data->searchmark);
free(data->searchstr);
@@ -567,13 +693,8 @@ window_copy_add(struct window_pane *wp, int parse, const char *fmt, ...)
static void
window_copy_init_ctx_cb(__unused struct screen_write_ctx *ctx,
struct tty_ctx *ttyctx)
__unused struct tty_ctx *ttyctx)
{
memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults);
ttyctx->palette = NULL;
ttyctx->redraw_cb = NULL;
ttyctx->set_client_cb = NULL;
ttyctx->arg = NULL;
}
void
@@ -2786,34 +2907,136 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
return (action);
}
static enum window_copy_cmd_action
window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
/*
* Reconcile the backing screen with the live pane, incrementally if possible
* and otherwise by recloning, then reposition the view. When following, jump
* to the bottom so new output stays visible; otherwise keep the same lines on
* screen. Driven by the automatic refresh timer.
*/
static void
window_copy_do_refresh(struct window_mode_entry *wme, int follow)
{
struct window_mode_entry *wme = cs->wme;
struct window_pane *wp = wme->swp;
struct window_copy_mode_data *data = wme->data;
u_int oy_from_top;
if (data->viewmode)
return (WINDOW_COPY_CMD_NOTHING);
if (data->oy > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
oy_from_top = screen_hsize(data->backing) - data->oy;
screen_free(data->backing);
free(data->backing);
data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
NULL, wme->swp != wme->wp);
if (!window_copy_sync_backing(wme)) {
screen_free(data->backing);
free(data->backing);
data->backing = window_copy_clone_screen(&wp->base,
&data->screen, NULL, NULL, wme->swp != wme->wp);
}
if (oy_from_top <= screen_hsize(data->backing))
if (follow) {
data->cy = screen_size_y(&data->screen) - 1;
data->cx = window_copy_cursor_limit(wme,
screen_hsize(data->backing) + data->cy, 0);
data->oy = 0;
} else if (oy_from_top <= screen_hsize(data->backing))
data->oy = screen_hsize(data->backing) - oy_from_top;
else {
data->cy = 0;
data->oy = screen_hsize(data->backing);
}
window_copy_sync_snapshot(data, wp->base.grid);
window_copy_size_changed(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
static void
window_copy_refresh_arm(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
struct timeval tv = {
.tv_sec = WINDOW_COPY_REFRESH_INTERVAL / 1000000,
.tv_usec = WINDOW_COPY_REFRESH_INTERVAL % 1000000
};
if (data->refresh_active)
evtimer_add(&data->refresh_timer, &tv);
}
static void
window_copy_refresh_timer(__unused int fd, __unused short events, void *arg)
{
struct window_mode_entry *wme = arg;
struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
int follow;
if (TAILQ_FIRST(&wp->modes) != wme || !data->refresh_active)
return;
/*
* Skip the refresh while a selection is being made, otherwise it would
* move; only follow new output if the cursor is still at the bottom.
*/
if ((wp->flags & PANE_UNSEENCHANGES) && data->screen.sel == NULL &&
data->cursordrag == CURSORDRAG_NONE) {
follow = (data->oy == 0 &&
data->cy == screen_size_y(&data->screen) - 1);
window_copy_do_refresh(wme, follow);
window_copy_redraw_screen(wme);
/* The timer runs outside key handling, so force a repaint. */
wp->flags |= PANE_REDRAW;
wp->flags &= ~PANE_UNSEENCHANGES;
}
window_copy_refresh_arm(wme);
}
static void
window_copy_refresh_start(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
/*
* Do not refresh a view of another pane (copy-mode -s): the source may
* disappear and changes are not tracked on this pane.
*/
if (data->viewmode || wme->swp != wme->wp || data->refresh_active)
return;
data->refresh_active = 1;
window_copy_refresh_arm(wme);
}
static void
window_copy_refresh_stop(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
data->refresh_active = 0;
evtimer_del(&data->refresh_timer);
}
static enum window_copy_cmd_action
window_copy_cmd_refresh_on(struct window_copy_cmd_state *cs)
{
window_copy_refresh_start(cs->wme);
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_refresh_off(struct window_copy_cmd_state *cs)
{
window_copy_refresh_stop(cs->wme);
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_refresh_toggle(struct window_copy_cmd_state *cs)
{
struct window_copy_mode_data *data = cs->wme->data;
if (data->refresh_active)
window_copy_refresh_stop(cs->wme);
else
window_copy_refresh_start(cs->wme);
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
@@ -3280,11 +3503,23 @@ static const struct {
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_rectangle_toggle
},
{ .command = "refresh-from-pane",
{ .command = "refresh-on",
.args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_refresh_from_pane
.clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_refresh_on
},
{ .command = "refresh-off",
.args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_refresh_off
},
{ .command = "refresh-toggle",
.args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_refresh_toggle
},
{ .command = "scroll-bottom",
.args = { "", 0, 0, NULL },

View File

@@ -386,7 +386,7 @@ window_pane_destroy_ready(struct window_pane *wp)
* If a command queue item is blocked on this pane, wait for the
* child's exit status before destroying it.
*/
if (wp->block_item != NULL && (~wp->flags & PANE_STATUSREADY))
if (wp->wait_item != NULL && (~wp->flags & PANE_STATUSREADY))
return (0);
return (1);
}
@@ -1123,15 +1123,15 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
}
void
window_pane_block_finish(struct window_pane *wp)
window_pane_wait_finish(struct window_pane *wp)
{
struct cmdq_item *item = wp->block_item;
struct cmdq_item *item = wp->wait_item;
struct client *c;
int retval = 0;
if (item == NULL)
return;
wp->block_item = NULL;
wp->wait_item = NULL;
if (wp->flags & PANE_STATUSREADY) {
if (WIFEXITED(wp->status))
@@ -1152,7 +1152,7 @@ window_pane_destroy(struct window_pane *wp)
struct window_pane_resize *r;
struct window_pane_resize *r1;
window_pane_block_finish(wp);
window_pane_wait_finish(wp);
window_pane_reset_mode_all(wp);
free(wp->searchstr);