~sircmpwn/scurvy

d224a930f05e18ea2a1347772118163261c5ce69 — Drew DeVault 4 years ago 0946e86
Render vterm with cairo
8 files changed, 136 insertions(+), 24 deletions(-)

M include/child.h
M include/config.h
M include/term.h
M src/child.c
M src/config.c
M src/main.c
M src/term.c
M src/wayland/main.c
M include/child.h => include/child.h +1 -0
@@ 10,5 10,6 @@ struct scurvy_child {
struct scurvy_child *child_spawn(char **argv);
void child_free(struct scurvy_child *child);
bool child_read_pty(struct scurvy_child *child);
void child_write_pty(struct scurvy_child *child);

#endif

M include/config.h => include/config.h +1 -0
@@ 8,6 8,7 @@ struct scurvy_config {
	char *font;
	char *url;
	char *term;
	int font_width, font_height;
};

extern struct scurvy_config *config;

M include/term.h => include/term.h +4 -0
@@ 4,7 4,11 @@
#include <cairo/cairo.h>

extern VTerm *vterm;
extern VTermState *vtstate;
extern VTermScreen *vtscreen;

void term_init();
void term_render();
void set_term_size(cairo_t *cairo, int width, int height);

#endif

M src/child.c => src/child.c +11 -4
@@ 110,23 110,30 @@ struct scurvy_child *child_spawn(char **argv) {
	return child;
}

// TODO: support partial read/write correctly
bool child_read_pty(struct scurvy_child *child) {
	static char buf[4096];
	int r = read(child->fd, &buf, sizeof(buf));
	if (r == -1) {
		if (errno != EAGAIN) {
			scurvy_log(L_DEBUG, "pty read error %d", errno);
			// TODO: Abort
			return false;
			scurvy_log(L_ERROR, "pty read error %d", errno);
			exit(1);
		}
	}
	if (r > 0) {
		//vterm_input_write(vterm, buf, r);
		vterm_input_write(vterm, buf, r);
		vterm_screen_flush_damage(vtscreen);
		return true;
	}
	return false;
}

void child_write_pty(struct scurvy_child *child) {
	static char buf[4096];
	int r = vterm_output_read(vterm, buf, sizeof(buf));
	write(child->fd, &buf, r);
}

void child_free(struct scurvy_child *child) {
	if (!child) {
		return;

M src/config.c => src/config.c +4 -5
@@ 64,9 64,8 @@ static bool open_config(const char *path, FILE **f) {

static void set_color(struct scurvy_config *config,
		const char *key, const char *value) {
	VTermState *state = vterm_obtain_state(vterm);
	VTermColor fg, bg;
	vterm_state_get_default_colors(state, &fg, &bg);
	vterm_state_get_default_colors(vtstate, &fg, &bg);
	uint32_t color;
	if (!color_parse(value, &color)) {
		scurvy_log(L_ERROR, "Invalid color specification '%s'", value);


@@ 84,13 83,13 @@ static void set_color(struct scurvy_config *config,
			scurvy_log(L_ERROR, "Invalid color configuration '%s'", key);
			return;
		}
		vterm_state_set_palette_color(state, index, &col);
		vterm_state_set_palette_color(vtstate, index, &col);
		scurvy_log(L_DEBUG, "Set color%d to %08X", index, color);
	} else if (strcmp(key, "foreground") == 0) {
		vterm_state_set_default_colors(state, &col, &bg);
		vterm_state_set_default_colors(vtstate, &col, &bg);
		scurvy_log(L_DEBUG, "Set foreground to %08X", color);
	} else if (strcmp(key, "background") == 0) {
		vterm_state_set_default_colors(state, &fg, &col);
		vterm_state_set_default_colors(vtstate, &fg, &col);
		config->background = color;
		scurvy_log(L_DEBUG, "Set background to %08X", color);
	} else {

M src/main.c => src/main.c +2 -3
@@ 9,12 9,11 @@ int wayland_main(struct scurvy_child *);

int main(int argc, char **argv) {
	init_log(L_DEBUG);
	vterm = vterm_new(80, 24);
	vterm_set_utf8(vterm, 1);
	term_init();
	if (!load_scurvy_config(NULL)) {
		return 1;
	}
	char *_argv[] = { "/usr/bin/bash", NULL };
	char *_argv[] = { "/usr/bin/vim", NULL };
	struct scurvy_child *child = child_spawn(_argv);
	int status = wayland_main(child);
	child_free(child);

M src/term.c => src/term.c +64 -2
@@ 1,13 1,75 @@
#include <cairo/cairo.h>
#include <vterm.h>
#include <string.h>
#include "term.h"
#include "pango.h"
#include "config.h"
#include "child.h"
#include "log.h"

struct VTerm *vterm;
struct VTermState *vtstate;
struct VTermScreen *vtscreen;

void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
	cairo_set_source_rgba(cairo,
			(color >> (3*8) & 0xFF) / 255.0,
			(color >> (2*8) & 0xFF) / 255.0,
			(color >> (1*8) & 0xFF) / 255.0,
			(color >> (0*8) & 0xFF) / 255.0);
}

void term_render(cairo_t *cairo) {
	cairo_set_source_u32(cairo, config->background);
	cairo_paint(cairo);
	int rows, cols;
	vterm_get_size(vterm, &rows, &cols);
	VTermScreenCell cell;
	char buf[VTERM_MAX_CHARS_PER_CELL + 1];
	int tw, th, _;
	get_text_size(cairo, config->font, &tw, &th, 1, false, "Hello world");
	for (int row = 0; row < rows; ++row) {
		for (int col = 0, x = 0; col < cols; ++col) {
			VTermPos pos = { row, col };
			vterm_screen_get_cell(vtscreen, pos, &cell);
			memcpy(buf, cell.chars, VTERM_MAX_CHARS_PER_CELL);
			buf[(int)cell.width] = '\0';

			get_text_size(cairo, config->font, &tw, &_, 1, false, "%s", buf);
			cairo_set_source_rgb(cairo,
					cell.bg.red / 256.0,
					cell.bg.green / 256.0,
					cell.bg.blue / 256.0);
			cairo_rectangle(cairo, x, row * th, tw, _);

			cairo_move_to(cairo, x, row * th);
			cairo_set_source_rgb(cairo,
					cell.fg.red / 256.0,
					cell.fg.green / 256.0,
					cell.fg.blue / 256.0);
			pango_printf(cairo, config->font, 1, false, "%s", buf);
			x += tw;
		}
	}
}

void term_init() {
	vterm = vterm_new(24, 80);
	vtstate = vterm_obtain_state(vterm);
	vtscreen = vterm_obtain_screen(vterm);

	vterm_set_utf8(vterm, 1);
	vterm_screen_set_damage_merge(vtscreen, VTERM_DAMAGE_SCROLL);
	vterm_screen_reset(vtscreen, 1);
	vterm_state_set_bold_highbright(vtstate, true);
}

void set_term_size(cairo_t *cairo, int width, int height) {
	int w, h;
	get_text_size(cairo, config->font, &w, &h, 1, false, "Hello world");
	vterm_set_size(vterm, height / h, width / w);
	get_text_size(cairo, config->font, &w, &h, 1, false, "H");
	h = height / h;
	w = width / w;
	scurvy_log(L_DEBUG, "Setting size to %d rows %d cols", h, w);
	vterm_set_size(vterm, h, w);
	vterm_screen_flush_damage(vtscreen);
}

M src/wayland/main.c => src/wayland/main.c +49 -10
@@ 8,18 8,56 @@
#include "config.h"
#include "child.h"
#include "term.h"

void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
	cairo_set_source_rgba(cairo,
			(color >> (3*8) & 0xFF) / 255.0,
			(color >> (2*8) & 0xFF) / 255.0,
			(color >> (1*8) & 0xFF) / 255.0,
			(color >> (0*8) & 0xFF) / 255.0);
}
#include "log.h"

struct registry *registry;
struct window *win;

static int term_damage(VTermRect rect, void *data) {
	scurvy_log(L_DEBUG, "damage");
	return 0;
}

static int term_moverect(VTermRect dest, VTermRect src, void *data) {
	scurvy_log(L_DEBUG, "moverect");
	return 0;
}

static int term_movecursor(VTermPos new, VTermPos old, int visible, void *data) {
	scurvy_log(L_DEBUG, "movecursor");
	return 0;
}

static int term_settermprop(VTermProp prop, VTermValue *val, void *data) {
	scurvy_log(L_DEBUG, "prop");
	return 0;
}

static int term_bell(void *data) {
	scurvy_log(L_DEBUG, "bell");
	return 0;
}

static int term_sb_push(int cols, const VTermScreenCell *cells, void *data) {
	scurvy_log(L_DEBUG, "sb_push");
	return 0;
}

static int term_sb_pop(int cols, VTermScreenCell *cells, void *data) {
	scurvy_log(L_DEBUG, "sb_pop");
	return 0;
}

static VTermScreenCallbacks vterm_screen_callbacks = {
	.damage      = term_damage,
	.moverect    = term_moverect,
	.movecursor  = term_movecursor,
	.settermprop = term_settermprop,
	.bell        = term_bell,
	.sb_pushline = term_sb_push,
	.sb_popline  = term_sb_pop,
};

static void window_resize(struct window *_win) {
	set_term_size(win->cairo, win->width, win->height);
}


@@ 30,15 68,16 @@ static void keyboard_event(enum wl_keyboard_key_state state,
}

int wayland_main(struct scurvy_child *child) {
	vterm_screen_set_callbacks(vtscreen, &vterm_screen_callbacks, NULL);
	registry = registry_poll();
	registry->input->notify = keyboard_event;
	win = window_setup(registry, 640, 480, 1, true);
	win->notify_resize = window_resize;
	while (wl_display_dispatch(registry->display) != -1) {
		if (window_prerender(win) && win->cairo) {
			cairo_set_source_u32(win->cairo, config->background);
			cairo_paint(win->cairo);
			child_read_pty(child);
			child_write_pty(child);
			term_render(win->cairo);
			window_render(win);
			wl_display_flush(registry->display);
		}