aboutsummaryrefslogtreecommitdiff
path: root/src/sysbin/terminal/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sysbin/terminal/main.c')
-rw-r--r--src/sysbin/terminal/main.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/sysbin/terminal/main.c b/src/sysbin/terminal/main.c
new file mode 100644
index 0000000..9ba7afe
--- /dev/null
+++ b/src/sysbin/terminal/main.c
@@ -0,0 +1,253 @@
+#include <string.h>
+#include <malloc.h>
+#include <user_region.h>
+#include <debug.h>
+
+#include <gip.h>
+#include <draw.h>
+#include <keyboard.h>
+
+typedef char tchar_t;
+
+typedef struct {
+ fb_info_t mode;
+ fd_t fd;
+ fb_t *fb;
+
+ uint32_t sv_features, cl_features;
+
+ font_t *font;
+ int cw, ch; // size of a character
+ color_t fg, bg;
+
+ keyboard_t *kb;
+
+ int w, h;
+ tchar_t* scr_chars;
+ int csrl, csrc;
+ bool csr_visible;
+
+} term_t;
+
+void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m);
+void c_key_down(gip_handler_t *s, gip_msg_header *p);
+void c_key_up(gip_handler_t *s, gip_msg_header *p);
+void c_unknown_msg(gip_handler_t *s, gip_msg_header *p);
+void c_fd_error(gip_handler_t *s);
+
+void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata);
+
+gip_handler_callbacks_t term_gip_cb = {
+ .reset = 0,
+ .initiate = 0,
+ .ok = 0,
+ .failure = 0,
+ .enable_features = 0,
+ .disable_features = 0,
+ .query_mode = 0,
+ .set_mode = 0,
+ .buffer_info = c_buffer_info,
+ .mode_info = 0,
+ .buffer_damage = 0,
+ .key_down = c_key_down,
+ .key_up = c_key_up,
+ .unknown_msg = c_unknown_msg,
+ .fd_error = c_fd_error,
+};
+
+
+int main(int argc, char **argv) {
+ dbg_print("[terminal] Starting up.\n");
+
+ term_t term;
+ memset(&term, 0, sizeof(term));
+
+ term.kb = init_keyboard();
+ ASSERT(term.kb != 0);
+
+ term.font = g_load_font("default");
+ ASSERT(term.font != 0);
+ term.cw = g_text_width(term.font, "#");
+ term.ch = g_text_height(term.font, "#");
+
+ gip_handler_t *h = new_gip_handler(&term_gip_cb, &term);
+ ASSERT(h != 0);
+
+ h->mainloop_item.fd = 1;
+ mainloop_add_fd(&h->mainloop_item);
+
+ gip_msg_header reset_msg = { .code = GIPC_RESET, .arg = 0 };
+ gip_cmd(h, &reset_msg, 0, c_async_initiate, 0);
+
+ mainloop_run();
+
+ return 0;
+}
+
+// Terminal features
+
+void term_draw_c(term_t *t, int l, int c) {
+ color_t bg = t->bg;
+ if (l == t->csrl && c == t->csrc) bg = g_color_rgb(t->fb, 0, 100, 0);
+
+ char ss[2];
+ ss[0] = t->scr_chars[l * t->w + c];
+ ss[1] = 0;
+
+ g_fillrect(t->fb, c * t->cw, l * t->ch, t->cw, t->ch, bg);
+ g_write(t->fb, c * t->cw, l * t->ch, ss, t->font, t->fg);
+}
+
+void term_move_cursor(term_t *t, int l, int c) {
+ int l0 = t->csrl, c0 = t->csrc;
+ t->csrl = l;
+ t->csrc = c;
+ term_draw_c(t, l0, c0);
+ term_draw_c(t, l, c);
+}
+
+void term_clear_screen(term_t *t) {
+ t->csr_visible = true;
+
+ for (int i = 0; i < t->w * t->h; i++) t->scr_chars[i] = ' ';
+
+ g_fillrect(t->fb, 0, 0, t->mode.width, t->mode.height, t->bg);
+
+ term_move_cursor(t, 0, 0);
+}
+
+void term_scroll1(term_t *t) {
+ for (int i = 0; i < t->w * (t->h - 1); i++)
+ t->scr_chars[i] = t->scr_chars[i + t->w];
+ for (int i = 0; i < t->w; i++) {
+ t->scr_chars[i + (t->h - 1) * t->w] = ' ';
+ }
+ t->csrl--;
+
+ g_scroll_up(t->fb, t->ch);
+ g_fillrect(t->fb, 0, t->ch * (t->h - 1), t->cw * t->w, t->ch, t->bg);
+}
+
+void term_putc(term_t *t, int c) {
+ int nl = t->csrl, nc = t->csrc;
+ if (c == '\n') {
+ nl++; nc = 0;
+ } else if (c == '\b') {
+ if (nc > 0) {
+ nc--;
+ t->scr_chars[nl * t->w + nc] = ' ';
+ }
+ } else if (c == '\t') {
+ while (nc % 4 != 0) nc++;
+ } else if (c >= ' ' && c < 128) {
+ t->scr_chars[nl * t->w + nc] = c;
+ nc++;
+ }
+ if (nc >= t->w) {
+ nc = 0;
+ nl++;
+ }
+ if (nl >= t->h) {
+ term_scroll1(t);
+ nl--;
+ }
+ term_move_cursor(t, nl, nc);
+}
+
+void term_puts(term_t *t, char* s) {
+ while ((*s) != 0) {
+ term_putc(t, *s);
+ s++;
+ }
+}
+
+// GIP client connection
+
+void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) {
+ dbg_printf("[terminal] Got buffer info msg\n");
+
+ term_t *c = (term_t*)s->data;
+
+ if (c->fb != 0) {
+ g_delete_fb(c->fb);
+ c->fb = 0;
+ }
+ if (c->fd != 0) {
+ close(c->fd);
+ c->fd = 0;
+ }
+
+ c->fd = use_token(&m->tok);
+ if (c->fd != 0) {
+ memcpy(&c->mode, &m->geom, sizeof(fb_info_t));
+
+ dbg_printf("[terminal] Got buffer on FD %d, %dx%dx%d\n",
+ c->fd, c->mode.width, c->mode.height, c->mode.bpp);
+
+ if (c->scr_chars != 0) {
+ free(c->scr_chars);
+ c->scr_chars = 0;
+ }
+ c->w = c->mode.width / c->cw;
+ c->h = c->mode.height / c->ch;
+ c->scr_chars = (tchar_t*)malloc(c->w * c->h * sizeof(tchar_t));
+ ASSERT(c->scr_chars != 0);
+
+ c->fb = g_fb_from_file(c->fd, &m->geom);
+ if (c->fb != 0) {
+ c->bg = g_color_rgb(c->fb, 0, 0, 0);
+ c->fg = g_color_rgb(c->fb, 200, 200, 200);
+ term_clear_screen(c);
+ } else {
+ dbg_printf("[terminal] Could not open framebuffer file %d\n", c->fd);
+ }
+
+ }
+}
+
+void c_key_down(gip_handler_t *s, gip_msg_header *p) {
+ term_t *c = (term_t*)s->data;
+
+ key_t k = keyboard_press(c->kb, p->arg);
+
+ if (k.flags & KBD_CHAR)
+ dbg_printf("D %x %c\n", k.flags, k.key);
+ else
+ dbg_printf("D %x %d\n", k.flags, k.key);
+}
+
+void c_key_up(gip_handler_t *s, gip_msg_header *p) {
+ term_t *c = (term_t*)s->data;
+
+ key_t k = keyboard_release(c->kb, p->arg);
+
+ if (k.flags & KBD_CHAR)
+ dbg_printf("U %x %c\n", k.flags, k.key);
+ else
+ dbg_printf("U %x %d\n", k.flags, k.key);
+
+ if (k.flags & KBD_CHAR) {
+ term_putc(c, k.chr);
+ } else {
+ if (k.key == KBD_CODE_RETURN) term_putc(c, '\n');
+ if (k.key == KBD_CODE_TAB) term_putc(c, '\t');
+ if (k.key == KBD_CODE_BKSP) term_putc(c, '\b');
+ }
+}
+
+void c_unknown_msg(gip_handler_t *s, gip_msg_header *p) {
+ // TODO
+}
+
+void c_fd_error(gip_handler_t *s) {
+ // TODO
+}
+
+void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata) {
+ term_t *c = (term_t*)s->data;
+ c->sv_features = p->arg;
+
+ dbg_printf("[temrinal] Got initiate reply to reset request (features 0x%p).\n", c->sv_features);
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/