Redo screen.c functions to make them readable and more flexible. Make scroll mode only redraw waht it needs.

This commit is contained in:
Nicholas Marriott 2007-11-21 18:24:49 +00:00
parent df158734c2
commit 24c39950ff
6 changed files with 333 additions and 89 deletions

View File

@ -1,5 +1,9 @@
21 November 2007
* Redo screen redrawing so it is a) readable b) split into utility functions
that can be used outside screen.c. Use these to make scroll mode only
redraw what it has to which gets rid of irritating flickering status box and
makes it much faster.
* Full line width memory and horizontal scrolling in history.
* Initial support for scroll history. = to enter scrolling mode, and then
vi keys or up/down/pgup/pgdown to navigate. Q to exit. No horizontal history
@ -241,4 +245,4 @@
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
$Id: CHANGES,v 1.77 2007-11-21 15:35:53 nicm Exp $
$Id: CHANGES,v 1.78 2007-11-21 18:24:49 nicm Exp $

2
TODO
View File

@ -72,8 +72,6 @@
- there is to much redrawing. use flags? (there was a problem with this idea...
CLIENT_HOLD?)
- use modes for help etc
- scrollback should only draw scrolled line on up/down
- horizontal scrolling
-- For 0.2 --------------------------------------------------------------------
- copy and paste

187
screen.c
View File

@ -1,4 +1,4 @@
/* $Id: screen.c,v 1.31 2007-11-21 15:35:53 nicm Exp $ */
/* $Id: screen.c,v 1.32 2007-11-21 18:24:49 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -212,60 +212,159 @@ screen_destroy(struct screen *s)
xfree(s->grid_size);
}
/* Draw a set of lines on the screen. */
/* Initialise drawing. */
void
screen_draw(
struct screen *s, struct buffer *b, u_int py, u_int ny, u_int ox, u_int oy)
screen_draw_start(struct screen_draw_ctx *ctx,
struct screen *s, struct buffer *b, u_int ox, u_int oy)
{
u_char attr, colr;
u_int i, j, nx, base;
ctx->s = s;
ctx->b = b;
/* XXX. This is naive and rough right now. */
attr = 0;
colr = SCREEN_DEFCOLR;
ctx->ox = ox;
ctx->oy = oy;
ctx->cx = s->cx;
ctx->cy = s->cy;
ctx->attr = s->attr;
ctx->colr = s->colr;
input_store_two(b, CODE_SCROLLREGION, 1, screen_size_y(s));
if (s->mode & MODE_CURSOR)
input_store_zero(b, CODE_CURSOROFF);
}
/* Finalise drawing. */
void
screen_draw_stop(struct screen_draw_ctx *ctx)
{
struct screen *s = ctx->s;
struct buffer *b = ctx->b;
input_store_two(b, CODE_SCROLLREGION, s->rupper + 1, s->rlower + 1);
input_store_zero(b, CODE_CURSOROFF);
input_store_two(b, CODE_ATTRIBUTES, attr, colr);
if (ctx->cx != s->cx || ctx->cy != s->cy)
input_store_two(b, CODE_CURSORMOVE, s->cy + 1, s->cx + 1);
base = screen_y(s, 0);
if (oy > base)
base = 0;
else
base -= oy;
for (j = py; j < py + ny; j++) {
input_store_two(b, CODE_CURSORMOVE, j + 1, 1);
nx = s->grid_size[base + j] - ox;
if (nx > screen_size_x(s))
nx = screen_size_x(s);
for (i = 0; i < nx; i++) {
if (s->grid_attr[base + j][ox + i] != attr ||
s->grid_colr[base + j][ox + i] != colr) {
input_store_two(b, CODE_ATTRIBUTES,
s->grid_attr[base + j][ox + i],
s->grid_colr[base + j][ox + i]);
attr = s->grid_attr[base + j][ox + i];
colr = s->grid_colr[base + j][ox + i];
}
input_store8(b, s->grid_data[base + j][ox + i]);
}
if (nx != screen_size_x(s)) {
input_store_two(
b, CODE_ATTRIBUTES, SCREEN_DEFATTR, SCREEN_DEFCOLR);
for (i = nx; i < screen_size_x(s); i++)
input_store8(b, SCREEN_DEFDATA);
}
}
input_store_two(b, CODE_CURSORMOVE, s->cy + 1, s->cx + 1);
input_store_two(b, CODE_ATTRIBUTES, s->attr, s->colr);
if (ctx->attr != s->attr || ctx->colr != s->colr)
input_store_two(b, CODE_ATTRIBUTES, s->attr, s->colr);
if (s->mode & MODE_CURSOR)
input_store_zero(b, CODE_CURSORON);
}
/* Get cell data. */
void
screen_draw_get_cell(struct screen_draw_ctx *ctx,
u_int px, u_int py, u_char *data, u_char *attr, u_char *colr)
{
struct screen *s = ctx->s;
u_int cx, cy;
cx = ctx->ox + px;
cy = screen_y(s, py) - ctx->oy;
if (cx >= s->grid_size[cy]) {
*data = SCREEN_DEFDATA;
*attr = SCREEN_DEFATTR;
*colr = SCREEN_DEFCOLR;
} else {
*data = s->grid_data[cy][cx];
*attr = s->grid_attr[cy][cx];
*colr = s->grid_colr[cy][cx];
}
}
/* Move cursor. */
void
screen_draw_move(struct screen_draw_ctx *ctx, u_int px, u_int py)
{
if (px == ctx->cx && py == ctx->cy)
return;
input_store_two(ctx->b, CODE_CURSORMOVE, py + 1, px + 1);
ctx->cx = px;
ctx->cy = py;
}
/* Set attributes. */
void
screen_draw_set_attributes(
struct screen_draw_ctx *ctx, u_char attr, u_char colr)
{
if (attr != ctx->attr || colr != ctx->colr) {
input_store_two(ctx->b, CODE_ATTRIBUTES, attr, colr);
ctx->attr = attr;
ctx->colr = colr;
}
}
/* Draw single cell. */
void
screen_draw_cell(struct screen_draw_ctx *ctx, u_int px, u_int py)
{
struct buffer *b = ctx->b;
u_char data, attr, colr;
screen_draw_move(ctx, px, py);
screen_draw_get_cell(ctx, px, py, &data, &attr, &colr);
screen_draw_set_attributes(ctx, attr, colr);
input_store8(b, data);
/*
* Don't try to wrap as it will cause problems when screen is smaller
* than client.
*/
ctx->cx++;
}
/* Draw range of cells. */
void
screen_draw_cells(struct screen_draw_ctx *ctx, u_int px, u_int py, u_int nx)
{
u_int i;
for (i = px; i < px + nx; i++)
screen_draw_cell(ctx, i, py);
}
/* Draw single column. */
void
screen_draw_column(struct screen_draw_ctx *ctx, u_int px)
{
u_int i;
for (i = 0; i < screen_size_y(ctx->s); i++)
screen_draw_cell(ctx, px, i);
}
/* Draw single line. */
void
screen_draw_line(struct screen_draw_ctx *ctx, u_int py)
{
screen_draw_cells(ctx, 0, py, screen_size_x(ctx->s));
}
/* Draw set of lines. */
void
screen_draw_lines(struct screen_draw_ctx *ctx, u_int py, u_int ny)
{
u_int i;
for (i = py; i < py + ny; i++)
screen_draw_line(ctx, i);
}
/* Draw entire screen. */
void
screen_draw_screen(struct screen_draw_ctx *ctx)
{
screen_draw_lines(ctx, 0, screen_size_y(ctx->s));
}
/* Create a range of lines. */
void
screen_make_lines(struct screen *s, u_int py, u_int ny)

