mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-24 01:40:12 -05:00
Merge branch 'fast-scroll'
This commit is contained in:
commit
9f12bca21e
10 changed files with 610 additions and 253 deletions
166
csi.c
166
csi.c
|
|
@ -10,7 +10,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOG_MODULE "csi"
|
#define LOG_MODULE "csi"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
|
|
||||||
|
|
@ -57,10 +57,6 @@ initialize_colors256(void)
|
||||||
b * 51 / 255.0,
|
b * 51 / 255.0,
|
||||||
1.0,
|
1.0,
|
||||||
};
|
};
|
||||||
#if 0
|
|
||||||
colors256[16 + r * 6 * 6 + g * 6 + b] =
|
|
||||||
(51 * r) << 24 | (51 * g) << 16 | (51 * b) << 8 | 0xff;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +68,6 @@ initialize_colors256(void)
|
||||||
i * 11 / 255.0,
|
i * 11 / 255.0,
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
//(11 * i) << 24 | (11 * i) << 16 | (11 * i) << 8 | 0xff;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,7 +275,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
i == term->vt.params.idx - 1 ? "" : ";");
|
i == term->vt.params.idx - 1 ? "" : ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
c += snprintf(&log[c], sizeof(log) - c, "%c (%zu parameters)",
|
c += snprintf(&log[c], sizeof(log) - c, "%c (%d parameters)",
|
||||||
final, term->vt.params.idx);
|
final, term->vt.params.idx);
|
||||||
LOG_DBG("%s", log);
|
LOG_DBG("%s", log);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -292,11 +287,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
case 'd': {
|
case 'd': {
|
||||||
/* VPA - vertical line position absolute */
|
/* VPA - vertical line position absolute */
|
||||||
int row = param_get(term, 0, 1);
|
int row = min(param_get(term, 0, 1), term->rows);
|
||||||
|
|
||||||
if (row > term->rows)
|
|
||||||
row = term->rows;
|
|
||||||
|
|
||||||
term_cursor_to(term, row - 1, term->cursor.col);
|
term_cursor_to(term, row - 1, term->cursor.col);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -323,25 +314,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
case 'G': {
|
case 'G': {
|
||||||
/* Cursor horizontal absolute */
|
/* Cursor horizontal absolute */
|
||||||
int col = param_get(term, 0, 1);
|
int col = min(param_get(term, 0, 1), term->cols);
|
||||||
|
term_cursor_to(term, term->cursor.row, col - 1);
|
||||||
if (col > term->cols)
|
|
||||||
col = term->cols;
|
|
||||||
|
|
||||||
term_cursor_to(term, term->cursor.row, col);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'H': {
|
case 'H': {
|
||||||
/* Move cursor */
|
/* Move cursor */
|
||||||
int row = param_get(term, 0, 1);
|
int row = min(param_get(term, 0, 1), term->rows);
|
||||||
int col = param_get(term, 1, 1);
|
int col = min(param_get(term, 1, 1), term->cols);
|
||||||
|
|
||||||
if (row > term->rows)
|
|
||||||
row = term->rows;
|
|
||||||
if (col > term->cols)
|
|
||||||
col = term->cols;
|
|
||||||
|
|
||||||
term_cursor_to(term, row - 1, col - 1);
|
term_cursor_to(term, row - 1, col - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -452,27 +433,49 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
case 'P': {
|
case 'P': {
|
||||||
/* DCH: Delete character */
|
/* DCH: Delete character */
|
||||||
int count = param_get(term, 0, 1);
|
|
||||||
|
|
||||||
/* Only delete up to the right margin */
|
/* Number of characters to delete */
|
||||||
const int max_end = term_cursor_linear(
|
int count = min(
|
||||||
term, term->cursor.row, term->cols);
|
param_get(term, 0, 1), term->cols - term->cursor.col);
|
||||||
|
|
||||||
int start = term->cursor.linear;
|
/* Number of characters left after deletion (on current line) */
|
||||||
int end = min(start + count, max_end);
|
int remaining = term->cols - (term->cursor.col + count);
|
||||||
|
|
||||||
/* Erase the requested number of characters */
|
/* 'Delete' characters by moving the remaining ones */
|
||||||
term_erase(term, start, end);
|
memmove(&term->grid->cur_line[term->cursor.col],
|
||||||
|
&term->grid->cur_line[term->cursor.col + count],
|
||||||
/* Move remaining (up til the right margin) characters */
|
remaining * sizeof(term->grid->cur_line[0]));
|
||||||
int remaining = max_end - end;
|
|
||||||
memmove(&term->grid->cells[start],
|
|
||||||
&term->grid->cells[end],
|
|
||||||
remaining * sizeof(term->grid->cells[0]));
|
|
||||||
term_damage_update(term, term->cursor.linear, remaining);
|
term_damage_update(term, term->cursor.linear, remaining);
|
||||||
|
|
||||||
|
/* Erase the remainder of the line */
|
||||||
|
term_erase(
|
||||||
|
term, term->cursor.linear + remaining,
|
||||||
|
term->cursor.linear + remaining + count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'X': {
|
||||||
|
/* Erase chars */
|
||||||
|
int count = min(
|
||||||
|
param_get(term, 0, 1), term->cols - term->cursor.col);
|
||||||
|
|
||||||
|
memset(&term->grid->cur_line[term->cursor.col],
|
||||||
|
0, count * sizeof(term->grid->cur_line[0]));
|
||||||
|
term_damage_erase(term, term->cursor.linear, count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
/* smir - insert mode enable */
|
||||||
|
assert(false && "untested");
|
||||||
|
term->insert_mode = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
/* rmir - insert mode disable */
|
||||||
|
term->insert_mode = false;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'r': {
|
case 'r': {
|
||||||
int start = param_get(term, 0, 1);
|
int start = param_get(term, 0, 1);
|
||||||
int end = param_get(term, 1, term->rows);
|
int end = param_get(term, 1, term->rows);
|
||||||
|
|
@ -481,9 +484,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
term->scroll_region.start = start - 1;
|
term->scroll_region.start = start - 1;
|
||||||
term->scroll_region.end = end;
|
term->scroll_region.end = end;
|
||||||
|
|
||||||
LOG_INFO("scroll region: %d-%d",
|
term_cursor_to(term, start - 1, 0);
|
||||||
term->scroll_region.start,
|
|
||||||
term->scroll_region.end);
|
LOG_DBG("scroll region: %d-%d",
|
||||||
|
term->scroll_region.start,
|
||||||
|
term->scroll_region.end);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -560,12 +565,16 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
LOG_WARN("unimplemented: flash");
|
LOG_WARN("unimplemented: flash");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
term->auto_margin = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
LOG_WARN("unimplemented: cursor blinking");
|
LOG_WARN("unimplemented: cursor blinking");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 25:
|
case 25:
|
||||||
LOG_WARN("unimplemented: civis");
|
term->hide_cursor = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1000:
|
case 1000:
|
||||||
|
|
@ -576,15 +585,28 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
LOG_WARN("unimplemented: report cell mouse motion");
|
LOG_WARN("unimplemented: report cell mouse motion");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1005:
|
||||||
|
LOG_WARN("unimplemented: UTF-8 mouse");
|
||||||
|
break;
|
||||||
|
|
||||||
case 1006:
|
case 1006:
|
||||||
LOG_WARN("unimplemented: SGR mouse");
|
LOG_WARN("unimplemented: SGR mouse");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1015:
|
||||||
|
LOG_WARN("unimplemented: URXVT mosue");
|
||||||
|
break;
|
||||||
|
|
||||||
case 1049:
|
case 1049:
|
||||||
if (term->grid != &term->alt) {
|
if (term->grid != &term->alt) {
|
||||||
term->grid = &term->alt;
|
term->grid = &term->alt;
|
||||||
term->saved_cursor = term->cursor;
|
term->saved_cursor = term->cursor;
|
||||||
term_damage_all(term);
|
|
||||||
|
term_cursor_to(term, term->cursor.row, term->cursor.col);
|
||||||
|
|
||||||
|
tll_free(term->alt.damage);
|
||||||
|
tll_free(term->alt.scroll_damage);
|
||||||
|
term_erase(term, 0, term->rows * term->cols);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -613,12 +635,16 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
LOG_WARN("unimplemented: flash");
|
LOG_WARN("unimplemented: flash");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
term->auto_margin = false;
|
||||||
|
break;
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
LOG_WARN("unimplemented: cursor blinking");
|
LOG_WARN("unimplemented: cursor blinking");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 25:
|
case 25:
|
||||||
LOG_WARN("unimplemented: civis");
|
term->hide_cursor = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1000:
|
case 1000:
|
||||||
|
|
@ -629,19 +655,27 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
LOG_WARN("unimplemented: report cell mouse motion");
|
LOG_WARN("unimplemented: report cell mouse motion");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1005:
|
||||||
|
LOG_WARN("unimplemented: UTF-8 mouse");
|
||||||
|
break;
|
||||||
|
|
||||||
case 1006:
|
case 1006:
|
||||||
LOG_WARN("unimplemented: SGR mouse");
|
LOG_WARN("unimplemented: SGR mouse");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1015:
|
||||||
|
LOG_WARN("unimplemented: URXVT mosue");
|
||||||
|
break;
|
||||||
|
|
||||||
case 1049:
|
case 1049:
|
||||||
if (term->grid == &term->alt) {
|
if (term->grid == &term->alt) {
|
||||||
term->grid = &term->normal;
|
term->grid = &term->normal;
|
||||||
|
|
||||||
term->cursor = term->saved_cursor;
|
term->cursor = term->saved_cursor;
|
||||||
|
term_cursor_to(term, term->cursor.row, term->cursor.col);
|
||||||
|
|
||||||
/* Should these be restored from saved values? */
|
tll_free(term->alt.damage);
|
||||||
term->scroll_region.start = 0;
|
tll_free(term->alt.scroll_damage);
|
||||||
term->scroll_region.end = term->rows;
|
|
||||||
|
|
||||||
term_damage_all(term);
|
term_damage_all(term);
|
||||||
}
|
}
|
||||||
|
|
@ -661,8 +695,40 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
for (size_t i = 0; i < term->vt.params.idx; i++) {
|
||||||
|
switch (term->vt.params.v[i].value) {
|
||||||
|
case 1001: /* save old highlight mouse tracking mode? */
|
||||||
|
LOG_WARN(
|
||||||
|
"unimplemented: CSI ?1001s "
|
||||||
|
"(save 'highlight mouse tracking' mode)");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERR("unimplemented: CSI ?%ds", term->vt.params.v[i].value);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
for (size_t i = 0; i < term->vt.params.idx; i++) {
|
||||||
|
switch (term->vt.params.v[i].value) {
|
||||||
|
case 1001: /* restore old highlight mouse tracking mode? */
|
||||||
|
LOG_WARN(
|
||||||
|
"unimplemented: CSI ?1001r "
|
||||||
|
"(restore 'highlight mouse tracking' mode)");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERR("unimplemented: CSI ?%dr", term->vt.params.v[i].value);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG_ERR("CSI: intermediate '?': unimplemented final: %c", final);
|
LOG_ERR("unimplemented: CSI: ?%c", final);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
72
grid.c
72
grid.c
|
|
@ -4,5 +4,75 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#define LOG_MODULE "grid"
|
#define LOG_MODULE "grid"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
struct cell *
|
||||||
|
grid_get_range(struct grid *grid, int start, int *length)
|
||||||
|
{
|
||||||
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
assert(*length <= grid->size);
|
||||||
|
|
||||||
|
int real_start = (grid->offset + start) % grid->size;
|
||||||
|
if (real_start < 0)
|
||||||
|
real_start += grid->size;
|
||||||
|
assert(real_start >= 0);
|
||||||
|
assert(real_start < grid->size);
|
||||||
|
|
||||||
|
*length = min(*length, grid->size - real_start);
|
||||||
|
assert(real_start + *length <= grid->size);
|
||||||
|
|
||||||
|
return &grid->cells[real_start];
|
||||||
|
#undef min
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grid_memset(struct grid *grid, int start, int c, int length)
|
||||||
|
{
|
||||||
|
int left = length;
|
||||||
|
while (left > 0) {
|
||||||
|
int count = left;
|
||||||
|
struct cell *cells = grid_get_range(grid, start, &count);
|
||||||
|
|
||||||
|
assert(count > 0);
|
||||||
|
assert(count <= left);
|
||||||
|
|
||||||
|
memset(cells, c, count * sizeof(cells[0]));
|
||||||
|
|
||||||
|
left -= count;
|
||||||
|
start += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grid_memmove(struct grid *grid, int dst, int src, int length)
|
||||||
|
{
|
||||||
|
int left = length;
|
||||||
|
int copy_idx = 0;
|
||||||
|
struct cell copy[left];
|
||||||
|
|
||||||
|
while (left > 0) {
|
||||||
|
int count = left;
|
||||||
|
struct cell *src_cells = grid_get_range(grid, src, &count);
|
||||||
|
|
||||||
|
memcpy(©[copy_idx], src_cells, count * sizeof(copy[0]));
|
||||||
|
|
||||||
|
left -= count;
|
||||||
|
src += count;
|
||||||
|
copy_idx += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
left = length;
|
||||||
|
copy_idx = 0;
|
||||||
|
|
||||||
|
while (left > 0) {
|
||||||
|
int count = left;
|
||||||
|
struct cell *dst_cells = grid_get_range(grid, dst, &count);
|
||||||
|
|
||||||
|
memcpy(dst_cells, ©[copy_idx], count * sizeof(copy[0]));
|
||||||
|
|
||||||
|
left -= count;
|
||||||
|
dst += count;
|
||||||
|
copy_idx += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
5
grid.h
5
grid.h
|
|
@ -1,3 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
|
struct cell *grid_get_range(struct grid *grid, int start, int *length);
|
||||||
|
void grid_memset(struct grid *grid, int start, int c, int length);
|
||||||
|
void grid_memmove(struct grid *grid, int dst, int src, int length);
|
||||||
|
|
|
||||||
2
input.c
2
input.c
|
|
@ -10,7 +10,7 @@
|
||||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||||
|
|
||||||
#define LOG_MODULE "input"
|
#define LOG_MODULE "input"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
|
|
|
||||||
285
main.c
285
main.c
|
|
@ -6,7 +6,9 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
//#include <termios.h>
|
//#include <termios.h>
|
||||||
|
|
@ -15,7 +17,7 @@
|
||||||
#include <xdg-shell.h>
|
#include <xdg-shell.h>
|
||||||
|
|
||||||
#define LOG_MODULE "main"
|
#define LOG_MODULE "main"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
@ -48,7 +50,7 @@ struct wayland {
|
||||||
struct context {
|
struct context {
|
||||||
bool quit;
|
bool quit;
|
||||||
|
|
||||||
cairo_scaled_font_t *fonts[8];
|
cairo_scaled_font_t *fonts[4];
|
||||||
cairo_font_extents_t fextents;
|
cairo_font_extents_t fextents;
|
||||||
|
|
||||||
int width;
|
int width;
|
||||||
|
|
@ -61,7 +63,6 @@ struct context {
|
||||||
bool frame_is_scheduled;
|
bool frame_is_scheduled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void frame_callback(
|
static void frame_callback(
|
||||||
void *data, struct wl_callback *wl_callback, uint32_t callback_data);
|
void *data, struct wl_callback *wl_callback, uint32_t callback_data);
|
||||||
|
|
||||||
|
|
@ -76,27 +77,66 @@ attrs_to_font(struct context *c, const struct attributes *attrs)
|
||||||
return c->fonts[idx];
|
return c->fonts[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct glyph_sequence {
|
||||||
|
cairo_glyph_t glyphs[10000];
|
||||||
|
cairo_glyph_t *g;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
struct attributes attrs;
|
||||||
|
struct rgba foreground;
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
grid_render_update(struct context *c, struct buffer *buf, const struct damage *dmg)
|
grid_render_update(struct context *c, struct buffer *buf, const struct damage *dmg)
|
||||||
{
|
{
|
||||||
LOG_DBG("damage: UPDATE: %d -> %d",
|
LOG_DBG("damage: UPDATE: %d -> %d (offset = %d)",
|
||||||
dmg->range.start, dmg->range.start + dmg->range.length);
|
(dmg->range.start - c->term.grid->offset) % c->term.grid->size,
|
||||||
|
(dmg->range.start - c->term.grid->offset) % c->term.grid->size + dmg->range.length,
|
||||||
|
c->term.grid->offset);
|
||||||
|
|
||||||
|
int start = dmg->range.start;
|
||||||
|
int length = dmg->range.length;
|
||||||
|
|
||||||
|
if (start < c->term.grid->offset) {
|
||||||
|
int end = start + length;
|
||||||
|
if (end >= c->term.grid->offset) {
|
||||||
|
start = c->term.grid->offset;
|
||||||
|
length = end - start;
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const int cols = c->term.cols;
|
const int cols = c->term.cols;
|
||||||
|
|
||||||
for (int linear_cursor = dmg->range.start,
|
struct glyph_sequence gseq = {.g = gseq.glyphs};
|
||||||
row = dmg->range.start / cols,
|
|
||||||
col = dmg->range.start % cols;
|
for (int linear_cursor = start,
|
||||||
linear_cursor < dmg->range.start + dmg->range.length;
|
row = ((start - c->term.grid->offset) % c->term.grid->size) / cols,
|
||||||
|
col = ((start - c->term.grid->offset) % c->term.grid->size) % cols;
|
||||||
|
linear_cursor < start + length;
|
||||||
linear_cursor++,
|
linear_cursor++,
|
||||||
//col = (col + 1) % cols,
|
|
||||||
col = col + 1 >= c->term.cols ? 0 : col + 1,
|
col = col + 1 >= c->term.cols ? 0 : col + 1,
|
||||||
row += col == 0 ? 1 : 0)
|
row += col == 0 ? 1 : 0)
|
||||||
{
|
{
|
||||||
//LOG_DBG("UPDATE: %d (%dx%d)", linear_cursor, row, col);
|
|
||||||
|
|
||||||
const struct cell *cell = &c->term.grid->cells[linear_cursor];
|
assert(row >= 0);
|
||||||
bool has_cursor = c->term.cursor.linear == linear_cursor;
|
assert(row < c->term.rows);
|
||||||
|
assert(col >= 0);
|
||||||
|
assert(col < c->term.cols);
|
||||||
|
|
||||||
|
int cell_idx = linear_cursor % c->term.grid->size;
|
||||||
|
if (cell_idx < 0)
|
||||||
|
cell_idx += c->term.grid->size;
|
||||||
|
|
||||||
|
assert(cell_idx >= 0);
|
||||||
|
assert(cell_idx < c->term.rows * c->term.cols);
|
||||||
|
|
||||||
|
const struct cell *cell = &c->term.grid->cells[cell_idx];
|
||||||
|
|
||||||
|
/* Cursor here? */
|
||||||
|
bool has_cursor
|
||||||
|
= (!c->term.hide_cursor &&
|
||||||
|
(c->term.cursor.linear == linear_cursor - c->term.grid->offset));
|
||||||
|
|
||||||
int x = col * c->term.cell_width;
|
int x = col * c->term.cell_width;
|
||||||
int y = row * c->term.cell_height;
|
int y = row * c->term.cell_height;
|
||||||
|
|
@ -120,15 +160,9 @@ grid_render_update(struct context *c, struct buffer *buf, const struct damage *d
|
||||||
background = swap;
|
background = swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
//LOG_DBG("cell %dx%d dirty: c=0x%02x (%c)",
|
/* Background */
|
||||||
// row, col, cell->c[0], cell->c[0]);
|
|
||||||
|
|
||||||
cairo_scaled_font_t *font = attrs_to_font(c, &cell->attrs);
|
|
||||||
cairo_set_scaled_font(buf->cairo, font);
|
|
||||||
cairo_set_source_rgba(
|
cairo_set_source_rgba(
|
||||||
buf->cairo, background.r, background.g, background.b, background.a);
|
buf->cairo, background.r, background.g, background.b, background.a);
|
||||||
|
|
||||||
/* Background */
|
|
||||||
cairo_rectangle(buf->cairo, x, y, width, height);
|
cairo_rectangle(buf->cairo, x, y, width, height);
|
||||||
cairo_fill(buf->cairo);
|
cairo_fill(buf->cairo);
|
||||||
|
|
||||||
|
|
@ -138,37 +172,75 @@ grid_render_update(struct context *c, struct buffer *buf, const struct damage *d
|
||||||
if (cell->attrs.conceal)
|
if (cell->attrs.conceal)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cairo_glyph_t *glyphs = NULL;
|
/*
|
||||||
int num_glyphs = 0;
|
* cairo_show_glyphs() apparently works *much* faster when
|
||||||
|
* called once with a large array of glyphs, compared to
|
||||||
|
* multiple calls with a single glyph.
|
||||||
|
*
|
||||||
|
* So, collect glyphs until cell attributes change, then we
|
||||||
|
* 'flush' (render) the glyphs.
|
||||||
|
*/
|
||||||
|
|
||||||
cairo_status_t status = cairo_scaled_font_text_to_glyphs(
|
if (memcmp(&cell->attrs, &gseq.attrs, sizeof(cell->attrs)) != 0 ||
|
||||||
font, x, y + c->fextents.ascent,
|
gseq.count >= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - 10 ||
|
||||||
cell->c, strlen(cell->c), &glyphs, &num_glyphs,
|
memcmp(&gseq.foreground, &foreground, sizeof(foreground)) != 0)
|
||||||
NULL, NULL, NULL);
|
{
|
||||||
|
if (gseq.count >= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - 10)
|
||||||
|
LOG_WARN("hit glyph limit");
|
||||||
|
cairo_set_scaled_font(buf->cairo, attrs_to_font(c, &gseq.attrs));
|
||||||
|
cairo_set_source_rgba(
|
||||||
|
buf->cairo, gseq.foreground.r, gseq.foreground.g,
|
||||||
|
gseq.foreground.b, gseq.foreground.a);
|
||||||
|
|
||||||
if (status != CAIRO_STATUS_SUCCESS) {
|
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER);
|
||||||
if (glyphs != NULL)
|
cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count);
|
||||||
cairo_glyph_free(glyphs);
|
|
||||||
continue;
|
gseq.g = gseq.glyphs;
|
||||||
|
gseq.count = 0;
|
||||||
|
gseq.attrs = cell->attrs;
|
||||||
|
gseq.foreground = foreground;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int new_glyphs
|
||||||
|
= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - gseq.count;
|
||||||
|
|
||||||
|
cairo_status_t status = cairo_scaled_font_text_to_glyphs(
|
||||||
|
attrs_to_font(c, &cell->attrs), x, y + c->fextents.ascent,
|
||||||
|
cell->c, strlen(cell->c), &gseq.g, &new_glyphs,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (status != CAIRO_STATUS_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gseq.g += new_glyphs;
|
||||||
|
gseq.count += new_glyphs;
|
||||||
|
assert(gseq.count <= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gseq.count > 0) {
|
||||||
|
cairo_set_scaled_font(buf->cairo, attrs_to_font(c, &gseq.attrs));
|
||||||
cairo_set_source_rgba(
|
cairo_set_source_rgba(
|
||||||
buf->cairo, foreground.r, foreground.g, foreground.b, foreground.a);
|
buf->cairo, gseq.foreground.r, gseq.foreground.g,
|
||||||
cairo_show_glyphs(buf->cairo, glyphs, num_glyphs);
|
gseq.foreground.b, gseq.foreground.a);
|
||||||
cairo_glyph_free(glyphs);
|
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER);
|
||||||
|
cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_surface_damage_buffer(
|
wl_surface_damage_buffer(
|
||||||
c->wl.surface,
|
c->wl.surface,
|
||||||
0, (dmg->range.start / cols) * c->term.cell_height,
|
0, ((dmg->range.start - c->term.grid->offset) / cols) * c->term.cell_height,
|
||||||
buf->width, (dmg->range.length + cols - 1) / cols * c->term.cell_height);
|
buf->width, (dmg->range.length + cols - 1) / cols * c->term.cell_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dmg)
|
grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dmg)
|
||||||
{
|
{
|
||||||
LOG_DBG("damage: ERASE: %d -> %d",
|
LOG_DBG("damage: ERASE: %d -> %d (offset = %d)",
|
||||||
dmg->range.start, dmg->range.start + dmg->range.length);
|
(dmg->range.start - c->term.grid->offset) % c->term.grid->size,
|
||||||
|
(dmg->range.start - c->term.grid->offset) % c->term.grid->size + dmg->range.length,
|
||||||
|
c->term.grid->offset);
|
||||||
|
|
||||||
|
assert(dmg->range.start >= c->term.grid->offset);
|
||||||
|
|
||||||
cairo_set_source_rgba(
|
cairo_set_source_rgba(
|
||||||
buf->cairo, default_background.r, default_background.g,
|
buf->cairo, default_background.r, default_background.g,
|
||||||
|
|
@ -176,7 +248,7 @@ grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dm
|
||||||
|
|
||||||
const int cols = c->term.cols;
|
const int cols = c->term.cols;
|
||||||
|
|
||||||
int start = dmg->range.start;
|
int start = (dmg->range.start - c->term.grid->offset) % c->term.grid->size;
|
||||||
int left = dmg->range.length;
|
int left = dmg->range.length;
|
||||||
|
|
||||||
int row = start / cols;
|
int row = start / cols;
|
||||||
|
|
@ -238,17 +310,6 @@ grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dm
|
||||||
cairo_fill(buf->cairo);
|
cairo_fill(buf->cairo);
|
||||||
wl_surface_damage_buffer(c->wl.surface, x, y, width, height);
|
wl_surface_damage_buffer(c->wl.surface, x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redraw cursor, if it's inside the erased range */
|
|
||||||
if (c->term.cursor.linear >= dmg->range.start &&
|
|
||||||
c->term.cursor.linear < dmg->range.start + dmg->range.length)
|
|
||||||
{
|
|
||||||
grid_render_update(
|
|
||||||
c, buf,
|
|
||||||
&(struct damage){
|
|
||||||
.type = DAMAGE_UPDATE,
|
|
||||||
.range = {.start = c->term.cursor.linear, .length = 1}});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -284,7 +345,7 @@ grid_render_scroll(struct context *c, struct buffer *buf,
|
||||||
struct damage erase = {
|
struct damage erase = {
|
||||||
.type = DAMAGE_ERASE,
|
.type = DAMAGE_ERASE,
|
||||||
.range = {
|
.range = {
|
||||||
.start = max(dmg->scroll.region.end - dmg->scroll.lines,
|
.start = c->term.grid->offset + max(dmg->scroll.region.end - dmg->scroll.lines,
|
||||||
dmg->scroll.region.start) * cols,
|
dmg->scroll.region.start) * cols,
|
||||||
.length = min(dmg->scroll.region.end - dmg->scroll.region.start,
|
.length = min(dmg->scroll.region.end - dmg->scroll.region.start,
|
||||||
dmg->scroll.lines) * cols,
|
dmg->scroll.lines) * cols,
|
||||||
|
|
@ -326,7 +387,7 @@ grid_render_scroll_reverse(struct context *c, struct buffer *buf,
|
||||||
struct damage erase = {
|
struct damage erase = {
|
||||||
.type = DAMAGE_ERASE,
|
.type = DAMAGE_ERASE,
|
||||||
.range = {
|
.range = {
|
||||||
.start = dmg->scroll.region.start * cols,
|
.start = c->term.grid->offset + dmg->scroll.region.start * cols,
|
||||||
.length = min(dmg->scroll.region.end - dmg->scroll.region.start,
|
.length = min(dmg->scroll.region.end - dmg->scroll.region.start,
|
||||||
dmg->scroll.lines) * cols,
|
dmg->scroll.lines) * cols,
|
||||||
},
|
},
|
||||||
|
|
@ -337,8 +398,11 @@ grid_render_scroll_reverse(struct context *c, struct buffer *buf,
|
||||||
static void
|
static void
|
||||||
grid_render(struct context *c)
|
grid_render(struct context *c)
|
||||||
{
|
{
|
||||||
|
static int last_cursor;
|
||||||
|
|
||||||
if (tll_length(c->term.grid->damage) == 0 &&
|
if (tll_length(c->term.grid->damage) == 0 &&
|
||||||
tll_length(c->term.grid->scroll_damage) == 0)
|
tll_length(c->term.grid->scroll_damage) == 0 &&
|
||||||
|
last_cursor == c->term.grid->offset + c->term.cursor.linear)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -347,9 +411,15 @@ grid_render(struct context *c)
|
||||||
assert(c->height > 0);
|
assert(c->height > 0);
|
||||||
|
|
||||||
struct buffer *buf = shm_get_buffer(c->wl.shm, c->width, c->height);
|
struct buffer *buf = shm_get_buffer(c->wl.shm, c->width, c->height);
|
||||||
|
|
||||||
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
|
|
||||||
|
static struct buffer *last_buf = NULL;
|
||||||
|
if (last_buf != buf) {
|
||||||
|
if (last_buf != NULL)
|
||||||
|
LOG_WARN("new buffer");
|
||||||
|
last_buf = buf;
|
||||||
|
}
|
||||||
|
|
||||||
tll_foreach(c->term.grid->scroll_damage, it) {
|
tll_foreach(c->term.grid->scroll_damage, it) {
|
||||||
switch (it->item.type) {
|
switch (it->item.type) {
|
||||||
case DAMAGE_SCROLL:
|
case DAMAGE_SCROLL:
|
||||||
|
|
@ -383,6 +453,28 @@ grid_render(struct context *c)
|
||||||
tll_remove(c->term.grid->damage, it);
|
tll_remove(c->term.grid->damage, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: break out to function */
|
||||||
|
/* Re-render last cursor cell and current cursor cell */
|
||||||
|
/* Make sure previous cursor is refreshed (to avoid "ghost" cursors) */
|
||||||
|
if (last_cursor != c->term.cursor.linear) {
|
||||||
|
struct damage prev_cursor = {
|
||||||
|
.type = DAMAGE_UPDATE,
|
||||||
|
.range = {.start = last_cursor, .length = 1},
|
||||||
|
};
|
||||||
|
grid_render_update(c, buf, &prev_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct damage cursor = {
|
||||||
|
.type = DAMAGE_UPDATE,
|
||||||
|
.range = {.start = c->term.grid->offset + c->term.cursor.linear, .length = 1},
|
||||||
|
};
|
||||||
|
grid_render_update(c, buf, &cursor);
|
||||||
|
last_cursor = c->term.grid->offset + c->term.cursor.linear;
|
||||||
|
|
||||||
|
c->term.grid->offset %= c->term.grid->size;
|
||||||
|
if (c->term.grid->offset < 0)
|
||||||
|
c->term.grid->offset += c->term.grid->size;
|
||||||
|
|
||||||
//cairo_surface_flush(buf->cairo_surface);
|
//cairo_surface_flush(buf->cairo_surface);
|
||||||
wl_surface_attach(c->wl.surface, buf->wl_buf, 0, 0);
|
wl_surface_attach(c->wl.surface, buf->wl_buf, 0, 0);
|
||||||
|
|
||||||
|
|
@ -416,8 +508,6 @@ resize(struct context *c, int width, int height)
|
||||||
const size_t normal_old_size = c->term.normal.size;
|
const size_t normal_old_size = c->term.normal.size;
|
||||||
const size_t alt_old_size = c->term.alt.size;
|
const size_t alt_old_size = c->term.alt.size;
|
||||||
|
|
||||||
c->term.cell_width = (int)ceil(c->fextents.max_x_advance);
|
|
||||||
c->term.cell_height = (int)ceil(c->fextents.height);
|
|
||||||
c->term.cols = c->width / c->term.cell_width;
|
c->term.cols = c->width / c->term.cell_width;
|
||||||
c->term.rows = c->height / c->term.cell_height;
|
c->term.rows = c->height / c->term.cell_height;
|
||||||
|
|
||||||
|
|
@ -426,10 +516,10 @@ resize(struct context *c, int width, int height)
|
||||||
|
|
||||||
c->term.normal.cells = realloc(
|
c->term.normal.cells = realloc(
|
||||||
c->term.normal.cells,
|
c->term.normal.cells,
|
||||||
c->term.cols * c->term.rows * sizeof(c->term.normal.cells[0]));
|
c->term.normal.size * sizeof(c->term.normal.cells[0]));
|
||||||
c->term.alt.cells = realloc(
|
c->term.alt.cells = realloc(
|
||||||
c->term.alt.cells,
|
c->term.alt.cells,
|
||||||
c->term.cols * c->term.rows * sizeof(c->term.alt.cells[0]));
|
c->term.alt.size * sizeof(c->term.alt.cells[0]));
|
||||||
|
|
||||||
for (size_t i = normal_old_size; i < c->term.normal.size; i++) {
|
for (size_t i = normal_old_size; i < c->term.normal.size; i++) {
|
||||||
c->term.normal.cells[i] = (struct cell){
|
c->term.normal.cells[i] = (struct cell){
|
||||||
|
|
@ -445,13 +535,13 @@ resize(struct context *c, int width, int height)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("resize: %dx%d, grid: cols=%d, rows=%d",
|
LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d",
|
||||||
c->width, c->height, c->term.cols, c->term.rows);
|
c->width, c->height, c->term.cols, c->term.rows);
|
||||||
|
|
||||||
/* Update environment variables */
|
/* Update environment variables */
|
||||||
char cols_s[12], rows_s[12];
|
char cols_s[12], rows_s[12];
|
||||||
sprintf(cols_s, "%u", c->term.cols);
|
sprintf(cols_s, "%d", c->term.cols);
|
||||||
sprintf(rows_s, "%u", c->term.rows);
|
sprintf(rows_s, "%d", c->term.rows);
|
||||||
setenv("COLUMNS", cols_s, 1);
|
setenv("COLUMNS", cols_s, 1);
|
||||||
setenv("LINES", rows_s, 1);
|
setenv("LINES", rows_s, 1);
|
||||||
|
|
||||||
|
|
@ -469,6 +559,11 @@ resize(struct context *c, int width, int height)
|
||||||
if (c->term.scroll_region.end == old_rows)
|
if (c->term.scroll_region.end == old_rows)
|
||||||
c->term.scroll_region.end = c->term.rows;
|
c->term.scroll_region.end = c->term.rows;
|
||||||
|
|
||||||
|
term_cursor_to(
|
||||||
|
&c->term,
|
||||||
|
min(c->term.cursor.row, c->term.rows),
|
||||||
|
min(c->term.cursor.col, c->term.cols));
|
||||||
|
|
||||||
term_damage_all(&c->term);
|
term_damage_all(&c->term);
|
||||||
|
|
||||||
if (!c->frame_is_scheduled)
|
if (!c->frame_is_scheduled)
|
||||||
|
|
@ -721,10 +816,40 @@ keyboard_repeater(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, const char *const *argv)
|
main(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
int ret = EXIT_FAILURE;
|
int ret = EXIT_FAILURE;
|
||||||
|
|
||||||
|
static const struct option longopts[] = {
|
||||||
|
{"font", required_argument, 0, 'f'},
|
||||||
|
{NULL, no_argument, 0, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *font_name = "Dina:pixelsize=12";
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int c = getopt_long(argc, argv, ":f:h", longopts, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'f':
|
||||||
|
font_name = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ':':
|
||||||
|
fprintf(stderr, "error: -%c: missing required argument\n", optopt);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
fprintf(stderr, "error: -%c: invalid option\n", optopt);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
|
|
||||||
int repeat_pipe_fds[2] = {-1, -1};
|
int repeat_pipe_fds[2] = {-1, -1};
|
||||||
|
|
@ -739,6 +864,7 @@ main(int argc, const char *const *argv)
|
||||||
.ptmx = posix_openpt(O_RDWR | O_NOCTTY),
|
.ptmx = posix_openpt(O_RDWR | O_NOCTTY),
|
||||||
.decckm = DECCKM_CSI,
|
.decckm = DECCKM_CSI,
|
||||||
.keypad_mode = KEYPAD_NUMERICAL, /* TODO: verify */
|
.keypad_mode = KEYPAD_NUMERICAL, /* TODO: verify */
|
||||||
|
.auto_margin = true,
|
||||||
.vt = {
|
.vt = {
|
||||||
.state = 1, /* STATE_GROUND */
|
.state = 1, /* STATE_GROUND */
|
||||||
},
|
},
|
||||||
|
|
@ -764,7 +890,6 @@ main(int argc, const char *const *argv)
|
||||||
thrd_t keyboard_repeater_id;
|
thrd_t keyboard_repeater_id;
|
||||||
thrd_create(&keyboard_repeater_id, &keyboard_repeater, &c.term);
|
thrd_create(&keyboard_repeater_id, &keyboard_repeater, &c.term);
|
||||||
|
|
||||||
const char *font_name = "Dina:pixelsize=12";
|
|
||||||
c.fonts[0] = font_from_name(font_name);
|
c.fonts[0] = font_from_name(font_name);
|
||||||
if (c.fonts[0] == NULL)
|
if (c.fonts[0] == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -779,11 +904,11 @@ main(int argc, const char *const *argv)
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s:style=bold italic", font_name);
|
snprintf(fname, sizeof(fname), "%s:style=bold italic", font_name);
|
||||||
c.fonts[3] = font_from_name(fname);
|
c.fonts[3] = font_from_name(fname);
|
||||||
|
|
||||||
/* TODO; underline */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_scaled_font_extents(c.fonts[0], &c.fextents);
|
cairo_scaled_font_extents(c.fonts[0], &c.fextents);
|
||||||
|
c.term.cell_width = (int)ceil(c.fextents.max_x_advance);
|
||||||
|
c.term.cell_height = (int)ceil(c.fextents.height);
|
||||||
|
|
||||||
LOG_DBG("font: height: %.2f, x-advance: %.2f",
|
LOG_DBG("font: height: %.2f, x-advance: %.2f",
|
||||||
c.fextents.height, c.fextents.max_x_advance);
|
c.fextents.height, c.fextents.max_x_advance);
|
||||||
|
|
@ -864,6 +989,20 @@ main(int argc, const char *const *argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read logic requires non-blocking mode */
|
||||||
|
{
|
||||||
|
int fd_flags = fcntl(c.term.ptmx, F_GETFL);
|
||||||
|
if (fd_flags == -1) {
|
||||||
|
LOG_ERRNO("failed to set non blocking mode on PTY master");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(c.term.ptmx, F_SETFL, fd_flags | O_NONBLOCK) == -1) {
|
||||||
|
LOG_ERRNO("failed to set non blocking mode on PTY master");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
struct pollfd fds[] = {
|
struct pollfd fds[] = {
|
||||||
{.fd = wl_display_get_fd(c.wl.display), .events = POLLIN},
|
{.fd = wl_display_get_fd(c.wl.display), .events = POLLIN},
|
||||||
|
|
@ -888,16 +1027,18 @@ main(int argc, const char *const *argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fds[1].revents & POLLIN) {
|
if (fds[1].revents & POLLIN) {
|
||||||
uint8_t data[8192];
|
for (size_t i = 0; i < 3; i++) {
|
||||||
ssize_t count = read(c.term.ptmx, data, sizeof(data));
|
uint8_t data[8192];
|
||||||
if (count < 0) {
|
ssize_t count = read(c.term.ptmx, data, sizeof(data));
|
||||||
LOG_ERRNO("failed to read from pseudo terminal");
|
if (count < 0) {
|
||||||
break;
|
if (errno != EAGAIN)
|
||||||
|
LOG_ERRNO("failed to read from pseudo terminal");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vt_from_slave(&c.term, data, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
//LOG_DBG("%.*s", (int)count, data);
|
|
||||||
|
|
||||||
vt_from_slave(&c.term, data, count);
|
|
||||||
if (!c.frame_is_scheduled)
|
if (!c.frame_is_scheduled)
|
||||||
grid_render(&c);
|
grid_render(&c);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
osc.c
2
osc.c
|
|
@ -1,7 +1,7 @@
|
||||||
#include "osc.h"
|
#include "osc.h"
|
||||||
|
|
||||||
#define LOG_MODULE "osc"
|
#define LOG_MODULE "osc"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
2
slave.c
2
slave.c
|
|
@ -9,7 +9,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#define LOG_MODULE "slave"
|
#define LOG_MODULE "slave"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
261
terminal.c
261
terminal.c
|
|
@ -4,8 +4,9 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#define LOG_MODULE "terminal"
|
#define LOG_MODULE "terminal"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "grid.h"
|
||||||
|
|
||||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
|
@ -37,10 +38,6 @@ damage_merge_range(struct terminal *term, const struct damage *dmg)
|
||||||
old->range.start = new_start;
|
old->range.start = new_start;
|
||||||
old->range.length = new_end - new_start;
|
old->range.length = new_end - new_start;
|
||||||
|
|
||||||
assert(old->range.start >= 0);
|
|
||||||
assert(old->range.start < term->rows * term->cols);
|
|
||||||
assert(old->range.length >= 0);
|
|
||||||
assert(old->range.start + old->range.length <= term->rows * term->cols);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,16 +48,18 @@ static void
|
||||||
term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type,
|
term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type,
|
||||||
int start, int length)
|
int start, int length)
|
||||||
{
|
{
|
||||||
|
#if 1
|
||||||
|
if (tll_length(term->grid->damage) > 1024) {
|
||||||
|
term_damage_all(term);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct damage dmg = {
|
struct damage dmg = {
|
||||||
.type = damage_type,
|
.type = damage_type,
|
||||||
.range = {.start = start, .length = length},
|
.range = {.start = term->grid->offset + start, .length = length},
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(dmg.range.start >= 0);
|
|
||||||
assert(dmg.range.start < term->rows * term->cols);
|
|
||||||
assert(dmg.range.length >= 0);
|
|
||||||
assert(dmg.range.start + dmg.range.length <= term->rows * term->cols);
|
|
||||||
|
|
||||||
if (damage_merge_range(term, &dmg))
|
if (damage_merge_range(term, &dmg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -70,12 +69,14 @@ term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type,
|
||||||
void
|
void
|
||||||
term_damage_update(struct terminal *term, int start, int length)
|
term_damage_update(struct terminal *term, int start, int length)
|
||||||
{
|
{
|
||||||
|
assert(start + length <= term->rows * term->cols);
|
||||||
term_damage_update_or_erase(term, DAMAGE_UPDATE, start, length);
|
term_damage_update_or_erase(term, DAMAGE_UPDATE, start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_damage_erase(struct terminal *term, int start, int length)
|
term_damage_erase(struct terminal *term, int start, int length)
|
||||||
{
|
{
|
||||||
|
assert(start + length <= term->rows * term->cols);
|
||||||
term_damage_update_or_erase(term, DAMAGE_ERASE, start, length);
|
term_damage_update_or_erase(term, DAMAGE_ERASE, start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,82 +88,53 @@ term_damage_all(struct terminal *term)
|
||||||
term_damage_update(term, 0, term->rows * term->cols);
|
term_damage_update(term, 0, term->rows * term->cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void
|
static void
|
||||||
damage_adjust_after_scroll(struct terminal *term, enum damage_type damage_type,
|
damage_adjust_after_scroll(struct terminal *term, enum damage_type damage_type,
|
||||||
struct scroll_region region, int lines)
|
struct scroll_region region, int lines)
|
||||||
{
|
{
|
||||||
const int adjustment
|
|
||||||
= lines * term->cols * (damage_type == DAMAGE_SCROLL_REVERSE ? -1 : 1);
|
|
||||||
|
|
||||||
const int scroll_start = region.start * term->cols;
|
|
||||||
const int scroll_end = region.end * term->cols;
|
|
||||||
|
|
||||||
tll_foreach(term->grid->damage, it) {
|
tll_foreach(term->grid->damage, it) {
|
||||||
|
#if 0
|
||||||
|
if (it->item.range.start < term->grid->offset) {
|
||||||
|
int end = it->item.range.start + it->item.range.length;
|
||||||
|
if (end >= term->grid->offset) {
|
||||||
|
it->item.range.start = term->grid->offset;
|
||||||
|
it->item.range.length = end - it->item.range.start;
|
||||||
|
} else {
|
||||||
|
tll_remove(term->grid->damage, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int start = it->item.range.start;
|
int start = it->item.range.start;
|
||||||
int length = it->item.range.length;
|
int end = start + it->item.range.length;
|
||||||
int end = start + length;
|
|
||||||
|
|
||||||
if (start < scroll_start && end > scroll_start) {
|
if (start -
|
||||||
/* Start outside, end either inside or on the other side */
|
|
||||||
struct damage outside = {
|
|
||||||
.type = it->item.type,
|
|
||||||
.range = {.start = start, .length = scroll_start - start},
|
|
||||||
};
|
|
||||||
|
|
||||||
tll_push_back(term->grid->damage, outside);
|
|
||||||
start = scroll_start;
|
|
||||||
length = end - start;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start < scroll_end && end > scroll_end) {
|
|
||||||
/* End outside, start either inside or on the other side */
|
|
||||||
struct damage outside = {
|
|
||||||
.type = it->item.type,
|
|
||||||
.range = {.start = scroll_end, .length = length - scroll_end},
|
|
||||||
};
|
|
||||||
|
|
||||||
tll_push_back(term->grid->damage, outside);
|
|
||||||
end = scroll_end;
|
|
||||||
length = end - start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start >= scroll_start && end <= scroll_end) {
|
|
||||||
/* Completely inside scroll region */
|
|
||||||
start -= adjustment;
|
|
||||||
it->item.range.start = start;
|
|
||||||
|
|
||||||
if (start < scroll_start) {
|
|
||||||
/* Scrolled up outside scroll region */
|
|
||||||
int new_length = length - (scroll_start - start);
|
|
||||||
assert(new_length < length);
|
|
||||||
|
|
||||||
if (new_length <= 0)
|
|
||||||
tll_remove(term->grid->damage, it);
|
|
||||||
else {
|
|
||||||
it->item.range.start = scroll_start;
|
|
||||||
it->item.range.length = new_length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start + length > scroll_end) {
|
|
||||||
/* Scrolled down outside scroll region */
|
|
||||||
if (start >= scroll_end)
|
|
||||||
tll_remove(term->grid->damage, it);
|
|
||||||
else {
|
|
||||||
it->item.range.start = start;
|
|
||||||
it->item.range.length = scroll_end - start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
term_damage_scroll(struct terminal *term, enum damage_type damage_type,
|
term_damage_scroll(struct terminal *term, enum damage_type damage_type,
|
||||||
struct scroll_region region, int lines)
|
struct scroll_region region, int lines)
|
||||||
{
|
{
|
||||||
damage_adjust_after_scroll(term, damage_type, region, lines);
|
//damage_adjust_after_scroll(term, damage_type, region, lines);
|
||||||
|
if (damage_type == DAMAGE_SCROLL) {
|
||||||
|
tll_foreach(term->grid->damage, it) {
|
||||||
|
int start = it->item.range.start;
|
||||||
|
int length = it->item.range.length;
|
||||||
|
|
||||||
|
if (start < term->grid->offset) {
|
||||||
|
int end = start + length;
|
||||||
|
if (end >= term->grid->offset) {
|
||||||
|
it->item.range.start = term->grid->offset;
|
||||||
|
it->item.range.length = end - it->item.range.start;
|
||||||
|
} else
|
||||||
|
tll_remove(term->grid->damage, it);
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tll_length(term->grid->scroll_damage) > 0) {
|
if (tll_length(term->grid->scroll_damage) > 0) {
|
||||||
struct damage *dmg = &tll_back(term->grid->scroll_damage);
|
struct damage *dmg = &tll_back(term->grid->scroll_damage);
|
||||||
|
|
@ -185,8 +157,11 @@ term_damage_scroll(struct terminal *term, enum damage_type damage_type,
|
||||||
void
|
void
|
||||||
term_erase(struct terminal *term, int start, int end)
|
term_erase(struct terminal *term, int start, int end)
|
||||||
{
|
{
|
||||||
|
LOG_DBG("erase: %d-%d", start, end);
|
||||||
assert(end >= start);
|
assert(end >= start);
|
||||||
memset(&term->grid->cells[start], 0, (end - start) * sizeof(term->grid->cells[0]));
|
assert(end <= term->rows * term->cols);
|
||||||
|
|
||||||
|
grid_memset(term->grid, start, 0, end - start);
|
||||||
term_damage_erase(term, start, end - start);
|
term_damage_erase(term, start, end - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,36 +174,41 @@ term_cursor_linear(const struct terminal *term, int row, int col)
|
||||||
void
|
void
|
||||||
term_cursor_to(struct terminal *term, int row, int col)
|
term_cursor_to(struct terminal *term, int row, int col)
|
||||||
{
|
{
|
||||||
assert(row >= 0);
|
|
||||||
assert(row < term->rows);
|
assert(row < term->rows);
|
||||||
assert(col >= 0);
|
|
||||||
assert(col < term->cols);
|
assert(col < term->cols);
|
||||||
|
|
||||||
int new_linear = row * term->cols + col;
|
int new_linear = row * term->cols + col;
|
||||||
assert(new_linear >= 0);
|
|
||||||
assert(new_linear < term->rows * term->cols);
|
assert(new_linear < term->rows * term->cols);
|
||||||
|
|
||||||
term_damage_update(term, term->cursor.linear, 1);
|
|
||||||
term_damage_update(term, new_linear, 1);
|
|
||||||
term->print_needs_wrap = false;
|
term->print_needs_wrap = false;
|
||||||
|
|
||||||
term->cursor.linear = new_linear;
|
term->cursor.linear = new_linear;
|
||||||
term->cursor.col = col;
|
term->cursor.col = col;
|
||||||
term->cursor.row = row;
|
term->cursor.row = row;
|
||||||
|
|
||||||
|
int len = term->cols;
|
||||||
|
term->grid->cur_line = grid_get_range(
|
||||||
|
term->grid, term->cursor.linear - col, &len);
|
||||||
|
|
||||||
|
assert(len == term->cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_cursor_left(struct terminal *term, int count)
|
term_cursor_left(struct terminal *term, int count)
|
||||||
{
|
{
|
||||||
int move_amount = min(term->cursor.col, count);
|
int move_amount = min(term->cursor.col, count);
|
||||||
term_cursor_to(term, term->cursor.row, term->cursor.col - move_amount);
|
term->cursor.linear -= move_amount;
|
||||||
|
term->cursor.col -= move_amount;
|
||||||
|
term->print_needs_wrap = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_cursor_right(struct terminal *term, int count)
|
term_cursor_right(struct terminal *term, int count)
|
||||||
{
|
{
|
||||||
int move_amount = min(term->cols - term->cursor.col - 1, count);
|
int move_amount = min(term->cols - term->cursor.col - 1, count);
|
||||||
term_cursor_to(term, term->cursor.row, term->cursor.col + move_amount);
|
term->cursor.linear += move_amount;
|
||||||
|
term->cursor.col += move_amount;
|
||||||
|
term->print_needs_wrap = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -248,27 +228,61 @@ term_cursor_down(struct terminal *term, int count)
|
||||||
void
|
void
|
||||||
term_scroll_partial(struct terminal *term, struct scroll_region region, int rows)
|
term_scroll_partial(struct terminal *term, struct scroll_region region, int rows)
|
||||||
{
|
{
|
||||||
if (rows >= region.end - region.start) {
|
LOG_DBG("scroll: %d rows", rows);
|
||||||
assert(false && "untested");
|
|
||||||
return;
|
if (region.start > 0) {
|
||||||
|
/* TODO: check if it's worth memoving the scroll area instead,
|
||||||
|
* under certain circumstances */
|
||||||
|
|
||||||
|
grid_memmove(term->grid, rows * term->cols, 0, region.start * term->cols);
|
||||||
|
|
||||||
|
tll_foreach(term->grid->damage, it) {
|
||||||
|
int start = it->item.range.start - term->grid->offset;
|
||||||
|
int end __attribute__((unused)) = start + it->item.range.length;
|
||||||
|
|
||||||
|
if (start < region.start * term->cols) {
|
||||||
|
assert(end <= region.start * term->cols);
|
||||||
|
it->item.range.start += rows * term->cols;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int cell_dst = (region.start + 0) * term->cols;
|
if (region.end < term->rows) {
|
||||||
int cell_src = (region.start + rows) * term->cols;
|
/* Copy scrolled-up bottom region to new bottom region */
|
||||||
int cell_count = (region.end - region.start - rows) * term->cols;
|
grid_memmove(
|
||||||
|
term->grid,
|
||||||
|
(region.end + rows) * term->cols,
|
||||||
|
region.end * term->cols,
|
||||||
|
(term->rows - region.end) * term->cols);
|
||||||
|
|
||||||
LOG_DBG("moving %d lines from row %d to row %d", cell_count / term->cols,
|
tll_foreach(term->grid->damage, it) {
|
||||||
cell_src / term->cols, cell_dst / term->cols);
|
int start = it->item.range.start - term->grid->offset;
|
||||||
|
int end = start + it->item.range.length;
|
||||||
|
|
||||||
const size_t bytes = cell_count * sizeof(term->grid->cells[0]);
|
if (end > region.end * term->cols) {
|
||||||
memmove(
|
assert(start >= region.end * term->cols);
|
||||||
&term->grid->cells[cell_dst], &term->grid->cells[cell_src],
|
it->item.range.start += rows * term->cols;
|
||||||
bytes);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memset(&term->grid->cells[(region.end - rows) * term->cols], 0,
|
/* Offset grid origin */
|
||||||
rows * term->cols * sizeof(term->grid->cells[0]));
|
term->grid->offset += rows * term->cols;
|
||||||
|
|
||||||
|
/* Clear scrolled-in lines */
|
||||||
|
grid_memset(
|
||||||
|
term->grid,
|
||||||
|
max(0, region.end - rows) * term->cols,
|
||||||
|
0,
|
||||||
|
min(rows, term->rows) * term->cols);
|
||||||
|
|
||||||
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
||||||
|
|
||||||
|
int len = term->cols;
|
||||||
|
term->grid->cur_line = grid_get_range(
|
||||||
|
term->grid, term->cursor.linear - term->cursor.col, &len);
|
||||||
|
|
||||||
|
assert(len == term->cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -281,27 +295,56 @@ void
|
||||||
term_scroll_reverse_partial(struct terminal *term,
|
term_scroll_reverse_partial(struct terminal *term,
|
||||||
struct scroll_region region, int rows)
|
struct scroll_region region, int rows)
|
||||||
{
|
{
|
||||||
if (rows >= region.end - region.start) {
|
if (region.end < term->rows) {
|
||||||
assert(false && "todo");
|
grid_memmove(
|
||||||
return;
|
term->grid,
|
||||||
|
(region.end - rows) * term->cols,
|
||||||
|
region.end * term->cols,
|
||||||
|
(term->rows - region.end) * term->cols);
|
||||||
|
|
||||||
|
tll_foreach(term->grid->damage, it) {
|
||||||
|
int start = it->item.range.start - term->grid->offset;
|
||||||
|
int end = start + it->item.range.length;
|
||||||
|
|
||||||
|
if (end > region.end * term->cols) {
|
||||||
|
assert(start >= region.end * term->cols);
|
||||||
|
it->item.range.start -= rows * term->cols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cell_dst = (region.start + rows) * term->cols;
|
if (region.start > 0) {
|
||||||
int cell_src = (region.start + 0) * term->cols;
|
grid_memmove(
|
||||||
int cell_count = (region.end - region.start - rows) * term->cols;
|
term->grid, -rows * term->cols, 0, region.start * term->cols);
|
||||||
|
|
||||||
LOG_DBG("moving %d lines from row %d to row %d", cell_count / term->cols,
|
tll_foreach(term->grid->damage, it) {
|
||||||
cell_src / term->cols, cell_dst / term->cols);
|
int start = it->item.range.start - term->grid->offset;
|
||||||
|
int end __attribute__((unused)) = start + it->item.range.length;
|
||||||
|
|
||||||
const size_t bytes = cell_count * sizeof(term->grid->cells[0]);
|
if (start < region.start * term->cols) {
|
||||||
memmove(
|
if (end > region.start * term->cols) {
|
||||||
&term->grid->cells[cell_dst], &term->grid->cells[cell_src],
|
LOG_ERR("region.start = %d, rows = %d, damage.start = %d, damage.end = %d (%s)",
|
||||||
bytes);
|
region.start, rows, start, end, it->item.type == DAMAGE_UPDATE ? "UPDATE" : "ERASE");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
assert(end <= region.start * term->cols);
|
||||||
|
it->item.range.start -= rows * term->cols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memset(&term->grid->cells[cell_src], 0,
|
term->grid->offset -= rows * term->cols;
|
||||||
rows * term->cols * sizeof(term->grid->cells[0]));
|
|
||||||
|
grid_memset(term->grid, region.start * term->cols, 0, rows * term->cols);
|
||||||
|
|
||||||
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
||||||
|
|
||||||
|
int len = term->cols;
|
||||||
|
term->grid->cur_line = grid_get_range(
|
||||||
|
term->grid, term->cursor.linear - term->cursor.col, &len);
|
||||||
|
|
||||||
|
assert(len == term->cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
20
terminal.h
20
terminal.h
|
|
@ -62,10 +62,11 @@ struct damage {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct grid {
|
struct grid {
|
||||||
size_t size;
|
int size;
|
||||||
size_t offset;
|
int offset;
|
||||||
|
|
||||||
struct cell *cells;
|
struct cell *cells;
|
||||||
|
struct cell *cur_line;
|
||||||
|
|
||||||
tll(struct damage) damage;
|
tll(struct damage) damage;
|
||||||
tll(struct damage) scroll_damage;
|
tll(struct damage) scroll_damage;
|
||||||
|
|
@ -73,7 +74,7 @@ struct grid {
|
||||||
|
|
||||||
struct vt_subparams {
|
struct vt_subparams {
|
||||||
unsigned value[16];
|
unsigned value[16];
|
||||||
size_t idx;
|
int idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vt_param {
|
struct vt_param {
|
||||||
|
|
@ -85,20 +86,20 @@ struct vt {
|
||||||
int state; /* enum state */
|
int state; /* enum state */
|
||||||
struct {
|
struct {
|
||||||
struct vt_param v[16];
|
struct vt_param v[16];
|
||||||
size_t idx;
|
int idx;
|
||||||
} params;
|
} params;
|
||||||
struct {
|
struct {
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
size_t idx;
|
int idx;
|
||||||
} intermediates;
|
} intermediates;
|
||||||
struct {
|
struct {
|
||||||
uint8_t data[1024];
|
uint8_t data[1024];
|
||||||
size_t idx;
|
int idx;
|
||||||
} osc;
|
} osc;
|
||||||
struct {
|
struct {
|
||||||
uint8_t data[4];
|
uint8_t data[4];
|
||||||
size_t idx;
|
int idx;
|
||||||
size_t left;
|
int left;
|
||||||
} utf8;
|
} utf8;
|
||||||
struct attributes attrs;
|
struct attributes attrs;
|
||||||
bool dim;
|
bool dim;
|
||||||
|
|
@ -132,6 +133,9 @@ struct terminal {
|
||||||
|
|
||||||
enum decckm decckm;
|
enum decckm decckm;
|
||||||
enum keypad_mode keypad_mode;
|
enum keypad_mode keypad_mode;
|
||||||
|
bool hide_cursor;
|
||||||
|
bool auto_margin;
|
||||||
|
bool insert_mode;
|
||||||
bool bracketed_paste;
|
bool bracketed_paste;
|
||||||
|
|
||||||
struct vt vt;
|
struct vt vt;
|
||||||
|
|
|
||||||
48
vt.c
48
vt.c
|
|
@ -5,7 +5,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#define LOG_MODULE "vt"
|
#define LOG_MODULE "vt"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "csi.h"
|
#include "csi.h"
|
||||||
#include "osc.h"
|
#include "osc.h"
|
||||||
|
|
@ -555,7 +555,7 @@ static const enum action exit_actions[] = {
|
||||||
static bool
|
static bool
|
||||||
esc_dispatch(struct terminal *term, uint8_t final)
|
esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
{
|
{
|
||||||
#if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLED_DBG
|
#if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
||||||
char log[1024];
|
char log[1024];
|
||||||
int c = snprintf(log, sizeof(log), "ESC: ");
|
int c = snprintf(log, sizeof(log), "ESC: ");
|
||||||
|
|
||||||
|
|
@ -568,6 +568,7 @@ esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
switch (final) {
|
switch (final) {
|
||||||
case 'B': {
|
case 'B': {
|
||||||
|
/* Configure G0-G3 to use ASCII */
|
||||||
char param = term->vt.params.idx > 0 ? term->vt.params.v[0].value : '(';
|
char param = term->vt.params.idx > 0 ? term->vt.params.v[0].value : '(';
|
||||||
|
|
||||||
switch (param) {
|
switch (param) {
|
||||||
|
|
@ -578,11 +579,30 @@ esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
case ')':
|
case ')':
|
||||||
case '*':
|
case '*':
|
||||||
case '+':
|
case '+':
|
||||||
LOG_ERR("unimplemented: character charset: %c", param);
|
LOG_WARN("unimplemented: charset %c uses ASCII", param);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG_ERR("ESC <id> B: invalid charset identifier: %c", param);
|
LOG_ERR("<ESC>%cB: invalid charset identifier", param);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '0': {
|
||||||
|
/* Configure G0-G3 to use special chars + line drawing */
|
||||||
|
char param = term->vt.params.idx > 0 ? term->vt.params.v[0].value : '(';
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '*':
|
||||||
|
case '+':
|
||||||
|
LOG_WARN("unimplemented: charset %c uses special characters and line drawings", param);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERR("<ESC>%c0: invalid charset identifier", param);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -664,13 +684,13 @@ action(struct terminal *term, enum action action, uint8_t c)
|
||||||
|
|
||||||
case ACTION_CLEAR:
|
case ACTION_CLEAR:
|
||||||
memset(&term->vt.params, 0, sizeof(term->vt.params));
|
memset(&term->vt.params, 0, sizeof(term->vt.params));
|
||||||
memset(&term->vt.intermediates, 0, sizeof(term->vt.intermediates));
|
term->vt.intermediates.idx = 0;
|
||||||
memset(&term->vt.osc, 0, sizeof(term->vt.osc));
|
term->vt.osc.idx = 0;
|
||||||
memset(&term->vt.utf8, 0, sizeof(term->vt.utf8));
|
term->vt.utf8.idx = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_PRINT: {
|
case ACTION_PRINT: {
|
||||||
if (term->print_needs_wrap) {
|
if (term->auto_margin && term->print_needs_wrap) {
|
||||||
if (term->cursor.row == term->scroll_region.end - 1) {
|
if (term->cursor.row == term->scroll_region.end - 1) {
|
||||||
term_scroll(term, 1);
|
term_scroll(term, 1);
|
||||||
term_cursor_to(term, term->cursor.row, 0);
|
term_cursor_to(term, term->cursor.row, 0);
|
||||||
|
|
@ -678,14 +698,22 @@ action(struct terminal *term, enum action action, uint8_t c)
|
||||||
term_cursor_to(term, term->cursor.row + 1, 0);
|
term_cursor_to(term, term->cursor.row + 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cell *cell = &term->grid->cells[term->cursor.linear];
|
struct cell *cell = &term->grid->cur_line[term->cursor.col];
|
||||||
term_damage_update(term, term->cursor.linear, 1);
|
term_damage_update(term, term->cursor.linear, 1);
|
||||||
|
|
||||||
|
if (term->insert_mode) {
|
||||||
|
assert(false && "untested");
|
||||||
|
grid_memmove(
|
||||||
|
term->grid, term->cursor.linear + 1, term->cursor.linear,
|
||||||
|
term->cols - term->cursor.col - 1);
|
||||||
|
term_damage_update(
|
||||||
|
term, term->cursor.linear + 1, term->cols - term->cursor.col - 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (term->vt.utf8.idx > 0) {
|
if (term->vt.utf8.idx > 0) {
|
||||||
//LOG_DBG("print: UTF8: %.*s", (int)term->vt.utf8.idx, term->vt.utf8.data);
|
//LOG_DBG("print: UTF8: %.*s", (int)term->vt.utf8.idx, term->vt.utf8.data);
|
||||||
memcpy(cell->c, term->vt.utf8.data, term->vt.utf8.idx);
|
memcpy(cell->c, term->vt.utf8.data, term->vt.utf8.idx);
|
||||||
cell->c[term->vt.utf8.idx] = '\0';
|
cell->c[term->vt.utf8.idx] = '\0';
|
||||||
memset(&term->vt.utf8, 0, sizeof(term->vt.utf8));
|
|
||||||
} else {
|
} else {
|
||||||
//LOG_DBG("print: ASCII: %c", c);
|
//LOG_DBG("print: ASCII: %c", c);
|
||||||
cell->c[0] = c;
|
cell->c[0] = c;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue