add some runtime options, add some OSC (including glyph width report)

This commit is contained in:
uobikiemukot 2014-03-24 22:27:41 +09:00 committed by uobikiemukot
parent 8fd4f4995d
commit 42a3fbdbe6
17 changed files with 8012 additions and 678 deletions

View file

@ -91,3 +91,57 @@
* LAZY_DRAW(データ量が多いときに描画を抑制する)を追加
* BACKGROUND_DRAW(VT切り替え後も描画を続ける)を追加
* struct terminalのoffsetを削除
2014-03-24
* version 0.2.1
* BACKGROUND_DRAW, ROTATEの設定をconf.hでなく環境変数YAFTでするようにした
(実行時に変更する必要がないと思われるものは相変わらずconf.hで指定)
* 環境変数YAFTで有効なオプション
wall: 背景画像を有効にする
background or bg: activeになっていないVTでも描画を続ける(2画面用)
clockwise or cw: 90度描画を回転
counter_clockwise or ccw: 270度描画を回転
upside_down or ud: 180度描画を回転
ex) YAFT="wall cw bg" yaft
* 環境変数FRAMEBUFFER
framebuffer deviceを指定する
ex) FRAMEBUFFER="/dev/fb0" yaft
* 幾つかのOSCを実装した
OSC 4: color paletteの変更
色の設定(rgbの指定は1-4桁)
OSC 4 ; c ; rgb:rr/gg/bb ST
OSC 4 ; c ; #rrggbb ST
c番目の色設定の応答
request
OSC 4 ; c ; ? ST
response
OSC 4 ; c ; rgb:rr/gg/bb ST
OSC 104: color paletteの初期化
c番目の色を初期化
OSC 104 ; c ST
全ての色を初期化
OSC 104 ST
OSC 8900: glyph width report
requestの際にwidth, from, toの指定を強制するようにした
* request *
OSC 8900 ; Ps ; ? : Pw : Pf : Pt ST
Ps: reserved
Pw: width (0 or 1 or 2)
Pf: beginning of unicode code point
Pt: end of unicode code point
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
* answer *
OSC 8900 ; Ps ; Pt ; Pf : Pt ; Pf : Pt ; ... ST
Ps: responce code
0: ok (default)
1: recognized but not supported
2: not recognized
Pt: reserved (maybe East Asian Width Version)
<!-- Pw: width (0 or 1 or 2) depricated -->
Pf: beginning of unicode code point
Pt: end of unicode code point
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
(ref)
http://uobikiemukot.github.io/yaft/glyph_width_report.html
https://gist.github.com/saitoha/8767268
* コードを色々整理した

15
color.h
View file

@ -4,22 +4,9 @@
http://en.wikipedia.org/wiki/ANSI_escape_code
*/
const uint32_t color_list[COLORS] = {
/* system color: 16
*/
/* system color: 16 */
0x000000, 0xAA0000, 0x00AA00, 0xAA5500, 0x0000AA, 0xAA00AA, 0x00AAAA, 0xAAAAAA/* 0xAAAAAA */,
0x555555, 0xFF5555, 0x55FF55, 0xFFFF55, 0x5555FF, 0xFF55FF, 0x55FFFF, 0xDFDFDF/* 0xFFFFFF */,
/* dark system color
0x000000, 0x660000, 0x006600, 0x661100, 0x000066, 0x660066, 0x006666, 0x666666,
0x444444, 0x774444, 0x447744, 0x777744, 0x444477, 0x774477, 0x447777, 0x777777,
*/
/* solarized
0x073642, 0xDC322F, 0x859900, 0xB58900, 0x268BD2, 0xD33682, 0x2AA198, 0xEEE8D5,
0x002B36, 0xCB4B16, 0x586E75, 0x657B83, 0x839496, 0x6C71C4, 0x93A1A1, 0xFDF6E3,
*/
/* solarized fix
0x000000, 0xDC322F, 0x859900, 0xB58900, 0x268BD2, 0xD33682, 0x2AA198, 0x93A1A1,
0x555555, 0xEC423F, 0x95A910, 0xA59910, 0x6C71C4, 0xE34692, 0x3AB1A8, 0xCEC8B5,
*/
/* color cube: 216 */
0x000000, 0x00005F, 0x000087, 0x0000AF, 0x0000D7, 0x0000FF, 0x005F00, 0x005F5F,
0x005F87, 0x005FAF, 0x005FD7, 0x005FFF, 0x008700, 0x00875F, 0x008787, 0x0087AF,

View file

@ -4,9 +4,6 @@
#include <errno.h>
/* #include <execinfo.h> for DEBUG */
#include <fcntl.h>
#include <linux/fb.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <locale.h>
#include <signal.h>
#include <stdbool.h>
@ -38,7 +35,7 @@ enum char_code {
REPLACEMENT_CHARACTER = 0xFFFD,
};
enum {
enum misc {
BITS_PER_BYTE = 8,
BUFSIZE = 1024, /* read, esc, various buffer size */
SELECT_TIMEOUT = 20000, /* used by select() */
@ -50,6 +47,7 @@ enum {
DEFAULT_CHAR = SPACE, /* used for erase char, cell_size */
RESET = 0x00, /* reset for char_attr, term_mode, esc_state */
BRIGHT_INC = 8, /* value used for brightening color */
OSC_GWREPT = 8900, /* OSC Ps: mode number of yaft GWREPT */
};
enum char_attr {
@ -83,9 +81,12 @@ enum term_mode {
};
enum esc_state {
STATE_ESC = 1, /* 0x1B, \033, ESC */
STATE_RESET = 0,
STATE_ESC, /* 0x1B, \033, ESC */
STATE_CSI, /* ESC [ */
STATE_OSC, /* ESC ] */
STATE_DCS, /* ESC P */
STATE_DSCS,
};
enum width_flag {
@ -94,6 +95,13 @@ enum width_flag {
WIDE,
};
enum rotate_mode {
NORMAL = 0,
CLOCKWISE = 90,
UPSIDE_DOWN = 180,
COUNTER_CLOCKWISE = 270,
};
#include "glyph.h"
struct tty_state {
@ -101,6 +109,8 @@ struct tty_state {
bool visible;
bool redraw_flag;
bool loop_flag;
bool background_draw;
bool lazy_draw;
};
struct pair { int x, y; };
@ -112,7 +122,7 @@ struct cell {
const struct static_glyph_t *gp; /* pointer to glyph */
struct color_pair color; /* color (fg, bg) */
uint8_t attribute; /* bold, underscore, etc... */
int wide; /* wide char flag: WIDE, NEXT_TO_WIDE, HALF */
enum width_flag width; /* wide char flag: WIDE, NEXT_TO_WIDE, HALF */
};
struct parm_t { /* for parse_arg() */
@ -123,7 +133,7 @@ struct parm_t { /* for parse_arg() */
struct esc_t {
char buf[BUFSIZE];
char *bp;
int state; /* esc state */
enum esc_state state; /* esc state */
};
struct ucs_t {
@ -133,14 +143,18 @@ struct ucs_t {
};
struct state_t { /* for save, restore state */
int mode;
enum term_mode mode;
struct pair cursor;
uint8_t attribute;
};
//struct drcs_t { /* for drcs */
//int erase_mode;
//uint8_t start_char;
//};
struct terminal {
int fd; /* master fd */
//struct pair offset; /* window offset (x, y) */
int width, height; /* terminal size (pixel) */
int cols, lines; /* terminal size (cell) */
struct cell *cells; /* pointer to each cell: cells[cols + lines * num_of_cols] */
@ -148,26 +162,28 @@ struct terminal {
struct pair cursor; /* cursor pos (x, y) */
bool *line_dirty; /* dirty flag */
bool *tabstop; /* tabstop flag */
int mode; /* for set/reset mode */
enum term_mode mode; /* for set/reset mode */
bool wrap; /* whether auto wrap occured or not */
struct state_t state; /* for restore */
struct color_pair color; /* color (fg, bg) */
uint8_t attribute; /* bold, underscore, etc... */
struct esc_t esc; /* store escape sequence */
struct ucs_t ucs; /* store UTF-8 sequence */
uint32_t color_palette[COLORS]; /* 256 color palette */
};
struct framebuffer {
char *fp; /* pointer of framebuffer(read only) */
char *wall; /* buffer for wallpaper */
char *buf; /* copy of framebuffer */
int fd; /* file descriptor of framebuffer */
struct pair res; /* resolution (x, y) */
long screen_size; /* screen data size (byte) */
int line_length; /* line length (byte) */
int bpp; /* BYTES per pixel */
uint32_t color_palette[COLORS];
struct fb_cmap *cmap, *cmap_org;
//struct sixel {
//uint8_t width; /* always 1 */
//char *pixmap[CELL_HEIGHT]; /* size: 24bpp * cell width */
//};
struct tty_state tty = {
.save_tm = NULL,
.visible = true,
.redraw_flag = false,
.loop_flag = true,
.background_draw = false,
.lazy_draw = true,
};
#include "conf.h" /* user configuration */

12
conf.h
View file

@ -1,9 +1,11 @@
/* See LICENSE for licence details. */
/* framubuffer device */
const char *fb_path = "/dev/fb0";
//const char *fb_path = "/dev/tty"; /* for FreeBSD */
/* shell */
const char *shell_cmd = "/bin/bash";
//const char *shell_cmd = "/bin/csh"; /* for FreeBSD */
/* TERM value */
const char *term_name = "yaft-256color";
@ -12,18 +14,16 @@ const char *term_name = "yaft-256color";
enum {
DEFAULT_FG = 7,
DEFAULT_BG = 0,
CURSOR_COLOR = 2,
ACTIVE_CURSOR_COLOR = 2,
PASSIVE_CURSOR_COLOR = 1,
};
/* misc */
enum {
DEBUG = false,
DEBUG = true,
TABSTOP = 8,
SUBSTITUTE_HALF = 0x20, /* used for missing glyph: SPACE (0x20) */
SUBSTITUTE_WIDE = 0x3000, /* used for missing glyph: IDEOGRAPHIC SPACE(0x3000) */
REPLACEMENT_CHAR = 0xFFFD, /* used for malformed UTF-8 sequence: REPLACEMENT CHARACTER */
LAZY_DRAW = false,
BACKGROUND_DRAW = false,
NORMAL = 0, CLOCKWISE = 90, UPSIDE_DOWN = 180, COUNTER_CLOCKWISE = 270,
ROTATE = CLOCKWISE, /* 0 or 90 or 180 or 270 (see above) */
LAZY_DRAW = true,
};

124
draw.h Normal file
View file

@ -0,0 +1,124 @@
/* See LICENSE for licence details. */
int get_rotated_pos(struct framebuffer *fb, struct terminal *term, int x, int y)
{
int p, q;
long pos;
if (fb->rotate == CLOCKWISE) {
p = y;
q = (term->width - 1) - x;
}
else if (fb->rotate == UPSIDE_DOWN) {
p = (term->width - 1) - x;
q = (term->height - 1) - y;
}
else if (fb->rotate == COUNTER_CLOCKWISE) {
p = (term->height - 1) - y;
q = x;
}
else { /* rotate: NORMAL */
p = x;
q = y;
}
pos = p * fb->bpp + q * fb->line_length;
if (pos < 0 || pos >= fb->screen_size) {
fprintf(stderr, "(%d, %d) -> (%d, %d) term:(%d, %d) res:(%d, %d) pos:%ld\n",
x, y, p, q, term->width, term->height, fb->res.x, fb->res.y, pos);
exit(EXIT_FAILURE);
}
return pos;
}
void draw_line(struct framebuffer *fb, struct terminal *term, int line)
{
int copy_size, pos, bit_shift, margin_right;
int col, glyph_width_offset, glyph_height_offset;
uint32_t pixel;
struct color_pair color;
struct cell *cp;
const struct static_glyph_t *gp;
copy_size = (fb->rotate == CLOCKWISE || fb->rotate == COUNTER_CLOCKWISE) ?
CELL_HEIGHT * fb->bpp: CELL_HEIGHT * fb->line_length;
for (col = term->cols - 1; col >= 0; col--) {
margin_right = (term->cols - 1 - col) * CELL_WIDTH;
/* get cell color and glyph */
cp = &term->cells[col + line * term->cols];
color = cp->color;
gp = cp->gp;
/* check cursor positon */
if ((term->mode & MODE_CURSOR && line == term->cursor.y)
&& (col == term->cursor.x
|| (cp->width == WIDE && (col + 1) == term->cursor.x)
|| (cp->width == NEXT_TO_WIDE && (col - 1) == term->cursor.x))) {
color.fg = DEFAULT_BG;
color.bg = (!tty.visible && tty.background_draw) ? PASSIVE_CURSOR_COLOR: ACTIVE_CURSOR_COLOR;
}
for (glyph_height_offset = 0; glyph_height_offset < CELL_HEIGHT; glyph_height_offset++) {
if ((glyph_height_offset == (CELL_HEIGHT - 1)) && (cp->attribute & attr_mask[UNDERLINE]))
color.bg = color.fg;
for (glyph_width_offset = 0; glyph_width_offset < CELL_WIDTH; glyph_width_offset++) {
pos = get_rotated_pos(fb, term, term->width - 1 - margin_right - glyph_width_offset,
line * CELL_HEIGHT + glyph_height_offset);
if (cp->width == WIDE)
bit_shift = glyph_width_offset + CELL_WIDTH;
else
bit_shift = glyph_width_offset;
/* set color palette */
if (gp->bitmap[glyph_height_offset] & (0x01 << bit_shift))
pixel = term->color_palette[color.fg];
else if (fb->wall && color.bg == DEFAULT_BG) /* wallpaper */
memcpy(&pixel, fb->wall + pos, fb->bpp);
else
pixel = term->color_palette[color.bg];
memcpy(fb->buf + pos, &pixel, fb->bpp);
}
}
if (fb->rotate == CLOCKWISE) {
for (glyph_width_offset = 0; glyph_width_offset < CELL_WIDTH; glyph_width_offset++) {
pos = get_rotated_pos(fb, term, term->width - 1 - margin_right - glyph_width_offset, line * CELL_HEIGHT);
memcpy(fb->fp + pos, fb->buf + pos, copy_size);
}
} else if (fb->rotate == COUNTER_CLOCKWISE) {
for (glyph_width_offset = 0; glyph_width_offset < CELL_WIDTH; glyph_width_offset++) {
pos = get_rotated_pos(fb, term, term->width - 1 - margin_right - glyph_width_offset, (line + 1) * CELL_HEIGHT - 1);
memcpy(fb->fp + pos, fb->buf + pos, copy_size);
}
}
}
if (fb->rotate == NORMAL) {
pos = get_rotated_pos(fb, term, 0, line * CELL_HEIGHT);
memcpy(fb->fp + pos, fb->buf + pos, copy_size);
} else if (fb->rotate == UPSIDE_DOWN) {
pos = get_rotated_pos(fb, term, term->width - 1, (line + 1) * CELL_HEIGHT - 1);
memcpy(fb->fp + pos, fb->buf + pos, copy_size);
}
term->line_dirty[line] = ((term->mode & MODE_CURSOR) && term->cursor.y == line) ? true: false;
}
void refresh(struct framebuffer *fb, struct terminal *term)
{
int line;
if (term->mode & MODE_CURSOR)
term->line_dirty[term->cursor.y] = true;
for (line = 0; line < term->lines; line++) {
if (term->line_dirty[line])
draw_line(fb, term, line);
}
}

View file

@ -1,319 +0,0 @@
/* See LICENSE for licence details. */
char *load_wallpaper(struct framebuffer *fb)
{
char *ptr;
ptr = (char *) emalloc(fb->screen_size);
memcpy(ptr, fb->fp, fb->screen_size);
return ptr;
}
struct fb_cmap *cmap_create(struct fb_var_screeninfo *vinfo)
{
struct fb_cmap *cmap;
cmap = (struct fb_cmap *) emalloc(sizeof(struct fb_cmap));
cmap->start = 0;
cmap->len = COLORS;
cmap->red = (uint16_t *) emalloc(sizeof(uint16_t) * COLORS);
cmap->green = (uint16_t *) emalloc(sizeof(uint16_t) * COLORS);
cmap->blue = (uint16_t *) emalloc(sizeof(uint16_t) * COLORS);
cmap->transp = NULL;
return cmap;
}
void cmap_die(struct fb_cmap *cmap)
{
if (cmap) {
free(cmap->red);
free(cmap->green);
free(cmap->blue);
free(cmap->transp);
free(cmap);
}
}
void get_rgb(int i, struct color_t *color)
{
color->r = (color_list[i] >> 16) & bit_mask[8];
color->g = (color_list[i] >> 8) & bit_mask[8];
color->b = (color_list[i] >> 0) & bit_mask[8];
}
uint32_t bit_reverse(uint32_t val, int bits)
{
uint32_t ret = val;
int shift = bits - 1;
for (val >>= 1; val; val >>= 1) {
ret <<= 1;
ret |= val & 1;
shift--;
}
return ret <<= shift;
}
void cmap_init(struct framebuffer *fb, struct fb_var_screeninfo *vinfo)
{
int i;
uint16_t r, g, b;
struct color_t color;
if (ioctl(fb->fd, FBIOGETCMAP, fb->cmap_org) < 0) { /* not fatal */
cmap_die(fb->cmap_org);
fb->cmap_org = NULL;
}
for (i = 0; i < COLORS; i++) {
get_rgb(i, &color);
r = (color.r << BITS_PER_BYTE) | color.r;
g = (color.g << BITS_PER_BYTE) | color.g;
b = (color.b << BITS_PER_BYTE) | color.b;
*(fb->cmap->red + i) = (vinfo->red.msb_right) ?
bit_reverse(r, 16) & bit_mask[16]: r;
*(fb->cmap->green + i) = (vinfo->green.msb_right) ?
bit_reverse(g, 16) & bit_mask[16]: g;
*(fb->cmap->blue + i) = (vinfo->blue.msb_right) ?
bit_reverse(b, 16) & bit_mask[16]: b;
}
if (ioctl(fb->fd, FBIOPUTCMAP, fb->cmap) < 0)
fatal("ioctl: FBIOPUTCMAP failed");
}
uint32_t get_color(struct fb_var_screeninfo *vinfo, int i)
{
uint32_t r, g, b;
struct color_t color;
if (vinfo->bits_per_pixel == 8)
return i;
get_rgb(i, &color);
r = color.r >> (BITS_PER_BYTE - vinfo->red.length);
g = color.g >> (BITS_PER_BYTE - vinfo->green.length);
b = color.b >> (BITS_PER_BYTE - vinfo->blue.length);
if (vinfo->red.msb_right)
r = bit_reverse(r, vinfo->red.length) & bit_mask[vinfo->red.length];
if (vinfo->green.msb_right)
g = bit_reverse(g, vinfo->green.length) & bit_mask[vinfo->green.length];
if (vinfo->blue.msb_right)
b = bit_reverse(b, vinfo->blue.length) & bit_mask[vinfo->blue.length];
return (r << vinfo->red.offset)
+ (g << vinfo->green.offset)
+ (b << vinfo->blue.offset);
}
void fb_init(struct framebuffer *fb)
{
int i;
char *path, *env;
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
if ((path = getenv("FRAMEBUFFER")) != NULL)
fb->fd = eopen(path, O_RDWR);
else
fb->fd = eopen(fb_path, O_RDWR);
if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &finfo) < 0)
fatal("ioctl: FBIOGET_FSCREENINFO failed");
if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
fatal("ioctl: FBIOGET_VSCREENINFO failed");
fb->res.x = vinfo.xres;
fb->res.y = vinfo.yres;
fb->screen_size = finfo.smem_len;
fb->line_length = finfo.line_length;
if ((finfo.visual == FB_VISUAL_TRUECOLOR || finfo.visual == FB_VISUAL_DIRECTCOLOR)
&& (vinfo.bits_per_pixel == 15 || vinfo.bits_per_pixel == 16
|| vinfo.bits_per_pixel == 24 || vinfo.bits_per_pixel == 32)) {
fb->cmap = fb->cmap_org = NULL;
fb->bpp = (vinfo.bits_per_pixel + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
}
else if (finfo.visual == FB_VISUAL_PSEUDOCOLOR
&& vinfo.bits_per_pixel == 8) {
fb->cmap = cmap_create(&vinfo);
fb->cmap_org = cmap_create(&vinfo);
cmap_init(fb, &vinfo);
fb->bpp = 1;
}
else
/* non packed pixel, mono color, grayscale: not implimented */
fatal("unsupported framebuffer type");
for (i = 0; i < COLORS; i++) /* init color palette */
fb->color_palette[i] = get_color(&vinfo, i);
fb->fp = (char *) emmap(0, fb->screen_size, PROT_WRITE | PROT_READ, MAP_SHARED, fb->fd, 0);
fb->buf = (char *) emalloc(fb->screen_size);
if ((env = getenv("YAFT")) != NULL && strncmp(env, "wall", 4) == 0 && fb->bpp > 1)
fb->wall = load_wallpaper(fb);
else
fb->wall = NULL;
}
void fb_die(struct framebuffer *fb)
{
cmap_die(fb->cmap);
if (fb->cmap_org) {
ioctl(fb->fd, FBIOPUTCMAP, fb->cmap_org); /* not fatal */
cmap_die(fb->cmap_org);
}
free(fb->wall);
free(fb->buf);
emunmap(fb->fp, fb->screen_size);
eclose(fb->fd);
}
int get_rotated_pos(struct framebuffer *fb, struct terminal *term, int x, int y)
{
int p, q;
long pos;
if (ROTATE == CLOCKWISE) {
p = y;
q = (term->width - 1) - x;
}
else if (ROTATE == UPSIDE_DOWN) {
p = (term->width - 1) - x;
q = (term->height - 1) - y;
}
else if (ROTATE == COUNTER_CLOCKWISE) {
p = (term->height - 1) - y;
q = x;
}
else { /* rotate: NORMAL */
p = x;
q = y;
}
pos = p * fb->bpp + q * fb->line_length;
if (pos < 0 || pos >= fb->screen_size) {
fprintf(stderr, "(%d, %d) -> (%d, %d) term:(%d, %d) res:(%d, %d) pos:%ld\n",
x, y, p, q, term->width, term->height, fb->res.x, fb->res.y, pos);
exit(EXIT_FAILURE);
}
return pos;
}
void draw_line(struct framebuffer *fb, struct terminal *term, int line)
{
int copy_size, pos, bit_shift, margin_right;
int col, glyph_width_offset, glyph_height_offset;
uint32_t pixel;
struct color_pair color;
struct cell *cp;
const struct static_glyph_t *gp;
/*
1280(width) x 1024(height) = 1310720 pixels
0 1279
+-- ... --+
| |
1280 +-- ... --+2559
| |
. .
. .
+-- ... --+
1309440 1310719
cell size: 8x16
term cell: line 0 - 63 col 0 - 159
*/
pos = get_rotated_pos(fb, term, term->width - 1, line * cell_height);
copy_size = (ROTATE == CLOCKWISE || ROTATE == COUNTER_CLOCKWISE) ?
cell_height * fb->bpp: cell_height * fb->line_length;
for (col = term->cols - 1; col >= 0; col--) {
margin_right = (term->cols - 1 - col) * cell_width;
/* get cell color and glyph */
cp = &term->cells[col + line * term->cols];
color = cp->color;
gp = cp->gp;
/* check cursor positon */
if ((term->mode & MODE_CURSOR && line == term->cursor.y)
&& (col == term->cursor.x
|| (cp->wide == WIDE && (col + 1) == term->cursor.x)
|| (cp->wide == NEXT_TO_WIDE && (col - 1) == term->cursor.x))) {
color.fg = DEFAULT_BG;
color.bg = CURSOR_COLOR;
}
for (glyph_height_offset = 0; glyph_height_offset < cell_height; glyph_height_offset++) {
if ((glyph_height_offset == (cell_height - 1)) && (cp->attribute & attr_mask[UNDERLINE]))
color.bg = color.fg;
for (glyph_width_offset = 0; glyph_width_offset < cell_width; glyph_width_offset++) {
pos = get_rotated_pos(fb, term, term->width - 1 - margin_right - glyph_width_offset,
// min: 1280 - 1 - (160 - 1 - 0) * 8 - 7 = 0 / max: 1280 - 1 - (160 - 1 - 159) * 8 - 0 = 1279
line * cell_height + glyph_height_offset);
// min: 0 * 16 + 0 = 0 / max: (64 - 1) * 16 + 15 = 1023
if (cp->wide == WIDE)
bit_shift = glyph_width_offset + cell_width;
else
bit_shift = glyph_width_offset;
/* set color palette */
if (gp->bitmap[glyph_height_offset] & (0x01 << bit_shift))
pixel = fb->color_palette[color.fg];
else if (fb->wall && color.bg == DEFAULT_BG) /* wallpaper */
memcpy(&pixel, fb->wall + pos, fb->bpp);
else
pixel = fb->color_palette[color.bg];
memcpy(fb->buf + pos, &pixel, fb->bpp);
}
}
if (ROTATE == CLOCKWISE || ROTATE == COUNTER_CLOCKWISE) {
for (glyph_width_offset = 0; glyph_width_offset < cell_width; glyph_width_offset++) {
pos = (ROTATE == CLOCKWISE) ?
get_rotated_pos(fb, term, term->width - 1 - margin_right - glyph_width_offset, line * cell_height):
// min: 1024 - 1 - (128 - 1 - 0) * 8 - 7 = 0 / max: 1024 - 1 - (128 - 1 - 127) * 8 - 0 = 1023
// min: 0 * 16 = 0 / max: 79 * 16 = 1264
get_rotated_pos(fb, term, term->width - 1 - margin_right - glyph_width_offset, (line + 1) * cell_height - 1);
// min: 1 * 16 - 1 = 15 / max: 80 * 16 - 1 = 1279
memcpy(fb->fp + pos, fb->buf + pos, copy_size);
}
}
}
if (ROTATE == NORMAL || ROTATE == UPSIDE_DOWN) {
pos = (ROTATE == NORMAL) ?
get_rotated_pos(fb, term, 0, line * cell_height):
get_rotated_pos(fb, term, term->width - 1, (line + 1) * cell_height - 1);
memcpy(fb->fp + pos, fb->buf + pos, copy_size);
}
term->line_dirty[line] = ((term->mode & MODE_CURSOR) && term->cursor.y == line) ? true: false;
}
void refresh(struct framebuffer *fb, struct terminal *term)
{
int line;
if (term->mode & MODE_CURSOR)
term->line_dirty[term->cursor.y] = true;
for (line = 0; line < term->lines; line++) {
if (term->line_dirty[line])
draw_line(fb, term, line);
}
}

167
freebsd.h Normal file
View file

@ -0,0 +1,167 @@
/* See LICENSE for licence details. */
#include <machine/param.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#include <sys/kbio.h>
#include <sys/types.h>
#include "common.h"
/* some structs for FreeBSD */
struct framebuffer {
char *fp; /* pointer of framebuffer(read only) */
char *wall; /* buffer for wallpaper */
char *buf; /* copy of framebuffer */
int fd; /* file descriptor of framebuffer */
struct pair res; /* resolution (x, y) */
long screen_size; /* screen data size (byte) */
int line_length; /* line length (byte) */
int bpp; /* BYTES per pixel */
uint32_t color_palette[COLORS];
video_color_palette_t *cmap, *cmap_org;
enum rotate_mode rotate;
};
#include "util.h"
/* some functions for FreeBSD framebuffer */
video_color_palette_t *cmap_create(video_info_t *video_info)
{
video_color_palette_t *cmap;
cmap = (video_color_palette_t *) emalloc(sizeof(video_color_palette_t));
cmap->index = 0;
cmap->count = COLORS;
cmap->red = (u_char *) emalloc(sizeof(u_char) * COLORS);
cmap->green = (u_char *) emalloc(sizeof(u_char) * COLORS);
cmap->blue = (u_char *) emalloc(sizeof(u_char) * COLORS);
cmap->transparent = NULL;
return cmap;
}
void cmap_die(video_color_palette_t *cmap)
{
if (cmap) {
free(cmap->red);
free(cmap->green);
free(cmap->blue);
free(cmap->transparent);
free(cmap);
}
}
void cmap_init(struct framebuffer *fb, video_info_t *video_info)
{
int i;
struct color_t color;
if (ioctl(fb->fd, FBIOGETCMAP, fb->cmap_org) < 0) { /* not fatal */
cmap_die(fb->cmap_org);
fb->cmap_org = NULL;
}
for (i = 0; i < COLORS; i++) {
/* where is endian info? */
get_rgb(i, &color);
*(fb->cmap->red + i) = color.r;
*(fb->cmap->green + i) = color.g;
*(fb->cmap->blue + i) = color.b;
}
if (ioctl(fb->fd, FBIOPUTCMAP, fb->cmap) < 0)
fatal("ioctl: FBIOPUTCMAP failed");
}
uint32_t get_color(video_info_t *video_info, int i)
{
uint32_t r, g, b;
struct color_t color;
if (video_info->vi_depth == 8)
return i;
/* where is endian info? */
get_rgb(i, &color);
r = color.r >> (BITS_PER_BYTE - video_info->vi_pixel_fsizes[0]);
g = color.g >> (BITS_PER_BYTE - video_info->vi_pixel_fsizes[1]);
b = color.b >> (BITS_PER_BYTE - video_info->vi_pixel_fsizes[2]);
return (r << video_info->vi_pixel_fields[0])
+ (g << video_info->vi_pixel_fields[1])
+ (b << video_info->vi_pixel_fields[2]);
}
void fb_init(struct framebuffer *fb)
{
int i, video_mode;
char *path;
video_info_t video_info;
video_adapter_info_t video_adapter_info;
if ((path = getenv("FRAMEBUFFER")) != NULL)
fb->fd = eopen(path, O_RDWR);
else
fb->fd = eopen(fb_path, O_RDWR);
if (ioctl(fb->fd, FBIO_GETMODE, &video_mode) < 0)
fatal("ioctl: FBIO_GETMODE failed");
/*
if (video_mode != VIDEO_MODE) {
fprintf(stderr, "current mode:%d request mode:%d\n", video_mode, VIDEO_MODE);
fatal("video mode unmatch");
}
*/
video_info.vi_mode = video_mode;
if (ioctl(fb->fd, FBIO_MODEINFO, &video_info) < 0)
fatal("ioctl: FBIO_MODEINFO failed");
if (ioctl(fb->fd, FBIO_ADPINFO, &video_adapter_info) < 0)
fatal("ioctl: FBIO_ADPINFO failed");
fb->res.x = video_info.vi_width;
fb->res.y = video_info.vi_height;
fb->screen_size = video_adapter_info.va_window_size;
fb->line_length = video_adapter_info.va_line_width;
if ((video_info.vi_mem_model == V_INFO_MM_PACKED || video_info.vi_mem_model == V_INFO_MM_DIRECT)
&& (video_info.vi_depth == 15 || video_info.vi_depth == 16
|| video_info.vi_depth == 24 || video_info.vi_depth == 32)) {
fb->cmap = fb->cmap_org = NULL;
fb->bpp = (video_info.vi_depth + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
}
else if ((video_adapter_info.va_flags & V_ADP_PALETTE) &&
video_info.vi_mem_model == V_INFO_MM_PACKED && video_info.vi_depth == 8) {
fb->cmap = cmap_create(&video_info);
fb->cmap_org = cmap_create(&video_info);
cmap_init(fb, &video_info);
fb->bpp = 1;
}
else
/* non packed pixel, mono color, grayscale: not implimented */
fatal("unsupported framebuffer type");
for (i = 0; i < COLORS; i++) /* init color palette */
fb->color_palette[i] = get_color(&video_info, i);
fb->fp = (char *) emmap(0, fb->screen_size, PROT_WRITE | PROT_READ, MAP_SHARED, fb->fd, 0);
fb->buf = (char *) emalloc(fb->screen_size);
}
void fb_die(struct framebuffer *fb)
{
cmap_die(fb->cmap);
if (fb->cmap_org) {
ioctl(fb->fd, FBIOPUTCMAP, fb->cmap_org); // not fatal
cmap_die(fb->cmap_org);
}
free(fb->wall);
free(fb->buf);
emunmap(fb->fp, fb->screen_size);
eclose(fb->fd);
}
#include "draw.h"

View file

@ -93,6 +93,11 @@ void enter_osc(struct terminal *term, void *arg)
term->esc.state = STATE_OSC;
}
void enter_dcs(struct terminal *term, void *arg)
{
term->esc.state = STATE_DCS;
}
void ris(struct terminal *term, void *arg)
{
reset(term);
@ -489,4 +494,307 @@ void clear_tabstop(struct terminal *term, void *arg)
}
/* function for osc sequence */
/* not implemented */
void set_palette(struct terminal *term, void *arg)
{
/*
OSC Ps ; Pt ST
ref: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
ref: http://ttssh2.sourceforge.jp/manual/ja/about/ctrlseq.html#OSC
only recognize change color palette:
Ps: 4
Pt: c ; spec
c: color index (from 0 to 255)
spec:
rgb:r/g/b
rgb:rr/gg/bb
rgb:rrr/ggg/bbb
rgb:rrrr/gggg/bbbb
#rgb
#rrggbb
#rrrgggbbb
#rrrrggggbbbb
this rgb format is "RGB Device String Specification"
see http://xjman.dsl.gr.jp/X11R6/X11/CH06.html
PT: c ; ?
response rgb color
OSC 4 ; c ; rgb:rr/gg/bb ST
*/
struct parm_t *pt = (struct parm_t *) arg, sub_parm;
int i, argc = pt->argc, c, length;
char **argv = pt->argv;
long val;
uint8_t rgb[3];
uint32_t color;
char buf[BUFSIZE];
if (argc != 3)
return;
if (strncmp(argv[2], "rgb:", 4) == 0) {
/*
rgb:r/g/b
rgb:rr/gg/bb
rgb:rrr/ggg/bbb
rgb:rrrr/gggg/bbbb
*/
reset_parm(&sub_parm);
parse_arg(argv[2] + 4, &sub_parm, '/', isalnum); /* skip "rgb:" */
if (DEBUG)
for (i = 0; i < sub_parm.argc; i++)
fprintf(stderr, "sub_parm.argv[%d]: %s\n", i, sub_parm.argv[i]);
if (sub_parm.argc != 3)
return;
length = strlen(sub_parm.argv[0]);
c = atoi(argv[1]);
for (i = 0; i < 3; i++) {
val = strtol(sub_parm.argv[i], NULL, 16);
if (DEBUG)
fprintf(stderr, "val:%ld\n", val);
if (length == 1)
rgb[i] = (double) val * 0xFF / 0x0F;
else if (length == 2)
rgb[i] = val;
else if (length == 3)
rgb[i] = (double) val * 0xFF / 0xFFF;
else if (length == 4)
rgb[i] = (double) val * 0xFF / 0xFFFF;
else
return;
}
color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
if (DEBUG)
fprintf(stderr, "color:0x%.6X\n", color);
if (0 <= c && c < COLORS)
term->color_palette[c] = color;
}
else if (strncmp(argv[2], "#", 1) == 0) {
/*
#rgb
#rrggbb
#rrrgggbbb
#rrrrggggbbbb
*/
c = atoi(argv[1]);
length = strlen(argv[2] + 1); /* skip '#' */
memset(buf, '\0', BUFSIZE);
if (length == 3) {
for (i = 0; i < 3; i++) {
strncpy(buf, argv[2] + 1 + i, 1);
rgb[i] = (double) strtol(buf, NULL, 16) * 0xFF / 0x0F;
}
}
else if (length == 6) {
for (i = 0; i < 3; i++) {
strncpy(buf, argv[2] + 1 + i * 2, 2);
rgb[i] = strtol(buf, NULL, 16);
}
}
else if (length == 9) {
for (i = 0; i < 3; i++) {
strncpy(buf, argv[2] + 1 + i * 3, 3);
rgb[i] = (double) strtol(buf, NULL, 16) * 0xFF / 0xFFF;
}
}
else if (length == 12) {
for (i = 0; i < 3; i++) {
strncpy(buf, argv[2] + 1 + i * 4, 4);
rgb[i] = (double) strtol(buf, NULL, 16) * 0xFF / 0xFFFF;
}
}
else
return;
color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
if (DEBUG)
fprintf(stderr, "color:0x%.6X\n", color);
if (0 <= c && c < COLORS)
term->color_palette[c] = color;
}
else if (strncmp(argv[2], "?", 1) == 0) {
/*
?
*/
c = atoi(argv[1]);
if (0 <= c && c < COLORS) {
for (i = 2; i >= 0; i--)
rgb[i] = (term->color_palette[c] >> (8 * i)) & 0xFF;
snprintf(buf, BUFSIZE, "\033]4;%d;rgb:%.2X/%.2X/%.2X\033\\", c, rgb[0], rgb[1], rgb[2]);
ewrite(term->fd, buf, strlen(buf));
}
}
}
void reset_palette(struct terminal *term, void *arg)
{
/*
reset color c
OSC 104 ; c ST
c: index of color
ST: BEL or ESC \
reset all color
OSC 104 ST
ST: BEL or ESC \
terminfo: oc=\E]104\E\\
*/
struct parm_t *pt = (struct parm_t *) arg;
int i, argc = pt->argc, c;
char **argv = pt->argv;
if (argc < 2) { /* reset all color palette */
for (i = 0; i < COLORS; i++)
term->color_palette[i] = color_list[i];
}
else if (argc == 2) { /* reset color_palette[c] */
c = atoi(argv[1]);
if (0 <= c && c < COLORS)
term->color_palette[c] = color_list[c];
}
}
void glyph_width_report(struct terminal *term, void *arg)
{
/*
glyph width report
* request *
OSC 8900 ; Ps ; ? : Pw : Pf : Pt ST
Ps: reserved
Pw: width (0 or 1 or 2)
Pf: beginning of unicode code point
Pt: end of unicode code point
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
* answer *
OSC 8900 ; Ps ; Pt ; Pf : Pt ; Pf : Pt ; ... ST
Ps: responce code
0: ok (default)
1: recognized but not supported
2: not recognized
Pt: reserved (maybe East Asian Width Version)
<!-- Pw: width (0 or 1 or 2) depricated -->
Pf: beginning of unicode code point
Pt: end of unicode code point
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
ref
http://uobikiemukot.github.io/yaft/glyph_width_report.html
https://gist.github.com/saitoha/8767268
*/
struct parm_t *pt = (struct parm_t *) arg, sub_parm;
int i, width, from, to, left, right, w; //reserved
char **argv = pt->argv, buf[BUFSIZE];
reset_parm(&sub_parm);
parse_arg(argv[2], &sub_parm, ':', isdigit_or_questionmark);
if (sub_parm.argc != 4 || *sub_parm.argv[0] != '?')
return;
//reserved = atoi(argv[1]);
width = atoi(sub_parm.argv[1]);
from = atoi(sub_parm.argv[2]);
to = atoi(sub_parm.argv[3]);
if ((from < 0 || to >= UCS2_CHARS) /* change here when implement DRCS */
|| (width < 0 || width > 2))
return;
ewrite(term->fd, "\033]8900;0;0;", 11); /* OSC 8900 ; Ps; Pt ; */
left = right = -1;
for (i = from; i <= to; i++) {
w = fonts[i].width;
if (w != width) {
if (right != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, right);
ewrite(term->fd, buf, strlen(buf));
}
else if (left != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, left);
ewrite(term->fd, buf, strlen(buf));
}
left = right = -1;
continue;
}
if (left == -1)
left = i;
else
right = i;
}
if (right != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, right);
ewrite(term->fd, buf, strlen(buf));
}
else if (left != -1) {
snprintf(buf, BUFSIZE, "%d:%d;", left, left);
ewrite(term->fd, buf, strlen(buf));
}
ewrite(term->fd, "\033\\", 2); /* ST (ESC BACKSLASH) */
}
/* function for dcs sequence */
void decdld_header(struct terminal *term, void *arg)
{
/*
DECDLD header:
(http://vt100.net/docs/vt510-rm/DECDLD#T5-2)
DCS Pfn ; Pcn; Pe; Pcmw; Pss; Pt; Pcmh; Pcss {
Pfn: Font number (ignored)
Pcn: Starting character (from 0 to 95 (0x20 - 0x7F))
Pe: Erase control (0, 1, 2)
Pcmw: Character matrix width (ignored)
Pss: Font set size (ignored)
Pt: Text or full cell (force "2": full cell mode)
Pcmh: Character matrix height (ignored)
Pcss: Character set size (force "1": 96 character set)
in yaft, DRCS font size must be the same as cell size.
So some parameters (Pcmw, Pss, Pcmh, Pcss) are ignored.
Pt force "2" (full cell mode) or "3" for sixel...(not implemented)
DRCS are mapped on UCS Private Area.
~~~
DRCSMMv1
(https://github.com/saitoha/drcsterm)
U+10XXYY (0x40 <= 0xXX <=0x7E, 0x20 <= 0xYY <= 0x7F)
Dcsc: from '@' (0x40) to '~' (0x7E)
('0' (0x30) - '?' (0x3F) are not available)
each character set has 96 glyph (0x20 - 0x7F)
~~~
ISO-2022-JP-MS
~~~
*/
struct parm_t *pt = (struct parm_t *) arg;
int argc = pt->argc;
char **argv = pt->argv;
if (argc != 7) /* invalid DECDLD header */
return;
if (argv[0])
;
term->esc.state = STATE_DSCS;
}

6908
glyph.h Normal file

File diff suppressed because it is too large Load diff

165
linux.h Normal file
View file

@ -0,0 +1,165 @@
/* See LICENSE for licence details. */
#include <linux/fb.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include "common.h"
/* struct for Linux */
struct framebuffer {
char *fp; /* pointer of framebuffer(read only) */
char *wall; /* buffer for wallpaper */
char *buf; /* copy of framebuffer */
int fd; /* file descriptor of framebuffer */
struct pair res; /* resolution (x, y) */
long screen_size; /* screen data size (byte) */
int line_length; /* line length (byte) */
int bpp; /* BYTES per pixel */
struct fb_cmap *cmap, *cmap_org; /* cmap for legacy framebuffer (pseudocolor) */
enum rotate_mode rotate; /* rotate mode: see "enum rotate mode" */
};
#include "util.h"
/* some functions for Linux framebuffer */
struct fb_cmap *cmap_create(struct fb_var_screeninfo *vinfo)
{
struct fb_cmap *cmap;
cmap = (struct fb_cmap *) emalloc(sizeof(struct fb_cmap));
cmap->start = 0;
cmap->len = COLORS;
cmap->red = (uint16_t *) emalloc(sizeof(uint16_t) * COLORS);
cmap->green = (uint16_t *) emalloc(sizeof(uint16_t) * COLORS);
cmap->blue = (uint16_t *) emalloc(sizeof(uint16_t) * COLORS);
cmap->transp = NULL;
return cmap;
}
void cmap_die(struct fb_cmap *cmap)
{
if (cmap) {
free(cmap->red);
free(cmap->green);
free(cmap->blue);
free(cmap->transp);
free(cmap);
}
}
void cmap_init(struct framebuffer *fb, struct fb_var_screeninfo *vinfo)
{
int i;
uint16_t r, g, b;
struct color_t color;
if (ioctl(fb->fd, FBIOGETCMAP, fb->cmap_org) < 0) { /* not fatal */
cmap_die(fb->cmap_org);
fb->cmap_org = NULL;
}
for (i = 0; i < COLORS; i++) {
get_rgb(i, &color);
r = (color.r << BITS_PER_BYTE) | color.r;
g = (color.g << BITS_PER_BYTE) | color.g;
b = (color.b << BITS_PER_BYTE) | color.b;
*(fb->cmap->red + i) = (vinfo->red.msb_right) ?
bit_reverse(r, 16) & bit_mask[16]: r;
*(fb->cmap->green + i) = (vinfo->green.msb_right) ?
bit_reverse(g, 16) & bit_mask[16]: g;
*(fb->cmap->blue + i) = (vinfo->blue.msb_right) ?
bit_reverse(b, 16) & bit_mask[16]: b;
}
if (ioctl(fb->fd, FBIOPUTCMAP, fb->cmap) < 0)
fatal("ioctl: FBIOPUTCMAP failed");
}
uint32_t get_color(struct fb_var_screeninfo *vinfo, int i)
{
uint32_t r, g, b;
struct color_t color;
if (vinfo->bits_per_pixel == 8)
return i;
get_rgb(i, &color);
r = color.r >> (BITS_PER_BYTE - vinfo->red.length);
g = color.g >> (BITS_PER_BYTE - vinfo->green.length);
b = color.b >> (BITS_PER_BYTE - vinfo->blue.length);
if (vinfo->red.msb_right)
r = bit_reverse(r, vinfo->red.length) & bit_mask[vinfo->red.length];
if (vinfo->green.msb_right)
g = bit_reverse(g, vinfo->green.length) & bit_mask[vinfo->green.length];
if (vinfo->blue.msb_right)
b = bit_reverse(b, vinfo->blue.length) & bit_mask[vinfo->blue.length];
return (r << vinfo->red.offset)
+ (g << vinfo->green.offset)
+ (b << vinfo->blue.offset);
}
void fb_init(struct framebuffer *fb, uint32_t *color_palette)
{
int i;
char *path;
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
if ((path = getenv("FRAMEBUFFER")) != NULL)
fb->fd = eopen(path, O_RDWR);
else
fb->fd = eopen(fb_path, O_RDWR);
if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &finfo) < 0)
fatal("ioctl: FBIOGET_FSCREENINFO failed");
if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
fatal("ioctl: FBIOGET_VSCREENINFO failed");
fb->res.x = vinfo.xres;
fb->res.y = vinfo.yres;
fb->screen_size = finfo.smem_len;
fb->line_length = finfo.line_length;
if ((finfo.visual == FB_VISUAL_TRUECOLOR || finfo.visual == FB_VISUAL_DIRECTCOLOR)
&& (vinfo.bits_per_pixel == 15 || vinfo.bits_per_pixel == 16
|| vinfo.bits_per_pixel == 24 || vinfo.bits_per_pixel == 32)) {
fb->cmap = fb->cmap_org = NULL;
fb->bpp = (vinfo.bits_per_pixel + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
}
else if (finfo.visual == FB_VISUAL_PSEUDOCOLOR
&& vinfo.bits_per_pixel == 8) {
fb->cmap = cmap_create(&vinfo);
fb->cmap_org = cmap_create(&vinfo);
cmap_init(fb, &vinfo);
fb->bpp = 1;
}
else
/* non packed pixel, mono color, grayscale: not implimented */
fatal("unsupported framebuffer type");
for (i = 0; i < COLORS; i++) /* init color palette */
color_palette[i] = get_color(&vinfo, i);
fb->fp = (char *) emmap(0, fb->screen_size, PROT_WRITE | PROT_READ, MAP_SHARED, fb->fd, 0);
fb->buf = (char *) emalloc(fb->screen_size);
}
void fb_die(struct framebuffer *fb)
{
cmap_die(fb->cmap);
if (fb->cmap_org) {
ioctl(fb->fd, FBIOPUTCMAP, fb->cmap_org); /* not fatal */
cmap_die(fb->cmap_org);
}
free(fb->wall);
free(fb->buf);
emunmap(fb->fp, fb->screen_size);
eclose(fb->fd);
}
#include "draw.h"

95
parse.h
View file

@ -16,6 +16,7 @@ void (*esc_func[ESC_CHARS])(struct terminal * term, void *arg) = {
['E'] = crnl,
['H'] = set_tabstop,
['M'] = reverse_nl,
['P'] = enter_dcs,
['Z'] = identify,
['['] = enter_csi,
[']'] = enter_osc,
@ -54,45 +55,9 @@ void (*csi_func[ESC_CHARS])(struct terminal * term, void *arg) = {
['`'] = curs_col,
};
void reset_parm(struct parm_t *pt)
{
int i;
pt->argc = 0;
for (i = 0; i < ESC_PARAMS; i++)
pt->argv[i] = NULL;
}
void parse_arg(char *buf, struct parm_t *pt, int delim, int (is_valid)(int c))
{
int length;
char *cp;
length = strlen(buf);
cp = buf;
while (cp < &buf[length - 1]) {
if (*cp == delim)
*cp = '\0';
cp++;
}
cp = buf;
start:
if (pt->argc < ESC_PARAMS && is_valid(*cp)) {
pt->argv[pt->argc] = cp;
pt->argc++;
}
while (is_valid(*cp))
cp++;
while (!is_valid(*cp) && cp < &buf[length - 1])
cp++;
if (cp < &buf[length - 1])
goto start;
}
void (*dcs_func[ESC_CHARS])(struct terminal * term, void *arg) = {
['{'] = decdld_header,
};
void control_character(struct terminal *term, uint8_t ch)
{
@ -130,7 +95,7 @@ void csi_sequence(struct terminal *term, uint8_t ch)
fprintf(stderr, "csi: CSI %s\n", term->esc.buf);
reset_parm(&parm);
parse_arg(term->esc.buf, &parm, ';', isdigit);
parse_arg(term->esc.buf + 1, &parm, ';', isdigit); /* skip '[' */
*(term->esc.bp - 1) = '\0'; /* omit final character */
if (csi_func[ch])
@ -141,9 +106,53 @@ void csi_sequence(struct terminal *term, uint8_t ch)
void osc_sequence(struct terminal *term, uint8_t ch)
{
int i, osc_mode;
struct parm_t parm;
if (DEBUG)
fprintf(stderr, "osc: OSC %s\n", term->esc.buf);
reset_parm(&parm);
parse_arg(term->esc.buf + 1, &parm, ';', is_osc_parm); /* skip ']' */
if (*(term->esc.bp - 1) == BACKSLASH) /* ST: ESC BACKSLASH */
*(term->esc.bp - 2) = '\0';
*(term->esc.bp - 1) = '\0'; /* omit final character */
if (DEBUG)
for (i = 0; i < parm.argc; i++)
fprintf(stderr, "\targv[%d]: %s\n", i, parm.argv[i]);
if (parm.argc > 0) {
osc_mode = atoi(parm.argv[0]);
if (DEBUG)
fprintf(stderr, "osc_mode:%d\n", osc_mode);
if (osc_mode == 4)
set_palette(term, &parm);
else if (osc_mode == 104)
reset_palette(term, &parm);
else if (osc_mode == 8900)
glyph_width_report(term, &parm);
}
reset_esc(term);
}
void dcs_sequence(struct terminal *term, uint8_t ch)
{
struct parm_t parm;
if (DEBUG)
fprintf(stderr, "dcs: DCS %s\n", term->esc.buf);
reset_parm(&parm);
parse_arg(term->esc.buf, &parm, ';', isdigit);
*(term->esc.bp - 1) = '\0'; /* omit final character */
if (dcs_func[ch])
dcs_func[ch](term, &parm);
if (ch != '{')
reset_esc(term);
}
@ -239,7 +248,7 @@ void parse(struct terminal *term, uint8_t *buf, int size)
for (i = 0; i < size; i++) {
ch = buf[i];
if (term->esc.state == RESET) {
if (term->esc.state == STATE_RESET) {
if (term->ucs.following_byte > 0 && (ch < 0x80 || ch > 0xBF)) { /* interrupt */
addch(term, REPLACEMENT_CHAR);
reset_ucs(term);
@ -264,5 +273,9 @@ void parse(struct terminal *term, uint8_t *buf, int size)
if (push_esc(term, ch))
osc_sequence(term, ch);
}
else if (term->esc.state == STATE_DCS) {
if (push_esc(term, ch))
dcs_sequence(term, ch);
}
}
}

View file

@ -1,46 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
enum {
NORMAL = 0,
CLOCKWISE = 90,
UPSIDE_DOWN = 180,
COUNTER_CLOCKWISE = 270,
};
struct disp_t {
int x, y;
int bpp, line_length;
};
int get_rotated_pos(struct disp_t disp, int x, int y, int rotate)
{
if (rotate == CLOCKWISE)
return y * disp.bpp + (disp.x - 1 - x) * disp.y * disp.bpp;
else if (rotate == UPSIDE_DOWN)
return (disp.x - 1 - x) * disp.bpp + (disp.y - 1 - y) * disp.line_length;
else if (rotate == COUNTER_CLOCKWISE)
return (disp.y - 1 - y) * disp.bpp + x * disp.y * disp.bpp;
else /* rotate: NORMAL */
return x * disp.bpp + y * disp.line_length;
}
int main()
{
int i, j, pos;
struct disp_t disp = {.x = 1280, .y = 1024, .bpp = 4, .line_length = 5120};
for (i = 0; i < disp.x; i++) {
for (j = 0; j < disp.y; j++) {
pos = get_rotated_pos(disp, i, j, COUNTER_CLOCKWISE);
if (!(0 <= pos && pos < 5242880)) {
printf("i:%d j:%d pos:%d\n", i, j, pos);
exit(EXIT_FAILURE);
}
else
printf("%d\n", pos);
}
}
}

171
rotate.h
View file

@ -1,171 +0,0 @@
/* See LICENSE for licence details. */
int my_ceil(int value, int division)
{
return ((value + division - 1) / division);
}
void set_bit_normal(struct framebuffer *fb, struct terminal *term, int y, int x, int offset, char *src)
{
int i, shift, glyph_width;
uint32_t pixel;
struct color_pair color;
struct cell *cp;
const struct static_glyph_t *gp;
cp = &term->cells[x + y * term->cols];
if (cp->wide == NEXT_TO_WIDE)
return;
gp = cp->gp;
glyph_width = gp->width * cell_width;
shift = ((glyph_width + BITS_PER_BYTE - 1) / BITS_PER_BYTE) * BITS_PER_BYTE;
color = cp->color;
if ((term->mode & MODE_CURSOR && y == term->cursor.y) /* cursor */
&& (x == term->cursor.x || (cp->wide == WIDE && (x + 1) == term->cursor.x))) {
color.fg = DEFAULT_BG;
color.bg = CURSOR_COLOR;
}
if ((offset == (cell_height - 1)) /* underline */
&& (cp->attribute & attr_mask[UNDERLINE]))
color.bg = color.fg;
for (i = 0; i < glyph_width; i++) {
if (gp->bitmap[offset] & (0x01 << (shift - i - 1)))
pixel = fb->color_palette[color.fg];
else if (fb->wall && color.bg == DEFAULT_BG) /* wallpaper */
memcpy(&pixel, fb->wall + (i + x * cell_width) * fb->bpp
+ (offset + y * cell_height) * fb->line_length, fb->bpp);
else
pixel = fb->color_palette[color.bg];
memcpy(src + i * fb->bpp, &pixel, fb->bpp);
}
}
void draw_line_normal(struct framebuffer *fb, struct terminal *term, int y)
{
int offset, x, size, pos;
char *src, *dst;
pos = (y * cell_height) * fb->line_length;
size = fb->res.x * fb->bpp;
for (offset = 0; offset < cell_height; offset++) {
for (x = 0; x < term->cols; x++)
fb->set_bit(fb, term, y, x, offset,
fb->buf + pos + x * cell_width * fb->bpp + offset * fb->line_length);
src = fb->buf + pos + offset * fb->line_length;
dst = fb->fp + pos + offset * fb->line_length;
memcpy(dst, src, size);
}
term->line_dirty[y] = (term->mode & MODE_CURSOR && term->cursor.y == y) ? true: false;
}
void draw_line_clockwise(struct framebuffer *fb, struct terminal *term, int line)
{
int y, pos, copy_size;
char *src, *dst;
int col, glyph_width_offset, glyph_height_offset, glyph_width; //bits_per_glyph_width;
uint32_t pixel;
struct color_pair color;
struct cell *cp;
const struct static_glyph_t *gp;
/* calc address of framebuffer */
/*
terminal pos
(fb->res.x, line * cell_height)
framebuffer pos
((line * cell_height), 0)
*/
pos = (line * cell_height) * fb->bpp;
copy_size = cell_height * fb->bpp;
for (y = 0; y < fb->res.x; y++) {
col = term->cols - 1 - (y / cell_width);
for (glyph_height_offset = 0; glyph_height_offset < cell_height; glyph_height_offset++) {
/* check cell */
cp = &term->cells[col + line * term->cols];
color = cp->color;
if (cp->wide == NEXT_TO_WIDE)
continue;
/* check glyph */
gp = cp->gp;
glyph_width = gp->width * cell_width; /* gp->width: 1 or 2 */
//bits_per_glyph_width = my_ceil(glyph_width, BITS_PER_BYTE) * BITS_PER_BYTE;
glyph_width_offset = (y / cell_width);
/* check cursor position */
if ((term->mode & MODE_CURSOR && line == term->cursor.y)
&& (col == term->cursor.x || (cp->wide == WIDE && (col + 1) == term->cursor.x))) {
color.fg = DEFAULT_BG;
color.bg = CURSOR_COLOR;
}
/* set underline */
if ((glyph_height_offset == (cell_height - 1)) && (cp->attribute & attr_mask[UNDERLINE]))
color.bg = color.fg;
/* set color palette */
if (gp->bitmap[glyph_height_offset] & (0x01 << glyph_width_offset))
pixel = fb->color_palette[color.fg];
else if (fb->wall && color.bg == DEFAULT_BG) /* wallpaper */
memcpy(&pixel, fb->wall + (col * cell_width) * fb->bpp
+ (glyph_height_offset + line * cell_height) * fb->line_length, fb->bpp);
else
pixel = fb->color_palette[color.bg];
memcpy(fb->buf + glyph_height_offset * fb->bpp + y * fb->line_length, &pixel, fb->bpp);
}
src = fb->buf + pos + y * fb->line_length;
dst = fb->fp + pos + y * fb->line_length;
memcpy(dst, src, copy_size);
}
}
void set_bit_upside_down(struct framebuffer *fb, struct terminal *term, int y, int x, int offset, char *src)
{
}
void draw_line_upside_down(struct framebuffer *fb, struct terminal *term, int y)
{
}
void set_bit_counter_clockwise(struct framebuffer *fb, struct terminal *term, int y, int x, int offset, char *src)
{
}
void draw_line_counter_clockwise(struct framebuffer *fb, struct terminal *term, int y)
{
}
void check_rotate(struct framebuffer *fb)
{
int tmp;
if (ROTATE == CLOCKWISE || ROTATE == COUNTER_CLOCKWISE) {
tmp = fb->res.x;
fb->res.x = fb->res.y;
fb->res.y = tmp;
}
if (ROTATE == CLOCKWISE) {
//fb->set_bit = set_bit_clockwise;
fb->draw_line = draw_line_clockwise;
}
else if (ROTATE == UPSIDE_DOWN) {
fb->set_bit = set_bit_upside_down;
fb->draw_line = draw_line_upside_down;
}
else if (ROTATE == COUNTER_CLOCKWISE) {
fb->set_bit = set_bit_counter_clockwise;
fb->draw_line = draw_line_counter_clockwise;
}
else { /* rotate: NORMAL */
fb->set_bit = set_bit_normal;
fb->draw_line = draw_line_normal;
}
}

View file

@ -7,7 +7,7 @@ void erase_cell(struct terminal *term, int y, int x)
cp->gp = &fonts[DEFAULT_CHAR];
cp->color = term->color; /* bce */
cp->attribute = RESET;
cp->wide = HALF;
cp->width = HALF;
term->line_dirty[y] = true;
}
@ -19,15 +19,15 @@ void copy_cell(struct terminal *term, int dst_y, int dst_x, int src_y, int src_x
dst = &term->cells[dst_x + dst_y * term->cols];
src = &term->cells[src_x + src_y * term->cols];
if (src->wide == NEXT_TO_WIDE)
if (src->width == NEXT_TO_WIDE)
return;
else if (src->wide == WIDE && dst_x == (term->cols - 1))
else if (src->width == WIDE && dst_x == (term->cols - 1))
erase_cell(term, dst_y, dst_x);
else {
*dst = *src;
if (src->wide == WIDE) {
if (src->width == WIDE) {
*(dst + 1) = *src;
(dst + 1)->wide = NEXT_TO_WIDE;
(dst + 1)->width = NEXT_TO_WIDE;
}
term->line_dirty[dst_y] = true;
}
@ -57,15 +57,15 @@ int set_cell(struct terminal *term, int y, int x, const struct static_glyph_t *g
swap_color(&nc.color);
nc.attribute = term->attribute;
nc.wide = gp->width;
nc.width = gp->width;
*cp = nc;
term->line_dirty[y] = true;
if (nc.wide == WIDE && x + 1 < term->cols) {
if (nc.width == WIDE && x + 1 < term->cols) {
cp = &term->cells[x + 1 + y * term->cols];
*cp = nc;
cp->wide = NEXT_TO_WIDE;
cp->width = NEXT_TO_WIDE;
return WIDE;
}
@ -224,6 +224,12 @@ bool push_esc(struct terminal *term, uint8_t ch)
else if ((ch != ESC) && (' ' > ch || ch > '~'))
reset_esc(term);
}
else if (term->esc.state == STATE_DCS) {
if (ch == '{')
return true;
else if (ch != ';' && (ch < '0' || ch > '9'))
reset_esc(term);
}
return false;
}
@ -278,7 +284,7 @@ void reset(struct terminal *term)
reset_ucs(term);
}
void swap(int *a, int *b)
void swap_int(int *a, int *b)
{
int tmp;
@ -287,18 +293,16 @@ void swap(int *a, int *b)
*b = tmp;
}
void term_init(struct terminal *term, struct pair res)
void term_init(struct terminal *term, struct pair res, int rotate)
{
//term->offset.x = TERM_OFFSET_X;
//term->offset.y = TERM_OFFSET_Y;
term->width = res.x;
term->height = res.y;
if (ROTATE == CLOCKWISE || ROTATE == COUNTER_CLOCKWISE)
swap(&term->width, &term->height);
if (rotate == CLOCKWISE || rotate == COUNTER_CLOCKWISE)
swap_int(&term->width, &term->height);
term->cols = term->width / cell_width;
term->lines = term->height / cell_height;
term->cols = term->width / CELL_WIDTH;
term->lines = term->height / CELL_HEIGHT;
if (DEBUG)
fprintf(stderr, "width:%d height:%d cols:%d lines:%d\n",

View file

@ -138,8 +138,12 @@ void dump_fonts(struct glyph_t *fonts)
"\tuint%d_t bitmap[%d];\n"
"};\n\n", ((cell_width + BITS_PER_BYTE - 1) / BITS_PER_BYTE) * BITS_PER_BYTE * 2, cell_height);
/*
fprintf(stdout, "static const uint8_t cell_width = %d, cell_height = %d;\n",
cell_width, cell_height);
*/
fprintf(stdout, "enum {\n\tCELL_WIDTH = %d,\n\tCELL_HEIGHT = %d\n};\n\n",
cell_width, cell_height);
fprintf(stdout, "static const struct static_glyph_t fonts[UCS2_CHARS] = {\n");
for (i = 0; i < UCS2_CHARS; i++) {

94
util.h
View file

@ -1,4 +1,5 @@
/* See LICENSE for licence details. */
/* error functions */
void error(char *str)
{
/* for DEBUG
@ -18,6 +19,7 @@ void fatal(char *str)
exit(EXIT_FAILURE);
}
/* wrapper of C functions */
int eopen(const char *path, int flag)
{
int fd;
@ -99,7 +101,7 @@ void ewrite(int fd, void *buf, int size)
void eforkpty(int *master, int lines, int cols)
{
int slave;
char *name;
char *name = NULL;
pid_t pid;
if ((*master = posix_openpt(O_RDWR | O_NOCTTY)) < 0
@ -149,3 +151,93 @@ void etcsetattr(int fd, int action, struct termios *tm)
if (tcsetattr(fd, action, tm) < 0)
error("tcgetattr");
}
/* functions for framebuffer */
char *load_wallpaper(struct framebuffer *fb)
{
char *ptr;
ptr = (char *) emalloc(fb->screen_size);
memcpy(ptr, fb->fp, fb->screen_size);
return ptr;
}
void get_rgb(int i, struct color_t *color)
{
color->r = (color_list[i] >> 16) & bit_mask[8];
color->g = (color_list[i] >> 8) & bit_mask[8];
color->b = (color_list[i] >> 0) & bit_mask[8];
}
uint32_t bit_reverse(uint32_t val, int bits)
{
uint32_t ret = val;
int shift = bits - 1;
for (val >>= 1; val; val >>= 1) {
ret <<= 1;
ret |= val & 1;
shift--;
}
return ret <<= shift;
}
/* parse arguments */
void reset_parm(struct parm_t *pt)
{
int i;
pt->argc = 0;
for (i = 0; i < ESC_PARAMS; i++)
pt->argv[i] = NULL;
}
void parse_arg(char *buf, struct parm_t *pt, int delim, int (is_valid)(int c))
{
int length;
char *cp;
length = strlen(buf);
cp = buf;
while (cp <= &buf[length - 1]) {
if (*cp == delim)
*cp = '\0';
cp++;
}
cp = buf;
start:
if (pt->argc < ESC_PARAMS && is_valid(*cp)) {
pt->argv[pt->argc] = cp;
pt->argc++;
}
while (is_valid(*cp))
cp++;
while (!is_valid(*cp) && cp <= &buf[length - 1])
cp++;
if (cp <= &buf[length - 1])
goto start;
}
int isdigit_or_questionmark(int c)
{
if (isdigit(c) || c == '?')
return 1;
else
return 0;
}
int is_osc_parm(int c)
{
if (isdigit(c) || isalpha(c) ||
c == '?' || c == ':' || c == '/' || c == '#')
return 1;
else
return 0;
}

56
yaft.c
View file

@ -1,18 +1,10 @@
/* See LICENSE for licence details. */
#include "common.h"
#include "util.h"
#include "framebuffer.h"
#include "linux.h"
//#include "freebsd.h"
#include "terminal.h"
#include "function.h"
#include "parse.h"
struct tty_state tty = {
.save_tm = NULL,
.visible = true,
.redraw_flag = false,
.loop_flag = true,
};
void handler(int signo)
{
sigset_t sigset;
@ -25,7 +17,9 @@ void handler(int signo)
ioctl(STDIN_FILENO, VT_RELDISP, 1);
sigfillset(&sigset);
sigdelset(&sigset, SIGUSR1);
if (!BACKGROUND_DRAW)
if (tty.background_draw)
tty.redraw_flag = true;
else
sigsuspend(&sigset);
}
else {
@ -51,11 +45,37 @@ void set_rawmode(int fd, struct termios *save_tm)
etcsetattr(fd, TCSAFLUSH, &tm);
}
void check_env(struct framebuffer *fb)
{
extern struct tty_state tty; /* global var */
char *env;
if ((env = getenv("YAFT")) != NULL) {
if (strstr(env, "wall") != NULL && fb->bpp > 1)
fb->wall = load_wallpaper(fb);
if (strstr(env, "clockwise") != NULL || strstr(env, "cw") != NULL)
fb->rotate = CLOCKWISE;
else if (strstr(env, "upside_down") != NULL || strstr(env, "ud") != NULL)
fb->rotate = UPSIDE_DOWN;
else if (strstr(env, "counter_clockwise") != NULL || strstr(env, "ccw") != NULL)
fb->rotate = COUNTER_CLOCKWISE;
if (strstr(env, "background") != NULL || strstr(env, "bg") != NULL)
tty.background_draw = true;
}
else {
fb->wall = NULL;
fb->rotate = NORMAL;
}
}
void tty_init()
{
extern struct tty_state tty; /* global var */
struct sigaction sigact;
struct vt_mode vtm;
char *env;
memset(&sigact, 0, sizeof(struct sigaction));
sigact.sa_handler = handler;
@ -74,6 +94,13 @@ void tty_init()
tty.save_tm = (struct termios *) emalloc(sizeof(struct termios));
set_rawmode(STDIN_FILENO, tty.save_tm);
ewrite(STDIN_FILENO, "\033[?25l", 6); /* make cusor invisible */
if ((env = getenv("YAFT")) != NULL) {
if (strstr(env, "background") != NULL)
tty.background_draw = true;
if (strstr(env, "lazy") != NULL)
tty.lazy_draw = true;
}
}
void tty_die()
@ -125,8 +152,9 @@ int main()
fatal("atexit failed");
tty_init();
fb_init(&fb);
term_init(&term, fb.res);
fb_init(&fb, term.color_palette);
check_env(&fb);
term_init(&term, fb.res, fb.rotate);
/* fork and exec shell */
eforkpty(&term.fd, term.lines, term.cols);
@ -151,7 +179,7 @@ int main()
if (DEBUG)
ewrite(STDOUT_FILENO, buf, size);
parse(&term, buf, size);
if (LAZY_DRAW && size == BUFSIZE)
if (tty.lazy_draw && size == BUFSIZE)
continue;
refresh(&fb, &term);
}