32
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.87 2007-11-21 15:35:53 nicm Exp $ */
/* $Id: tmux.h,v 1.88 2007-11-21 18:24:49 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -378,6 +378,21 @@ struct screen {
int mode;
};
/* Screen redraw context. */
struct screen_draw_ctx {
struct screen *s;
struct buffer *b;
u_int cx;
u_int cy;
u_int ox;
u_int oy;
u_int attr;
u_int colr;
};
/* Screen display access macros. */
#define screen_x(s, x) (x)
#define screen_y(s, y) ((s)->hsize + y)
@ -749,8 +764,19 @@ u_char screen_stringcolour(const char *);
void screen_create(struct screen *, u_int, u_int);
void screen_destroy(struct screen *);
void screen_resize(struct screen *, u_int, u_int);
void screen_draw(
struct screen *, struct buffer *, u_int, u_int, u_int, u_int);
void screen_draw_start(struct screen_draw_ctx *,
struct screen *, struct buffer *, u_int, u_int);
void screen_draw_stop(struct screen_draw_ctx *);
void screen_draw_get_cell(struct screen_draw_ctx *,
u_int, u_int, u_char *, u_char *, u_char *);
void screen_draw_move(struct screen_draw_ctx *, u_int, u_int);
void screen_draw_set_attributes(struct screen_draw_ctx *, u_char, u_char);
void screen_draw_cell(struct screen_draw_ctx *, u_int, u_int);
void screen_draw_cells(struct screen_draw_ctx *, u_int, u_int, u_int);
void screen_draw_column(struct screen_draw_ctx *, u_int);
void screen_draw_line(struct screen_draw_ctx *, u_int);
void screen_draw_lines(struct screen_draw_ctx *, u_int, u_int);
void screen_draw_screen(struct screen_draw_ctx *);
void screen_make_lines(struct screen *, u_int, u_int);
void screen_free_lines(struct screen *, u_int, u_int);
void screen_move_lines(struct screen *, u_int, u_int, u_int);

