Просмотр исходного кода

new: 初步完成了textui的基本显示功能

fslongjin 2 лет назад
Родитель
Сommit
17d5fea2cf

+ 4 - 1
.vscode/settings.json

@@ -117,7 +117,10 @@
         "sched.h": "c",
         "preempt.h": "c",
         "softirq.h": "c",
-        "screen_manager.h": "c"
+        "screen_manager.h": "c",
+        "textui.h": "c",
+        "atomic.h": "c",
+        "uart.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 33 - 82
kernel/common/printk.c

@@ -13,10 +13,11 @@
 #include <driver/video/video.h>
 #include "math.h"
 #include <common/string.h>
+#include <lib/libUI/textui.h>
 
 struct printk_screen_info pos;
 
-static spinlock_t printk_lock;
+static spinlock_t printk_lock={1};
 static bool sw_show_scroll_animation = false; // 显示换行动画的开关
 
 /**
@@ -662,49 +663,6 @@ static char *write_float_point_num(char *str, double num, int field_width, int p
     return str;
 }
 
-static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, unsigned int BKcolor, unsigned char font)
-{
-    /**
-     * @brief 在屏幕上指定位置打印字符
-     *
-     * @param fb 帧缓存线性地址
-     * @param Xsize 行分辨率
-     * @param x 左上角列像素点位置
-     * @param y 左上角行像素点位置
-     * @param FRcolor 字体颜色
-     * @param BKcolor 背景颜色
-     * @param font 字符的bitmap
-     */
-
-    //#if DEBUG
-    uart_send(COM1, font);
-    //#endif
-
-    unsigned char *font_ptr = font_ascii[font];
-    unsigned int *addr;
-
-    int testbit; // 用来测试某位是背景还是字体本身
-
-    for (int i = 0; i < pos.char_size_y; ++i)
-    {
-        // 计算出帧缓冲区的地址
-        addr = fb + Xsize * (y + i) + x;
-        testbit = (1 << (pos.char_size_x + 1));
-        for (int j = 0; j < pos.char_size_x; ++j)
-        {
-            //从左往右逐个测试相应位
-            testbit >>= 1;
-            if (*font_ptr & testbit)
-                *addr = FRcolor; // 字,显示前景色
-            else
-                *addr = BKcolor; // 背景色
-
-            ++addr;
-        }
-        ++font_ptr;
-    }
-}
-
 /**
  * @brief 格式化打印字符串
  *
@@ -714,10 +672,7 @@ static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, uns
  */
 int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...)
 {
-
-    uint64_t rflags = 0; // 加锁后rflags存储到这里
-    spin_lock_irqsave(&printk_lock, rflags);
-
+    
     va_list args;
     va_start(args, fmt);
     char buf[4096]; // vsprintf()的缓冲区
@@ -733,47 +688,43 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
         //输出换行
         if (current == '\n')
         {
-            pos.x = 0;
-            ++pos.y;
-            auto_newline();
-        }
-        else if (current == '\t') // 输出制表符
-        {
-            int space_to_print = 8 - pos.x % 8;
-
-            while (space_to_print--)
-            {
-                putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, ' ');
-                ++pos.x;
-
-                auto_newline();
-            }
-        }
-        else if (current == '\b') // 退格
-        {
-            --pos.x;
-            if (pos.x < 0)
-            {
-                --pos.y;
-                if (pos.y <= 0)
-                    pos.x = pos.y = 0;
-                else
-                    pos.x = pos.max_x;
-            }
-
-            putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, ' ');
 
-            auto_newline();
+            textui_putchar(current);
         }
+        // else if (current == '\t') // 输出制表符
+        // {
+        //     int space_to_print = 8 - pos.x % 8;
+
+        //     while (space_to_print--)
+        //     {
+        //         textui_putchar(' ');
+        //         ++pos.x;
+        //     }
+        // }
+        // else if (current == '\b') // 退格
+        // {
+        //     --pos.x;
+        //     if (pos.x < 0)
+        //     {
+        //         --pos.y;
+        //         if (pos.y <= 0)
+        //             pos.x = pos.y = 0;
+        //         else
+        //             pos.x = pos.max_x;
+        //     }
+
+        //     textui_putchar(' ');
+
+        //     auto_newline();
+        // }
         else
         {
-            putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, current);
-            ++pos.x;
-            auto_newline();
+            if (current != '\0')
+                textui_putchar(current);
         }
     }
 
