Browse Source

Add VGA terminal

K. Lange 3 years ago
parent
commit
7c6cd9c531
6 changed files with 1231 additions and 7 deletions
  1. 4 1
      Makefile
  2. 19 3
      apps/init.c
  3. 939 0
      apps/terminal-vga.c
  4. 259 0
      apps/vga-palette.h
  5. 10 2
      cdrom/boot/grub/menus.cfg
  6. 0 1
      lib/yutani.c

+ 4 - 1
Makefile

@@ -1,4 +1,4 @@
-APPS=init hello sh ls terminal uname compositor drawlines background session kdebug cat yutani-test sysinfo hostname yutani-query env mount date echo nyancat kill ps pstree bim
+APPS=init hello sh ls terminal uname compositor drawlines background session kdebug cat yutani-test sysinfo hostname yutani-query env mount date echo nyancat kill ps pstree bim terminal-vga
 
 CC=i686-pc-toaru-gcc
 AR=i686-pc-toaru-ar
@@ -89,6 +89,9 @@ base/bin/sysinfo: apps/sysinfo.c base/lib/libnihc.so base/lib/libtoaru_graphics.
 base/bin/terminal: apps/terminal.c base/lib/libnihc.so base/lib/libtoaru_graphics.so base/lib/libtoaru_yutani.so base/lib/libtoaru_decorations.so base/lib/libtoaru_dlfcn.so base/lib/libtoaru_list.so base/lib/libtoaru_kbd.so base/lib/libtoaru_termemu.so base/lib/libtoaru_pex.so base/lib/libtoaru_hashmap.so
 	$(CC) $(CFLAGS) -o $@ $< -ltoaru_termemu -ltoaru_decorations -ltoaru_yutani -ltoaru_graphics -ltoaru_pex -ltoaru_hashmap -ltoaru_dlfcn -ltoaru_kbd -ltoaru_list $(LIBS)
 
+base/bin/terminal-vga: apps/terminal-vga.c base/lib/libnihc.so base/lib/libtoaru_graphics.so base/lib/libtoaru_kbd.so base/lib/libtoaru_termemu.so
+	$(CC) $(CFLAGS) -o $@ $< -ltoaru_termemu -ltoaru_graphics -ltoaru_kbd $(LIBS)
+
 base/bin/background: apps/background.c base/lib/libnihc.so base/lib/libtoaru_graphics.so base/lib/libtoaru_yutani.so base/lib/libtoaru_pthread.so base/lib/libtoaru_drawstring.so
 	$(CC) $(CFLAGS) -o $@ $< -ltoaru_drawstring -ltoaru_yutani -ltoaru_graphics -ltoaru_pex -ltoaru_pthread -ltoaru_hashmap -ltoaru_list $(LIBS)
 

+ 19 - 3
apps/init.c

@@ -1,7 +1,7 @@
 #include <syscall.h>
 #include <errno.h>
-#include <_xlog.h>
 #include <wait.h>
