/* * Redraw scroll region using data from screen (already updated). Used when * CSR not supported, or window is a pane that doesn't take up the full * width of the terminal. */ void tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i; /* * If region is >= 50% of the screen, just schedule a window redraw. In * most cases, this is likely to be followed by some more scrolling - * without this, the entire pane ends up being redrawn many times which * can be much more data. */ if (ctx->orlower - ctx->orupper >= screen_size_y(s) / 2) { wp->flags |= PANE_REDRAW; return; } if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) { for (i = ctx->ocy; i < screen_size_y(s); i++) tty_draw_line(tty, s, i, wp->xoff, wp->yoff); } else { for (i = ctx->orupper; i <= ctx->orlower; i++) tty_draw_line(tty, s, i, wp->xoff, wp->yoff); } }
void tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i, j; tty_reset(tty); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i != screen_size_y(s) - 1) { tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); tty->cy++; } } } else { for (j = 0; j < screen_size_y(s); j++) { tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } } }
void tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i, j; tty_reset(tty); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { tty_putcode(tty, TTYC_EL); if (ctx->ocy != screen_size_y(s) - 1) { tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); for (i = ctx->ocy + 1; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i == screen_size_y(s) - 1) continue; tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); tty->cy++; } } } else { tty_repeat_space(tty, screen_size_x(s) - ctx->ocx); for (j = ctx->ocy + 1; j < screen_size_y(s); j++) { tty_cursor_pane(tty, ctx, 0, j); tty_repeat_space(tty, screen_size_x(s)); } } }
void window_more_key(struct window_pane *wp, unused struct client *c, int key) { struct window_more_mode_data *data = wp->modedata; struct screen *s = &data->screen; switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCHOICE_CANCEL: window_pane_reset_mode(wp); break; case MODEKEYCHOICE_UP: window_more_scroll_up(wp); break; case MODEKEYCHOICE_DOWN: window_more_scroll_down(wp); break; case MODEKEYCHOICE_PAGEUP: if (data->top < screen_size_y(s)) data->top = 0; else data->top -= screen_size_y(s); window_more_redraw_screen(wp); break; case MODEKEYCHOICE_PAGEDOWN: if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list)) data->top = ARRAY_LENGTH(&data->list); else data->top += screen_size_y(s); window_more_redraw_screen(wp); break; default: break; } }
/* Initialize writing with a window. */ void screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s) { u_int size; char tmp[16]; const char *cp = tmp; ctx->wp = wp; if (wp != NULL && s == NULL) ctx->s = wp->screen; else ctx->s = s; size = screen_size_x(ctx->s) * screen_size_y(ctx->s); if (ctx->s->dirtysize != size) { free(ctx->s->dirty); ctx->s->dirty = NULL; ctx->s->dirtysize = size; } ctx->dirty = 0; ctx->cells = ctx->written = ctx->skipped = 0; if (wp == NULL) cp = "no pane"; else snprintf(tmp, sizeof tmp, "pane %%%u", wp->id); log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s), screen_size_y(ctx->s), cp); }
/* VT100 alignment test. */ void screen_write_alignmenttest(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; struct tty_ctx ttyctx; struct grid_cell gc; u_int xx, yy; u_int sx = screen_size_x(s), sy = screen_size_y(s); screen_write_initctx(ctx, &ttyctx); screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); memcpy(&gc, &grid_default_cell, sizeof gc); utf8_set(&gc.data, 'E'); for (yy = 0; yy < screen_size_y(s); yy++) { for (xx = 0; xx < screen_size_x(s); xx++) grid_view_set_cell(s->grid, xx, yy, &gc); } s->cx = 0; s->cy = 0; s->rupper = 0; s->rlower = screen_size_y(s) - 1; tty_write(tty_cmd_alignmenttest, &ttyctx); }
/* VT100 alignment test. */ void screen_write_alignmenttest(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; struct tty_ctx ttyctx; struct grid_cell gc; u_int xx, yy; screen_write_initctx(ctx, &ttyctx, 0); memcpy(&gc, &grid_default_cell, sizeof gc); grid_cell_one(&gc, 'E'); for (yy = 0; yy < screen_size_y(s); yy++) { for (xx = 0; xx < screen_size_x(s); xx++) grid_view_set_cell(s->grid, xx, yy, &gc); } s->cx = 0; s->cy = 0; s->rupper = 0; s->rlower = screen_size_y(s) - 1; tty_write(tty_cmd_alignmenttest, &ttyctx); }
void tty_cmd_clearscreen( struct tty *tty, struct window_pane *wp, unused va_list ap) { struct screen *s = wp->screen; u_int i, j; tty_reset(tty); tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); tty_cursor(tty, 0, 0, wp->xoff, wp->yoff); if (wp->xoff == 0 && screen_size_x(s) >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i != screen_size_y(s) - 1) { tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); tty->cy++; } } } else { for (j = 0; j < screen_size_y(s); j++) { tty_cursor(tty, 0, j, wp->xoff, wp->yoff); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, ' '); } } }
int window_copy_update_selection(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct options *oo = &wp->window->options; struct grid_cell gc; u_int sx, sy, ty, cy; if (!s->sel.flag) return (0); /* Set colours. */ memcpy(&gc, &grid_default_cell, sizeof gc); colour_set_fg(&gc, options_get_number(oo, "mode-fg")); colour_set_bg(&gc, options_get_number(oo, "mode-bg")); gc.attr |= options_get_number(oo, "mode-attr"); /* Find top of screen. */ ty = screen_hsize(&wp->base) - data->oy; /* Adjust the selection. */ sx = data->selx; sy = data->sely; if (sy < ty) { /* above screen */ if (!data->rectflag) sx = 0; sy = 0; } else if (sy > ty + screen_size_y(s) - 1) { /* below screen */ if (!data->rectflag) sx = screen_size_x(s) - 1; sy = screen_size_y(s) - 1; } else sy -= ty; sy = screen_hsize(s) + sy; screen_set_selection(s, sx, sy, data->cx, screen_hsize(s) + data->cy, data->rectflag, &gc); if (data->rectflag) { /* * Can't rely on the caller to redraw the right lines for * rectangle selection - find the highest line and the number * of lines, and redraw just past that in both directions */ cy = data->cy; if (sy < cy) window_copy_redraw_lines(wp, sy, cy - sy + 1); else window_copy_redraw_lines(wp, cy, sy - cy + 1); } return (1); }
struct screen * window_copy_init(struct window_pane *wp) { struct window_copy_mode_data *data; struct screen *s; struct screen_write_ctx ctx; u_int i; int keys; wp->modedata = data = xmalloc(sizeof *data); data->oy = 0; data->cx = wp->base.cx; data->cy = wp->base.cy; data->lastcx = 0; data->lastsx = 0; data->rectflag = 0; data->inputtype = WINDOW_COPY_OFF; data->inputprompt = NULL; data->inputstr = xstrdup(""); data->numprefix = 0; data->searchtype = WINDOW_COPY_OFF; data->searchstr = NULL; wp->flags |= PANE_FREEZE; bufferevent_disable(wp->event, EV_READ|EV_WRITE); s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); if (options_get_number(&wp->window->options, "mode-mouse")) s->mode |= MODE_MOUSE; keys = options_get_number(&wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); else mode_key_init(&data->mdata, &mode_key_tree_vi_copy); s->cx = data->cx; s->cy = data->cy; screen_write_start(&ctx, NULL, s); for (i = 0; i < screen_size_y(s); i++) window_copy_write_line(wp, &ctx, i); screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); return (s); }
/* Move cursor to px,py. */ void screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) { struct screen *s = ctx->s; if (px > screen_size_x(s) - 1) px = screen_size_x(s) - 1; if (py > screen_size_y(s) - 1) py = screen_size_y(s) - 1; s->cx = px; s->cy = py; }
void window_copy_scroll_down(struct window_pane *wp, u_int ny) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct screen_write_ctx ctx; if (ny > screen_hsize(&wp->base)) return; if (data->oy > screen_hsize(&wp->base) - ny) ny = screen_hsize(&wp->base) - data->oy; if (ny == 0) return; data->oy += ny; screen_write_start(&ctx, wp, NULL); screen_write_cursormove(&ctx, 0, 0); screen_write_insertline(&ctx, ny); window_copy_write_lines(wp, &ctx, 0, ny); if (s->sel.flag && screen_size_y(s) > ny) { window_copy_update_selection(wp); window_copy_write_line(wp, &ctx, ny); } else if (ny == 1) /* nuke position */ window_copy_write_line(wp, &ctx, 1); screen_write_cursormove(&ctx, data->cx, data->cy); window_copy_update_selection(wp); screen_write_stop(&ctx); }
/* Resize screen. */ void screen_resize(struct screen *s, u_int sx, u_int sy, int reflow) { if (sx < 1) sx = 1; if (sy < 1) sy = 1; if (sx != screen_size_x(s)) { screen_resize_x(s, sx); /* * It is unclear what should happen to tabs on resize. xterm * seems to try and maintain them, rxvt resets them. Resetting * is simpler and more reliable so let's do that. */ screen_reset_tabs(s); } if (sy != screen_size_y(s)) screen_resize_y(s, sy); if (reflow) screen_reflow(s, sx); }
/* Line feed. */ void screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) { struct screen *s = ctx->s; struct grid_line *gl; struct tty_ctx ttyctx; u_int sx = screen_size_x(s), sy = screen_size_y(s); screen_write_initctx(ctx, &ttyctx); gl = &s->grid->linedata[s->grid->hsize + s->cy]; if (wrapped) gl->flags |= GRID_LINE_WRAPPED; else gl->flags &= ~GRID_LINE_WRAPPED; if (s->cy == s->rlower) { screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper); screen_write_flush(ctx); grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); } else if (s->cy < sy - 1) s->cy++; ttyctx.num = wrapped; tty_write(tty_cmd_linefeed, &ttyctx); }
void window_copy_redraw_screen(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; window_copy_redraw_lines(wp, 0, screen_size_y(&data->screen)); }
/* * Is the region large enough to be worth redrawing once later rather than * probably several times now? Currently yes if it is more than 50% of the * pane. */ int tty_large_region(unused struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; return (ctx->orlower - ctx->orupper >= screen_size_y(wp->screen) / 2); }
void window_copy_cursor_down(struct window_pane *wp, int scroll_only) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int ox, oy, px, py; oy = screen_hsize(&wp->base) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); if (ox != 0) { data->lastcx = data->cx; data->lastsx = ox; } data->cx = data->lastcx; if (scroll_only || data->cy == screen_size_y(s) - 1) { window_copy_scroll_up(wp, 1); if (scroll_only && data->cy > 0) window_copy_redraw_lines(wp, data->cy - 1, 2); } else { window_copy_update_cursor(wp, data->cx, data->cy + 1); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy - 1, 2); } if (!data->screen.sel.flag || !data->rectflag) { py = screen_hsize(&wp->base) + data->cy - data->oy; px = window_copy_find_length(wp, py); if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) window_copy_cursor_end_of_line(wp); } }
void tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i, j; tty_reset(tty); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { for (i = 0; i < ctx->ocy; i++) { tty_putcode(tty, TTYC_EL); tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); tty->cy++; } } else { for (j = 0; j < ctx->ocy; j++) { tty_cursor_pane(tty, ctx, 0, j); tty_repeat_space(tty, screen_size_x(s)); } } tty_repeat_space(tty, ctx->ocx + 1); }
/* Clear to end of screen from cursor. */ void screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) { struct screen *s = ctx->s; struct tty_ctx ttyctx; u_int sx = screen_size_x(s), sy = screen_size_y(s); screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; /* Scroll into history if it is enabled and clearing entire screen. */ if (s->cx == 0 && s->cy == 0 && s->grid->flags & GRID_HISTORY) { screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); grid_view_clear_history(s->grid, bg); } else { if (s->cx <= sx - 1) { screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy); grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); } screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1); grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1), bg); } tty_write(tty_cmd_clearendofscreen, &ttyctx); }
void window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct screen_write_ctx ctx; screen_resize(s, sx, sy); if (data->backing != &wp->base) screen_resize(data->backing, sx, sy); if (data->cy > sy - 1) data->cy = sy - 1; if (data->cx > sx) data->cx = sx; if (data->oy > screen_hsize(data->backing)) data->oy = screen_hsize(data->backing); window_copy_clear_selection(wp); screen_write_start(&ctx, NULL, s); window_copy_write_lines(wp, &ctx, 0, screen_size_y(s) - 1); screen_write_stop(&ctx); window_copy_redraw_screen(wp); }
void tty_cmd_alignmenttest( struct tty *tty, struct window_pane *wp, unused va_list ap) { struct screen *s = wp->screen; u_int i, j; tty_reset(tty); tty_region(tty, 0, screen_size_y(s) - 1, wp->yoff); for (j = 0; j < screen_size_y(s); j++) { tty_cursor(tty, 0, j, wp->xoff, wp->yoff); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, 'E'); } }
void tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; u_int i, j; tty_reset(tty); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); for (j = 0; j < screen_size_y(s); j++) { tty_cursor_pane(tty, ctx, 0, j); for (i = 0; i < screen_size_x(s); i++) tty_putc(tty, 'E'); } }
void window_copy_pageup(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int n; n = 1; if (screen_size_y(s) > 2) n = screen_size_y(s) - 2; if (data->oy + n > screen_hsize(&wp->base)) data->oy = screen_hsize(&wp->base); else data->oy += n; window_copy_update_selection(wp); window_copy_redraw_screen(wp); }
/* Delete ny lines. */ void screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) { struct screen *s = ctx->s; struct tty_ctx ttyctx; if (ny == 0) ny = 1; if (s->cy < s->rupper || s->cy > s->rlower) { if (ny > screen_size_y(s) - s->cy) ny = screen_size_y(s) - s->cy; if (ny == 0) return; screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); grid_view_delete_lines(s->grid, s->cy, ny, bg); ttyctx.num = ny; ttyctx.bg = bg; tty_write(tty_cmd_deleteline, &ttyctx); return; } if (ny > s->rlower + 1 - s->cy) ny = s->rlower + 1 - s->cy; if (ny == 0) return; screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_delete_lines(s->grid, s->cy, ny, bg); else { grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny, bg); } ttyctx.num = ny; ttyctx.bg = bg; tty_write(tty_cmd_deleteline, &ttyctx); }
void window_copy_init_for_output(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; data->backing = xmalloc(sizeof *data->backing); screen_init(data->backing, screen_size_x(&wp->base), screen_size_y(&wp->base), UINT_MAX); data->backing->mode &= ~MODE_WRAP; }
/* ARGSUSED */ void window_copy_mouse( struct window_pane *wp, unused struct session *sess, struct mouse_event *m) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int i; if (m->x >= screen_size_x(s)) return; if (m->y >= screen_size_y(s)) return; /* If mouse wheel (buttons 4 and 5), scroll. */ if ((m->b & MOUSE_45)) { if ((m->b & MOUSE_BUTTON) == MOUSE_1) { for (i = 0; i < 5; i++) window_copy_cursor_up(wp, 0); } else if ((m->b & MOUSE_BUTTON) == MOUSE_2) { for (i = 0; i < 5; i++) window_copy_cursor_down(wp, 0); } return; } /* * If already reading motion, move the cursor while buttons are still * pressed, or stop the selection on their release. */ if (s->mode & MODE_MOUSE_ANY) { if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); } else { s->mode &= ~MODE_MOUSE_ANY; s->mode |= MODE_MOUSE_STANDARD; if (sess != NULL) { window_copy_copy_selection(wp); window_pane_reset_mode(wp); } } return; } /* Otherwise if other buttons pressed, start selection and motion. */ if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { s->mode &= ~MODE_MOUSE_STANDARD; s->mode |= MODE_MOUSE_ANY; window_copy_update_cursor(wp, m->x, m->y); window_copy_start_selection(wp); window_copy_redraw_screen(wp); } }
/* Set scroll region. */ void screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper, u_int rlower) { struct screen *s = ctx->s; if (rupper > screen_size_y(s) - 1) rupper = screen_size_y(s) - 1; if (rlower > screen_size_y(s) - 1) rlower = screen_size_y(s) - 1; if (rupper >= rlower) /* cannot be one line */ return; /* Cursor moves to top-left. */ s->cx = 0; s->cy = 0; s->rupper = rupper; s->rlower = rlower; }
void window_copy_scroll_up(struct window_pane *wp, u_int ny) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct screen_write_ctx ctx; if (data->oy < ny) ny = data->oy; if (ny == 0) return; data->oy -= ny; screen_write_start(&ctx, wp, NULL); screen_write_cursormove(&ctx, 0, 0); screen_write_deleteline(&ctx, ny); window_copy_write_lines(wp, &ctx, screen_size_y(s) - ny, ny); window_copy_write_line(wp, &ctx, 0); if (screen_size_y(s) > 1) window_copy_write_line(wp, &ctx, 1); if (screen_size_y(s) > 3) window_copy_write_line(wp, &ctx, screen_size_y(s) - 2); if (s->sel.flag && screen_size_y(s) > ny) { window_copy_update_selection(wp); window_copy_write_line(wp, &ctx, screen_size_y(s) - ny - 1); } screen_write_cursormove(&ctx, data->cx, data->cy); window_copy_update_selection(wp); screen_write_stop(&ctx); }
void window_more_redraw_screen(struct window_pane *wp) { struct window_more_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct screen_write_ctx ctx; u_int i; screen_write_start(&ctx, wp, NULL); for (i = 0; i < screen_size_y(s); i++) window_more_write_line(wp, &ctx, i); screen_write_stop(&ctx); }
/* Insert ny lines. */ void screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) { struct screen *s = ctx->s; struct tty_ctx ttyctx; if (ny == 0) ny = 1; if (s->cy < s->rupper || s->cy > s->rlower) { if (ny > screen_size_y(s) - s->cy) ny = screen_size_y(s) - s->cy; if (ny == 0) return; screen_write_initctx(ctx, &ttyctx, 0); grid_view_insert_lines(s->grid, s->cy, ny); ttyctx.num = ny; tty_write(tty_cmd_insertline, &ttyctx); return; } if (ny > s->rlower + 1 - s->cy) ny = s->rlower + 1 - s->cy; if (ny == 0) return; screen_write_initctx(ctx, &ttyctx, 0); if (s->cy < s->rupper || s->cy > s->rlower) grid_view_insert_lines(s->grid, s->cy, ny); else grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny); ttyctx.num = ny; tty_write(tty_cmd_insertline, &ttyctx); }