-    spin_unlock_irqrestore(&printk_lock, rflags);
+    // spin_unlock_irqrestore(&printk_lock, rflags);
     return i;
 }
 

+ 5 - 2
kernel/lib/libUI/Makefile

@@ -1,5 +1,5 @@
 
-all: screen_manager.o textui.o
+all: screen_manager.o textui.o textui-render.o
 
 CFLAGS += -I .
 
@@ -7,4 +7,7 @@ screen_manager.o: screen_manager.c
 	gcc $(CFLAGS) -c screen_manager.c -o screen_manager.o
 
 textui.o: textui.c
-	gcc $(CFLAGS) -c textui.c -o textui.o
+	gcc $(CFLAGS) -c textui.c -o textui.o
+
+textui-render.o: textui-render.c
+	gcc $(CFLAGS) -c textui-render.c -o textui-render.o

+ 3 - 5
kernel/lib/libUI/screen_manager.c

@@ -8,8 +8,6 @@
 #include <driver/uart/uart.h>
 #include <driver/video/video.h>
 
-
-
 extern struct scm_buffer_info_t video_frame_buffer_info;
 static struct List scm_framework_list;
 static spinlock_t scm_register_lock;                   // 框架注册锁
@@ -32,7 +30,7 @@ static struct scm_buffer_info_t *__create_buffer(uint64_t type)
 
     struct scm_buffer_info_t *buf = (struct scm_buffer_info_t *)kmalloc(sizeof(struct scm_buffer_info_t), 0);
     if (buf == NULL)
-        return (void*)-ENOMEM;
+        return (void *)-ENOMEM;
     memset(buf, 0, sizeof(struct scm_buffer_info_t));
     buf->bit_depth = video_frame_buffer_info.bit_depth;
     buf->flags = SCM_BF_DB;
@@ -52,7 +50,7 @@ static struct scm_buffer_info_t *__create_buffer(uint64_t type)
     return buf;
 failed:;
     kfree(buf);