+#include <string.h>
 
 void set_console() {
 	int _stdin  = syscall_open("/dev/null", 0, 0);
@@ -37,7 +37,6 @@ int start_options(char * args[]) {
 }
 
 int main(int argc, char * argv[]) {
-	_XLOG("Init starting...");
 	set_console();
 
 	char * _argv[] = {
@@ -46,5 +45,22 @@ int main(int argc, char * argv[]) {
 	};
 
 	syscall_sethostname("base");
-	return start_options(_argv);
+
+	if (argc > 1) {
+		char * args = NULL;
+		if (argc > 2) {
+			args = argv[2];
+		}
+		if (!strcmp(argv[1], "--vga")) {
+			return start_options((char *[]){"/bin/terminal-vga","-l",NULL});
+#if 0
+		} else if (!strcmp(argv[1], "--migrate")) {
+			return start_options((char *[]){"/usr/bin/python","/bin/migrate.py",NULL});
+#endif
+		} else {
+			/* Pass it to the compositor... */
+			return start_options((char *[]){"/bin/compositor","--",argv[1],NULL});
+		}
+	}
+	return start_options((char *[]){"/bin/compositor",NULL});
 }

+ 939 - 0
apps/terminal-vga.c

@@ -0,0 +1,939 @@
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * This file is part of ToaruOS and is released under the terms
+ * of the NCSA / University of Illinois License - see LICENSE.md
+ * Copyright (C) 2014 Kevin Lange
+ *
+ * Terminal Emulator - VGA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <syscall.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include <wchar.h>
+
+#include "lib/utf8decode.h"
+#include "lib/kbd.h"
+#include "lib/graphics.h"
+#include "lib/termemu.h"
+
+#include "vga-palette.h"
+
+#define USE_BELL 0
+
+/* master and slave pty descriptors */
+static int fd_master, fd_slave;
+static FILE * terminal;
+
+uint16_t term_width     = 80;    /* Width of the terminal (in cells) */
+uint16_t term_height    = 25;    /* Height of the terminal (in cells) */
+uint16_t csr_x          = 0;    /* Cursor X */
+uint16_t csr_y          = 0;    /* Cursor Y */
+term_cell_t * term_buffer    = NULL; /* The terminal cell buffer */
+uint32_t current_fg     = 7;    /* Current foreground color */
+uint32_t current_bg     = 0;    /* Current background color */
+uint8_t  cursor_on      = 1;    /* Whether or not the cursor should be rendered */
+
+uint8_t  _login_shell   = 0;    /* Whether we're going to display a login shell or not */
+uint8_t  _hold_out      = 0;    /* state indicator on last cell ignore \n */
+
+uint64_t mouse_ticks = 0;
+
+#define char_width 1
+#define char_height 1
+
+term_state_t * ansi_state = NULL;
+
+void reinit(); /* Defined way further down */
+void term_redraw_cursor();
+
+/* Cursor bink timer */
+static unsigned int timer_tick = 0;
+
+void term_clear();
+
+void dump_buffer();
+
+static uint64_t get_ticks(void) {
+	struct timeval now;
+	gettimeofday(&now, NULL);
+
+	return (uint64_t)now.tv_sec * 1000000LL + (uint64_t)now.tv_usec;
+}
+
+static int color_distance(uint32_t a, uint32_t b) {
+	int a_r = (a & 0xFF0000) >> 16;
+	int a_g = (a & 0xFF00) >> 8;
+	int a_b = (a & 0xFF);
+
+	int b_r = (b & 0xFF0000) >> 16;
+	int b_g = (b & 0xFF00) >> 8;
+	int b_b = (b & 0xFF);
+
+	int distance = 0;
+	distance += abs(a_r - b_r) * 3;
+	distance += abs(a_g - b_g) * 6;
+	distance += abs(a_b - b_b) * 10;
+
+	return distance;
+}
+
+static uint32_t vga_base_colors[] = {
+	0x000000,
+	0xAA0000,
+	0x00AA00,
+	0xAA5500,
+	0x0000AA,
+	0xAA00AA,
+	0x00AAAA,
+	0xAAAAAA,
+	0x555555,
+	0xFF5555,
+	0x55AA55,
+	0xFFFF55,
+	0x5555FF,
+	0xFF55FF,
+	0x55FFFF,
+	0xFFFFFF,
+};
+
+static int is_gray(uint32_t a) {
+	int a_r = (a & 0xFF0000) >> 16;
+	int a_g = (a & 0xFF00) >> 8;
+	int a_b = (a & 0xFF);
+
+	return (a_r == a_g && a_g == a_b);
+}
+
+static int best_match(uint32_t a) {
+	int best_distance = INT32_MAX;
+	int best_index = 0;
+	for (int j = 0; j < 16; ++j) {
+		if (is_gray(a) && !is_gray(vga_base_colors[j]));
+		int distance = color_distance(a, vga_base_colors[j]);
+		if (distance < best_distance) {
+			best_index = j;
+			best_distance = distance;
+		}
+	}
+	return best_index;
+}
+
+
+volatile int exit_application = 0;
+
+static void set_term_font_size(float s) {
+	/* do nothing */
+}
+
+/* Returns the lower of two shorts */
+uint16_t min(uint16_t a, uint16_t b) {
+	return (a < b) ? a : b;
+}
+
+/* Returns the higher of two shorts */
+uint16_t max(uint16_t a, uint16_t b) {
+	return (a > b) ? a : b;
+}
+
+void set_title(char * c) {
+	/* Do nothing */
+}
+
+void input_buffer_stuff(char * str) {
+	size_t s = strlen(str) + 1;
+	write(fd_master, str, s);
+}
+
+unsigned short * textmemptr = (unsigned short *)0xB8000;
+void placech(unsigned char c, int x, int y, int attr) {
+	unsigned short *where;
+	unsigned att = attr << 8;
+	where = textmemptr + (y * 80 + x);
+	*where = c | att;
+}
+
+/* ANSI-to-VGA */
+char vga_to_ansi[] = {
+	0, 4, 2, 6, 1, 5, 3, 7,
+	8,12,10,14, 9,13,11,15
+};
+
+uint32_t ununicode(uint32_t c) {
+	switch (c) {
+		case L'☺': return 1;
+		case L'☻': return 2;
+		case L'♥': return 3;
+		case L'♦': return 4;
+		case L'♣': return 5;
+		case L'♠': return 6;
+		case L'•': return 7;
+		case L'◘': return 8;
+		case L'○': return 9;
+		case L'◙': return 10;
+		case L'♂': return 11;
+		case L'♀': return 12;
+		case L'♪': return 13;
+		case L'♫': return 14;
+		case L'☼': return 15;
+		case L'►': return 16;
+		case L'◄': return 17;
+		case L'↕': return 18;
+		case L'‼': return 19;
+		case L'¶': return 20;
+		case L'§': return 21;
+		case L'▬': return 22;
+		case L'↨': return 23;
+		case L'↑': return 24;
+		case L'↓': return 25;
+		case L'→': return 26;
+		case L'←': return 27;
+		case L'∟': return 28;
+		case L'↔': return 29;
+		case L'▲': return 30;
+		case L'▼': return 31;
+		/* ASCII text */
+		case L'⌂': return 127;
+		case L'Ç': return 128;
+		case L'ü': return 129;
+		case L'é': return 130;
+		case L'â': return 131;
+		case L'ä': return 132;
+		case L'à': return 133;
+		case L'å': return 134;
+		case L'ç': return 135;
+		case L'ê': return 136;
+		case L'ë': return 137;
+		case L'è': return 138;
+		case L'ï': return 139;
+		case L'î': return 140;
+		case L'ì': return 141;
+		case L'Ä': return 142;
+		case L'Å': return 143;
+		case L'É': return 144;
+		case L'æ': return 145;
+		case L'Æ': return 146;
+		case L'ô': return 147;
+		case L'ö': return 148;
+		case L'ò': return 149;
+		case L'û': return 150;
+		case L'ù': return 151;
+		case L'ÿ': return 152;
+		case L'Ö': return 153;
+		case L'Ü': return 154;
+		case L'¢': return 155;
+		case L'£': return 156;
+		case L'¥': return 157;
+		case L'₧': return 158;
+		case L'ƒ': return 159;
+		case L'á': return 160;
+		case L'í': return 161;
+		case L'ó': return 162;
+		case L'ú': return 163;
+		case L'ñ': return 164;
+		case L'Ñ': return 165;
+		case L'ª': return 166;
+		case L'º': return 167;
+		case L'¿': return 168;
+		case L'⌐': return 169;
+		case L'¬': return 170;
+		case L'½': return 171;
+		case L'¼': return 172;
+		case L'¡': return 173;
+		case L'«': return 174;
+		case L'»': return 175;
+		case L'░': return 176;
+		case L'▒': return 177;
+		case L'▓': return 178;
+		case L'│': return 179;
+		case L'┤': return 180;
+		case L'╡': return 181;
+		case L'╢': return 182;
+		case L'╖': return 183;
+		case L'╕': return 184;
+		case L'╣': return 185;
+		case L'║': return 186;
+		case L'╗': return 187;
+		case L'╝': return 188;
+		case L'╜': return 189;
+		case L'╛': return 190;
+		case L'┐': return 191;
+		case L'└': return 192;
+		case L'┴': return 193;
+		case L'┬': return 194;
+		case L'├': return 195;
+		case L'─': return 196;
+		case L'┼': return 197;
+		case L'╞': return 198;
+		case L'╟': return 199;
+		case L'╚': return 200;
+		case L'╔': return 201;
+		case L'╩': return 202;
+		case L'╦': return 203;
+		case L'╠': return 204;
+		case L'═': return 205;
+		case L'╬': return 206;
+		case L'╧': return 207;
+		case L'╨': return 208;
+		case L'╤': return 209;
+		case L'╥': return 210;
+		case L'╙': return 211;
+		case L'╘': return 212;
+		case L'╒': return 213;
+		case L'╓': return 214;
+		case L'╫': return 215;
+		case L'╪': return 216;
+		case L'┘': return 217;
+		case L'┌': return 218;
+		case L'█': return 219;
+		case L'▄': return 220;
+		case L'▌': return 221;
+		case L'▐': return 222;
+		case L'▀': return 223;
+		case L'α': return 224;
+		case L'ß': return 225;
+		case L'Γ': return 226;
+		case L'π': return 227;
+		case L'Σ': return 228;
+		case L'σ': return 229;
+		case L'µ': return 230;
+		case L'τ': return 231;
+		case L'Φ': return 232;
+		case L'Θ': return 233;
+		case L'Ω': return 234;
+		case L'δ': return 235;
+		case L'∞': return 236;
+		case L'φ': return 237;
+		case L'ε': return 238;
+		case L'∩': return 239;
+		case L'≡': return 240;
+		case L'±': return 241;
+		case L'≥': return 242;
+		case L'≤': return 243;
+		case L'⌠': return 244;
+		case L'⌡': return 245;
+		case L'÷': return 246;
+		case L'≈': return 247;
+		case L'°': return 248;
+		case L'∙': return 249;
+		case L'·': return 250;
+		case L'√': return 251;
+		case L'ⁿ': return 252;
+		case L'²': return 253;
+		case L'■': return 254;
+	}
+	return 4;
+}
+
+void
+term_write_char(
+		uint32_t val,
+		uint16_t x,
+		uint16_t y,
+		uint32_t fg,
+		uint32_t bg,
+		uint8_t flags
+		) {
+	if (val > 128) val = ununicode(val);
+	if (fg > 256) {
+		fg = best_match(fg);
+	}
+	if (bg > 256) {
+		bg = best_match(bg);
+	}
+	if (fg > 16) {
+		fg = vga_colors[fg];
+	}
+	if (bg > 16) {
+		bg = vga_colors[bg];
+	}
+	if (fg == 16) fg = 0;
+	if (bg == 16) bg = 0;
+	placech(val, x, y, (vga_to_ansi[fg] & 0xF) | (vga_to_ansi[bg] << 4));
+}
+
+static void cell_set(uint16_t x, uint16_t y, uint32_t c, uint32_t fg, uint32_t bg, uint8_t flags) {
+	if (x >= term_width || y >= term_height) return;
+	term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+	cell->c     = c;
+	cell->fg    = fg;
+	cell->bg    = bg;
+	cell->flags = flags;
+}
+
+static void cell_redraw(uint16_t x, uint16_t y) {
+	if (x >= term_width || y >= term_height) return;
+	term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+	if (((uint32_t *)cell)[0] == 0x00000000) {
+		term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS);
+	} else {
+		term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags);
+	}
+}
+
+static void cell_redraw_inverted(uint16_t x, uint16_t y) {
+	if (x >= term_width || y >= term_height) return;
+	term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+	if (((uint32_t *)cell)[0] == 0x00000000) {
+		term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_BG, TERM_DEFAULT_FG, TERM_DEFAULT_FLAGS | ANSI_SPECBG);
+	} else {
+		term_write_char(cell->c, x * char_width, y * char_height, cell->bg, cell->fg, cell->flags | ANSI_SPECBG);
+	}
+}
+
+static void cell_redraw_box(uint16_t x, uint16_t y) {
+	if (x >= term_width || y >= term_height) return;
+	term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
+	if (((uint32_t *)cell)[0] == 0x00000000) {
+		term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS | ANSI_BORDER);
+	} else {
+		term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags | ANSI_BORDER);
+	}
+}
+
+void render_cursor() {
+	cell_redraw_inverted(csr_x, csr_y);
+}
+
+void draw_cursor() {
+	if (!cursor_on) return;
+	mouse_ticks = get_ticks();
+	render_cursor();
+}
+
+void term_redraw_all() { 
+	for (uint16_t y = 0; y < term_height; ++y) {
+		for (uint16_t x = 0; x < term_width; ++x) {
+			cell_redraw(x,y);
+		}
+	}
+}
+
+void term_scroll(int how_much) {
+	if (how_much >= term_height || -how_much >= term_height) {
+		term_clear();
+		return;
+	}
+	if (how_much == 0) {
+		return;
+	}
+	if (how_much > 0) {
+		/* Shift terminal cells one row up */
+		memmove(term_buffer, (void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width), sizeof(term_cell_t) * term_width * (term_height - how_much));
+		/* Reset the "new" row to clean cells */
+		memset((void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width * (term_height - how_much)), 0x0, sizeof(term_cell_t) * term_width * how_much);
+		for (int i = 0; i < how_much; ++i) {
+			for (uint16_t x = 0; x < term_width; ++x) {
+				cell_set(x,term_height - how_much,' ', current_fg, current_bg, ansi_state->flags);
+			}
+		}
+		term_redraw_all();
+	} else {
+		how_much = -how_much;
+		/* Shift terminal cells one row up */
+		memmove((void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width), term_buffer, sizeof(term_cell_t) * term_width * (term_height - how_much));
+		/* Reset the "new" row to clean cells */
+		memset(term_buffer, 0x0, sizeof(term_cell_t) * term_width * how_much);
+		term_redraw_all();
+	}
+}
+
+int is_wide(uint32_t codepoint) {
+	if (codepoint < 256) return 0;
+	return wcwidth(codepoint) == 2;
+}
+
+void term_write(char c) {
+	static uint32_t codepoint = 0;
+	static uint32_t unicode_state = 0;
+
+	cell_redraw(csr_x, csr_y);
+	if (!decode(&unicode_state, &codepoint, (uint8_t)c)) {
+		if (c == '\r') {
+			csr_x = 0;
+			return;
+		}
+		if (csr_x == term_width) {
+			csr_x = 0;
+			++csr_y;
+		}
+		if (csr_y == term_height) {
+			term_scroll(1);
+			csr_y = term_height - 1;
+		}
+		if (c == '\n') {
+			if (csr_x == 0 && _hold_out) {
+				_hold_out = 0;
+				return;
+			}
+			++csr_y;
+			if (csr_y == term_height) {
+				term_scroll(1);
+				csr_y = term_height - 1;
+			}
+			draw_cursor();
+		} else if (c == '\007') {
+			/* bell */
+#if USE_BELL
+			for (int i = 0; i < term_height; ++i) {
+				for (int j = 0; j < term_width; ++j) {
+					cell_redraw_inverted(j, i);
+				}
+			}
+			syscall_nanosleep(0,10);
+			term_redraw_all();
+#endif
+		} else if (c == '\b') {
+			if (csr_x > 0) {
+				--csr_x;
+			}
+			cell_redraw(csr_x, csr_y);
+			draw_cursor();
+		} else if (c == '\t') {
+			csr_x += (8 - csr_x % 8);
+			draw_cursor();
+		} else {
+			int wide = is_wide(codepoint);
+			uint8_t flags = ansi_state->flags;
+			if (wide && csr_x == term_width - 1) {
+				csr_x = 0;
+				++csr_y;
+			}
+			if (wide) {
+				flags = flags | ANSI_WIDE;
+			}
+			cell_set(csr_x,csr_y, codepoint, current_fg, current_bg, flags);
+			cell_redraw(csr_x,csr_y);
+			csr_x++;
+			if (wide && csr_x != term_width) {
+				cell_set(csr_x, csr_y, 0xFFFF, current_fg, current_bg, ansi_state->flags);
+				cell_redraw(csr_x,csr_y);
+				cell_redraw(csr_x-1,csr_y);
+				csr_x++;
+			}
+		}
+	} else if (unicode_state == UTF8_REJECT) {
+		unicode_state = 0;
+	}
+	draw_cursor();
+}
+
+void term_set_csr(int x, int y) {
+	cell_redraw(csr_x,csr_y);
+	csr_x = x;
+	csr_y = y;
+	draw_cursor();
+}
+
+int term_get_csr_x() {
+	return csr_x;
+}
+
+int term_get_csr_y() {
+	return csr_y;
+}
+
+void term_set_csr_show(int on) {
+	cursor_on = on;
+}
+
+void term_set_colors(uint32_t fg, uint32_t bg) {
+	current_fg = fg;
+	current_bg = bg;
+}
+
+void term_redraw_cursor() {
+	if (term_buffer) {
+		draw_cursor();
+	}
+}
+
+void flip_cursor() {
+	static uint8_t cursor_flipped = 0;
+	if (cursor_flipped) {
+		cell_redraw(csr_x, csr_y);
+	} else {
+		render_cursor();
+	}
+	cursor_flipped = 1 - cursor_flipped;
+}
+
+void term_set_cell(int x, int y, uint32_t c) {
+	cell_set(x, y, c, current_fg, current_bg, ansi_state->flags);
+	cell_redraw(x, y);
+}
+
+void term_redraw_cell(int x, int y) {
+	if (x < 0 || y < 0 || x >= term_width || y >= term_height) return;
+	cell_redraw(x,y);
+}
+
+void term_clear(int i) {
+	if (i == 2) {
+		/* Oh dear */
+		csr_x = 0;
+		csr_y = 0;
+		memset((void *)term_buffer, 0x00, term_width * term_height * sizeof(term_cell_t));
+		term_redraw_all();
+	} else if (i == 0) {
+		for (int x = csr_x; x < term_width; ++x) {
+			term_set_cell(x, csr_y, ' ');
+		}
+		for (int y = csr_y + 1; y < term_height; ++y) {
+			for (int x = 0; x < term_width; ++x) {
+				term_set_cell(x, y, ' ');
+			}
+		}
+	} else if (i == 1) {
+		for (int y = 0; y < csr_y; ++y) {
+			for (int x = 0; x < term_width; ++x) {
+				term_set_cell(x, y, ' ');
+			}
+		}
+		for (int x = 0; x < csr_x; ++x) {
+			term_set_cell(x, csr_y, ' ');
+		}
+	}
+}
+
+#define INPUT_SIZE 1024
+char input_buffer[INPUT_SIZE];
+int  input_collected = 0;
+
+void clear_input() {
+	memset(input_buffer, 0x0, INPUT_SIZE);
+	input_collected = 0;
+}
+
+uint32_t child_pid = 0;
+
+void handle_input(char c) {
+	write(fd_master, &c, 1);
+}
+
+void handle_input_s(char * c) {
+	write(fd_master, c, strlen(c));
+}
+
+void key_event(int ret, key_event_t * event) {
+	if (ret) {
+		if (event->modifiers & KEY_MOD_LEFT_ALT || event->modifiers & KEY_MOD_RIGHT_ALT) {
+			handle_input('\033');
+		}
+		if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) &&
+		    event->key == '\t') {
+			handle_input_s("\033[Z");
+			return;
+		}
+		handle_input(event->key);
+	} else {
+		if (event->action == KEY_ACTION_UP) return;
+		switch (event->keycode) {
+			case KEY_F1:
+				handle_input_s("\033OP");
+				break;
+			case KEY_F2:
+				handle_input_s("\033OQ");
+				break;
+			case KEY_F3:
+				handle_input_s("\033OR");
+				break;
+			case KEY_F4:
+				handle_input_s("\033OS");
+				break;
+			case KEY_F5:
+				handle_input_s("\033[15~");
+				break;
+			case KEY_F6:
+				handle_input_s("\033[17~");
+				break;
+			case KEY_F7:
+				handle_input_s("\033[18~");
+				break;
+			case KEY_F8:
+				handle_input_s("\033[19~");
+				break;
+			case KEY_F9:
+				handle_input_s("\033[20~");
+				break;
+			case KEY_F10:
+				handle_input_s("\033[21~");
+				break;
+			case KEY_F11:
+				handle_input_s("\033[23~");
+				break;
+			case KEY_F12:
+				/* XXX This is for testing only */
+				handle_input_s("テスト");
+				//handle_input_s("\033[24~");
+				break;
+			case KEY_ARROW_UP:
+				handle_input_s("\033[A");
+				break;
+			case KEY_ARROW_DOWN:
+				handle_input_s("\033[B");
+				break;
+			case KEY_ARROW_RIGHT:
+				handle_input_s("\033[C");
+				break;
+			case KEY_ARROW_LEFT:
+				handle_input_s("\033[D");
+				break;
+			case KEY_PAGE_UP:
+				handle_input_s("\033[5~");
+				break;
+			case KEY_PAGE_DOWN:
+				handle_input_s("\033[6~");
+				break;
+			case KEY_HOME:
+				handle_input_s("\033OH");
+				break;
+			case KEY_END:
+				handle_input_s("\033OF");
+				break;
+			case KEY_DEL:
+				handle_input_s("\033[3~");
+				break;
+		}
+	}
+}
+
+void usage(char * argv[]) {
+	printf(
+			"VGA Terminal Emulator\n"
+			"\n"
+			"usage: %s [-b] [-F] [-h]\n"
+			"\n"
+			" -h --help       \033[3mShow this help message.\033[0m\n"
+			"\n",
+			argv[0]);
+}
+
+int unsupported_int(void) { return 0; }
+void unsupported(int x, int y, char * data) { }
+
+term_callbacks_t term_callbacks = {
+	term_write,
+	term_set_colors,
+	term_set_csr,
+	term_get_csr_x,
+	term_get_csr_y,
+	term_set_cell,
+	term_clear,
+	term_scroll,
+	term_redraw_cursor,
+	input_buffer_stuff,
+	set_term_font_size,
+	set_title,
+	unsupported,
+	unsupported_int,
+	unsupported_int,
+	term_set_csr_show,
+};
+
+void reinit(int send_sig) {
+	if (term_buffer) {
+		/* Do nothing */
+	} else {
+		term_buffer = malloc(sizeof(term_cell_t) * term_width * term_height);
+		memset(term_buffer, 0x0, sizeof(term_cell_t) * term_width * term_height);
+	}
+
+	ansi_state = ansi_init(ansi_state, term_width, term_height, &term_callbacks);
+	term_redraw_all();
+}
+
+
+void maybe_flip_cursor(void) {
+	uint64_t ticks = get_ticks();
+	if (ticks > mouse_ticks + 600000LL) {
+		mouse_ticks = ticks;
+		flip_cursor();
+	}
+}
+
+
+void check_for_exit(void) {
+	if (exit_application) return;
+
+	int pid = waitpid(-1, NULL, WNOHANG);
+
+	if (pid != child_pid) return;
+
+	/* Clean up */
+	exit_application = 1;
+	/* Exit */
+	char exit_message[] = "[Process terminated]\n";
+	write(fd_slave, exit_message, sizeof(exit_message));
+}
+
+
+int main(int argc, char ** argv) {
+
+	_login_shell = 0;
+
+#if 0
+	static struct option long_opts[] = {
+		{"login",      no_argument,       0, 'l'},
+		{"help",       no_argument,       0, 'h'},
+		{0,0,0,0}
+	};
+
+	/* Read some arguments */
+	int index, c;
+	while ((c = getopt_long(argc, argv, "hl", long_opts, &index)) != -1) {
+		if (!c) {
+			if (long_opts[index].flag == 0) {
+				c = long_opts[index].val;
+			}
+		}
+		switch (c) {
+			case 'l':
+				_login_shell = 1;
+				break;
+			case 'h':
+				usage(argv);
+				return 0;
+				break;
+			case '?':
+				break;
+			default:
+				break;
+		}
+	}
+
+	putenv("TERM=toaru");
+#endif
+
+#if 1
+	char * _env = malloc(strlen("TERM=toaru"));
+	sprintf(_env, "TERM=toaru");
+	size_t env_c = 0;
+	for (char ** env = environ; *env; env++, env_c++);
+	char ** env_new = malloc(sizeof(char *) * (env_c + 2));
+	int set_env = 0;
+	for (size_t i = 0; i < env_c; ++i) {
+		if (strstr(environ[i], "TERM=") == environ[i]) {
+			env_new[i] = _env;
+			set_env = 1;
+		} else {
+			env_new[i] = environ[i];
+		}
+	}
+	if (!set_env) {
+		env_new[env_c] = _env;
+		env_c++;
+	}
+	env_new[env_c] = NULL;
+	environ = env_new;
+#endif
+
+	syscall_openpty(&fd_master, &fd_slave, NULL, NULL, NULL);
+
+	terminal = fdopen(fd_slave, "w");
+
+	struct winsize w;
+	w.ws_row = term_height;
+	w.ws_col = term_width;
+	w.ws_xpixel = 0;
+	w.ws_ypixel = 0;
+	ioctl(fd_master, TIOCSWINSZ, &w);
+
+	reinit(0);
+
+	fflush(stdin);
+
+	system("cursor-off"); /* Might GPF */
+
+	int pid = getpid();
+	uint32_t f = fork();
+
+	if (getpid() != pid) {
+		dup2(fd_slave, 0);
+		dup2(fd_slave, 1);
+		dup2(fd_slave, 2);
+
+#if 0
+		if (argv[optind] != NULL) {
+			char * tokens[] = {argv[optind], NULL};
+			int i = execvp(tokens[0], tokens);
+			fprintf(stderr, "Failed to launch requested startup application.\n");
+		} else {
+#endif
+			if (_login_shell) {
+				char * tokens[] = {"/bin/login",NULL};
+				int i = execvp(tokens[0], tokens);
+			} else {
+				char * shell = getenv("SHELL");
+				if (!shell) shell = "/bin/sh"; /* fallback */
+				char * tokens[] = {shell,NULL};
+				int i = execvp(tokens[0], tokens);
+			}
+#if 0
+		}
+#endif
+
+		exit_application = 1;
+
+		return 1;
+	} else {
+
+		child_pid = f;
+
+		int kfd = open("/dev/kbd", O_RDONLY);
+		key_event_t event;
+		char c;
+
+		key_event_state_t kbd_state = {0};
+
+		/* Prune any keyboard input we got before the terminal started. */
+		struct stat s;
+		fstat(kfd, &s);
+		for (int i = 0; i < s.st_size; i++) {
+			char tmp[1];
+			read(kfd, tmp, 1);
+		}
+
+		int fds[2] = {fd_master, kfd};
+
+		unsigned char buf[1024];
+		while (!exit_application) {
+
+			int index = syscall_fswait2(2,fds,200);
+
+			check_for_exit();
+
+			if (index == 0) {
+				maybe_flip_cursor();
+				int r = read(fd_master, buf, 1024);
+				for (uint32_t i = 0; i < r; ++i) {
+					ansi_put(ansi_state, buf[i]);
+				}
+			} else if (index == 1) {
+				maybe_flip_cursor();
+				int r = read(kfd, &c, 1);
+				if (r > 0) {
+					int ret = kbd_scancode(&kbd_state, c, &event);
+					key_event(ret, &event);
+				}
+			} else if (index == 2) {
+				maybe_flip_cursor();
+			}
+		}
+
+	}
+
+	return 0;
+}

