term: Move to use external, portable terminal
This commit is contained in:
parent
fc6e44c82c
commit
ad8151a6a6
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
/limine-efi
|
||||
/freestanding-headers
|
||||
/libgcc-binaries
|
||||
/common/term
|
||||
/ovmf*
|
||||
*.o
|
||||
*.d
|
||||
|
@ -251,6 +251,7 @@ dist:
|
||||
cp -r '$(call SHESCAPE,$(SRCDIR))'/.git '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)"/
|
||||
cd '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)" && git checkout .
|
||||
cd '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)" && ./bootstrap
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/common/term/.git"
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/freestanding-headers/.git"
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.git"
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.gitignore"
|
||||
@ -287,7 +288,7 @@ distclean: clean
|
||||
|
||||
.PHONY: maintainer-clean
|
||||
maintainer-clean: distclean
|
||||
cd '$(call SHESCAPE,$(SRCDIR))' && rm -rf freestanding-headers libgcc-binaries limine-efi cross-detect configure build-aux *'~' autom4te.cache *.tar.xz *.tar.gz
|
||||
cd '$(call SHESCAPE,$(SRCDIR))' && rm -rf common/term freestanding-headers libgcc-binaries limine-efi cross-detect configure build-aux *'~' autom4te.cache *.tar.xz *.tar.gz
|
||||
|
||||
.PHONY: common-uefi-x86-64
|
||||
common-uefi-x86-64:
|
||||
|
@ -7,6 +7,7 @@ test -z "$srcdir" && srcdir=.
|
||||
|
||||
cd "$srcdir"
|
||||
|
||||
[ -d common/term ] || git clone https://github.com/limine-bootloader/terminal.git common/term
|
||||
[ -d cross-detect ] || git clone https://github.com/mintsuki/cross-detect.git
|
||||
[ -d freestanding-headers ] || git clone https://github.com/mintsuki/freestanding-headers.git
|
||||
[ -d limine-efi ] || git clone https://github.com/limine-bootloader/limine-efi.git
|
||||
|
@ -15,149 +15,99 @@
|
||||
#define VD_COLS (80 * 2)
|
||||
#define VD_ROWS 25
|
||||
|
||||
static volatile uint8_t *video_mem = (uint8_t *)0xb8000;
|
||||
|
||||
static uint8_t *back_buffer = NULL;
|
||||
static uint8_t *front_buffer = NULL;
|
||||
|
||||
static struct context {
|
||||
size_t cursor_offset;
|
||||
#define cursor_offset context.cursor_offset
|
||||
bool cursor_status;
|
||||
#define cursor_status context.cursor_status
|
||||
uint8_t text_palette;
|
||||
#define text_palette context.text_palette
|
||||
bool scroll_enabled;
|
||||
#define scroll_enabled context.scroll_enabled
|
||||
|
||||
uint8_t saved_state_text_palette;
|
||||
#define saved_state_text_palette context.saved_state_text_palette
|
||||
size_t saved_state_cursor_offset;
|
||||
#define saved_state_cursor_offset context.saved_state_cursor_offset
|
||||
} context;
|
||||
|
||||
static size_t old_cursor_offset = 0;
|
||||
|
||||
static void draw_cursor(void) {
|
||||
uint8_t pal = back_buffer[cursor_offset + 1];
|
||||
video_mem[cursor_offset + 1] = ((pal & 0xf0) >> 4) | ((pal & 0x0f) << 4);
|
||||
static void draw_cursor(struct textmode_context *ctx) {
|
||||
uint8_t pal = ctx->back_buffer[ctx->cursor_offset + 1];
|
||||
ctx->video_mem[ctx->cursor_offset + 1] = ((pal & 0xf0) >> 4) | ((pal & 0x0f) << 4);
|
||||
}
|
||||
|
||||
void text_save_state(void) {
|
||||
saved_state_text_palette = text_palette;
|
||||
saved_state_cursor_offset = cursor_offset;
|
||||
void text_save_state(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->saved_state_text_palette = ctx->text_palette;
|
||||
ctx->saved_state_cursor_offset = ctx->cursor_offset;
|
||||
}
|
||||
|
||||
void text_restore_state(void) {
|
||||
text_palette = saved_state_text_palette;
|
||||
cursor_offset = saved_state_cursor_offset;
|
||||
void text_restore_state(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette = ctx->saved_state_text_palette;
|
||||
ctx->cursor_offset = ctx->saved_state_cursor_offset;
|
||||
}
|
||||
|
||||
void text_swap_palette(void) {
|
||||
text_palette = (text_palette << 4) | (text_palette >> 4);
|
||||
void text_swap_palette(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette = (ctx->text_palette << 4) | (ctx->text_palette >> 4);
|
||||
}
|
||||
|
||||
bool text_scroll_disable(void) {
|
||||
bool ret = scroll_enabled;
|
||||
scroll_enabled = false;
|
||||
return ret;
|
||||
}
|
||||
void text_scroll(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
void text_scroll_enable(void) {
|
||||
scroll_enabled = true;
|
||||
}
|
||||
|
||||
void text_scroll(void) {
|
||||
// move the text up by one row
|
||||
for (size_t i = term_context.scroll_top_margin * VD_COLS;
|
||||
i < (term_context.scroll_bottom_margin - 1) * VD_COLS; i++) {
|
||||
back_buffer[i] = back_buffer[i + VD_COLS];
|
||||
for (size_t i = _ctx->scroll_top_margin * VD_COLS;
|
||||
i < (_ctx->scroll_bottom_margin - 1) * VD_COLS; i++) {
|
||||
ctx->back_buffer[i] = ctx->back_buffer[i + VD_COLS];
|
||||
}
|
||||
// clear the last line of the screen
|
||||
for (size_t i = (term_context.scroll_bottom_margin - 1) * VD_COLS;
|
||||
i < term_context.scroll_bottom_margin * VD_COLS; i += 2) {
|
||||
back_buffer[i] = ' ';
|
||||
back_buffer[i + 1] = text_palette;
|
||||
for (size_t i = (_ctx->scroll_bottom_margin - 1) * VD_COLS;
|
||||
i < _ctx->scroll_bottom_margin * VD_COLS; i += 2) {
|
||||
ctx->back_buffer[i] = ' ';
|
||||
ctx->back_buffer[i + 1] = ctx->text_palette;
|
||||
}
|
||||
}
|
||||
|
||||
void text_revscroll(void) {
|
||||
void text_revscroll(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
// move the text up by one row
|
||||
for (size_t i = (term_context.scroll_bottom_margin - 1) * VD_COLS - 2; ; i--) {
|
||||
back_buffer[i + VD_COLS] = back_buffer[i];
|
||||
if (i == term_context.scroll_top_margin * VD_COLS) {
|
||||
for (size_t i = (_ctx->scroll_bottom_margin - 1) * VD_COLS - 2; ; i--) {
|
||||
ctx->back_buffer[i + VD_COLS] = ctx->back_buffer[i];
|
||||
if (i == _ctx->scroll_top_margin * VD_COLS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// clear the first line of the screen
|
||||
for (size_t i = term_context.scroll_top_margin * VD_COLS;
|
||||
i < (term_context.scroll_top_margin + 1) * VD_COLS; i += 2) {
|
||||
back_buffer[i] = ' ';
|
||||
back_buffer[i + 1] = text_palette;
|
||||
for (size_t i = _ctx->scroll_top_margin * VD_COLS;
|
||||
i < (_ctx->scroll_top_margin + 1) * VD_COLS; i += 2) {
|
||||
ctx->back_buffer[i] = ' ';
|
||||
ctx->back_buffer[i + 1] = ctx->text_palette;
|
||||
}
|
||||
}
|
||||
|
||||
void text_clear(bool move) {
|
||||
void text_clear(struct term_context *_ctx, bool move) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) {
|
||||
back_buffer[i] = ' ';
|
||||
back_buffer[i + 1] = text_palette;
|
||||
ctx->back_buffer[i] = ' ';
|
||||
ctx->back_buffer[i + 1] = ctx->text_palette;
|
||||
}
|
||||
if (move) {
|
||||
ctx->cursor_offset = 0;
|
||||
}
|
||||
if (move)
|
||||
cursor_offset = 0;
|
||||
}
|
||||
|
||||
void text_enable_cursor(void) {
|
||||
cursor_status = true;
|
||||
void text_enable_cursor(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
ctx->cursor_status = true;
|
||||
}
|
||||
|
||||
bool text_disable_cursor(void) {
|
||||
bool ret = cursor_status;
|
||||
cursor_status = false;
|
||||
bool text_disable_cursor(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
bool ret = ctx->cursor_status;
|
||||
ctx->cursor_status = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t text_context_size(void) {
|
||||
uint64_t ret = 0;
|
||||
|
||||
ret += sizeof(struct context);
|
||||
ret += VD_ROWS * VD_COLS; // front buffer
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void text_context_save(uint64_t ptr) {
|
||||
memcpy32to64(ptr, (uint64_t)(uintptr_t)&context, sizeof(struct context));
|
||||
ptr += sizeof(struct context);
|
||||
|
||||
memcpy32to64(ptr, (uint64_t)(uintptr_t)front_buffer, VD_ROWS * VD_COLS);
|
||||
}
|
||||
|
||||
void text_context_restore(uint64_t ptr) {
|
||||
memcpy32to64((uint64_t)(uintptr_t)&context, ptr, sizeof(struct context));
|
||||
ptr += sizeof(struct context);
|
||||
|
||||
memcpy32to64((uint64_t)(uintptr_t)front_buffer, ptr, VD_ROWS * VD_COLS);
|
||||
void text_full_refresh(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) {
|
||||
video_mem[i] = front_buffer[i];
|
||||
back_buffer[i] = front_buffer[i];
|
||||
ctx->video_mem[i] = ctx->front_buffer[i];
|
||||
ctx->back_buffer[i] = ctx->front_buffer[i];
|
||||
}
|
||||
|
||||
if (cursor_status) {
|
||||
draw_cursor();
|
||||
old_cursor_offset = cursor_offset;
|
||||
}
|
||||
}
|
||||
|
||||
void text_full_refresh(void) {
|
||||
for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) {
|
||||
video_mem[i] = front_buffer[i];
|
||||
back_buffer[i] = front_buffer[i];
|
||||
}
|
||||
|
||||
if (cursor_status) {
|
||||
draw_cursor();
|
||||
old_cursor_offset = cursor_offset;
|
||||
if (ctx->cursor_status) {
|
||||
draw_cursor(ctx);
|
||||
ctx->old_cursor_offset = ctx->cursor_offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,23 +120,26 @@ void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) {
|
||||
current_video_mode = 0x3;
|
||||
}
|
||||
|
||||
if (back_buffer == NULL) {
|
||||
back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
|
||||
struct textmode_context *ctx = (void *)term;
|
||||
|
||||
if (ctx->back_buffer == NULL) {
|
||||
ctx->back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
|
||||
} else {
|
||||
memset(back_buffer, 0, VD_ROWS * VD_COLS);
|
||||
memset(ctx->back_buffer, 0, VD_ROWS * VD_COLS);
|
||||
}
|
||||
if (front_buffer == NULL) {
|
||||
front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
|
||||
if (ctx->front_buffer == NULL) {
|
||||
ctx->front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
|
||||
} else {
|
||||
memset(front_buffer, 0, VD_ROWS * VD_COLS);
|
||||
memset(ctx->front_buffer, 0, VD_ROWS * VD_COLS);
|
||||
}
|
||||
|
||||
cursor_offset = 0;
|
||||
cursor_status = true;
|
||||
text_palette = 0x07;
|
||||
scroll_enabled = true;
|
||||
ctx->cursor_offset = 0;
|
||||
ctx->cursor_status = true;
|
||||
ctx->text_palette = 0x07;
|
||||
|
||||
text_clear(false);
|
||||
ctx->video_mem = (volatile uint8_t *)0xb8000;
|
||||
|
||||
text_clear(term, false);
|
||||
|
||||
*_rows = VD_ROWS;
|
||||
*_cols = VD_COLS / 2;
|
||||
@ -194,7 +147,7 @@ void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) {
|
||||
// VGA cursor code taken from: https://wiki.osdev.org/Text_Mode_Cursor
|
||||
|
||||
if (!managed) {
|
||||
text_disable_cursor();
|
||||
text_disable_cursor(term);
|
||||
|
||||
outb(0x3d4, 0x0a);
|
||||
outb(0x3d5, (inb(0x3d5) & 0xc0) | 14);
|
||||
@ -213,51 +166,59 @@ void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) {
|
||||
outb(0x3d5, 0x20);
|
||||
}
|
||||
|
||||
text_double_buffer_flush();
|
||||
text_double_buffer_flush(term);
|
||||
}
|
||||
|
||||
void text_double_buffer_flush(void) {
|
||||
if (cursor_status) {
|
||||
draw_cursor();
|
||||
void text_double_buffer_flush(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
if (ctx->cursor_status) {
|
||||
draw_cursor(ctx);
|
||||
}
|
||||
|
||||
if (cursor_offset != old_cursor_offset || cursor_status == false) {
|
||||
video_mem[old_cursor_offset + 1] = back_buffer[old_cursor_offset + 1];
|
||||
if (ctx->cursor_offset != ctx->old_cursor_offset || ctx->cursor_status == false) {
|
||||
ctx->video_mem[ctx->old_cursor_offset + 1] = ctx->back_buffer[ctx->old_cursor_offset + 1];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) {
|
||||
if (back_buffer[i] == front_buffer[i]) {
|
||||
if (ctx->back_buffer[i] == ctx->front_buffer[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cursor_status && i == cursor_offset + 1) {
|
||||
if (ctx->cursor_status && i == ctx->cursor_offset + 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
front_buffer[i] = back_buffer[i];
|
||||
video_mem[i] = back_buffer[i];
|
||||
ctx->front_buffer[i] = ctx->back_buffer[i];
|
||||
ctx->video_mem[i] = ctx->back_buffer[i];
|
||||
}
|
||||
|
||||
if (cursor_status) {
|
||||
old_cursor_offset = cursor_offset;
|
||||
if (ctx->cursor_status) {
|
||||
ctx->old_cursor_offset = ctx->cursor_offset;
|
||||
}
|
||||
}
|
||||
|
||||
void text_get_cursor_pos(size_t *x, size_t *y) {
|
||||
*x = (cursor_offset % VD_COLS) / 2;
|
||||
*y = cursor_offset / VD_COLS;
|
||||
void text_get_cursor_pos(struct term_context *_ctx, size_t *x, size_t *y) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
*x = (ctx->cursor_offset % VD_COLS) / 2;
|
||||
*y = ctx->cursor_offset / VD_COLS;
|
||||
}
|
||||
|
||||
void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
|
||||
void text_move_character(struct term_context *_ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
if (old_x >= VD_COLS / 2 || old_y >= VD_ROWS
|
||||
|| new_x >= VD_COLS / 2 || new_y >= VD_ROWS) {
|
||||
return;
|
||||
}
|
||||
|
||||
back_buffer[new_y * VD_COLS + new_x * 2] = back_buffer[old_y * VD_COLS + old_x * 2];
|
||||
ctx->back_buffer[new_y * VD_COLS + new_x * 2] = ctx->back_buffer[old_y * VD_COLS + old_x * 2];
|
||||
}
|
||||
|
||||
void text_set_cursor_pos(size_t x, size_t y) {
|
||||
void text_set_cursor_pos(struct term_context *_ctx, size_t x, size_t y) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
if (x >= VD_COLS / 2) {
|
||||
if ((int)x < 0) {
|
||||
x = 0;
|
||||
@ -272,48 +233,56 @@ void text_set_cursor_pos(size_t x, size_t y) {
|
||||
y = VD_ROWS - 1;
|
||||
}
|
||||
}
|
||||
cursor_offset = y * VD_COLS + x * 2;
|
||||
ctx->cursor_offset = y * VD_COLS + x * 2;
|
||||
}
|
||||
|
||||
static uint8_t ansi_colours[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
|
||||
void text_set_text_fg(size_t fg) {
|
||||
text_palette = (text_palette & 0xf0) | ansi_colours[fg];
|
||||
void text_set_text_fg(struct term_context *_ctx, size_t fg) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette = (ctx->text_palette & 0xf0) | ansi_colours[fg];
|
||||
}
|
||||
|
||||
void text_set_text_bg(size_t bg) {
|
||||
text_palette = (text_palette & 0x0f) | (ansi_colours[bg] << 4);
|
||||
void text_set_text_bg(struct term_context *_ctx, size_t bg) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette = (ctx->text_palette & 0x0f) | (ansi_colours[bg] << 4);
|
||||
}
|
||||
|
||||
void text_set_text_fg_bright(size_t fg) {
|
||||
text_palette = (text_palette & 0xf0) | (ansi_colours[fg] | (1 << 3));
|
||||
void text_set_text_fg_bright(struct term_context *_ctx, size_t fg) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette = (ctx->text_palette & 0xf0) | (ansi_colours[fg] | (1 << 3));
|
||||
}
|
||||
|
||||
void text_set_text_bg_bright(size_t bg) {
|
||||
text_palette = (text_palette & 0x0f) | ((ansi_colours[bg] | (1 << 3)) << 4);
|
||||
void text_set_text_bg_bright(struct term_context *_ctx, size_t bg) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette = (ctx->text_palette & 0x0f) | ((ansi_colours[bg] | (1 << 3)) << 4);
|
||||
}
|
||||
|
||||
void text_set_text_fg_default(void) {
|
||||
text_palette = (text_palette & 0xf0) | 7;
|
||||
void text_set_text_fg_default(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette = (ctx->text_palette & 0xf0) | 7;
|
||||
}
|
||||
|
||||
void text_set_text_bg_default(void) {
|
||||
text_palette &= 0x0f;
|
||||
void text_set_text_bg_default(struct term_context *_ctx) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
ctx->text_palette &= 0x0f;
|
||||
}
|
||||
|
||||
void text_putchar(uint8_t c) {
|
||||
back_buffer[cursor_offset] = c;
|
||||
back_buffer[cursor_offset + 1] = text_palette;
|
||||
if (cursor_offset / VD_COLS == term_context.scroll_bottom_margin - 1
|
||||
&& cursor_offset % VD_COLS == VD_COLS - 2) {
|
||||
if (scroll_enabled) {
|
||||
text_scroll();
|
||||
cursor_offset -= cursor_offset % VD_COLS;
|
||||
void text_putchar(struct term_context *_ctx, uint8_t c) {
|
||||
struct textmode_context *ctx = (void *)_ctx;
|
||||
|
||||
ctx->back_buffer[ctx->cursor_offset] = c;
|
||||
ctx->back_buffer[ctx->cursor_offset + 1] = ctx->text_palette;
|
||||
if (ctx->cursor_offset / VD_COLS == _ctx->scroll_bottom_margin - 1
|
||||
&& ctx->cursor_offset % VD_COLS == VD_COLS - 2) {
|
||||
if (_ctx->scroll_enabled) {
|
||||
text_scroll(_ctx);
|
||||
ctx->cursor_offset -= ctx->cursor_offset % VD_COLS;
|
||||
}
|
||||
} else if (cursor_offset >= (VIDEO_BOTTOM - 1)) {
|
||||
cursor_offset -= cursor_offset % VD_COLS;
|
||||
} else if (ctx->cursor_offset >= (VIDEO_BOTTOM - 1)) {
|
||||
ctx->cursor_offset -= ctx->cursor_offset % VD_COLS;
|
||||
} else {
|
||||
cursor_offset += 2;
|
||||
ctx->cursor_offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,36 +4,48 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <term/term.h>
|
||||
|
||||
struct textmode_context {
|
||||
struct term_context term;
|
||||
|
||||
volatile uint8_t *video_mem;
|
||||
|
||||
uint8_t *back_buffer;
|
||||
uint8_t *front_buffer;
|
||||
|
||||
size_t cursor_offset;
|
||||
size_t old_cursor_offset;
|
||||
bool cursor_status;
|
||||
uint8_t text_palette;
|
||||
|
||||
uint8_t saved_state_text_palette;
|
||||
size_t saved_state_cursor_offset;
|
||||
};
|
||||
|
||||
void init_vga_textmode(size_t *rows, size_t *cols, bool managed);
|
||||
|
||||
void text_putchar(uint8_t c);
|
||||
void text_clear(bool move);
|
||||
void text_enable_cursor(void);
|
||||
bool text_disable_cursor(void);
|
||||
void text_set_cursor_pos(size_t x, size_t y);
|
||||
void text_get_cursor_pos(size_t *x, size_t *y);
|
||||
void text_set_text_fg(size_t fg);
|
||||
void text_set_text_bg(size_t bg);
|
||||
void text_set_text_fg_bright(size_t fg);
|
||||
void text_set_text_bg_bright(size_t bg);
|
||||
void text_set_text_fg_default(void);
|
||||
void text_set_text_bg_default(void);
|
||||
bool text_scroll_disable(void);
|
||||
void text_scroll_enable(void);
|
||||
void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
|
||||
void text_scroll(void);
|
||||
void text_revscroll(void);
|
||||
void text_swap_palette(void);
|
||||
void text_save_state(void);
|
||||
void text_restore_state(void);
|
||||
|
||||
void text_double_buffer(bool state);
|
||||
void text_double_buffer_flush(void);
|
||||
|
||||
uint64_t text_context_size(void);
|
||||
void text_context_save(uint64_t ptr);
|
||||
void text_context_restore(uint64_t ptr);
|
||||
void text_full_refresh(void);
|
||||
void text_putchar(struct term_context *ctx, uint8_t c);
|
||||
void text_clear(struct term_context *ctx, bool move);
|
||||
void text_enable_cursor(struct term_context *ctx);
|
||||
bool text_disable_cursor(struct term_context *ctx);
|
||||
void text_set_cursor_pos(struct term_context *ctx, size_t x, size_t y);
|
||||
void text_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y);
|
||||
void text_set_text_fg(struct term_context *ctx, size_t fg);
|
||||
void text_set_text_bg(struct term_context *ctx, size_t bg);
|
||||
void text_set_text_fg_bright(struct term_context *ctx, size_t fg);
|
||||
void text_set_text_bg_bright(struct term_context *ctx, size_t bg);
|
||||
void text_set_text_fg_default(struct term_context *ctx);
|
||||
void text_set_text_bg_default(struct term_context *ctx);
|
||||
bool text_scroll_disable(struct term_context *ctx);
|
||||
void text_scroll_enable(struct term_context *ctx);
|
||||
void text_move_character(struct term_context *ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y);
|
||||
void text_scroll(struct term_context *ctx);
|
||||
void text_revscroll(struct term_context *ctx);
|
||||
void text_swap_palette(struct term_context *ctx);
|
||||
void text_save_state(struct term_context *ctx);
|
||||
void text_restore_state(struct term_context *ctx);
|
||||
void text_double_buffer_flush(struct term_context *ctx);
|
||||
void text_full_refresh(struct term_context *ctx);
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <lib/gterm.h>
|
||||
#include <lib/term.h>
|
||||
#include <lib/misc.h>
|
||||
#include <lib/libc.h>
|
||||
#include <lib/config.h>
|
||||
@ -9,121 +8,23 @@
|
||||
#include <lib/uri.h>
|
||||
#include <lib/fb.h>
|
||||
#include <mm/pmm.h>
|
||||
|
||||
// Maximum allowed font size in bytes. 16kB should be enough as 9x32 is the
|
||||
// largest font I've seen, and that would take 9*32 * 256 * 1/8 byte =
|
||||
// 9216 bytes.
|
||||
#define VGA_FONT_MAX 16384
|
||||
#define VGA_FONT_GLYPHS 256
|
||||
|
||||
#define DEFAULT_FONT_WIDTH 8
|
||||
#define DEFAULT_FONT_HEIGHT 16
|
||||
|
||||
static size_t vga_font_width;
|
||||
static size_t vga_font_height;
|
||||
static size_t glyph_width = 8;
|
||||
static size_t glyph_height = 16;
|
||||
|
||||
static size_t vga_font_scale_x = 1;
|
||||
static size_t vga_font_scale_y = 1;
|
||||
|
||||
static size_t offset_x, offset_y;
|
||||
#include <term/term.h>
|
||||
#include <term/backends/framebuffer.h>
|
||||
#include <lib/term.h>
|
||||
|
||||
struct fb_info fbinfo;
|
||||
static volatile uint32_t *gterm_framebuffer;
|
||||
static uint16_t gterm_pitch;
|
||||
static uint16_t gterm_width;
|
||||
static uint16_t gterm_height;
|
||||
static uint16_t gterm_bpp;
|
||||
|
||||
extern symbol _binary_font_bin_start;
|
||||
|
||||
static uint8_t *vga_font_bits = NULL;
|
||||
static size_t vga_font_bool_size = 0;
|
||||
static bool *vga_font_bool = NULL;
|
||||
|
||||
static uint32_t ansi_colours[8];
|
||||
static uint32_t ansi_bright_colours[8];
|
||||
static uint32_t default_fg, default_bg;
|
||||
extern symbol _binary_font_bin_start, _binary_font_bin_size;
|
||||
|
||||
static struct image *background;
|
||||
|
||||
static size_t bg_canvas_size = 0;
|
||||
static uint32_t *bg_canvas = NULL;
|
||||
static size_t margin = 64;
|
||||
static size_t margin_gradient = 4;
|
||||
|
||||
static size_t rows;
|
||||
static size_t cols;
|
||||
static size_t margin;
|
||||
static size_t margin_gradient;
|
||||
static uint32_t default_bg, default_fg;
|
||||
|
||||
static size_t grid_size = 0;
|
||||
static size_t queue_size = 0;
|
||||
static size_t map_size = 0;
|
||||
|
||||
struct gterm_char {
|
||||
uint32_t c;
|
||||
uint32_t fg;
|
||||
uint32_t bg;
|
||||
};
|
||||
|
||||
static struct gterm_char *grid = NULL;
|
||||
|
||||
struct queue_item {
|
||||
size_t x, y;
|
||||
struct gterm_char c;
|
||||
};
|
||||
|
||||
static struct queue_item *queue = NULL;
|
||||
static size_t queue_i = 0;
|
||||
|
||||
static struct queue_item **map = NULL;
|
||||
|
||||
static struct context {
|
||||
uint32_t text_fg;
|
||||
#define text_fg context.text_fg
|
||||
uint32_t text_bg;
|
||||
#define text_bg context.text_bg
|
||||
bool cursor_status;
|
||||
#define cursor_status context.cursor_status
|
||||
size_t cursor_x;
|
||||
#define cursor_x context.cursor_x
|
||||
size_t cursor_y;
|
||||
#define cursor_y context.cursor_y
|
||||
bool scroll_enabled;
|
||||
#define scroll_enabled context.scroll_enabled
|
||||
|
||||
uint32_t saved_state_text_fg;
|
||||
#define saved_state_text_fg context.saved_state_text_fg
|
||||
uint32_t saved_state_text_bg;
|
||||
#define saved_state_text_bg context.saved_state_text_bg
|
||||
size_t saved_state_cursor_x;
|
||||
#define saved_state_cursor_x context.saved_state_cursor_x
|
||||
size_t saved_state_cursor_y;
|
||||
#define saved_state_cursor_y context.saved_state_cursor_y
|
||||
} context;
|
||||
|
||||
static size_t old_cursor_x = 0;
|
||||
static size_t old_cursor_y = 0;
|
||||
|
||||
void gterm_save_state(void) {
|
||||
saved_state_text_fg = text_fg;
|
||||
saved_state_text_bg = text_bg;
|
||||
saved_state_cursor_x = cursor_x;
|
||||
saved_state_cursor_y = cursor_y;
|
||||
}
|
||||
|
||||
void gterm_restore_state(void) {
|
||||
text_fg = saved_state_text_fg;
|
||||
text_bg = saved_state_text_bg;
|
||||
cursor_x = saved_state_cursor_x;
|
||||
cursor_y = saved_state_cursor_y;
|
||||
}
|
||||
|
||||
void gterm_swap_palette(void) {
|
||||
uint32_t tmp = text_bg;
|
||||
text_bg = text_fg;
|
||||
text_fg = tmp;
|
||||
}
|
||||
static size_t bg_canvas_size;
|
||||
static uint32_t *bg_canvas;
|
||||
|
||||
#define A(rgb) (uint8_t)(rgb >> 24)
|
||||
#define R(rgb) (uint8_t)(rgb >> 16)
|
||||
@ -142,20 +43,10 @@ static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
|
||||
return ARGB(0, r, g, b);
|
||||
}
|
||||
|
||||
static inline void gterm_plot_px(size_t x, size_t y, uint32_t hex) {
|
||||
if (x >= gterm_width || y >= gterm_height) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t fb_i = x + (gterm_pitch / sizeof(uint32_t)) * y;
|
||||
|
||||
gterm_framebuffer[fb_i] = hex;
|
||||
}
|
||||
|
||||
static uint32_t blend_gradient_from_box(size_t x, size_t y, uint32_t bg_px, uint32_t hex) {
|
||||
size_t distance, x_distance, y_distance;
|
||||
size_t gradient_stop_x = gterm_width - margin;
|
||||
size_t gradient_stop_y = gterm_height - margin;
|
||||
size_t gradient_stop_x = fbinfo.framebuffer_width - margin;
|
||||
size_t gradient_stop_y = fbinfo.framebuffer_height - margin;
|
||||
|
||||
if (x < margin)
|
||||
x_distance = margin - x;
|
||||
@ -199,11 +90,11 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
|
||||
for (size_t y = ystart; y < yend; y++) {
|
||||
size_t image_y = y % img_height, image_x = xstart % img_width;
|
||||
const size_t off = img_pitch * (img_height - 1 - image_y);
|
||||
size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
|
||||
size_t canvas_off = fbinfo.framebuffer_width * y;
|
||||
for (size_t x = xstart; x < xend; x++) {
|
||||
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
|
||||
uint32_t i = blend(x, y, img_pixel);
|
||||
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
|
||||
bg_canvas[canvas_off + x] = i;
|
||||
if (image_x++ == img_width) image_x = 0; // image_x = x % img_width, but modulo is too expensive
|
||||
}
|
||||
}
|
||||
@ -213,11 +104,11 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
|
||||
for (size_t y = ystart; y < yend; y++) {
|
||||
size_t image_y = y - background->y_displacement;
|
||||
const size_t off = img_pitch * (img_height - 1 - image_y);
|
||||
size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
|
||||
size_t canvas_off = fbinfo.framebuffer_width * y;
|
||||
if (image_y >= background->y_size) { /* external part */
|
||||
for (size_t x = xstart; x < xend; x++) {
|
||||
uint32_t i = blend(x, y, background->back_colour);
|
||||
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
|
||||
bg_canvas[canvas_off + x] = i;
|
||||
}
|
||||
}
|
||||
else { /* internal part */
|
||||
@ -226,7 +117,7 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
|
||||
bool x_external = image_x >= background->x_size;
|
||||
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
|
||||
uint32_t i = blend(x, y, x_external ? background->back_colour : img_pixel);
|
||||
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
|
||||
bg_canvas[canvas_off + x] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -236,16 +127,16 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
|
||||
// so you can set x = xstart * ratio, and increment by ratio at each iteration
|
||||
case IMAGE_STRETCHED:
|
||||
for (size_t y = ystart; y < yend; y++) {
|
||||
size_t img_y = (y * img_height) / gterm_height; // calculate Y with full precision
|
||||
size_t img_y = (y * img_height) / fbinfo.framebuffer_height; // calculate Y with full precision
|
||||
size_t off = img_pitch * (img_height - 1 - img_y);
|
||||
size_t canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y;
|
||||
size_t canvas_off = fbinfo.framebuffer_width * y;
|
||||
|
||||
size_t ratio = int_to_fixedp6(img_width) / gterm_width;
|
||||
size_t ratio = int_to_fixedp6(img_width) / fbinfo.framebuffer_width;
|
||||
fixedp6 img_x = ratio * xstart;
|
||||
for (size_t x = xstart; x < xend; x++) {
|
||||
uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off);
|
||||
uint32_t i = blend(x, y, img_pixel);
|
||||
bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i;
|
||||
bg_canvas[canvas_off + x] = i;
|
||||
img_x += ratio;
|
||||
}
|
||||
}
|
||||
@ -261,24 +152,27 @@ static void loop_external(size_t xstart, size_t xend, size_t ystart, size_t yend
|
||||
static void loop_margin(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_margin); }
|
||||
static void loop_internal(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_internal); }
|
||||
|
||||
static void gterm_generate_canvas(void) {
|
||||
static void *generate_canvas(void) {
|
||||
if (background) {
|
||||
bg_canvas_size = fbinfo.framebuffer_width * fbinfo.framebuffer_height * sizeof(uint32_t);
|
||||
bg_canvas = ext_mem_alloc(bg_canvas_size);
|
||||
|
||||
int64_t margin_no_gradient = (int64_t)margin - margin_gradient;
|
||||
|
||||
if (margin_no_gradient < 0) {
|
||||
margin_no_gradient = 0;
|
||||
}
|
||||
|
||||
size_t scan_stop_x = gterm_width - margin_no_gradient;
|
||||
size_t scan_stop_y = gterm_height - margin_no_gradient;
|
||||
size_t scan_stop_x = fbinfo.framebuffer_width - margin_no_gradient;
|
||||
size_t scan_stop_y = fbinfo.framebuffer_height - margin_no_gradient;
|
||||
|
||||
loop_external(0, gterm_width, 0, margin_no_gradient);
|
||||
loop_external(0, gterm_width, scan_stop_y, gterm_height);
|
||||
loop_external(0, fbinfo.framebuffer_width, 0, margin_no_gradient);
|
||||
loop_external(0, fbinfo.framebuffer_width, scan_stop_y, fbinfo.framebuffer_height);
|
||||
loop_external(0, margin_no_gradient, margin_no_gradient, scan_stop_y);
|
||||
loop_external(scan_stop_x, gterm_width, margin_no_gradient, scan_stop_y);
|
||||
loop_external(scan_stop_x, fbinfo.framebuffer_width, margin_no_gradient, scan_stop_y);
|
||||
|
||||
size_t gradient_stop_x = gterm_width - margin;
|
||||
size_t gradient_stop_y = gterm_height - margin;
|
||||
size_t gradient_stop_x = fbinfo.framebuffer_width - margin;
|
||||
size_t gradient_stop_y = fbinfo.framebuffer_height - margin;
|
||||
|
||||
if (margin_gradient) {
|
||||
loop_margin(margin_no_gradient, scan_stop_x, margin_no_gradient, margin);
|
||||
@ -288,327 +182,17 @@ static void gterm_generate_canvas(void) {
|
||||
}
|
||||
|
||||
loop_internal(margin, gradient_stop_x, margin, gradient_stop_y);
|
||||
} else {
|
||||
for (size_t y = 0; y < gterm_height; y++) {
|
||||
for (size_t x = 0; x < gterm_width; x++) {
|
||||
bg_canvas[y * gterm_width + x] = default_bg;
|
||||
gterm_plot_px(x, y, default_bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void plot_char(struct gterm_char *c, size_t x, size_t y) {
|
||||
if (x >= cols || y >= rows) {
|
||||
return;
|
||||
return bg_canvas;
|
||||
}
|
||||
|
||||
x = offset_x + x * glyph_width;
|
||||
y = offset_y + y * glyph_height;
|
||||
|
||||
bool *glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width];
|
||||
// naming: fx,fy for font coordinates, gx,gy for glyph coordinates
|
||||
for (size_t gy = 0; gy < glyph_height; gy++) {
|
||||
uint8_t fy = gy / vga_font_scale_y;
|
||||
volatile uint32_t *fb_line = gterm_framebuffer + x + (y + gy) * (gterm_pitch / 4);
|
||||
uint32_t *canvas_line = bg_canvas + x + (y + gy) * gterm_width;
|
||||
for (size_t fx = 0; fx < vga_font_width; fx++) {
|
||||
bool draw = glyph[fy * vga_font_width + fx];
|
||||
for (size_t i = 0; i < vga_font_scale_x; i++) {
|
||||
size_t gx = vga_font_scale_x * fx + i;
|
||||
uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
|
||||
uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
|
||||
fb_line[gx] = draw ? fg : bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void plot_char_fast(struct gterm_char *old, struct gterm_char *c, size_t x, size_t y) {
|
||||
if (x >= cols || y >= rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
x = offset_x + x * glyph_width;
|
||||
y = offset_y + y * glyph_height;
|
||||
|
||||
bool *new_glyph = &vga_font_bool[c->c * vga_font_height * vga_font_width];
|
||||
bool *old_glyph = &vga_font_bool[old->c * vga_font_height * vga_font_width];
|
||||
for (size_t gy = 0; gy < glyph_height; gy++) {
|
||||
uint8_t fy = gy / vga_font_scale_y;
|
||||
volatile uint32_t *fb_line = gterm_framebuffer + x + (y + gy) * (gterm_pitch / 4);
|
||||
uint32_t *canvas_line = bg_canvas + x + (y + gy) * gterm_width;
|
||||
for (size_t fx = 0; fx < vga_font_width; fx++) {
|
||||
bool old_draw = old_glyph[fy * vga_font_width + fx];
|
||||
bool new_draw = new_glyph[fy * vga_font_width + fx];
|
||||
if (old_draw == new_draw)
|
||||
continue;
|
||||
for (size_t i = 0; i < vga_font_scale_x; i++) {
|
||||
size_t gx = vga_font_scale_x * fx + i;
|
||||
uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
|
||||
uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
|
||||
fb_line[gx] = new_draw ? fg : bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool compare_char(struct gterm_char *a, struct gterm_char *b) {
|
||||
return !(a->c != b->c || a->bg != b->bg || a->fg != b->fg);
|
||||
}
|
||||
|
||||
static void push_to_queue(struct gterm_char *c, size_t x, size_t y) {
|
||||
if (x >= cols || y >= rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = y * cols + x;
|
||||
|
||||
struct queue_item *q = map[i];
|
||||
|
||||
if (q == NULL) {
|
||||
if (compare_char(&grid[i], c)) {
|
||||
return;
|
||||
}
|
||||
q = &queue[queue_i++];
|
||||
q->x = x;
|
||||
q->y = y;
|
||||
map[i] = q;
|
||||
}
|
||||
|
||||
q->c = *c;
|
||||
}
|
||||
|
||||
bool gterm_scroll_disable(void) {
|
||||
bool ret = scroll_enabled;
|
||||
scroll_enabled = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gterm_scroll_enable(void) {
|
||||
scroll_enabled = true;
|
||||
}
|
||||
|
||||
void gterm_revscroll(void) {
|
||||
for (size_t i = (term_context.scroll_bottom_margin - 1) * cols - 1; ; i--) {
|
||||
struct gterm_char *c;
|
||||
struct queue_item *q = map[i];
|
||||
if (q != NULL) {
|
||||
c = &q->c;
|
||||
} else {
|
||||
c = &grid[i];
|
||||
}
|
||||
push_to_queue(c, (i + cols) % cols, (i + cols) / cols);
|
||||
if (i == term_context.scroll_top_margin * cols) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the first line of the screen.
|
||||
struct gterm_char empty;
|
||||
empty.c = ' ';
|
||||
empty.fg = text_fg;
|
||||
empty.bg = text_bg;
|
||||
for (size_t i = term_context.scroll_top_margin * cols;
|
||||
i < (term_context.scroll_top_margin + 1) * cols; i++) {
|
||||
push_to_queue(&empty, i % cols, i / cols);
|
||||
}
|
||||
}
|
||||
|
||||
void gterm_scroll(void) {
|
||||
for (size_t i = (term_context.scroll_top_margin + 1) * cols;
|
||||
i < term_context.scroll_bottom_margin * cols; i++) {
|
||||
struct gterm_char *c;
|
||||
struct queue_item *q = map[i];
|
||||
if (q != NULL) {
|
||||
c = &q->c;
|
||||
} else {
|
||||
c = &grid[i];
|
||||
}
|
||||
push_to_queue(c, (i - cols) % cols, (i - cols) / cols);
|
||||
}
|
||||
|
||||
// Clear the last line of the screen.
|
||||
struct gterm_char empty;
|
||||
empty.c = ' ';
|
||||
empty.fg = text_fg;
|
||||
empty.bg = text_bg;
|
||||
for (size_t i = (term_context.scroll_bottom_margin - 1) * cols;
|
||||
i < term_context.scroll_bottom_margin * cols; i++) {
|
||||
push_to_queue(&empty, i % cols, i / cols);
|
||||
}
|
||||
}
|
||||
|
||||
void gterm_clear(bool move) {
|
||||
struct gterm_char empty;
|
||||
empty.c = ' ';
|
||||
empty.fg = text_fg;
|
||||
empty.bg = text_bg;
|
||||
for (size_t i = 0; i < rows * cols; i++) {
|
||||
push_to_queue(&empty, i % cols, i / cols);
|
||||
}
|
||||
|
||||
if (move) {
|
||||
cursor_x = 0;
|
||||
cursor_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void gterm_enable_cursor(void) {
|
||||
cursor_status = true;
|
||||
}
|
||||
|
||||
bool gterm_disable_cursor(void) {
|
||||
bool ret = cursor_status;
|
||||
cursor_status = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gterm_set_cursor_pos(size_t x, size_t y) {
|
||||
if (x >= cols) {
|
||||
if ((int)x < 0) {
|
||||
x = 0;
|
||||
} else {
|
||||
x = cols - 1;
|
||||
}
|
||||
}
|
||||
if (y >= rows) {
|
||||
if ((int)y < 0) {
|
||||
y = 0;
|
||||
} else {
|
||||
y = rows - 1;
|
||||
}
|
||||
}
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
void gterm_get_cursor_pos(size_t *x, size_t *y) {
|
||||
*x = cursor_x;
|
||||
*y = cursor_y;
|
||||
}
|
||||
|
||||
void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
|
||||
if (old_x >= cols || old_y >= rows
|
||||
|| new_x >= cols || new_y >= rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = old_x + old_y * cols;
|
||||
|
||||
struct gterm_char *c;
|
||||
struct queue_item *q = map[i];
|
||||
if (q != NULL) {
|
||||
c = &q->c;
|
||||
} else {
|
||||
c = &grid[i];
|
||||
}
|
||||
|
||||
push_to_queue(c, new_x, new_y);
|
||||
}
|
||||
|
||||
void gterm_set_text_fg(size_t fg) {
|
||||
text_fg = ansi_colours[fg];
|
||||
}
|
||||
|
||||
void gterm_set_text_bg(size_t bg) {
|
||||
text_bg = ansi_colours[bg];
|
||||
}
|
||||
|
||||
void gterm_set_text_fg_bright(size_t fg) {
|
||||
text_fg = ansi_bright_colours[fg];
|
||||
}
|
||||
|
||||
void gterm_set_text_bg_bright(size_t bg) {
|
||||
text_bg = ansi_bright_colours[bg];
|
||||
}
|
||||
|
||||
void gterm_set_text_fg_rgb(uint32_t fg) {
|
||||
text_fg = fg;
|
||||
}
|
||||
|
||||
void gterm_set_text_bg_rgb(uint32_t bg) {
|
||||
text_bg = bg;
|
||||
}
|
||||
|
||||
void gterm_set_text_fg_default(void) {
|
||||
text_fg = default_fg;
|
||||
}
|
||||
|
||||
void gterm_set_text_bg_default(void) {
|
||||
text_bg = 0xffffffff;
|
||||
}
|
||||
|
||||
static void draw_cursor(void) {
|
||||
size_t i = cursor_x + cursor_y * cols;
|
||||
struct gterm_char c;
|
||||
struct queue_item *q = map[i];
|
||||
if (q != NULL) {
|
||||
c = q->c;
|
||||
} else {
|
||||
c = grid[i];
|
||||
}
|
||||
uint32_t tmp = c.fg;
|
||||
c.fg = c.bg;
|
||||
c.bg = tmp;
|
||||
plot_char(&c, cursor_x, cursor_y);
|
||||
if (q != NULL) {
|
||||
grid[i] = q->c;
|
||||
map[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gterm_double_buffer_flush(void) {
|
||||
if (cursor_status) {
|
||||
draw_cursor();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < queue_i; i++) {
|
||||
struct queue_item *q = &queue[i];
|
||||
size_t offset = q->y * cols + q->x;
|
||||
if (map[offset] == NULL) {
|
||||
continue;
|
||||
}
|
||||
struct gterm_char *old = &grid[offset];
|
||||
if (q->c.bg == old->bg && q->c.fg == old->fg) {
|
||||
plot_char_fast(old, &q->c, q->x, q->y);
|
||||
} else {
|
||||
plot_char(&q->c, q->x, q->y);
|
||||
}
|
||||
grid[offset] = q->c;
|
||||
map[offset] = NULL;
|
||||
}
|
||||
|
||||
if ((old_cursor_x != cursor_x || old_cursor_y != cursor_y) || cursor_status == false) {
|
||||
plot_char(&grid[old_cursor_x + old_cursor_y * cols], old_cursor_x, old_cursor_y);
|
||||
}
|
||||
|
||||
old_cursor_x = cursor_x;
|
||||
old_cursor_y = cursor_y;
|
||||
|
||||
queue_i = 0;
|
||||
}
|
||||
|
||||
void gterm_putchar(uint8_t c) {
|
||||
struct gterm_char ch;
|
||||
ch.c = c;
|
||||
ch.fg = text_fg;
|
||||
ch.bg = text_bg;
|
||||
push_to_queue(&ch, cursor_x++, cursor_y);
|
||||
if (cursor_x == cols && (cursor_y < term_context.scroll_bottom_margin - 1 || scroll_enabled)) {
|
||||
cursor_x = 0;
|
||||
cursor_y++;
|
||||
}
|
||||
if (cursor_y == term_context.scroll_bottom_margin) {
|
||||
cursor_y--;
|
||||
gterm_scroll();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool last_serial = false;
|
||||
static char *last_config = NULL;
|
||||
|
||||
bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t height) {
|
||||
bool gterm_init(char *config, size_t width, size_t height) {
|
||||
if (current_video_mode >= 0
|
||||
#if defined (BIOS)
|
||||
&& current_video_mode != 0x03
|
||||
@ -619,9 +203,7 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
&& fbinfo.framebuffer_bpp == 32
|
||||
&& serial == last_serial
|
||||
&& config == last_config) {
|
||||
*_rows = rows;
|
||||
*_cols = cols;
|
||||
gterm_clear(true);
|
||||
term->clear(term, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -634,9 +216,7 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
&& fbinfo.framebuffer_bpp == 32
|
||||
&& serial == last_serial
|
||||
&& config == last_config) {
|
||||
*_rows = rows;
|
||||
*_cols = cols;
|
||||
gterm_clear(true);
|
||||
term->clear(term, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -644,15 +224,23 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
if (!fb_init(&fbinfo, width, height, 32))
|
||||
return false;
|
||||
|
||||
last_serial = serial;
|
||||
// Ensure this is xRGB8888, we only support that for the menu
|
||||
if (fbinfo.red_mask_size != 8
|
||||
|| fbinfo.red_mask_shift != 16
|
||||
|| fbinfo.green_mask_size != 8
|
||||
|| fbinfo.green_mask_shift != 8
|
||||
|| fbinfo.blue_mask_size != 8
|
||||
|| fbinfo.blue_mask_shift != 0)
|
||||
return false;
|
||||
|
||||
cursor_status = true;
|
||||
scroll_enabled = true;
|
||||
last_serial = serial;
|
||||
|
||||
// default scheme
|
||||
margin = 64;
|
||||
margin_gradient = 4;
|
||||
|
||||
uint32_t ansi_colours[8];
|
||||
|
||||
ansi_colours[0] = 0x00000000; // black
|
||||
ansi_colours[1] = 0x00aa0000; // red
|
||||
ansi_colours[2] = 0x0000aa00; // green
|
||||
@ -678,6 +266,8 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ansi_bright_colours[8];
|
||||
|
||||
ansi_bright_colours[0] = 0x00555555; // black
|
||||
ansi_bright_colours[1] = 0x00ff5555; // red
|
||||
ansi_bright_colours[2] = 0x0055ff55; // green
|
||||
@ -716,9 +306,6 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
default_fg = strtoui(theme_foreground, NULL, 16) & 0xffffff;
|
||||
}
|
||||
|
||||
text_fg = default_fg;
|
||||
text_bg = 0xffffffff;
|
||||
|
||||
background = NULL;
|
||||
char *background_path = config_get_value(config, 0, "TERM_WALLPAPER");
|
||||
if (background_path != NULL) {
|
||||
@ -762,27 +349,14 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure this is xRGB8888, we only support that for the menu
|
||||
if (fbinfo.red_mask_size != 8
|
||||
|| fbinfo.red_mask_shift != 16
|
||||
|| fbinfo.green_mask_size != 8
|
||||
|| fbinfo.green_mask_shift != 8
|
||||
|| fbinfo.blue_mask_size != 8
|
||||
|| fbinfo.blue_mask_shift != 0)
|
||||
return false;
|
||||
size_t font_width = 8;
|
||||
size_t font_height = 16;
|
||||
size_t font_size = (font_width * font_height * FBTERM_FONT_GLYPHS) / 8;
|
||||
|
||||
gterm_framebuffer = (void *)(uintptr_t)fbinfo.framebuffer_addr;
|
||||
gterm_width = fbinfo.framebuffer_width;
|
||||
gterm_height = fbinfo.framebuffer_height;
|
||||
gterm_bpp = fbinfo.framebuffer_bpp;
|
||||
gterm_pitch = fbinfo.framebuffer_pitch;
|
||||
#define FONT_MAX 16384
|
||||
uint8_t *font = ext_mem_alloc(FONT_MAX);
|
||||
|
||||
vga_font_width = DEFAULT_FONT_WIDTH, vga_font_height = DEFAULT_FONT_HEIGHT;
|
||||
size_t font_bytes = (vga_font_width * vga_font_height * VGA_FONT_GLYPHS) / 8;
|
||||
|
||||
vga_font_bits = ext_mem_alloc(VGA_FONT_MAX);
|
||||
|
||||
memcpy(vga_font_bits, (void *)_binary_font_bin_start, VGA_FONT_MAX);
|
||||
memcpy(font, (void *)_binary_font_bin_start, (uintptr_t)_binary_font_bin_size);
|
||||
|
||||
size_t tmp_font_width, tmp_font_height;
|
||||
|
||||
@ -790,14 +364,14 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
if (menu_font_size != NULL) {
|
||||
parse_resolution(&tmp_font_width, &tmp_font_height, NULL, menu_font_size);
|
||||
|
||||
size_t tmp_font_bytes = (tmp_font_width * tmp_font_height * VGA_FONT_GLYPHS) / 8;
|
||||
size_t tmp_font_size = (tmp_font_width * tmp_font_height * FBTERM_FONT_GLYPHS) / 8;
|
||||
|
||||
if (tmp_font_bytes > VGA_FONT_MAX) {
|
||||
print("Font would be too large (%u bytes, %u bytes allowed). Not loading.\n", tmp_font_bytes, VGA_FONT_MAX);
|
||||
if (tmp_font_size > FONT_MAX) {
|
||||
print("Font would be too large (%u bytes, %u bytes allowed). Not loading.\n", tmp_font_size, FONT_MAX);
|
||||
goto no_load_font;
|
||||
}
|
||||
|
||||
font_bytes = tmp_font_bytes;
|
||||
font_size = tmp_font_size;
|
||||
}
|
||||
|
||||
char *menu_font = config_get_value(config, 0, "TERM_FONT");
|
||||
@ -806,10 +380,10 @@ bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t
|
||||
if ((f = uri_open(menu_font)) == NULL) {
|
||||
print("menu: Could not open font file.\n");
|
||||
} else {
|
||||
fread(f, vga_font_bits, 0, font_bytes);
|
||||
fread(f, font, 0, font_size);
|
||||
if (menu_font_size != NULL) {
|
||||
vga_font_width = tmp_font_width;
|
||||
vga_font_height = tmp_font_height;
|
||||
font_width = tmp_font_width;
|
||||
font_height = tmp_font_height;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
@ -822,138 +396,31 @@ no_load_font:;
|
||||
font_spacing = strtoui(font_spacing_str, NULL, 10);
|
||||
}
|
||||
|
||||
vga_font_width += font_spacing;
|
||||
|
||||
vga_font_bool_size = VGA_FONT_GLYPHS * vga_font_height * vga_font_width * sizeof(bool);
|
||||
vga_font_bool = ext_mem_alloc(vga_font_bool_size);
|
||||
|
||||
for (size_t i = 0; i < VGA_FONT_GLYPHS; i++) {
|
||||
uint8_t *glyph = &vga_font_bits[i * vga_font_height];
|
||||
|
||||
for (size_t y = 0; y < vga_font_height; y++) {
|
||||
// NOTE: the characters in VGA fonts are always one byte wide.
|
||||
// 9 dot wide fonts have 8 dots and one empty column, except
|
||||
// characters 0xC0-0xDF replicate column 9.
|
||||
for (size_t x = 0; x < 8; x++) {
|
||||
size_t offset = i * vga_font_height * vga_font_width + y * vga_font_width + x;
|
||||
|
||||
if ((glyph[y] & (0x80 >> x))) {
|
||||
vga_font_bool[offset] = true;
|
||||
} else {
|
||||
vga_font_bool[offset] = false;
|
||||
}
|
||||
}
|
||||
// fill columns above 8 like VGA Line Graphics Mode does
|
||||
for (size_t x = 8; x < vga_font_width; x++) {
|
||||
size_t offset = i * vga_font_height * vga_font_width + y * vga_font_width + x;
|
||||
|
||||
if (i >= 0xC0 && i <= 0xDF) {
|
||||
vga_font_bool[offset] = (glyph[y] & 1);
|
||||
} else {
|
||||
vga_font_bool[offset] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vga_font_scale_x = 1;
|
||||
vga_font_scale_y = 1;
|
||||
size_t font_scale_x = 1;
|
||||
size_t font_scale_y = 1;
|
||||
|
||||
char *menu_font_scale = config_get_value(config, 0, "TERM_FONT_SCALE");
|
||||
if (menu_font_scale != NULL) {
|
||||
parse_resolution(&vga_font_scale_x, &vga_font_scale_y, NULL, menu_font_scale);
|
||||
if (vga_font_scale_x > 8 || vga_font_scale_y > 8) {
|
||||
vga_font_scale_x = 1;
|
||||
vga_font_scale_y = 1;
|
||||
parse_resolution(&font_scale_x, &font_scale_y, NULL, menu_font_scale);
|
||||
if (font_scale_x > 8 || font_scale_y > 8) {
|
||||
font_scale_x = 1;
|
||||
font_scale_y = 1;
|
||||
}
|
||||
}
|
||||
|
||||
glyph_width = vga_font_width * vga_font_scale_x;
|
||||
glyph_height = vga_font_height * vga_font_scale_y;
|
||||
uint32_t *canvas = generate_canvas();
|
||||
|
||||
*_cols = cols = (gterm_width - margin * 2) / glyph_width;
|
||||
*_rows = rows = (gterm_height - margin * 2) / glyph_height;
|
||||
term->deinit(term, pmm_free);
|
||||
|
||||
offset_x = margin + ((gterm_width - margin * 2) % glyph_width) / 2;
|
||||
offset_y = margin + ((gterm_height - margin * 2) % glyph_height) / 2;
|
||||
|
||||
grid_size = rows * cols * sizeof(struct gterm_char);
|
||||
grid = ext_mem_alloc(grid_size);
|
||||
|
||||
queue_size = rows * cols * sizeof(struct queue_item);
|
||||
queue = ext_mem_alloc(queue_size);
|
||||
queue_i = 0;
|
||||
|
||||
map_size = rows * cols * sizeof(struct queue_item *);
|
||||
map = ext_mem_alloc(map_size);
|
||||
|
||||
bg_canvas_size = gterm_width * gterm_height * sizeof(uint32_t);
|
||||
bg_canvas = ext_mem_alloc(bg_canvas_size);
|
||||
|
||||
gterm_generate_canvas();
|
||||
gterm_clear(true);
|
||||
gterm_double_buffer_flush();
|
||||
term = fbterm_init(ext_mem_alloc,
|
||||
(void *)(uintptr_t)fbinfo.framebuffer_addr,
|
||||
fbinfo.framebuffer_width, fbinfo.framebuffer_height, fbinfo.framebuffer_pitch,
|
||||
canvas,
|
||||
ansi_colours, ansi_bright_colours,
|
||||
&default_bg, &default_fg,
|
||||
font, font_width, font_height, font_spacing,
|
||||
font_scale_x, font_scale_y,
|
||||
margin);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gterm_deinit(void) {
|
||||
if (background != NULL) {
|
||||
image_close(background);
|
||||
}
|
||||
pmm_free(vga_font_bits, VGA_FONT_MAX);
|
||||
pmm_free(vga_font_bool, vga_font_bool_size);
|
||||
pmm_free(grid, grid_size);
|
||||
pmm_free(queue, queue_size);
|
||||
pmm_free(map, map_size);
|
||||
pmm_free(bg_canvas, bg_canvas_size);
|
||||
}
|
||||
|
||||
uint64_t gterm_context_size(void) {
|
||||
uint64_t ret = 0;
|
||||
|
||||
ret += sizeof(struct context);
|
||||
ret += grid_size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gterm_context_save(uint64_t ptr) {
|
||||
memcpy32to64(ptr, (uint64_t)(uintptr_t)&context, sizeof(struct context));
|
||||
ptr += sizeof(struct context);
|
||||
|
||||
memcpy32to64(ptr, (uint64_t)(uintptr_t)grid, grid_size);
|
||||
}
|
||||
|
||||
void gterm_context_restore(uint64_t ptr) {
|
||||
memcpy32to64((uint64_t)(uintptr_t)&context, ptr, sizeof(struct context));
|
||||
ptr += sizeof(struct context);
|
||||
|
||||
memcpy32to64((uint64_t)(uintptr_t)grid, ptr, grid_size);
|
||||
|
||||
for (size_t i = 0; i < (size_t)rows * cols; i++) {
|
||||
size_t x = i % cols;
|
||||
size_t y = i / cols;
|
||||
|
||||
plot_char(&grid[i], x, y);
|
||||
}
|
||||
|
||||
if (cursor_status) {
|
||||
draw_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
void gterm_full_refresh(void) {
|
||||
gterm_generate_canvas();
|
||||
|
||||
for (size_t i = 0; i < (size_t)rows * cols; i++) {
|
||||
size_t x = i % cols;
|
||||
size_t y = i / cols;
|
||||
|
||||
plot_char(&grid[i], x, y);
|
||||
}
|
||||
|
||||
if (cursor_status) {
|
||||
draw_cursor();
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +1,12 @@
|
||||
#ifndef __LIB__GTERM_H__
|
||||
#define __LIB__GTERM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <lib/image.h>
|
||||
#include <drivers/vbe.h>
|
||||
#include <lib/fb.h>
|
||||
|
||||
extern struct fb_info fbinfo;
|
||||
|
||||
bool gterm_init(char *config, size_t *_rows, size_t *_cols, size_t width, size_t height);
|
||||
void gterm_deinit(void);
|
||||
|
||||
void gterm_putchar(uint8_t c);
|
||||
void gterm_clear(bool move);
|
||||
void gterm_enable_cursor(void);
|
||||
bool gterm_disable_cursor(void);
|
||||
void gterm_set_cursor_pos(size_t x, size_t y);
|
||||
void gterm_get_cursor_pos(size_t *x, size_t *y);
|
||||
void gterm_set_text_fg(size_t fg);
|
||||
void gterm_set_text_bg(size_t bg);
|
||||
void gterm_set_text_fg_bright(size_t fg);
|
||||
void gterm_set_text_bg_bright(size_t bg);
|
||||
void gterm_set_text_fg_rgb(uint32_t fg);
|
||||
void gterm_set_text_bg_rgb(uint32_t bg);
|
||||
void gterm_set_text_fg_default(void);
|
||||
void gterm_set_text_bg_default(void);
|
||||
bool gterm_scroll_disable(void);
|
||||
void gterm_scroll_enable(void);
|
||||
void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
|
||||
void gterm_scroll(void);
|
||||
void gterm_revscroll(void);
|
||||
void gterm_swap_palette(void);
|
||||
void gterm_save_state(void);
|
||||
void gterm_restore_state(void);
|
||||
|
||||
void gterm_double_buffer_flush(void);
|
||||
|
||||
uint64_t gterm_context_size(void);
|
||||
void gterm_context_save(uint64_t ptr);
|
||||
void gterm_context_restore(uint64_t ptr);
|
||||
void gterm_full_refresh(void);
|
||||
bool gterm_init(char *config, size_t width, size_t height);
|
||||
|
||||
#endif
|
||||
|
@ -203,7 +203,7 @@ out:
|
||||
#if defined (BIOS)
|
||||
if (stage3_loaded) {
|
||||
#endif
|
||||
term_write((uint64_t)(uintptr_t)print_buf, print_buf_i);
|
||||
term_write(term, print_buf, print_buf_i);
|
||||
#if defined (BIOS)
|
||||
} else {
|
||||
s2_print(print_buf, print_buf_i);
|
||||
|
@ -348,32 +348,32 @@ again:
|
||||
|
||||
static void reprint_string(int x, int y, const char *s) {
|
||||
size_t orig_x, orig_y;
|
||||
disable_cursor();
|
||||
get_cursor_pos(&orig_x, &orig_y);
|
||||
term->disable_cursor(term);
|
||||
term->get_cursor_pos(term, &orig_x, &orig_y);
|
||||
set_cursor_pos_helper(x, y);
|
||||
print("%s", s);
|
||||
set_cursor_pos_helper(orig_x, orig_y);
|
||||
enable_cursor();
|
||||
term->enable_cursor(term);
|
||||
}
|
||||
|
||||
static void cursor_back(void) {
|
||||
size_t x, y;
|
||||
get_cursor_pos(&x, &y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
if (x) {
|
||||
x--;
|
||||
} else if (y) {
|
||||
y--;
|
||||
x = term_cols - 1;
|
||||
x = term->cols - 1;
|
||||
}
|
||||
set_cursor_pos_helper(x, y);
|
||||
}
|
||||
|
||||
static void cursor_fwd(void) {
|
||||
size_t x, y;
|
||||
get_cursor_pos(&x, &y);
|
||||
if (x < term_cols - 1) {
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
if (x < term->cols - 1) {
|
||||
x++;
|
||||
} else if (y < term_rows - 1) {
|
||||
} else if (y < term->rows - 1) {
|
||||
y++;
|
||||
x = 0;
|
||||
}
|
||||
@ -381,20 +381,20 @@ static void cursor_fwd(void) {
|
||||
}
|
||||
|
||||
void readline(const char *orig_str, char *buf, size_t limit) {
|
||||
bool prev_autoflush = term_autoflush;
|
||||
term_autoflush = false;
|
||||
bool prev_autoflush = term->autoflush;
|
||||
term->autoflush = false;
|
||||
|
||||
size_t orig_str_len = strlen(orig_str);
|
||||
memmove(buf, orig_str, orig_str_len);
|
||||
buf[orig_str_len] = 0;
|
||||
|
||||
size_t orig_x, orig_y;
|
||||
get_cursor_pos(&orig_x, &orig_y);
|
||||
term->get_cursor_pos(term, &orig_x, &orig_y);
|
||||
|
||||
print("%s", orig_str);
|
||||
|
||||
for (size_t i = orig_str_len; ; ) {
|
||||
term_double_buffer_flush();
|
||||
term->double_buffer_flush(term);
|
||||
int c = getchar();
|
||||
switch (c) {
|
||||
case GETCHAR_CURSOR_LEFT:
|
||||
@ -461,6 +461,6 @@ void readline(const char *orig_str, char *buf, size_t limit) {
|
||||
}
|
||||
|
||||
out:
|
||||
term_double_buffer_flush();
|
||||
term_autoflush = prev_autoflush;
|
||||
term->double_buffer_flush(term);
|
||||
term->autoflush = prev_autoflush;
|
||||
}
|
||||
|
1339
common/lib/term.c
1339
common/lib/term.c
File diff suppressed because it is too large
Load Diff
@ -6,37 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <lib/image.h>
|
||||
#include <lib/print.h>
|
||||
|
||||
#define TERM_TABSIZE (8)
|
||||
#define MAX_ESC_VALUES (16)
|
||||
|
||||
extern struct term_context {
|
||||
bool control_sequence;
|
||||
bool csi;
|
||||
bool escape;
|
||||
bool rrr;
|
||||
bool discard_next;
|
||||
bool bold;
|
||||
bool reverse_video;
|
||||
bool dec_private;
|
||||
bool insert_mode;
|
||||
uint8_t g_select;
|
||||
uint8_t charsets[2];
|
||||
size_t current_charset;
|
||||
size_t escape_offset;
|
||||
size_t esc_values_i;
|
||||
size_t saved_cursor_x;
|
||||
size_t saved_cursor_y;
|
||||
size_t current_primary;
|
||||
size_t scroll_top_margin;
|
||||
size_t scroll_bottom_margin;
|
||||
uint32_t esc_values[MAX_ESC_VALUES];
|
||||
|
||||
bool saved_state_bold;
|
||||
bool saved_state_reverse_video;
|
||||
size_t saved_state_current_charset;
|
||||
size_t saved_state_current_primary;
|
||||
} term_context;
|
||||
#include <term/term.h>
|
||||
|
||||
enum {
|
||||
_NOT_READY,
|
||||
@ -47,76 +17,29 @@ enum {
|
||||
|
||||
extern int current_video_mode;
|
||||
extern int term_backend;
|
||||
extern size_t term_rows, term_cols;
|
||||
extern bool term_runtime;
|
||||
|
||||
void term_notready(void);
|
||||
void term_fallback(void);
|
||||
|
||||
void term_reinit(void);
|
||||
void term_deinit(void);
|
||||
void term_vbe(char *config, size_t width, size_t height);
|
||||
void term_textmode(void);
|
||||
void term_write(uint64_t buf, uint64_t count);
|
||||
|
||||
extern void (*raw_putchar)(uint8_t c);
|
||||
extern void (*clear)(bool move);
|
||||
extern void (*enable_cursor)(void);
|
||||
extern bool (*disable_cursor)(void);
|
||||
extern void (*set_cursor_pos)(size_t x, size_t y);
|
||||
extern void (*get_cursor_pos)(size_t *x, size_t *y);
|
||||
extern void (*set_text_fg)(size_t fg);
|
||||
extern void (*set_text_bg)(size_t bg);
|
||||
extern void (*set_text_fg_bright)(size_t fg);
|
||||
extern void (*set_text_bg_bright)(size_t bg);
|
||||
extern void (*set_text_fg_rgb)(uint32_t fg);
|
||||
extern void (*set_text_bg_rgb)(uint32_t bg);
|
||||
extern void (*set_text_fg_default)(void);
|
||||
extern void (*set_text_bg_default)(void);
|
||||
extern bool (*scroll_disable)(void);
|
||||
extern void (*scroll_enable)(void);
|
||||
extern void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
|
||||
extern void (*term_scroll)(void);
|
||||
extern void (*term_revscroll)(void);
|
||||
extern void (*term_swap_palette)(void);
|
||||
extern void (*term_save_state)(void);
|
||||
extern void (*term_restore_state)(void);
|
||||
|
||||
extern void (*term_double_buffer_flush)(void);
|
||||
|
||||
extern uint64_t (*term_context_size)(void);
|
||||
extern void (*term_context_save)(uint64_t ptr);
|
||||
extern void (*term_context_restore)(uint64_t ptr);
|
||||
extern void (*term_full_refresh)(void);
|
||||
|
||||
#define TERM_CB_DEC 10
|
||||
#define TERM_CB_BELL 20
|
||||
#define TERM_CB_PRIVATE_ID 30
|
||||
#define TERM_CB_STATUS_REPORT 40
|
||||
#define TERM_CB_POS_REPORT 50
|
||||
#define TERM_CB_KBD_LEDS 60
|
||||
#define TERM_CB_MODE 70
|
||||
#define TERM_CB_LINUX 80
|
||||
extern struct term_context *term;
|
||||
|
||||
#define TERM_CTX_SIZE ((uint64_t)(-1))
|
||||
#define TERM_CTX_SAVE ((uint64_t)(-2))
|
||||
#define TERM_CTX_RESTORE ((uint64_t)(-3))
|
||||
#define TERM_FULL_REFRESH ((uint64_t)(-4))
|
||||
|
||||
extern uint64_t term_arg;
|
||||
extern void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
|
||||
extern bool term_autoflush;
|
||||
|
||||
inline void reset_term(void) {
|
||||
term_autoflush = true;
|
||||
enable_cursor();
|
||||
term->autoflush = true;
|
||||
term->enable_cursor(term);
|
||||
print("\e[2J\e[H");
|
||||
term_double_buffer_flush();
|
||||
term->double_buffer_flush(term);
|
||||
}
|
||||
|
||||
inline void set_cursor_pos_helper(size_t x, size_t y) {
|
||||
print("\e[%u;%uH", (int)y + 1, (int)x + 1);
|
||||
}
|
||||
|
||||
void term_fallback(void);
|
||||
void term_vbe(char *config, size_t width, size_t height);
|
||||
void term_textmode(void);
|
||||
|
||||
void _term_write(uint64_t buf, uint64_t count);
|
||||
|
||||
#endif
|
||||
|
@ -43,6 +43,7 @@ SECTIONS
|
||||
term_write = .;
|
||||
term_backend = .;
|
||||
term_fallback = .;
|
||||
term = .;
|
||||
stage3_addr = .;
|
||||
#else
|
||||
#ifdef LINKER_NOS2MAP
|
||||
|
112
common/menu.c
112
common/menu.c
@ -154,17 +154,17 @@ static void putchar_tokencol(int type, char c) {
|
||||
static bool editor_no_term_reset = false;
|
||||
|
||||
char *config_entry_editor(const char *title, const char *orig_entry) {
|
||||
term_autoflush = false;
|
||||
term->autoflush = false;
|
||||
|
||||
enable_cursor();
|
||||
term->enable_cursor(term);
|
||||
|
||||
print("\e[2J\e[H");
|
||||
|
||||
size_t cursor_offset = 0;
|
||||
size_t entry_size = strlen(orig_entry);
|
||||
size_t _window_size = term_rows - 8;
|
||||
size_t _window_size = term->rows - 8;
|
||||
size_t window_offset = 0;
|
||||
size_t line_size = term_cols - 2;
|
||||
size_t line_size = term->cols - 2;
|
||||
|
||||
bool display_overflow_error = false;
|
||||
|
||||
@ -200,12 +200,12 @@ refresh:
|
||||
invalid_syntax = false;
|
||||
|
||||
print("\e[2J\e[H");
|
||||
disable_cursor();
|
||||
term->disable_cursor(term);
|
||||
{
|
||||
size_t x, y;
|
||||
print("\n");
|
||||
get_cursor_pos(&x, &y);
|
||||
set_cursor_pos_helper(term_cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y);
|
||||
print("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding);
|
||||
print("\n\n");
|
||||
}
|
||||
@ -213,7 +213,7 @@ refresh:
|
||||
print(" \e[32mESC\e[0m Discard and Exit \e[32mF10\e[0m Boot\n\n");
|
||||
|
||||
print(serial ? "/" : "\xda");
|
||||
for (size_t i = 0; i < term_cols - 2; i++) {
|
||||
for (size_t i = 0; i < term->cols - 2; i++) {
|
||||
switch (i) {
|
||||
case 1: case 2: case 3:
|
||||
if (window_offset > 0) {
|
||||
@ -223,7 +223,7 @@ refresh:
|
||||
// FALLTHRU
|
||||
default: {
|
||||
size_t title_length = strlen(title);
|
||||
if (i == (term_cols / 2) - DIV_ROUNDUP(title_length, 2) - 1) {
|
||||
if (i == (term->cols / 2) - DIV_ROUNDUP(title_length, 2) - 1) {
|
||||
print("%s", title);
|
||||
i += title_length - 1;
|
||||
} else {
|
||||
@ -234,7 +234,7 @@ refresh:
|
||||
}
|
||||
size_t tmpx, tmpy;
|
||||
|
||||
get_cursor_pos(&tmpx, &tmpy);
|
||||
term->get_cursor_pos(term, &tmpx, &tmpy);
|
||||
print(serial ? "\\" : "\xbf");
|
||||
set_cursor_pos_helper(0, tmpy + 1);
|
||||
print(serial ? "|" : "\xb3");
|
||||
@ -250,20 +250,20 @@ refresh:
|
||||
&& current_line < window_offset + window_size
|
||||
&& current_line >= window_offset) {
|
||||
size_t x, y;
|
||||
get_cursor_pos(&x, &y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
if (i == cursor_offset) {
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
printed_cursor = true;
|
||||
}
|
||||
set_cursor_pos_helper(term_cols - 1, y);
|
||||
set_cursor_pos_helper(term->cols - 1, y);
|
||||
if (current_line == window_offset + window_size - 1) {
|
||||
get_cursor_pos(&tmpx, &tmpy);
|
||||
term->get_cursor_pos(term, &tmpx, &tmpy);
|
||||
print(serial ? "|" : "\xb3");
|
||||
set_cursor_pos_helper(0, tmpy + 1);
|
||||
print(serial ? "\\" : "\xc0");
|
||||
} else {
|
||||
get_cursor_pos(&tmpx, &tmpy);
|
||||
term->get_cursor_pos(term, &tmpx, &tmpy);
|
||||
print(serial ? "|" : "\xb3");
|
||||
set_cursor_pos_helper(0, tmpy + 1);
|
||||
print(serial ? "|" : "\xb3");
|
||||
@ -281,7 +281,7 @@ refresh:
|
||||
if (current_line < window_offset + window_size
|
||||
&& current_line >= window_offset) {
|
||||
if (i == cursor_offset) {
|
||||
get_cursor_pos(&cursor_x, &cursor_y);
|
||||
term->get_cursor_pos(term, &cursor_x, &cursor_y);
|
||||
printed_cursor = true;
|
||||
}
|
||||
if (syntax_highlighting_enabled) {
|
||||
@ -291,8 +291,8 @@ refresh:
|
||||
}
|
||||
printed_early = true;
|
||||
size_t x, y;
|
||||
get_cursor_pos(&x, &y);
|
||||
if (y == term_rows - 3) {
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
if (y == term->rows - 3) {
|
||||
print(serial ? ">" : "\x1a");
|
||||
set_cursor_pos_helper(0, y + 1);
|
||||
print(serial ? "\\" : "\xc0");
|
||||
@ -309,7 +309,7 @@ refresh:
|
||||
&& current_line < window_offset + window_size
|
||||
&& current_line >= window_offset
|
||||
&& !printed_cursor) {
|
||||
get_cursor_pos(&cursor_x, &cursor_y);
|
||||
term->get_cursor_pos(term, &cursor_x, &cursor_y);
|
||||
printed_cursor = true;
|
||||
}
|
||||
|
||||
@ -356,35 +356,35 @@ refresh:
|
||||
// syntax error alert
|
||||
if (validation_enabled) {
|
||||
size_t x, y;
|
||||
get_cursor_pos(&x, &y);
|
||||
set_cursor_pos_helper(0, term_rows-1);
|
||||
scroll_disable();
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
set_cursor_pos_helper(0, term->rows - 1);
|
||||
term->scroll_enabled = false;
|
||||
if (invalid_syntax) {
|
||||
print("\e[31mConfiguration is INVALID.\e[0m");
|
||||
} else {
|
||||
print("\e[32mConfiguration is valid.\e[0m");
|
||||
}
|
||||
scroll_enable();
|
||||
term->scroll_enabled = true;
|
||||
set_cursor_pos_helper(x, y);
|
||||
}
|
||||
|
||||
if (current_line - window_offset < window_size) {
|
||||
size_t x, y;
|
||||
for (size_t i = 0; i < (window_size - (current_line - window_offset)) - 1; i++) {
|
||||
get_cursor_pos(&x, &y);
|
||||
set_cursor_pos_helper(term_cols - 1, y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
set_cursor_pos_helper(term->cols - 1, y);
|
||||
print(serial ? "|" : "\xb3");
|
||||
set_cursor_pos_helper(0, y + 1);
|
||||
print(serial ? "|" : "\xb3");
|
||||
}
|
||||
get_cursor_pos(&x, &y);
|
||||
set_cursor_pos_helper(term_cols - 1, y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
set_cursor_pos_helper(term->cols - 1, y);
|
||||
print(serial ? "|" : "\xb3");
|
||||
set_cursor_pos_helper(0, y + 1);
|
||||
print(serial ? "\\" : "\xc0");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < term_cols - 2; i++) {
|
||||
for (size_t i = 0; i < term->cols - 2; i++) {
|
||||
switch (i) {
|
||||
case 1: case 2: case 3:
|
||||
if (current_line - window_offset >= window_size) {
|
||||
@ -396,22 +396,22 @@ refresh:
|
||||
print(serial ? "-" : "\xc4");
|
||||
}
|
||||
}
|
||||
get_cursor_pos(&tmpx, &tmpy);
|
||||
term->get_cursor_pos(term, &tmpx, &tmpy);
|
||||
print(serial ? "/" : "\xd9");
|
||||
set_cursor_pos_helper(0, tmpy + 1);
|
||||
|
||||
if (display_overflow_error) {
|
||||
scroll_disable();
|
||||
term->scroll_enabled = false;
|
||||
print("\e[31mText buffer not big enough, delete something instead.");
|
||||
scroll_enable();
|
||||
term->scroll_enabled = true;
|
||||
display_overflow_error = false;
|
||||
}
|
||||
|
||||
// Hack to redraw the cursor
|
||||
set_cursor_pos_helper(cursor_x, cursor_y);
|
||||
enable_cursor();
|
||||
term->enable_cursor(term);
|
||||
|
||||
term_double_buffer_flush();
|
||||
term->double_buffer_flush(term);
|
||||
|
||||
int c = getchar();
|
||||
size_t buffer_len = strlen(buffer);
|
||||
@ -689,16 +689,16 @@ noreturn void _menu(bool first_run) {
|
||||
menu_init_term();
|
||||
|
||||
refresh:
|
||||
term_autoflush = false;
|
||||
term->autoflush = false;
|
||||
|
||||
disable_cursor();
|
||||
term->disable_cursor(term);
|
||||
|
||||
print("\e[2J\e[H");
|
||||
{
|
||||
size_t x, y;
|
||||
print("\n");
|
||||
get_cursor_pos(&x, &y);
|
||||
set_cursor_pos_helper(term_cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y);
|
||||
print("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding);
|
||||
print("\n\n\n\n");
|
||||
}
|
||||
@ -707,14 +707,14 @@ refresh:
|
||||
if (quiet) {
|
||||
quiet = false;
|
||||
menu_init_term();
|
||||
term_autoflush = false;
|
||||
disable_cursor();
|
||||
term->autoflush = false;
|
||||
term->disable_cursor(term);
|
||||
}
|
||||
print("Config file %s.\n\n", config_ready ? "contains no valid entries" : "not found");
|
||||
print("For information on the format of Limine config entries, consult CONFIG.md in\n");
|
||||
print("the root of the Limine source repository.\n\n");
|
||||
print("Press a key to enter the Limine console...");
|
||||
term_double_buffer_flush();
|
||||
term->double_buffer_flush(term);
|
||||
getchar();
|
||||
reset_term();
|
||||
console();
|
||||
@ -722,24 +722,24 @@ refresh:
|
||||
|
||||
{ // Draw box around boot menu
|
||||
size_t x, y;
|
||||
get_cursor_pos(&x, &y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
|
||||
print(serial ? "/" : "\xda");
|
||||
for (size_t i = 0; i < term_cols - 2; i++) {
|
||||
for (size_t i = 0; i < term->cols - 2; i++) {
|
||||
print(serial ? "-" : "\xc4");
|
||||
}
|
||||
print(serial ? "\\" : "\xbf");
|
||||
|
||||
for (size_t i = y + 1; i < term_rows - 2; i++) {
|
||||
for (size_t i = y + 1; i < term->rows - 2; i++) {
|
||||
set_cursor_pos_helper(0, i);
|
||||
print(serial ? "|" : "\xb3");
|
||||
set_cursor_pos_helper(term_cols - 1, i);
|
||||
set_cursor_pos_helper(term->cols - 1, i);
|
||||
print(serial ? "|" : "\xb3");
|
||||
}
|
||||
set_cursor_pos_helper(0, term_rows - 2);
|
||||
set_cursor_pos_helper(0, term->rows - 2);
|
||||
|
||||
print(serial ? "\\" : "\xc0");
|
||||
for (size_t i = 0; i < term_cols - 2; i++) {
|
||||
for (size_t i = 0; i < term->cols - 2; i++) {
|
||||
print(serial ? "-" : "\xc4");
|
||||
}
|
||||
print(serial ? "/" : "\xd9");
|
||||
@ -752,7 +752,7 @@ refresh:
|
||||
|
||||
{
|
||||
size_t x, y;
|
||||
get_cursor_pos(&x, &y);
|
||||
term->get_cursor_pos(term, &x, &y);
|
||||
set_cursor_pos_helper(0, 3);
|
||||
if (editor_enabled && selected_menu_entry->sub == NULL) {
|
||||
print(" \e[32mARROWS\e[0m Select \e[32mENTER\e[0m Boot \e[32mE\e[0m Edit");
|
||||
@ -760,7 +760,7 @@ refresh:
|
||||
print(" \e[32mARROWS\e[0m Select \e[32mENTER\e[0m %s",
|
||||
selected_menu_entry->expanded ? "Collapse" : "Expand");
|
||||
}
|
||||
set_cursor_pos_helper(term_cols - 13, 3);
|
||||
set_cursor_pos_helper(term->cols - 13, 3);
|
||||
print("\e[32mC\e[0m Console");
|
||||
set_cursor_pos_helper(x, y);
|
||||
}
|
||||
@ -773,11 +773,11 @@ refresh:
|
||||
if (skip_timeout == false) {
|
||||
print("\n\n");
|
||||
for (size_t i = timeout; i; i--) {
|
||||
set_cursor_pos_helper(0, term_rows - 1);
|
||||
scroll_disable();
|
||||
set_cursor_pos_helper(0, term->rows - 1);
|
||||
term->scroll_enabled = false;
|
||||
print("\e[2K\e[32mBooting automatically in \e[92m%u\e[32m, press any key to stop the countdown...\e[0m", i);
|
||||
scroll_enable();
|
||||
term_double_buffer_flush();
|
||||
term->scroll_enabled = true;
|
||||
term->double_buffer_flush(term);
|
||||
if ((c = pit_sleep_and_quit_on_keypress(1))) {
|
||||
skip_timeout = true;
|
||||
if (quiet) {
|
||||
@ -786,21 +786,21 @@ refresh:
|
||||
goto timeout_aborted;
|
||||
}
|
||||
print("\e[2K");
|
||||
term_double_buffer_flush();
|
||||
term->double_buffer_flush(term);
|
||||
goto timeout_aborted;
|
||||
}
|
||||
}
|
||||
goto autoboot;
|
||||
}
|
||||
|
||||
set_cursor_pos_helper(0, term_rows - 1);
|
||||
set_cursor_pos_helper(0, term->rows - 1);
|
||||
if (selected_menu_entry->comment != NULL) {
|
||||
scroll_disable();
|
||||
term->scroll_enabled = false;
|
||||
print("\e[36m%s\e[0m", selected_menu_entry->comment);
|
||||
scroll_enable();
|
||||
term->scroll_enabled = true;
|
||||
}
|
||||
|
||||
term_double_buffer_flush();
|
||||
term->double_buffer_flush(term);
|
||||
|
||||
for (;;) {
|
||||
c = getchar();
|
||||
|
@ -217,7 +217,7 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) {
|
||||
pmm_free(_ptr, image->size);
|
||||
fclose(image);
|
||||
|
||||
term_deinit();
|
||||
term->deinit(term, pmm_free);
|
||||
|
||||
size_t req_width = 0, req_height = 0, req_bpp = 0;
|
||||
|
||||
|
@ -269,7 +269,7 @@ void limine_term_callback(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
|
||||
static void term_write_shim(uint64_t context, uint64_t buf, uint64_t count) {
|
||||
(void)context;
|
||||
term_write(buf, count);
|
||||
_term_write(buf, count);
|
||||
}
|
||||
|
||||
noreturn void limine_load(char *config, char *cmdline) {
|
||||
@ -697,17 +697,15 @@ FEAT_START
|
||||
|
||||
if (terminal_request->callback != 0) {
|
||||
#if defined (__i386__)
|
||||
term_callback = limine_term_callback;
|
||||
term->callback = (void *)limine_term_callback;
|
||||
limine_term_callback_ptr = terminal_request->callback;
|
||||
#elif defined (__x86_64__) || defined (__aarch64__)
|
||||
term_callback = (void *)terminal_request->callback;
|
||||
term->callback = (void *)terminal_request->callback;
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
term_arg = reported_addr(terminal);
|
||||
|
||||
#if defined (__i386__)
|
||||
if (limine_rt_stack == NULL) {
|
||||
limine_rt_stack = ext_mem_alloc(16384) + 16384;
|
||||
@ -723,8 +721,8 @@ FEAT_START
|
||||
|
||||
term_fb_ptr = &terminal->framebuffer;
|
||||
|
||||
terminal->columns = term_cols;
|
||||
terminal->rows = term_rows;
|
||||
terminal->columns = term->cols;
|
||||
terminal->rows = term->rows;
|
||||
|
||||
uint64_t *term_list = ext_mem_alloc(1 * sizeof(uint64_t));
|
||||
term_list[0] = reported_addr(terminal);
|
||||
@ -737,7 +735,7 @@ FEAT_START
|
||||
goto skip_fb_init;
|
||||
FEAT_END
|
||||
|
||||
term_deinit();
|
||||
term->deinit(term, pmm_free);
|
||||
|
||||
if (!fb_init(&fb, req_width, req_height, req_bpp)) {
|
||||
panic(true, "limine: Could not acquire framebuffer");
|
||||
@ -995,9 +993,9 @@ FEAT_START
|
||||
FEAT_END
|
||||
|
||||
// Clear terminal for kernels that will use the Limine terminal
|
||||
term_write((uint64_t)(uintptr_t)("\e[2J\e[H"), 7);
|
||||
term_write(term, "\e[2J\e[H", 7);
|
||||
|
||||
term_runtime = true;
|
||||
term->in_bootloader = false;
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
#if defined (BIOS)
|
||||
|
@ -495,7 +495,7 @@ noreturn void linux_load(char *config, char *cmdline) {
|
||||
// Video
|
||||
///////////////////////////////////////
|
||||
|
||||
term_deinit();
|
||||
term->deinit(term, pmm_free);
|
||||
|
||||
struct screen_info *screen_info = &boot_params->screen_info;
|
||||
|
||||
|
@ -302,7 +302,7 @@ noreturn void multiboot1_load(char *config, char *cmdline) {
|
||||
multiboot1_info->bootloader_name = (uint32_t)(size_t)lowmem_bootname - mb1_info_slide;
|
||||
multiboot1_info->flags |= (1 << 9);
|
||||
|
||||
term_deinit();
|
||||
term->deinit(term, pmm_free);
|
||||
|
||||
if (header.flags & (1 << 2)) {
|
||||
size_t req_width = header.fb_width;
|
||||
|
@ -505,7 +505,7 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
|
||||
tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
|
||||
tag->common.size = sizeof(struct multiboot_tag_framebuffer);
|
||||
|
||||
term_deinit();
|
||||
term->deinit(term, pmm_free);
|
||||
|
||||
if (fbtag) {
|
||||
size_t req_width = fbtag->width;
|
||||
|
Loading…
Reference in New Issue
Block a user