-    return (void*)-ENOMEM;
+    return (void *)-ENOMEM;
 }
 
 /**
@@ -106,7 +104,7 @@ static int __check_ui_param(const char *name, const uint8_t type, const struct s
 {
     if (name == NULL)
         return -EINVAL;
-    if (!(type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT))
+    if ((type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT) == 0)
         return -EINVAL;
     if (ops == NULL)
         return -EINVAL;

+ 3 - 3
kernel/lib/libUI/screen_manager.h

@@ -9,8 +9,8 @@
 #define SCM_BF_PIXEL (1 << 3) // 使用图像模式
 
 // ui框架类型
-#define SCM_FRAMWORK_TYPE_TEXT 0
-#define SCM_FRAMWORK_TYPE_GUI 1
+#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
+#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
 
 /**
  * @brief 帧缓冲区信息结构体
@@ -47,7 +47,7 @@ struct scm_ui_framework_t
     uint8_t type;
     struct scm_ui_framework_operations_t *ui_ops;
     struct scm_buffer_info_t *buf;
-} __attribute__((aligned(sizeof(uint64_t))));
+};
 
 /**
  * @brief 初始化屏幕管理模块

+ 155 - 0
kernel/lib/libUI/textui-render.c

@@ -0,0 +1,155 @@
+#include "textui.h"
+#include <driver/uart/uart.h>
+
+#define WHITE 0x00ffffff  //白
+#define BLACK 0x00000000  //黑
+#define RED 0x00ff0000    //红
+#define ORANGE 0x00ff8000 //橙
+#define YELLOW 0x00ffff00 //黄
+#define GREEN 0x0000ff00  //绿
+#define BLUE 0x000000ff   //蓝
+#define INDIGO 0x0000ffff //靛
+#define PURPLE 0x008000ff //紫
+
+// 根据rgb计算出最终的颜色值
+#define calculate_color(r, g, b) ((((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) & 0x00ffffff)
+
+extern struct scm_ui_framework_t textui_framework;
+
+static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character);
+
+/**
+ * @brief 重新渲染整个虚拟行
+ *
+ * @param window 窗口结构体
+ * @param vline_id 虚拟行号
+ * @return int 错误码
+ */
+int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id)
+{
+    if (textui_is_chromatic(window->flags))
+        return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
+    else
+        return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
+}
+
+int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count)
+{
+    char bufff[16] = {0};
+    // uart_send_str(COM1, "  BEGIN  ");
+    for (int i = start; i < window->vlines_num && count > 0; ++i, --count)
+    {
+        // sprintk(bufff, "[ 1fresh: %d ] ", i);
+        // uart_send_str(COM1, bufff);
+        textui_refresh_vline(window, i);
+    }
+    start = 0;
+    while (count>0)
+    {
+        // sprintk(bufff, "[ 2fresh: %d ] ", start);
+        // uart_send_str(COM1, bufff);
+        // sprintk(bufff, " index=%d ", (window->vlines.chromatic)[start].index);
+        // uart_send_str(COM1, bufff);
+        textui_refresh_vline(window, start);
+        ++start;
+        --count;
+    }
+    // uart_send_str(COM1, "  END  ");
+    return 0;
+}
+
+/**
+ * @brief 刷新某个虚拟行的连续n个字符对象
+ *
+ * @param window 窗口结构体
+ * @param vline_id 虚拟行号
+ * @param start 起始字符号
+ * @param count 要刷新的字符数量
+ * @return int 错误码
+ */
+int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count)
+{
+    if (window->id != __textui_get_current_window_id())
+        return 0;
+    // 判断虚拟行参数是否合法
+    if (unlikely(vline_id >= window->vlines_num && (start + count) > window->chars_per_line))
+        return -EINVAL;
+
+    // 计算虚拟行对应的真实行
+    int actual_line_id = (int)vline_id - window->top_vline;
+    if (actual_line_id < 0)
+        actual_line_id += __textui_get_actual_lines();
+    // 判断真实行id是否合理
+    if (unlikely(actual_line_id < 0 || actual_line_id >= __textui_get_actual_lines()))
+        return 0;
+
+    // 若是彩色像素模式
+    if (textui_is_chromatic(window->flags))
+    {
+        struct textui_vline_chromatic_t *vline = &(window->vlines.chromatic)[vline_id];
+        for (int i = 0; i < count; ++i)
+        {
+
+            __textui_render_chromatic(actual_line_id, start + i, &vline->chars[start + i]);
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * @brief 渲染彩色字符
+ *
+ * @param actual_line 真实行的行号
+ * @param index 列号
+ * @param character 要渲染的字符
+ */
+static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character)
+{
+    /**
+     * @brief 在屏幕上指定位置打印字符
+     *
+     * @param x 左上角列像素点位置
+     * @param y 左上角行像素点位置
+     * @param FRcolor 字体颜色
+     * @param BKcolor 背景颜色
+     * @param font 字符的bitmap
+     */
+
+    // #if DEBUG
+    // uart_send(COM1, font);
+    // #endif
+
+    unsigned char *font_ptr = font_ascii[(uint8_t)character->c];
+    unsigned int *addr;
+    uint32_t *fb = (uint32_t *)textui_framework.buf->vaddr;
+    // uint32_t FRcolor = YELLOW;
+    uint32_t FRcolor = calculate_color(character->Fr, character->Fg, character->Fb);
+    // uint32_t BKcolor = BLACK;
+    uint32_t BKcolor = calculate_color(character->Br, character->Bg, character->Bb);
+
+    uint32_t x = index * TEXTUI_CHAR_WIDTH;
+    uint32_t y = actual_line * TEXTUI_CHAR_HEIGHT;
+
+    int testbit; // 用来测试某位是背景还是字体本身
+
+    for (int i = 0; i < TEXTUI_CHAR_HEIGHT; ++i)
+    {
+        // 计算出帧缓冲区的地址
+        addr = (uint32_t *)(fb + textui_framework.buf->width * (y + i) + x);
+
+        testbit = (1 << (TEXTUI_CHAR_WIDTH + 1));
+        for (int j = 0; j < TEXTUI_CHAR_WIDTH; ++j)
+        {
+            // 从左往右逐个测试相应位
+            testbit >>= 1;
+            if (*font_ptr & testbit)
+                *addr = FRcolor; // 字,显示前景色
+            else
+                *addr = BKcolor; // 背景色
+
+            ++addr;
+        }
+        ++font_ptr;
+    }
+}

+ 260 - 6
kernel/lib/libUI/textui.c

@@ -4,31 +4,93 @@
 #include "driver/uart/uart.h"
 #include <common/string.h>
 #include <common/printk.h>
+#include <common/atomic.h>
 
 struct scm_ui_framework_t textui_framework;
+static spinlock_t __window_id_lock = {1};
+static uint32_t __window_max_id = 0;
+
+// 暂时初始化16080个初始字符对象以及67个虚拟行对象
+#define INITIAL_CHARS 16080
+#define INITIAL_VLINES (int)(1080 / 16)
+static struct textui_char_chromatic_t __initial_chars[INITIAL_CHARS] = {0};
+static struct textui_vline_chromatic_t __initial_vlines[INITIAL_VLINES] = {0};
+static struct textui_window_t __initial_window = {0}; // 初始窗口
+static struct textui_private_info_t __private_info = {0};
+static struct List __windows_list;
+
+/**
+ * @brief 初始化window对象
+ *
+ * @param window 窗口对象
+ * @param flags 标志位
+ * @param vlines_num 虚拟行的总数
+ * @param vlines_ptr 虚拟行数组指针
+ * @param cperline 每行最大的字符数
+ */
+static int __textui_init_window(struct textui_window_t *window, uint8_t flags, uint16_t vlines_num, void *vlines_ptr, uint16_t cperline)
+{
+    memset((window), 0, sizeof(struct textui_window_t));
+    list_init(&(window)->list);
+    window->lock.lock = 1;
+    spin_lock(&__window_id_lock);
+    window->id = __window_max_id++;
+    spin_unlock(&__window_id_lock);
+    window->flags = flags;
+    window->vlines_num = vlines_num;
+    window->vlines_used = 1;
+    window->top_vline = 0;
+    window->vline_operating = 0;
+    window->chars_per_line = cperline;
+    if (textui_is_chromatic(flags))
+        window->vlines.chromatic = vlines_ptr;
+    else
+        window->vlines.normal = vlines_ptr;
+    list_add(&__windows_list, &(window)->list);
+}
+
+/**
+ * @brief 初始化虚拟行对象
+ *
+ * @param vline 虚拟行对象指针
+ * @param chars_ptr 字符对象数组指针
+ */
+#define __textui_init_vline(vline, chars_ptr)                      \
+    do                                                             \
+    {                                                              \
+        memset(vline, 0, sizeof(struct textui_vline_chromatic_t)); \
+        (vline)->index = 0;                                        \
+        (vline)->chars = chars_ptr;                                \
+    } while (0)
 
 int textui_install_handler(struct scm_buffer_info_t *buf)
 {
-    return printk_init(buf);
+    // return printk_init(buf);
+    uart_send_str(COM1, "textui_install_handler");
+    return 0;
 }
 
 int textui_uninstall_handler(void *args)
 {
+    return 0;
 }
 
 int textui_enable_handler(void *args)
 {
+    uart_send_str(COM1, "textui_enable_handler");
+    return 0;
 }
 
 int textui_disable_handler(void *args)
 {
+    return 0;
 }
 
 int textui_change_handler(struct scm_buffer_info_t *buf)
 {
-    memcpy((void*)buf->vaddr, (void*)(textui_framework.buf->vaddr), textui_framework.buf->size);
+    memcpy((void *)buf->vaddr, (void *)(textui_framework.buf->vaddr), textui_framework.buf->size);
     textui_framework.buf = buf;
-    set_pos_VBE_FB_addr((uint*)buf->vaddr);
+    set_pos_VBE_FB_addr((uint *)buf->vaddr);
     return 0;
 }
 
@@ -41,6 +103,172 @@ struct scm_ui_framework_operations_t textui_ops =
         .disable = &textui_disable_handler,
 };
 
+/**
+ * @brief 获取textui的帧缓冲区能容纳的内容的行数
+ *
+ * @return uint16_t
+ */
+uint16_t __textui_get_actual_lines()
+{
+    return __private_info.actual_line;
+}
+
+/**
+ * @brief 获取当前渲染的窗口的id
+ *
+ * @return uint16_t
+ */
+uint32_t __textui_get_current_window_id()
+{
+    return __private_info.current_window->id;
+}
+
+/**
+ * @brief 插入换行
+ *
+ * @param window 窗口结构体
+ * @param vline_id 虚拟行号
+ * @return int
+ */
+static int __textui_new_line(struct textui_window_t *window, uint16_t vline_id)
+{
+    // todo: 支持在两个虚拟行之间插入一个新行
+
+    ++window->vline_operating;
+
+    if (unlikely(window->vline_operating == window->vlines_num))
+        window->vline_operating = 0;
+    struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
+    memset(vline->chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
+    vline->index = 0;
+
+    if (likely(window->vlines_used == window->vlines_num)) // 需要滚动屏幕
+    {
+        // uart_send_str(COM1, " scroll, top vline= ");
+        ++window->top_vline;
+        // uart_send(COM1, '0' + window->top_vline);
+        if (unlikely(window->top_vline >= window->vlines_num))
+            window->top_vline = 0;
+
+        // int delta = ABS((int)window->vline_operating - (int)window->top_vline);
+        // 刷新所有行
+        textui_refresh_vlines(window, window->top_vline, window->vlines_num);
+    }
+    else
+        ++window->vlines_used;
+
+    return 0;
+}
+static int __textui_putchar_window(struct textui_window_t *window, uint16_t character)
+{
+    if (textui_is_chromatic(window->flags)) // 启用彩色字符
+    {
+        struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
+
+        vline->chars[vline->index].c = character;
+        vline->chars[vline->index].Fr = 0xff;
+        vline->chars[vline->index].Fg = 0xff;
+        vline->chars[vline->index].Fb = 0xff;
+        vline->chars[vline->index].Br = 0;
+        vline->chars[vline->index].Bg = 0;
+        vline->chars[vline->index].Bb = 0;
+        ++vline->index;
+        textui_refresh_characters(window, window->vline_operating, vline->index - 1, 1);
+        // 换行
+        if (vline->index >= window->chars_per_line)
+        {
+            __textui_new_line(window, window->vline_operating);
+        }
+    }
+    else
+    {
+        // todo: 支持纯文本字符
+        while (1)
+            pause();
+    }
+    return 0;
+}
+/**
+ * @brief 在指定窗口上输出一个字符
+ *
+ * @param window 窗口
+ * @param character 字符
+ * @return int
+ */
+int textui_putchar_window(struct textui_window_t *window, uint16_t character)
+{
+    if (unlikely(character == '\0'))
+        return 0;
+    if (!textui_is_chromatic(window->flags)) // 暂不支持纯文本窗口
+        return 0;
+    
+    uint64_t rflags = 0; // 加锁后rflags存储到这里
+    spin_lock_irqsave(&window->lock, rflags);
+    uart_send(COM1, character);
+    if (unlikely(character == '\n'))
+    {
+        __textui_new_line(window, window->vline_operating);
+        spin_unlock_irqrestore(&window->lock, rflags);
+        return 0;
+    }
+    else if (character == '\t') // 输出制表符
+    {
+        int space_to_print = 8 - window->vlines.chromatic[window->vline_operating].index % 8;
+
+        while (space_to_print--)
+        {
+            __textui_putchar_window(window, ' ');
+        }
+    }
+    else if (character == '\b') // 退格
+    {
+
+        --window->vlines.chromatic[window->vline_operating].index;
+        {
+            uint16_t tmp = window->vlines.chromatic[window->vline_operating].index;
+            window->vlines.chromatic[window->vline_operating].chars[tmp].c = ' ';
+            textui_refresh_characters(window, window->vline_operating, tmp, 1);
+        }
+
+        // 需要向上缩一行
+        if (window->vlines.chromatic[window->vline_operating].index < 0)
+        {
+            window->vlines.chromatic[window->vline_operating].index = 0;
+            memset(window->vlines.chromatic[window->vline_operating].chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
+            --window->vline_operating;
+            if (unlikely(window->vline_operating < 0))
+                window->vline_operating = window->vlines_num - 1;
+
+            // 考虑是否向上滚动
+            if (likely(window->vlines_used >= __private_info.actual_line))
+            {
+                --window->top_vline;
+                if (unlikely(window->top_vline < 0))
+                    window->top_vline = window->vlines_num - 1;
+            }
+            --window->vlines_used;
+            textui_refresh_vlines(window, window->top_vline, __private_info.actual_line);
+        }
+    }
+    else
+        __textui_putchar_window(window, character);
+
+    spin_unlock_irqrestore(&window->lock, rflags);
+    return 0;
+}
+
+/**
+ * @brief 在默认窗口上输出一个字符
+ *
+ * @param character 字符
+ * @return int
+ */
+int textui_putchar(uint16_t character)
+{
+    
+    return textui_putchar_window(__private_info.default_window, character);
+}
+
 /**
  * @brief 初始化text ui框架
  *
@@ -48,14 +276,20 @@ struct scm_ui_framework_operations_t textui_ops =
  */
 int textui_init()
 {
-    memset(&textui_framework, 0, sizeof(textui_framework));
+    spin_init(&__window_id_lock);
+    __window_max_id = 0;
+    list_init(&__windows_list);
+    memset(&textui_framework, 0, sizeof(struct scm_ui_framework_t));
+    memset(&__private_info, 0, sizeof(struct textui_private_info_t));
+
     io_mfence();
     char name[] = "textUI";
     strcpy(textui_framework.name, name);
 
     textui_framework.ui_ops = &textui_ops;
-    textui_framework.type = SCM_FRAMWORK_TYPE_TEXT;
-    uart_send_str(COM1, "12121");
+    textui_framework.type = 0;
+
+    // 注册框架到屏幕管理器
     int retval = scm_register(&textui_framework);
     if (retval != 0)
     {
@@ -63,6 +297,26 @@ int textui_init()
         while (1)
             pause();
     }
+
+    uint16_t chars_per_vline = textui_framework.buf->width / TEXTUI_CHAR_WIDTH;
+    uint16_t total_vlines = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
+    int cnt = chars_per_vline * total_vlines;
+
+    struct textui_vline_chromatic_t *vl_ptr = __initial_vlines;
+    struct textui_char_chromatic_t *ch_ptr = __initial_chars;
+
+    // 初始化虚拟行
+    for (int i = 0; i < total_vlines; ++i)
+    {
+        __textui_init_vline((vl_ptr + i), (ch_ptr + i * chars_per_vline));
+    }
+
+    // 初始化窗口
+    __textui_init_window((&__initial_window), TEXTUI_WF_CHROMATIC, total_vlines, __initial_vlines, chars_per_vline);
+    __private_info.current_window = &__initial_window;
+    __private_info.default_window = &__initial_window;
+    __private_info.actual_line = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
+
     uart_send_str(COM1, "text ui initialized");
     return 0;
 }

+ 150 - 2
kernel/lib/libUI/textui.h

@@ -1,8 +1,156 @@
 #pragma once
+#include <common/glib.h>
+#include <common/sys/types.h>
+#include <common/spinlock.h>
+
+// 文本窗口标志位
+// 文本窗口是否为彩色
+#define TEXTUI_WF_CHROMATIC (1 << 0)
+
+// 窗口是否启用彩色字符
+#define textui_is_chromatic(flag) ((flag)&TEXTUI_WF_CHROMATIC)
+
+// 每个字符的宽度和高度(像素)
+#define TEXTUI_CHAR_WIDTH 8
+#define TEXTUI_CHAR_HEIGHT 16
+
+/**
+ * @brief 黑白字符对象
+ *
+ */
+struct textui_char_normal_t
+{
+    char c;
+};
+
+/**
+ * @brief 彩色字符对象
+ *
+ */
+struct textui_char_chromatic_t
+{
+    uint16_t c; // 字符
+    // 前景色
+    uint8_t Fr; // 红
+    uint8_t Fg; // 绿
+    uint8_t Fb; // 蓝
+
+    // 背景色
+    uint8_t Br;
+    uint8_t Bg;
+    uint8_t Bb;
+};
+
+// 注意!!! 请保持vline结构体的大小、成员变量命名相等!
+/**
+ * @brief 单色显示的虚拟行结构体
+ *
+ */
+struct textui_vline_normal_t
+{
+    struct textui_char_normal_t *chars; // 字符对象数组
+    uint16_t index;                     // 当前操作的位置
+};
+
+/**
+ * @brief 彩色显示的虚拟行结构体
+ *
+ */
+struct textui_vline_chromatic_t
+{
+    struct textui_char_chromatic_t *chars;
+    uint16_t index; // 当前操作的位置
+};
+
+/**
+ * @brief textu ui 框架的文本窗口结构体
+ *
+ */
+struct textui_window_t
+{
+    struct List list;
+
+    uint32_t id;          // 窗口id
+    uint16_t vlines_num;  // 虚拟行总数
+    uint16_t vlines_used; // 当前已经使用了的虚拟行总数
+
+    // 指向虚拟行的数组的指针(二选一)
+    union
+    {
+        struct textui_vline_normal_t *normal;
+        struct textui_vline_chromatic_t *chromatic;
+    } vlines;
+
+    uint16_t top_vline;       // 位于最顶上的那一个虚拟行的行号
+    uint16_t vline_operating; // 正在操作的vline
+    uint16_t chars_per_line;  // 每行最大容纳的字符数
+    uint8_t flags;            // 窗口flag
+    spinlock_t lock;          // 窗口操作锁
+};
+
+struct textui_private_info_t
+{
+    uint16_t actual_line;                   // 真实行的数量
+    struct textui_window_t *current_window; // 当前的主窗口
+    struct textui_window_t *default_window; // 默认print到的窗口
+};
+
+/**
+ * @brief 重新渲染整个虚拟行
+ *
+ * @param window 窗口结构体
+ * @param vline_id 虚拟行号
+ * @return int 错误码
+ */
+int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id);
+
+int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count);
+
+/**
+ * @brief 刷新某个虚拟行的连续n个字符对象
+ *
+ * @param window 窗口结构体
+ * @param vline_id 虚拟行号
+ * @param start 起始字符号
+ * @param count 要刷新的字符数量
+ * @return int 错误码
+ */
+int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count);
+
+/**
+ * @brief 在指定窗口上输出一个字符
+ *
+ * @param window 窗口
+ * @param character 字符
+ * @return int
+ */
+int textui_putchar_window(struct textui_window_t *window, uint16_t character);
+
+/**
+ * @brief 在默认窗口上输出一个字符
+ *
+ * @param character 字符
+ * @return int
+ */
+int textui_putchar(uint16_t character);
+
+/**
+ * @brief 获取textui的帧缓冲区能容纳的内容的行数
+ *
+ * @return uint16_t
+ */
+uint16_t __textui_get_actual_lines();
+
+/**
+ * @brief 获取当前渲染的窗口的id
+ *
+ * @return uint16_t
+ */
+uint32_t __textui_get_current_window_id();
 
 /**
  * @brief 初始化text ui框架
- * 
- * @return int 
+ *
+ * @return int
  */
 int textui_init();

+ 4 - 5
kernel/main.c

@@ -76,11 +76,9 @@ void system_initialize()
 
     scm_init();
     textui_init();
+    // kinfo("Kernel Starting...");
 
-    kinfo("Kernel Starting...");
-    
     // 重新加载gdt和idt
-
     ul tss_item_addr = (ul)phys_2_virt(0x7c00);
 
     _stack_start = head_stack_start; // 保存init proc的栈基地址(由于之后取消了地址重映射,因此必须在这里重新保存)
@@ -100,6 +98,7 @@ void system_initialize()
 
     //  初始化内存管理单元
     mm_init();
+    
     // 内存管理单元初始化完毕后,需要立即重新初始化显示驱动。
     // 原因是,系统启动初期,framebuffer被映射到48M地址处,
     // mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃
@@ -161,11 +160,10 @@ void system_initialize()
     io_mfence();
     // current_pcb->preempt_count = 0;
     // kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq());
-
+   
     process_init();
     // 启用double buffer
     scm_enable_double_buffer();
-    
     io_mfence();
 
     // fat32_init();
@@ -175,6 +173,7 @@ void system_initialize()
     // 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行
     apic_timer_init();
     io_mfence();
+     while(1);
 }
 
 //操作系统内核从这里开始执行