+ 259 - 0
apps/vga-palette.h

@@ -0,0 +1,259 @@
+#define PALETTE_COLORS 256
+uint32_t vga_colors[PALETTE_COLORS] = {
+	0x0,
+	0x1,
+	0x2,
+	0x3,
+	0x4,
+	0x5,
+	0x6,
+	0x7,
+	0x8,
+	0x9,
+	0xa,
+	0xb,
+	0xc,
+	0xd,
+	0xe,
+	0xf,
+	0x0, /* #000000 -> #000000 */
+	0x4, /* #00005f -> #0000aa */
+	0x4, /* #000087 -> #0000aa */
+	0x4, /* #0000af -> #0000aa */
+	0x4, /* #0000d7 -> #0000aa */
+	0xc, /* #0000ff -> #5555ff */
+	0x2, /* #005f00 -> #00aa00 */
+	0x8, /* #005f5f -> #555555 */
+	0x6, /* #005f87 -> #00aaaa */
+	0x6, /* #005faf -> #00aaaa */
+	0xc, /* #005fd7 -> #5555ff */
+	0xc, /* #005fff -> #5555ff */
+	0x2, /* #008700 -> #00aa00 */
+	0xa, /* #00875f -> #55aa55 */
+	0x6, /* #008787 -> #00aaaa */
+	0x6, /* #0087af -> #00aaaa */
+	0x6, /* #0087d7 -> #00aaaa */
+	0xc, /* #0087ff -> #5555ff */
+	0x2, /* #00af00 -> #00aa00 */
+	0xa, /* #00af5f -> #55aa55 */
+	0x6, /* #00af87 -> #00aaaa */
+	0x6, /* #00afaf -> #00aaaa */
+	0x6, /* #00afd7 -> #00aaaa */
+	0xe, /* #00afff -> #55ffff */
+	0x2, /* #00d700 -> #00aa00 */
+	0xa, /* #00d75f -> #55aa55 */
+	0x6, /* #00d787 -> #00aaaa */
+	0x6, /* #00d7af -> #00aaaa */
+	0x6, /* #00d7d7 -> #00aaaa */
+	0xe, /* #00d7ff -> #55ffff */
+	0x2, /* #00ff00 -> #00aa00 */
+	0xa, /* #00ff5f -> #55aa55 */
+	0x6, /* #00ff87 -> #00aaaa */
+	0x6, /* #00ffaf -> #00aaaa */
+	0xe, /* #00ffd7 -> #55ffff */
+	0xe, /* #00ffff -> #55ffff */
+	0x1, /* #5f0000 -> #aa0000 */
+	0x8, /* #5f005f -> #555555 */
+	0x5, /* #5f0087 -> #aa00aa */
+	0x5, /* #5f00af -> #aa00aa */
+	0x5, /* #5f00d7 -> #aa00aa */
+	0xc, /* #5f00ff -> #5555ff */
+	0x3, /* #5f5f00 -> #aa5500 */
+	0x8, /* #5f5f5f -> #555555 */
+	0x8, /* #5f5f87 -> #555555 */
+	0x7, /* #5f5faf -> #aaaaaa */
+	0xc, /* #5f5fd7 -> #5555ff */
+	0xc, /* #5f5fff -> #5555ff */
+	0x2, /* #5f8700 -> #00aa00 */
+	0xa, /* #5f875f -> #55aa55 */
+	0xa, /* #5f8787 -> #55aa55 */
+	0x7, /* #5f87af -> #aaaaaa */
+	0xc, /* #5f87d7 -> #5555ff */
+	0xc, /* #5f87ff -> #5555ff */
+	0x2, /* #5faf00 -> #00aa00 */
+	0xa, /* #5faf5f -> #55aa55 */
+	0xa, /* #5faf87 -> #55aa55 */
+	0x7, /* #5fafaf -> #aaaaaa */
+	0x7, /* #5fafd7 -> #aaaaaa */
+	0xe, /* #5fafff -> #55ffff */
+	0x2, /* #5fd700 -> #00aa00 */
+	0xa, /* #5fd75f -> #55aa55 */
+	0xa, /* #5fd787 -> #55aa55 */
+	0x7, /* #5fd7af -> #aaaaaa */
+	0xe, /* #5fd7d7 -> #55ffff */
+	0xe, /* #5fd7ff -> #55ffff */
+	0x2, /* #5fff00 -> #00aa00 */
+	0xb, /* #5fff5f -> #ffff55 */
+	0xb, /* #5fff87 -> #ffff55 */
+	0x7, /* #5fffaf -> #aaaaaa */
+	0xe, /* #5fffd7 -> #55ffff */
+	0xe, /* #5fffff -> #55ffff */
+	0x1, /* #870000 -> #aa0000 */
+	0x8, /* #87005f -> #555555 */
+	0x5, /* #870087 -> #aa00aa */
+	0x5, /* #8700af -> #aa00aa */
+	0x5, /* #8700d7 -> #aa00aa */
+	0xc, /* #8700ff -> #5555ff */
+	0x3, /* #875f00 -> #aa5500 */
+	0x8, /* #875f5f -> #555555 */
+	0x8, /* #875f87 -> #555555 */
+	0x7, /* #875faf -> #aaaaaa */
+	0xc, /* #875fd7 -> #5555ff */
+	0xc, /* #875fff -> #5555ff */
+	0x3, /* #878700 -> #aa5500 */
+	0xa, /* #87875f -> #55aa55 */
+	0x7, /* #878787 -> #aaaaaa */
+	0x7, /* #8787af -> #aaaaaa */
+	0x7, /* #8787d7 -> #aaaaaa */
+	0xc, /* #8787ff -> #5555ff */
+	0x2, /* #87af00 -> #00aa00 */
+	0xa, /* #87af5f -> #55aa55 */
+	0x7, /* #87af87 -> #aaaaaa */
+	0x7, /* #87afaf -> #aaaaaa */
+	0x7, /* #87afd7 -> #aaaaaa */
+	0xe, /* #87afff -> #55ffff */
+	0x2, /* #87d700 -> #00aa00 */
+	0xa, /* #87d75f -> #55aa55 */
+	0x7, /* #87d787 -> #aaaaaa */
+	0x7, /* #87d7af -> #aaaaaa */
+	0xe, /* #87d7d7 -> #55ffff */
+	0xe, /* #87d7ff -> #55ffff */
+	0x2, /* #87ff00 -> #00aa00 */
+	0xb, /* #87ff5f -> #ffff55 */
+	0xb, /* #87ff87 -> #ffff55 */
+	0x7, /* #87ffaf -> #aaaaaa */
+	0xe, /* #87ffd7 -> #55ffff */
+	0xe, /* #87ffff -> #55ffff */
+	0x1, /* #af0000 -> #aa0000 */
+	0x5, /* #af005f -> #aa00aa */
+	0x5, /* #af0087 -> #aa00aa */
+	0x5, /* #af00af -> #aa00aa */
+	0x5, /* #af00d7 -> #aa00aa */
+	0xd, /* #af00ff -> #ff55ff */
+	0x3, /* #af5f00 -> #aa5500 */
+	0x9, /* #af5f5f -> #ff5555 */
+	0x9, /* #af5f87 -> #ff5555 */
+	0x7, /* #af5faf -> #aaaaaa */
+	0xd, /* #af5fd7 -> #ff55ff */
+	0xd, /* #af5fff -> #ff55ff */
+	0x3, /* #af8700 -> #aa5500 */
+	0xa, /* #af875f -> #55aa55 */
+	0x7, /* #af8787 -> #aaaaaa */
+	0x7, /* #af87af -> #aaaaaa */
+	0x7, /* #af87d7 -> #aaaaaa */
+	0xd, /* #af87ff -> #ff55ff */
+	0x2, /* #afaf00 -> #00aa00 */
+	0xa, /* #afaf5f -> #55aa55 */
+	0x7, /* #afaf87 -> #aaaaaa */
+	0x7, /* #afafaf -> #aaaaaa */
+	0x7, /* #afafd7 -> #aaaaaa */
+	0xf, /* #afafff -> #ffffff */
+	0x2, /* #afd700 -> #00aa00 */
+	0xb, /* #afd75f -> #ffff55 */
+	0x7, /* #afd787 -> #aaaaaa */
+	0x7, /* #afd7af -> #aaaaaa */
+	0x7, /* #afd7d7 -> #aaaaaa */
+	0xf, /* #afd7ff -> #ffffff */
+	0x2, /* #afff00 -> #00aa00 */
+	0xb, /* #afff5f -> #ffff55 */
+	0xb, /* #afff87 -> #ffff55 */
+	0x7, /* #afffaf -> #aaaaaa */
+	0xf, /* #afffd7 -> #ffffff */
+	0xf, /* #afffff -> #ffffff */
+	0x1, /* #d70000 -> #aa0000 */
+	0x9, /* #d7005f -> #ff5555 */
+	0x5, /* #d70087 -> #aa00aa */
+	0x5, /* #d700af -> #aa00aa */
+	0x5, /* #d700d7 -> #aa00aa */
+	0xd, /* #d700ff -> #ff55ff */
+	0x3, /* #d75f00 -> #aa5500 */
+	0x9, /* #d75f5f -> #ff5555 */
+	0x9, /* #d75f87 -> #ff5555 */
+	0x7, /* #d75faf -> #aaaaaa */
+	0xd, /* #d75fd7 -> #ff55ff */
+	0xd, /* #d75fff -> #ff55ff */
+	0x3, /* #d78700 -> #aa5500 */
+	0x9, /* #d7875f -> #ff5555 */
+	0x7, /* #d78787 -> #aaaaaa */
+	0x7, /* #d787af -> #aaaaaa */
+	0x7, /* #d787d7 -> #aaaaaa */
+	0xd, /* #d787ff -> #ff55ff */
+	0x2, /* #d7af00 -> #00aa00 */
+	0xa, /* #d7af5f -> #55aa55 */
+	0x7, /* #d7af87 -> #aaaaaa */
+	0x7, /* #d7afaf -> #aaaaaa */
+	0x7, /* #d7afd7 -> #aaaaaa */
+	0xf, /* #d7afff -> #ffffff */
+	0x2, /* #d7d700 -> #00aa00 */
+	0xb, /* #d7d75f -> #ffff55 */
+	0x7, /* #d7d787 -> #aaaaaa */
+	0x7, /* #d7d7af -> #aaaaaa */
+	0xf, /* #d7d7d7 -> #ffffff */
+	0xf, /* #d7d7ff -> #ffffff */
+	0xb, /* #d7ff00 -> #ffff55 */
+	0xb, /* #d7ff5f -> #ffff55 */
+	0xb, /* #d7ff87 -> #ffff55 */
+	0x7, /* #d7ffaf -> #aaaaaa */
+	0xf, /* #d7ffd7 -> #ffffff */
+	0xf, /* #d7ffff -> #ffffff */
+	0x1, /* #ff0000 -> #aa0000 */
+	0x9, /* #ff005f -> #ff5555 */
+	0x5, /* #ff0087 -> #aa00aa */
+	0x5, /* #ff00af -> #aa00aa */
+	0x5, /* #ff00d7 -> #aa00aa */
+	0xd, /* #ff00ff -> #ff55ff */
+	0x3, /* #ff5f00 -> #aa5500 */
+	0x9, /* #ff5f5f -> #ff5555 */
+	0x9, /* #ff5f87 -> #ff5555 */
+	0x7, /* #ff5faf -> #aaaaaa */
+	0xd, /* #ff5fd7 -> #ff55ff */
+	0xd, /* #ff5fff -> #ff55ff */
+	0x3, /* #ff8700 -> #aa5500 */
+	0x9, /* #ff875f -> #ff5555 */
+	0x9, /* #ff8787 -> #ff5555 */
+	0x7, /* #ff87af -> #aaaaaa */
+	0xd, /* #ff87d7 -> #ff55ff */
+	0xd, /* #ff87ff -> #ff55ff */
+	0x2, /* #ffaf00 -> #00aa00 */
+	0xb, /* #ffaf5f -> #ffff55 */
+	0x7, /* #ffaf87 -> #aaaaaa */
+	0x7, /* #ffafaf -> #aaaaaa */
+	0x7, /* #ffafd7 -> #aaaaaa */
+	0xf, /* #ffafff -> #ffffff */
+	0x2, /* #ffd700 -> #00aa00 */
+	0xb, /* #ffd75f -> #ffff55 */
+	0xb, /* #ffd787 -> #ffff55 */
+	0x7, /* #ffd7af -> #aaaaaa */
+	0xf, /* #ffd7d7 -> #ffffff */
+	0xf, /* #ffd7ff -> #ffffff */
+	0xb, /* #ffff00 -> #ffff55 */
+	0xb, /* #ffff5f -> #ffff55 */
+	0xb, /* #ffff87 -> #ffff55 */
+	0xf, /* #ffffaf -> #ffffff */
+	0xf, /* #ffffd7 -> #ffffff */
+	0xf, /* #ffffff -> #ffffff */
+	0x0, /* #080808 -> #000000 */
+	0x0, /* #121212 -> #000000 */
+	0x0, /* #1c1c1c -> #000000 */
+	0x0, /* #262626 -> #000000 */
+	0x8, /* #303030 -> #555555 */
+	0x8, /* #3a3a3a -> #555555 */
+	0x8, /* #444444 -> #555555 */
+	0x8, /* #4e4e4e -> #555555 */
+	0x8, /* #585858 -> #555555 */
+	0x8, /* #626262 -> #555555 */
+	0x8, /* #6c6c6c -> #555555 */
+	0x8, /* #767676 -> #555555 */
+	0x7, /* #808080 -> #aaaaaa */
+	0x7, /* #8a8a8a -> #aaaaaa */
+	0x7, /* #949494 -> #aaaaaa */
+	0x7, /* #9e9e9e -> #aaaaaa */
+	0x7, /* #a8a8a8 -> #aaaaaa */
+	0x7, /* #b2b2b2 -> #aaaaaa */
+	0x7, /* #bcbcbc -> #aaaaaa */
+	0x7, /* #c6c6c6 -> #aaaaaa */
+	0x7, /* #d0d0d0 -> #aaaaaa */
+	0xf, /* #dadada -> #ffffff */
+	0xf, /* #e4e4e4 -> #ffffff */
+	0xf, /* #eeeeee -> #ffffff */
+};

+ 10 - 2
cdrom/boot/grub/menus.cfg

@@ -6,14 +6,22 @@ if [ ! "${seen_menu}" = "yes" ]; then
     export seen_menu
 fi
 
-submenu 'RUN' {
-    multiboot /kernel vid=${t_driver},${t_resolution} ${t_root} start=hello
+submenu 'Normal Graphical Boot' {
+    multiboot /kernel vid=${t_driver},${t_resolution} ${t_root} start=session
     load_modules
     load_ramdisk
     set_vidmode
     boot
 }
 
+submenu 'VGA Text-Mode Terminal (Debug)' {
+    multiboot /kernel ${t_root} start=--vga
+    load_modules
+    load_ramdisk
+    set gfxpayload=text
+    boot
+}
+
 submenu '> Advanced graphics configuration options...' {
     set_theme
     menuentry '800x600' {

+ 0 - 1
lib/yutani.c

@@ -567,7 +567,6 @@ yutani_t * yutani_init(void) {
 	FILE * c = pex_connect(server_name);
 
 	if (!c) {
-		fprintf(stderr, "Pex connection failed?\n");
 		return NULL; /* Connection failed. */
 	}