summaryrefslogtreecommitdiffstats
path: root/screen.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2008-09-25 20:08:57 +0000
committerNicholas Marriott <nicholas.marriott@gmail.com>2008-09-25 20:08:57 +0000
commitefe557313aef555b415fa2ea2c9a50c4404ed788 (patch)
tree4a197ade3d901f79bc8b0b990f9756d3da7f5f01 /screen.c
parent9edb4d4b85a8714162817f2ae428e654e6bf1f31 (diff)
Internal screen data rewrite for better 256 colour/UTF-8 support.
Diffstat (limited to 'screen.c')
-rw-r--r--screen.c365
1 files changed, 83 insertions, 282 deletions
diff --git a/screen.c b/screen.c
index de643ab0..d85eb676 100644
--- a/screen.c
+++ b/screen.c
@@ -1,4 +1,4 @@
-/* $Id: screen.c,v 1.71 2008-09-10 19:15:04 nicm Exp $ */
+/* $Id: screen.c,v 1.72 2008-09-25 20:08:54 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -22,90 +22,18 @@
#include "tmux.h"
-/*
- * Virtual screen.
- *
- * A screen is stored as three arrays of lines of 8-bit values, one for the
- * actual characters (data), one for attributes and one for colours. Three
- * seperate blocks means memset and friends can be used. Each array is y by x
- * in size, row then column order. Sizes are 0-based. There is an additional
- * array of u_ints with the size of each line.
- *
- * Each screen has a history starting at the beginning of the arrays and
- * extending for hsize lines. Beyond that is the screen display of size
- * dy:
- *
- * ----------- array base
- * | |
- * | history |
- * ----------- array base + hsize
- * | |
- * | display |
- * | |
- * ----------- array base + hsize + dy
- *
- * The screen_x/screen_y macros are used to convert a cell on the displayed
- * area to an absolute position in the arrays.
- *
- * Screen handling code is split into four files:
- *
- * screen.c: Creation/deletion, utility functions, and basic functions to
- * manipulate the screen based on offsets from the base.
- * screen-display.c: Basic functions for manipulating the displayed
- * part of the screen. x,y coordinates passed to these
- * are relative to the display. These are largely
- * utility functions for screen-write.c.
- * screen-redraw.c: Functions for redrawing all or part of a screen to
- * one or more ttys. A context is filled via one of the
- * screen_redraw_start* variants which sets up (removes
- * cursor etc) and figures out which tty_write_* function
- * to use to write to the terminals, then the other
- * screen_redraw_* functions are used to draw the screen,
- * and screen_redraw_stop used to reset the cursor and
- * clean up. These are used when changing window and a
- * few other bits (status line).
- * screen-write.c: Functions for modifying (writing into) the screen and
- * optionally simultaneously updating one or more ttys.
- * These are used in much the same way as the redraw
- * functions. These are used to update when parsing
- * input from the window (input.c) and for the various
- * other modes which maintain private screens.
- *
- * If you're thinking this all seems too complicated, that's because it is :-/.
- */
+void screen_resize_x(struct screen *, u_int);
+void screen_resize_y(struct screen *, u_int);
/* Create a new screen. */
void
-screen_init(struct screen *s, u_int dx, u_int dy, u_int hlimit)
+screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
{
- s->dx = dx;
- s->dy = dy;
- s->cx = 0;
- s->cy = 0;
+ s->grid = grid_create(sx, sy, hlimit);
- s->rupper = 0;
- s->rlower = s->dy - 1;
-
- s->hsize = 0;
- s->hlimit = hlimit;
-
- s->attr = 0;
- s->fg = 8;
- s->bg = 8;
-
- s->mode = MODE_CURSOR;
s->title = xstrdup("");
- s->grid_data = xmalloc(dy * (sizeof *s->grid_data));
- s->grid_attr = xmalloc(dy * (sizeof *s->grid_attr));
- s->grid_fg = xmalloc(dy * (sizeof *s->grid_fg));
- s->grid_bg = xmalloc(dy * (sizeof *s->grid_bg));
- s->grid_size = xmalloc(dy * (sizeof *s->grid_size));
- screen_make_lines(s, 0, dy);
-
- utf8_init(&s->utf8_table, UTF8_LIMIT);
-
- screen_clear_selection(s);
+ screen_reinit(s);
}
/* Reinitialise screen. */
@@ -116,16 +44,13 @@ screen_reinit(struct screen *s)
s->cy = 0;
s->rupper = 0;
- s->rlower = s->dy - 1;
-
- s->attr = 0;
- s->fg = 8;
- s->bg = 8;
+ s->rlower = screen_size_y(s) - 1;
s->mode = MODE_CURSOR;
- screen_display_fill_area(s, 0, 0,
- screen_size_x(s), screen_size_y(s), ' ', 0, 8, 8);
+ /* XXX */
+ grid_clear_lines(
+ s->grid, s->grid->hsize, s->grid->hsize + s->grid->sy - 1);
screen_clear_selection(s);
}
@@ -134,245 +59,121 @@ screen_reinit(struct screen *s)
void
screen_free(struct screen *s)
{
- utf8_free(&s->utf8_table);
xfree(s->title);
- screen_free_lines(s, 0, s->dy + s->hsize);
- xfree(s->grid_data);
- xfree(s->grid_attr);
- xfree(s->grid_fg);
- xfree(s->grid_bg);
- xfree(s->grid_size);
+ grid_destroy(s->grid);
+}
+
+/* Set screen title. */
+void
+screen_set_title(struct screen *s, const char *title)
+{
+ xfree(s->title);
+ s->title = xstrdup(title);
}
/* Resize screen. */
void
screen_resize(struct screen *s, u_int sx, u_int sy)
{
- u_int i, ox, oy, ny, my;
-
if (sx < 1)
sx = 1;
if (sy < 1)
sy = 1;
- ox = s->dx;
- oy = s->dy;
- if (sx == ox && sy == oy)
+ if (sx != screen_size_x(s))
+ screen_resize_x(s, sx);
+ if (sy != screen_size_y(s))
+ screen_resize_y(s, sy);
+}
+
+void
+screen_resize_x(struct screen *s, u_int sx)
+{
+ struct grid_data *gd = s->grid;
+ const struct grid_cell *gc;
+ u_int xx, yy;
+
+ /* If getting larger, not much to do. */
+ if (sx > screen_size_x(s)) {
+ gd->sx = sx;
return;
+ }
- /*
- * X dimension.
- */
- if (sx != ox) {
+ /* If getting smaller, nuke any data in lines over the new size. */
+ for (yy = gd->hsize; yy < gd->hsize + screen_size_y(s); yy++) {
/*
- * If getting smaller, nuke any data in lines over the new
- * size.
+ * If the character after the last is wide or padding, remove
+ * it and any leading padding.
*/
- if (sx < ox) {
- for (i = s->hsize; i < s->hsize + oy; i++) {
- if (s->grid_size[i] > sx)
- screen_reduce_line(s, i, sx);
- }
+ for (xx = sx; xx > 0; xx--) {
+ gc = grid_peek_cell(gd, xx - 1, yy);
+ if (!(gc->flags & GRID_FLAG_PADDING))
+ break;
+ grid_set_cell(gd, xx - 1, yy, &grid_default_cell);
}
+ if (xx > 0 && xx != sx && utf8_width(gc->data) != 1)
+ grid_set_cell(gd, xx - 1, yy, &grid_default_cell);
- if (s->cx >= sx)
- s->cx = sx - 1;
- s->dx = sx;
+ /* Reduce the line size. */
+ grid_reduce_line(gd, yy, sx);
}
- /*
- * Y dimension.
- */
- if (sy == oy)
- return;
+ if (s->cx >= sx)
+ s->cx = sx - 1;
+ gd->sx = sx;
+}
+
+void
+screen_resize_y(struct screen *s, u_int sy)
+{
+ struct grid_data *gd = s->grid;
+ u_int oy, yy, ny;
/* Size decreasing. */
- if (sy < oy) {
- ny = oy - sy;
+ if (sy < screen_size_y(s)) {
+ oy = screen_size_y(s);
+
if (s->cy != 0) {
/*
* The cursor is not at the start. Try to remove as
* many lines as possible from the top. (Up to the
* cursor line.)
*/
- my = s->cy;
- if (my > ny)
- my = ny;
+ ny = s->cy;
+ if (ny > oy - sy)
+ ny = oy - sy;
- screen_free_lines(s, s->hsize, my);
- screen_move_lines(s, s->hsize, s->hsize + my, oy - my);
+ grid_view_delete_lines(gd, 0, ny);
- s->cy -= my;
- oy -= my;
+ s->cy -= ny;
+ oy -= ny;
}
- ny = oy - sy;
- if (ny > 0) {
- /*
- * Remove any remaining lines from the bottom.
- */
- screen_free_lines(s, s->hsize + oy - ny, ny);
+ if (sy < oy) {
+ /* Remove any remaining lines from the bottom. */
+ grid_view_delete_lines(gd, sy, oy - sy);
if (s->cy >= sy)
s->cy = sy - 1;
}
}
/* Resize line arrays. */
- ny = s->hsize + sy;
- s->grid_data = xrealloc(s->grid_data, ny, sizeof *s->grid_data);
- s->grid_attr = xrealloc(s->grid_attr, ny, sizeof *s->grid_attr);
- s->grid_fg = xrealloc(s->grid_fg, ny, sizeof *s->grid_fg);
- s->grid_bg = xrealloc(s->grid_bg, ny, sizeof *s->grid_bg);
- s->grid_size = xrealloc(s->grid_size, ny, sizeof *s->grid_size);
- s->dy = sy;
+ gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size);
+ gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data);
/* Size increasing. */
- if (sy > oy)
- screen_make_lines(s, s->hsize + oy, sy - oy);
-
- s->rupper = 0;
- s->rlower = s->dy - 1;
-}
-
-/* Expand line. */
-void
-screen_expand_line(struct screen *s, u_int py, u_int nx)
-{
- u_int ox;
-
- ox = s->grid_size[py];
- s->grid_size[py] = nx;
-
- s->grid_data[py] = xrealloc(
- s->grid_data[py], sizeof **s->grid_data, nx);
- memset(&s->grid_data[py][ox], ' ', (nx - ox) * sizeof **s->grid_data);
- s->grid_attr[py] = xrealloc(
- s->grid_attr[py], sizeof **s->grid_attr, nx);
- memset(&s->grid_attr[py][ox], 0, (nx - ox) * sizeof **s->grid_attr);
- s->grid_fg[py] = xrealloc(
- s->grid_fg[py], sizeof **s->grid_fg, nx);
- memset(&s->grid_fg[py][ox], 8, (nx - ox) * sizeof **s->grid_fg);
- s->grid_bg[py] = xrealloc(
- s->grid_bg[py], sizeof **s->grid_bg, nx);
- memset(&s->grid_bg[py][ox], 8, (nx - ox) * sizeof **s->grid_bg);
-}
-
-/* Reduce line. */
-void
-screen_reduce_line(struct screen *s, u_int py, u_int nx)
-{
- s->grid_size[py] = nx;
-
- s->grid_data[py] = xrealloc(
- s->grid_data[py], sizeof **s->grid_data, nx);
- s->grid_attr[py] = xrealloc(
- s->grid_attr[py], sizeof **s->grid_attr, nx);
- s->grid_fg[py] = xrealloc(
- s->grid_fg[py], sizeof **s->grid_fg, nx);
- s->grid_bg[py] = xrealloc(
- s->grid_bg[py], sizeof **s->grid_bg, nx);
-}
-
-/* Get cell. */
-void
-screen_get_cell(struct screen *s,
- u_int cx, u_int cy, u_char *data, u_short *attr, u_char *fg, u_char *bg)
-{
- if (cx >= s->grid_size[cy]) {
- *data = ' ';
- *attr = 0;
- *fg = 8;
- *bg = 8;
- } else {
- *data = s->grid_data[cy][cx];
- *attr = s->grid_attr[cy][cx];
- *fg = s->grid_fg[cy][cx];
- *bg = s->grid_bg[cy][cx];
- }
-
- if (screen_check_selection(s, cx, cy))
- *attr |= ATTR_REVERSE;
-}
-
-/* Set a cell. */
-void
-screen_set_cell(struct screen *s,
- u_int cx, u_int cy, u_char data, u_short attr, u_char fg, u_char bg)
-{
- if (cx >= s->grid_size[cy])
- screen_expand_line(s, cy, cx + 1);
-
- s->grid_data[cy][cx] = data;
- s->grid_attr[cy][cx] = attr;
- s->grid_fg[cy][cx] = fg;
- s->grid_bg[cy][cx] = bg;
-}
-
-/* Create a range of lines. */
-void
-screen_make_lines(struct screen *s, u_int py, u_int ny)
-{
- u_int i;
-
- for (i = py; i < py + ny; i++) {
- s->grid_data[i] = NULL;
- s->grid_attr[i] = NULL;
- s->grid_fg[i] = NULL;
- s->grid_bg[i] = NULL;
- s->grid_size[i] = 0;
- }
-}
-
-/* Free a range of ny lines at py. */
-void
-screen_free_lines(struct screen *s, u_int py, u_int ny)
-{
- u_int i;
-
- for (i = py; i < py + ny; i++) {
- if (s->grid_data[i] != NULL)
- xfree(s->grid_data[i]);
- s->grid_data[i] = NULL;
- if (s->grid_attr[i] != NULL)
- xfree(s->grid_attr[i]);
- s->grid_attr[i] = NULL;
- if (s->grid_fg[i] != NULL)
- xfree(s->grid_fg[i]);
- s->grid_fg[i] = NULL;
- if (s->grid_bg[i] != NULL)
- xfree(s->grid_bg[i]);
- s->grid_bg[i] = NULL;
- s->grid_size[i] = 0;
+ if (sy > screen_size_y(s)) {
+ oy = screen_size_y(s);
+ for (yy = gd->hsize + oy; yy < gd->hsize + sy; yy++) {
+ gd->size[yy] = 0;
+ gd->data[yy] = NULL;
+ }
}
-}
-
-/* Move a range of lines. */
-void
-screen_move_lines(struct screen *s, u_int dy, u_int py, u_int ny)
-{
- memmove(
- &s->grid_data[dy], &s->grid_data[py], ny * (sizeof *s->grid_data));
- memmove(
- &s->grid_attr[dy], &s->grid_attr[py], ny * (sizeof *s->grid_attr));
- memmove(
- &s->grid_fg[dy], &s->grid_fg[py], ny * (sizeof *s->grid_fg));
- memmove(
- &s->grid_bg[dy], &s->grid_bg[py], ny * (sizeof *s->grid_bg));
- memmove(
- &s->grid_size[dy], &s->grid_size[py], ny * (sizeof *s->grid_size));
-}
-/* Fill an area. */
-void
-screen_fill_area(struct screen *s, u_int px, u_int py,
- u_int nx, u_int ny, u_char data, u_short attr, u_char fg, u_char bg)
-{
- u_int i, j;
-
- for (i = py; i < py + ny; i++) {
- for (j = px; j < px + nx; j++)
- screen_set_cell(s, j, i, data, attr, fg, bg);
- }
+ gd->sy = sy;
+
+ s->rupper = 0;
+ s->rlower = screen_size_y(s) - 1;
}
/* Set selection. */