diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 56e13333..eee9a7de 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -48,6 +48,16 @@ struct cmd_display_panes_data { struct args_command_state *state; }; +struct cmd_display_panes_ctx { + struct client *c; + int ox; + int oy; + u_int sx; + u_int sy; + u_int statuslines; + int statustop; +}; + static enum args_parse_type cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx, __unused char **cause) @@ -56,7 +66,7 @@ cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx, } static void -cmd_display_panes_put(struct screen_redraw_ctx *ctx, +cmd_display_panes_put(struct cmd_display_panes_ctx *ctx, struct window_pane *wp, u_int cx, u_int cy, const char *buf, size_t len) { struct client *c = ctx->c; @@ -76,7 +86,7 @@ cmd_display_panes_put(struct screen_redraw_ctx *ctx, } static void -cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx, +cmd_display_panes_draw_format(struct cmd_display_panes_ctx *ctx, struct window_pane *wp, u_int xoff, u_int yoff, u_int sx, const struct grid_cell *gc) { @@ -112,7 +122,7 @@ cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx, } static void -cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx, +cmd_display_panes_draw_pane(struct cmd_display_panes_ctx *ctx, struct window_pane *wp) { struct client *c = ctx->c; @@ -254,17 +264,26 @@ out: } static void -cmd_display_panes_draw(struct client *c, __unused void *data, - struct screen_redraw_ctx *ctx) +cmd_display_panes_draw(struct client *c, __unused void *data) { - struct window *w = c->session->curw->window; - struct window_pane *wp; + struct session *s = c->session; + struct window *w = s->curw->window; + struct window_pane *wp; + struct cmd_display_panes_ctx ctx; log_debug("%s: %s @%u", __func__, c->name, w->id); + memset(&ctx, 0, sizeof ctx); + ctx.c = c; + tty_window_offset(&c->tty, &ctx.ox, &ctx.oy, &ctx.sx, &ctx.sy); + if (options_get_number(s->options, "status-position") == 0) { + ctx.statuslines = status_line_size(c); + ctx.statustop = 1; + } + TAILQ_FOREACH(wp, &w->panes, entry) { if (window_pane_is_visible(wp)) - cmd_display_panes_draw_pane(ctx, wp); + cmd_display_panes_draw_pane(&ctx, wp); } } diff --git a/menu.c b/menu.c index 98d441fe..dcf0e1ff 100644 --- a/menu.c +++ b/menu.c @@ -257,8 +257,7 @@ menu_reapply_styles(struct menu_data *md, struct client *c) } void -menu_draw_cb(struct client *c, void *data, - __unused struct screen_redraw_ctx *rctx) +menu_draw_cb(struct client *c, void *data) { struct menu_data *md = data; struct tty *tty = &c->tty; diff --git a/popup.c b/popup.c index 999e4066..dc7f2fce 100644 --- a/popup.c +++ b/popup.c @@ -288,7 +288,7 @@ popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx) } static void -popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) +popup_draw_cb(struct client *c, void *data) { struct popup_data *pd = data; struct tty *tty = &c->tty; @@ -342,7 +342,7 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) if (pd->md != NULL) { c->overlay_check = NULL; c->overlay_data = NULL; - menu_draw_cb(c, pd->md, rctx); + menu_draw_cb(c, pd->md); } c->overlay_check = popup_check_cb; c->overlay_data = pd; diff --git a/screen-redraw.c b/screen-redraw.c index 3b731f97..562b2490 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -47,11 +47,13 @@ enum redraw_span_type { #define REDRAW_SCROLLBAR_RIGHT 0x4 /* Draw operations. */ -#define REDRAW_DRAW_PANE 0x1 -#define REDRAW_DRAW_BORDER 0x2 -#define REDRAW_DRAW_STATUS 0x4 -#define REDRAW_DRAW_SCROLLBAR 0x8 -#define REDRAW_DRAW_ALL 0xff +#define REDRAW_ALL 0x1 +#define REDRAW_PANE 0x2 +#define REDRAW_PANE_BORDER 0x4 +#define REDRAW_PANE_STATUS 0x8 +#define REDRAW_PANE_SCROLLBAR 0x10 +#define REDRAW_STATUS 0x20 +#define REDRAW_OVERLAY 0x40 /* UTF-8 isolate characters. */ #define REDRAW_START_ISOLATE "\342\201\246" @@ -183,9 +185,9 @@ struct redraw_draw_ctx { struct grid_cell default_gc; int flags; -#define REDRAW_DRAW_ISOLATES 0x1 -#define REDRAW_DRAW_DEFAULT_SET 0x2 -#define REDRAW_DRAW_STATUS_TOP 0x4 +#define REDRAW_ISOLATES 0x1 +#define REDRAW_DEFAULT_SET 0x2 +#define REDRAW_STATUS_TOP 0x4 }; /* Initialize the context for building scene. */ @@ -894,8 +896,6 @@ screen_redraw_draw_pane_span(struct redraw_draw_ctx *dctx, struct tty_style_ctx style_ctx; u_int px, py; - //XXX sync? - tty_default_colours(&defaults, wp); style_ctx.defaults = &defaults; style_ctx.palette = &wp->palette; @@ -917,12 +917,12 @@ screen_redraw_draw_get_default_style(struct redraw_draw_ctx *dctx, struct format_tree *ft; struct grid_cell *dgc = &dctx->default_gc; - if (~dctx->flags & REDRAW_DRAW_DEFAULT_SET) { + if (~dctx->flags & REDRAW_DEFAULT_SET) { ft = format_create_defaults(NULL, c, s, s->curw, NULL); memcpy(dgc, &grid_default_cell, sizeof *dgc); style_add(dgc, scene->w->options, "pane-border-style", ft); format_free(ft); - dctx->flags |= REDRAW_DRAW_DEFAULT_SET; + dctx->flags |= REDRAW_DEFAULT_SET; } memcpy(gc, dgc, sizeof *gc); } @@ -1019,7 +1019,7 @@ screen_redraw_draw_border_span(struct redraw_draw_ctx *dctx, gc.attr ^= GRID_ATTR_REVERSE; screen_redraw_draw_border_arrow(dctx, span, &gc); - if (cell_type == CELL_TOPBOTTOM && (dctx->flags & REDRAW_DRAW_ISOLATES)) + if (cell_type == CELL_TOPBOTTOM && (dctx->flags & REDRAW_ISOLATES)) isolates = 1; tty_cursor(tty, x, y); if (isolates) @@ -1139,6 +1139,10 @@ screen_redraw_draw_span(struct redraw_draw_ctx *dctx, struct redraw_span *span, struct visible_range *rr; u_int i, x, n; + if (span->data.type == REDRAW_SPAN_STATUS && + (~span->data.st.wp->flags & PANE_STATUSDIRTY)) + return; + r = tty_check_overlay_range(tty, span->x, y, span->width); for (i = 0; i < r->used; i++) { rr = &r->ranges[i]; @@ -1190,15 +1194,18 @@ screen_redraw_draw_pane_lines(struct redraw_draw_ctx *dctx, for (y = top; y < bottom; y++) { line = &scene->lines[y]; - cy = dctx->status_lines + y; - if (flags & REDRAW_DRAW_PANE) { + if (dctx->flags & REDRAW_STATUS_TOP) + cy = dctx->status_lines + y; + else + cy = y; + if (flags & REDRAW_PANE) { spans = &line->spans[REDRAW_SPAN_PANE]; TAILQ_FOREACH(span, spans, entry) { if (span->data.p.wp == wp) screen_redraw_draw_span(dctx, span, cy); } } - if (flags & REDRAW_DRAW_SCROLLBAR) { + if (flags & REDRAW_PANE_SCROLLBAR) { spans = &line->spans[REDRAW_SPAN_SCROLLBAR]; TAILQ_FOREACH(span, spans, entry) { if (span->data.sb.wp == wp) @@ -1220,24 +1227,27 @@ screen_redraw_draw_lines(struct redraw_draw_ctx *dctx, int flags) for (y = 0; y < scene->sy; y++) { line = &scene->lines[y]; - cy = dctx->status_lines + y; + if (dctx->flags & REDRAW_STATUS_TOP) + cy = dctx->status_lines + y; + else + cy = y; for (type = 0; type < REDRAW_SPAN_TYPES; type++) { - if (flags != REDRAW_DRAW_ALL) { + if (~flags & REDRAW_ALL) { switch (type) { case REDRAW_SPAN_PANE: - if (~flags & REDRAW_DRAW_PANE) + if (~flags & REDRAW_PANE) continue; break; case REDRAW_SPAN_BORDER: - if (~flags & REDRAW_DRAW_BORDER) + if (~flags & REDRAW_PANE_BORDER) continue; break; case REDRAW_SPAN_STATUS: - if (~flags & REDRAW_DRAW_STATUS) + if (~flags & REDRAW_PANE_STATUS) continue; break; case REDRAW_SPAN_SCROLLBAR: - if (~flags & REDRAW_DRAW_SCROLLBAR) + if (~flags & REDRAW_PANE_SCROLLBAR) continue; break; default: @@ -1307,7 +1317,9 @@ screen_redraw_set_draw_context(struct redraw_draw_ctx *dctx, { struct client *c = scene->c; struct session *s = c->session; + struct options *oo = s->options; struct tty *tty = &c->tty; + u_int lines; memset(dctx, 0, sizeof *dctx); dctx->scene = scene; @@ -1316,14 +1328,13 @@ screen_redraw_set_draw_context(struct redraw_draw_ctx *dctx, dctx->marked = marked_pane.wp; dctx->active = server_client_get_pane(c); - if (options_get_number(s->options, "status-position") == 0) { - dctx->status_lines = status_line_size(c); - if (dctx->status_lines != 0) - dctx->flags |= REDRAW_DRAW_STATUS_TOP; - } + lines = status_line_size(c); + if (lines != 0 && options_get_number(oo, "status-position") == 0) + dctx->flags |= REDRAW_STATUS_TOP; + dctx->status_lines = lines; if ((c->flags & CLIENT_UTF8) && tty_term_has(tty->term, TTYC_BIDI)) - dctx->flags |= REDRAW_DRAW_ISOLATES; + dctx->flags |= REDRAW_ISOLATES; } /* Draw scene to client. */ @@ -1332,10 +1343,12 @@ screen_redraw_draw(struct client *c, struct window_pane *wp, int flags) { struct redraw_draw_ctx dctx; struct tty *tty = &c->tty; + struct screen *sl = c->status.active; struct redraw_scene *scene; struct window_pane *loop; - u_int width; + u_int width, i, y; struct redraw_span *first; + int redraw; if (c->flags & CLIENT_SUSPENDED) return; @@ -1345,24 +1358,54 @@ screen_redraw_draw(struct client *c, struct window_pane *wp, int flags) return; screen_redraw_set_draw_context(&dctx, scene); - if (flags == REDRAW_DRAW_ALL || (flags & REDRAW_DRAW_STATUS)) { + if (flags & (REDRAW_ALL|REDRAW_STATUS|REDRAW_PANE_STATUS)) { + if (c->message_string != NULL) + redraw = status_message_redraw(c); + else if (c->prompt_string != NULL) + redraw = status_prompt_redraw(c); + else + redraw = status_redraw(c); + if (!redraw) + flags &= ~REDRAW_STATUS; + + redraw = 0; TAILQ_FOREACH(loop, &scene->w->panes, entry) { + loop->flags &= ~PANE_STATUSDIRTY; + width = screen_redraw_pane_status_width(&dctx, loop, &first); - if (width != 0) - window_make_pane_status(loop, c, width, first); + if (width == 0) + continue; + + if (window_make_pane_status(loop, c, width, first)) { + loop->flags |= PANE_STATUSDIRTY; + redraw = 1; + } } + if (!redraw) + flags &= ~REDRAW_PANE_STATUS; } - if (flags == REDRAW_DRAW_ALL || - (flags & REDRAW_DRAW_BORDER) || - (flags & REDRAW_DRAW_STATUS)) { + if (flags & (REDRAW_ALL|REDRAW_PANE_BORDER|REDRAW_PANE_STATUS)) { TAILQ_FOREACH(loop, &scene->w->panes, entry) { loop->border_gc_set = 0; loop->active_border_gc_set = 0; } } + if (flags & (REDRAW_ALL|REDRAW_PANE)) { + if (wp != NULL) { + if (wp->base.mode & MODE_SYNC) + screen_write_stop_sync(wp); + } else { + TAILQ_FOREACH(loop, &scene->w->panes, entry) { + if (!window_pane_is_visible(loop)) + continue; + if (loop->base.mode & MODE_SYNC) + screen_write_stop_sync(loop); + } + } + } tty_sync_start(tty); tty_update_mode(tty, 0, NULL); @@ -1371,6 +1414,20 @@ screen_redraw_draw(struct client *c, struct window_pane *wp, int flags) else screen_redraw_draw_lines(&dctx, flags); + if (c->overlay_draw != NULL && + (flags & (REDRAW_ALL|REDRAW_OVERLAY))) + c->overlay_draw(c, c->overlay_data); + + + if (flags & (REDRAW_ALL|REDRAW_STATUS)) { + if (dctx.flags & REDRAW_STATUS_TOP) + y = 0; + else + y = c->tty.sy - dctx.status_lines; + for (i = 0; i < dctx.status_lines; i++) + tty_draw_line(tty, sl, 0, i, UINT_MAX, 0, y + i, NULL); + } + tty_reset(tty); tty_sync_end(tty); @@ -1410,39 +1467,29 @@ screen_redraw_screen(struct client *c) int flags = 0; if (c->flags & CLIENT_REDRAWWINDOW) - screen_redraw_draw(c, NULL, REDRAW_DRAW_ALL); + screen_redraw_draw(c, NULL, REDRAW_ALL); else { if (c->flags & CLIENT_REDRAWBORDERS) - flags |= (REDRAW_DRAW_BORDER|REDRAW_DRAW_STATUS); + flags |= (REDRAW_PANE_BORDER|REDRAW_PANE_STATUS); if (c->flags & CLIENT_REDRAWSTATUS) - flags |= REDRAW_DRAW_STATUS; + flags |= (REDRAW_STATUS|REDRAW_PANE_STATUS); + if (c->flags & CLIENT_REDRAWOVERLAY) + flags |= REDRAW_OVERLAY; if (flags != 0) screen_redraw_draw(c, NULL, flags); } - -#if 0 //XXX - if (ctx.statuslines != 0 && - (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) { - log_debug("%s: redrawing status", c->name); - screen_redraw_draw_status(&ctx); - } - if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) { - log_debug("%s: redrawing overlay", c->name); - c->overlay_draw(c, c->overlay_data, &ctx); - } -#endif } /* Draw a single pane. */ void screen_redraw_pane(struct client *c, struct window_pane *wp) { - screen_redraw_draw(c, wp, REDRAW_DRAW_PANE|REDRAW_DRAW_SCROLLBAR); + screen_redraw_draw(c, wp, REDRAW_PANE|REDRAW_PANE_SCROLLBAR); } /* Draw a pane's scrollbar. */ void screen_redraw_pane_scrollbar(struct client *c, struct window_pane *wp) { - screen_redraw_draw(c, wp, REDRAW_DRAW_SCROLLBAR); + screen_redraw_draw(c, wp, REDRAW_PANE_SCROLLBAR); } diff --git a/tmux.h b/tmux.h index fcf45f98..dfd8bd9d 100644 --- a/tmux.h +++ b/tmux.h @@ -1113,24 +1113,6 @@ enum pane_lines { #define WINDOW_PANE_COPY_MODE 1 #define WINDOW_PANE_VIEW_MODE 2 -/* Screen redraw context. */ -struct screen_redraw_ctx { - struct client *c; - - u_int statuslines; - int statustop; - - enum pane_lines pane_lines; - - int pane_scrollbars; - int pane_scrollbars_pos; - - u_int sx; - u_int sy; - int ox; - int oy; -}; - /* Screen size. */ #define screen_size_x(s) ((s)->grid->sx) #define screen_size_y(s) ((s)->grid->sy) @@ -1281,7 +1263,7 @@ struct window_pane { #define PANE_FOCUSED 0x4 #define PANE_VISITED 0x8 #define PANE_ZOOMED 0x10 -/* 0x20 unused */ +#define PANE_STATUSDIRTY 0x20 #define PANE_INPUTOFF 0x40 #define PANE_CHANGED 0x80 #define PANE_EXITED 0x100 @@ -2041,12 +2023,11 @@ RB_HEAD(client_windows, client_window); /* Client connection. */ typedef int (*prompt_input_cb)(struct client *, void *, const char *, int); typedef void (*prompt_free_cb)(void *); -typedef struct visible_ranges *(*overlay_check_cb)(struct client*, void *, +typedef struct visible_ranges *(*overlay_check_cb)(struct client *, void *, u_int, u_int, u_int); typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *, u_int *); -typedef void (*overlay_draw_cb)(struct client *, void *, - struct screen_redraw_ctx *); +typedef void (*overlay_draw_cb)(struct client *, void *); typedef int (*overlay_key_cb)(struct client *, void *, struct key_event *); typedef void (*overlay_free_cb)(struct client *, void *); typedef void (*overlay_resize_cb)(struct client *, void *); @@ -3541,7 +3522,7 @@ void window_pane_get_border_cell(struct window_pane *, int, struct grid_cell *); void window_pane_get_border_style(struct window_pane *, struct client *, struct grid_cell *); -void window_make_pane_status(struct window_pane *, struct client *, +int window_make_pane_status(struct window_pane *, struct client *, u_int, struct redraw_span *); /* window-visible.c */ @@ -3839,8 +3820,7 @@ int menu_display(struct menu *, int, int, struct cmdq_item *, struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *); struct visible_ranges *menu_check_cb(struct client *, void *, u_int, u_int, u_int); -void menu_draw_cb(struct client *, void *, - struct screen_redraw_ctx *); +void menu_draw_cb(struct client *, void *); void menu_free_cb(struct client *, void *); int menu_key_cb(struct client *, void *, struct key_event *); diff --git a/window-border.c b/window-border.c index 8d2238da..fd0a8321 100644 --- a/window-border.c +++ b/window-border.c @@ -112,7 +112,7 @@ window_pane_get_border_style(struct window_pane *wp, struct client *c, } /* Build pane status line. */ -void +int window_make_pane_status(struct window_pane *wp, struct client *c, u_int width, struct redraw_span *span) { @@ -121,6 +121,7 @@ window_make_pane_status(struct window_pane *wp, struct client *c, u_int width, struct format_tree *ft; struct style_line_entry *sle = &wp->border_status_line; struct screen_write_ctx ctx; + struct screen old; char *expanded; u_int i; int pane_status, cell_type; @@ -132,7 +133,6 @@ window_make_pane_status(struct window_pane *wp, struct client *c, u_int width, ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS); format_defaults(ft, c, c->session, c->session->curw, wp); - fmt = options_get_string(wp->options, "pane-border-format"); expanded = format_expand_time(ft, fmt); @@ -140,6 +140,7 @@ window_make_pane_status(struct window_pane *wp, struct client *c, u_int width, screen_init(&wp->status_screen, width, 1, 0); wp->status_screen.mode = 0; + memcpy(&old, &wp->status_screen, sizeof old); screen_write_start(&ctx, &wp->status_screen); window_pane_get_border_style(wp, c, &gc); @@ -159,4 +160,11 @@ window_make_pane_status(struct window_pane *wp, struct client *c, u_int width, free(sle->expanded); sle->expanded = expanded; + + if (grid_compare(wp->status_screen.grid, old.grid) == 0) { + screen_free(&old); + return (0); + } + screen_free(&old); + return (1); }