View File

@ -1,4 +1,4 @@
/* $Id: window-scroll.c,v 1.6 2007-11-21 15:55:02 nicm Exp $ */
/* $Id: window-scroll.c,v 1.7 2007-11-21 18:24:49 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,8 +27,12 @@ void window_scroll_resize(struct window *, u_int, u_int);
void window_scroll_draw(struct window *, struct buffer *, u_int, u_int);
void window_scroll_key(struct window *, int);
void window_scroll_draw_position(struct window *, struct screen_draw_ctx *);
void window_scroll_up_1(struct window *);
void window_scroll_down_1(struct window *);
void window_scroll_left_1(struct window *);
void window_scroll_right_1(struct window *);
const struct window_mode window_scroll_mode = {
window_scroll_init,
@ -58,34 +62,52 @@ window_scroll_resize(unused struct window *w, unused u_int sx, unused u_int sy)
{
}
void
window_scroll_draw_position(struct window *w, struct screen_draw_ctx *ctx)
{
struct window_scroll_mode_data *data = w->modedata;
char *ptr, buf[32];
size_t len;
len = xsnprintf(
buf, sizeof buf, "[%u,%u/%u]", data->ox, data->oy, ctx->s->hsize);
if (len <= screen_size_x(ctx->s))
ptr = buf;
else {
ptr = buf + len - screen_size_x(ctx->s);
len -= len - screen_size_x(ctx->s);
}
screen_draw_cells(ctx, 0, 0, screen_size_x(ctx->s) - len);
screen_draw_move(ctx, screen_size_x(ctx->s) - len, 0);
screen_draw_set_attributes(ctx, 0, status_colour);
buffer_write(ctx->b, ptr, len);
}
void
window_scroll_draw(struct window *w, struct buffer *b, u_int py, u_int ny)
{
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &w->screen;
char buf[32];
size_t len;
struct screen_draw_ctx ctx;
if (s->hsize != data->size) {
data->ox += s->hsize - data->size;
data->size = s->hsize;
}
screen_draw(s, b, py, ny, data->ox, data->oy);
screen_draw_start(&ctx, s, b, data->ox, data->oy);
if (py != 0)
screen_draw_lines(&ctx, py, ny);
else if (ny > 1)
screen_draw_lines(&ctx, py + 1, ny - 1);
if (py == 0)
window_scroll_draw_position(w, &ctx);
screen_draw_stop(&ctx);
input_store_zero(b, CODE_CURSOROFF);
if (py == 0 && ny > 0) {
len = screen_size_x(s);
if (len > (sizeof buf) - 1)
len = (sizeof buf) - 1;
len = xsnprintf(
buf, len + 1, "[%u,%u/%u]", data->ox, data->oy, s->hsize);
input_store_two(
b, CODE_CURSORMOVE, 0, screen_size_x(s) - len + 1);
input_store_two(b, CODE_ATTRIBUTES, 0, status_colour);
buffer_write(b, buf, len);
}
}
void
@ -111,14 +133,12 @@ window_scroll_key(struct window *w, int key)
return;
case 'h':
case KEYC_LEFT:
if (data->ox > 0)
data->ox--;
break;
window_scroll_left_1(w);
return;
case 'l':
case KEYC_RIGHT:
if (data->ox < SHRT_MAX)
data->ox++;
break;
window_scroll_right_1(w);
return;
case 'k':
case 'K':
case KEYC_UP:
@ -127,9 +147,8 @@ window_scroll_key(struct window *w, int key)
case 'j':
case 'J':
case KEYC_DOWN:
if (data->oy > 0)
data->oy--;
break;
window_scroll_down_1(w);
return;
case '\025':
case KEYC_PPAGE:
if (data->oy + sy > data->size)
@ -154,6 +173,7 @@ window_scroll_up_1(struct window *w)
{
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &w->screen;
struct screen_draw_ctx ctx;
struct client *c;
u_int i;
struct hdr hdr;
@ -173,13 +193,15 @@ window_scroll_up_1(struct window *w)
buffer_ensure(c->out, sizeof hdr);
buffer_add(c->out, sizeof hdr);
size = BUFFER_USED(c->out);
input_store_two(c->out, CODE_CURSORMOVE, 1, screen_size_y(s));
input_store_one(c->out, CODE_INSERTLINE, 1);
/* Redraw the top two lines to nuke the position display too. */
window_scroll_draw(w, c->out, 0, 2);
screen_draw_start(&ctx, s, c->out, data->ox, data->oy);
screen_draw_move(&ctx, 0, 0);
input_store_one(c->out, CODE_INSERTLINE, 1);
window_scroll_draw_position(w, &ctx);
screen_draw_line(&ctx, 1); /* nuke old position */
screen_draw_stop(&ctx);
input_store_zero(c->out, CODE_CURSOROFF);
size = BUFFER_USED(c->out) - size;
hdr.type = MSG_DATA;
hdr.size = size;
@ -192,6 +214,7 @@ window_scroll_down_1(struct window *w)
{
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &w->screen;
struct screen_draw_ctx ctx;
struct client *c;
u_int i;
struct hdr hdr;
@ -212,11 +235,99 @@ window_scroll_down_1(struct window *w)
buffer_add(c->out, sizeof hdr);
size = BUFFER_USED(c->out);
input_store_two(c->out, CODE_CURSORMOVE, 1, 1);
screen_draw_start(&ctx, s, c->out, data->ox, data->oy);
screen_draw_move(&ctx, 0, 0);
input_store_one(c->out, CODE_DELETELINE, 1);
input_store_two(c->out, CODE_CURSORMOVE, 1, screen_size_y(s));
window_scroll_draw(w, c->out, screen_last_y(s), 1);
screen_draw_line(&ctx, screen_last_y(s));
window_scroll_draw_position(w, &ctx);
screen_draw_stop(&ctx);
input_store_zero(c->out, CODE_CURSOROFF);
size = BUFFER_USED(c->out) - size;
hdr.type = MSG_DATA;
hdr.size = size;
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
}
}
void
window_scroll_right_1(struct window *w)
{
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &w->screen;
struct screen_draw_ctx ctx;
struct client *c;
u_int i, j;
struct hdr hdr;
size_t size;
if (data->ox >= SHRT_MAX)
return;
data->ox++;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
if (!session_has(c->session, w))
continue;
buffer_ensure(c->out, sizeof hdr);
buffer_add(c->out, sizeof hdr);
size = BUFFER_USED(c->out);
screen_draw_start(&ctx, s, c->out, data->ox, data->oy);
for (j = 1; j < screen_size_y(s); j++) {
screen_draw_move(&ctx, 0, j);
input_store_one(c->out, CODE_DELETECHARACTER, 1);
}
screen_draw_column(&ctx, screen_last_x(s));
window_scroll_draw_position(w, &ctx);
screen_draw_stop(&ctx);
input_store_zero(c->out, CODE_CURSOROFF);
size = BUFFER_USED(c->out) - size;
hdr.type = MSG_DATA;
hdr.size = size;
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
}
}
void
window_scroll_left_1(struct window *w)
{
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &w->screen;
struct screen_draw_ctx ctx;
struct client *c;
u_int i, j;
struct hdr hdr;
size_t size;
if (data->ox == 0)
return;
data->ox--;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
if (!session_has(c->session, w))
continue;
buffer_ensure(c->out, sizeof hdr);
buffer_add(c->out, sizeof hdr);
size = BUFFER_USED(c->out);
screen_draw_start(&ctx, s, c->out, data->ox, data->oy);
for (j = 1; j < screen_size_y(s); j++) {
screen_draw_move(&ctx, 0, j);
input_store_one(c->out, CODE_INSERTCHARACTER, 1);
}
screen_draw_column(&ctx, 0);
window_scroll_draw_position(w, &ctx);
screen_draw_stop(&ctx);
input_store_zero(c->out, CODE_CURSOROFF);
size = BUFFER_USED(c->out) - size;
hdr.type = MSG_DATA;

View File

@ -1,4 +1,4 @@
/* $Id: window.c,v 1.29 2007-11-21 15:35:53 nicm Exp $ */
/* $Id: window.c,v 1.30 2007-11-21 18:24:49 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -284,10 +284,16 @@ window_parse(struct window *w, struct buffer *b)
void
window_draw(struct window *w, struct buffer *b, u_int py, u_int ny)
{
struct screen *s = &w->screen;
struct screen_draw_ctx ctx;
if (w->mode != NULL)
w->mode->draw(w, b, py, ny);
else
screen_draw(&w->screen, b, py, ny, 0, 0);
else {
screen_draw_start(&ctx, s, b, 0, 0);
screen_draw_lines(&ctx, py, ny);
screen_draw_stop(&ctx);
}
}
void