struct wl_display *display;
int redraw_scheduled, redraw_pending;
char *data;
- int width, height, tail, row, column, total_rows;
+ int width, height, start, row, column;
int fd, master;
struct buffer *buffer;
GIOChannel *channel;
int margin;
};
+static char *
+terminal_get_row(struct terminal *terminal, int row)
+{
+ int index;
+
+ index = (row + terminal->start) % terminal->height;
+
+ return &terminal->data[index * (terminal->width + 1)];
+}
+
static void
terminal_resize(struct terminal *terminal, int width, int height)
{
size_t size;
char *data;
- int i, l, total_rows, row, tail;
+ int i, l, total_rows, start;
if (terminal->width == width && terminal->height == height)
return;
else
l = width;
- if (terminal->total_rows > height) {
+ if (terminal->height > height) {
total_rows = height;
- tail = terminal->tail + terminal->total_rows - height;
+ start = terminal->height - height;
} else {
- total_rows = terminal->total_rows;
- tail = terminal->tail;
+ total_rows = terminal->height;
+ start = 0;
}
- for (i = 0; i < total_rows; i++) {
- row = (tail + i) % terminal->height;
+ for (i = 0; i < total_rows; i++)
memcpy(data + (width + 1) * i,
- &terminal->data[row * (terminal->width + 1)], l);
- }
+ terminal_get_row(terminal, i), l);
free(terminal->data);
- } else {
- total_rows = 1;
}
terminal->width = width;
terminal->height = height;
terminal->data = data;
- terminal->total_rows = total_rows;
- terminal->row = total_rows - 1;
+ if (terminal->row >= terminal->height)
+ terminal->row = terminal->height - 1;
if (terminal->column >= terminal->width)
terminal->column = terminal->width - 1;
- terminal->tail = 0;
+ terminal->start = 0;
}
static void
cairo_surface_t *surface;
cairo_t *cr;
cairo_font_extents_t extents;
- int i, row;
+ int i;
window_get_child_rectangle(terminal->window, &rectangle);
cairo_set_font_size(cr, 14);
cairo_font_extents(cr, &extents);
- for (i = 0; i < terminal->total_rows; i++) {
- row = (terminal->tail + i) % terminal->height;
+ for (i = 0; i < terminal->height; i++) {
cairo_move_to(cr, terminal->margin,
terminal->margin + extents.ascent + extents.height * i);
- cairo_show_text(cr, &terminal->data[row * (terminal->width + 1)]);
+ cairo_show_text(cr, terminal_get_row(terminal, i));
}
cairo_destroy(cr);
}
static void
+terminal_data(struct terminal *terminal, const char *data, size_t length);
+
+static void
handle_escape(struct terminal *terminal)
{
- char *row;
- int i, j;
+ char *row, *p;
+ int i, count;
+ int args[10], set[10] = { 0, };
terminal->escape[terminal->escape_length++] = '\0';
- if (strcmp(terminal->escape, "\e[J") == 0) {
- row = &terminal->data[terminal->row * (terminal->width + 1)];
- memset(&row[terminal->column], 0, terminal->width - terminal->column);
- for (i = terminal->total_rows; i < terminal->height; i++) {
-
- j = terminal->row + i;
- if (j >= terminal->height)
- j -= terminal->height;
-
- row = &terminal->data[j * (terminal->width + 1)];
- memset(row, 0, terminal->width);
+ i = 0;
+ p = &terminal->escape[2];
+ while ((isdigit(*p) || *p == ';') && i < 10) {
+ if (*p == ';') {
+ p++;
+ i++;
+ } else {
+ args[i] = strtol(p, &p, 10);
+ set[i] = 1;
}
- } else if (strcmp(terminal->escape, "\e[H") == 0) {
- terminal->row = terminal->tail;
- terminal->total_rows = 1;
- terminal->column = 0;
}
+
+ switch (*p) {
+ case 'A':
+ count = set[0] ? args[0] : 1;
+ if (terminal->row - count >= 0)
+ terminal->row -= count;
+ else
+ terminal->row = 0;
+ break;
+ case 'B':
+ count = set[0] ? args[0] : 1;
+ if (terminal->row + count < terminal->height)
+ terminal->row += count;
+ else
+ terminal->row = terminal->height;
+ break;
+ case 'C':
+ count = set[0] ? args[0] : 1;
+ if (terminal->column + count < terminal->width)
+ terminal->column += count;
+ else
+ terminal->column = terminal->width;
+ break;
+ case 'D':
+ count = set[0] ? args[0] : 1;
+ if (terminal->column - count >= 0)
+ terminal->column -= count;
+ else
+ terminal->column = 0;
+ break;
+ case 'J':
+ row = terminal_get_row(terminal, terminal->row);
+ memset(&row[terminal->column], 0, terminal->width - terminal->column);
+ for (i = terminal->row + 1; i < terminal->height; i++)
+ memset(terminal_get_row(terminal, i), 0, terminal->width);
+ break;
+ case 'G':
+ if (set[0])
+ terminal->column = args[0] - 1;
+ break;
+ case 'H':
+ case 'f':
+ terminal->row = set[0] ? args[0] - 1 : 0;
+ terminal->column = set[1] ? args[1] - 1 : 0;
+ break;
+ case 'K':
+ row = terminal_get_row(terminal, terminal->row);
+ memset(&row[terminal->column], 0, terminal->width - terminal->column);
+ break;
+ case 'm':
+ /* color, blink, bold etc*/
+ break;
+ case '?':
+ if (strcmp(p, "?25l") == 0) {
+ /* hide cursor */
+ } else if (strcmp(p, "?25h") == 0) {
+ /* show cursor */
+ }
+ break;
+ default:
+ terminal_data(terminal,
+ terminal->escape + 1,
+ terminal->escape_length - 2);
+ break;
+ }
}
static void
char *row;
for (i = 0; i < length; i++) {
- row = &terminal->data[terminal->row * (terminal->width + 1)];
+ row = terminal_get_row(terminal, terminal->row);
if (terminal->state == STATE_ESCAPE) {
terminal->escape[terminal->escape_length++] = data[i];
break;
case '\n':
terminal->column = 0;
- terminal->row++;
- if (terminal->row == terminal->height)
- terminal->row = 0;
- if (terminal->total_rows == terminal->height) {
- memset(&terminal->data[terminal->row * (terminal->width + 1)],
- 0, terminal->width);
- terminal->tail++;
+ if (terminal->row + 1 < terminal->height) {
+ terminal->row++;
} else {
- terminal->total_rows++;
+ terminal->start++;
+ if (terminal->start == terminal->height)
+ terminal->start = 0;
+ memset(terminal_get_row(terminal, terminal->row),
+ 0, terminal->width);
}
- if (terminal->tail == terminal->height)
- terminal->tail = 0;
break;
case '\t':
memset(&row[terminal->column], ' ', -terminal->column & 7);
terminal->escape[0] = '\e';
terminal->escape_length = 1;
break;
+ case '\b':
+ if (terminal->column > 0)
+ terminal->column--;
+ break;
+ case '\a':
+ /* Bell */
+ break;
default:
if (terminal->column < terminal->width)
- row[terminal->column++] = data[i];
+ row[terminal->column++] = data[i] < 32 ? data[i] + 64 : data[i];
break;
}
}