4
1
mirror of https://github.com/DragonOS-Community/DragonOS.git synced 2025-06-20 01:46:31 +00:00

Patch refactor scm and textui (#289)

* 重构屏幕管理器和textui框架

* 切换字体为spleen,并增加对字体的抽象

* 修正文档

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
hanjiezhou
2023-08-20 00:19:36 +08:00
committed by GitHub
parent 5db5a5652c
commit abe3a6ea3c
42 changed files with 2005 additions and 1726 deletions

@ -1,7 +1,7 @@
CFLAGS += -I .
kernel_lib_subdirs:= libUI sys
kernel_lib_subdirs:= sys
kernel_lib_objs:= $(shell find ./*.c)

@ -1,13 +0,0 @@
all: screen_manager.o textui.o textui-render.o
CFLAGS += -I .
screen_manager.o: screen_manager.c
$(CC) $(CFLAGS) -c screen_manager.c -o screen_manager.o
textui.o: textui.c
$(CC) $(CFLAGS) -c textui.c -o textui.o
textui-render.o: textui-render.c
$(CC) $(CFLAGS) -c textui-render.c -o textui-render.o

@ -1,351 +0,0 @@
#include "screen_manager.h"
#include <common/kprint.h>
#include <common/spinlock.h>
#include <common/string.h>
#include <driver/multiboot2/multiboot2.h>
#include <driver/uart/uart.h>
#include <driver/video/video.h>
#include <mm/mm.h>
#include <mm/slab.h>
extern struct scm_buffer_info_t video_frame_buffer_info;
static struct List scm_framework_list;
static spinlock_t scm_register_lock; // 框架注册锁
static spinlock_t scm_screen_own_lock = {1}; // 改变屏幕归属者时,需要对该锁加锁
static struct scm_ui_framework_t *__current_framework; // 当前拥有屏幕控制权的框架
static uint32_t scm_ui_max_id = 0;
static bool __scm_alloc_enabled = false; // 允许动态申请内存的标志位
static bool __scm_double_buffer_enabled = false; // 允许双缓冲的标志位
/**
* @brief 创建新的帧缓冲区
*
* @param type 帧缓冲区类型
* @return struct scm_buffer_info_t* 新的帧缓冲区结构体
*/
static struct scm_buffer_info_t *__create_buffer(uint64_t type)
{
// 若未启用双缓冲,则直接返回帧缓冲区
if (unlikely(__scm_double_buffer_enabled == false))
return &video_frame_buffer_info;
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;
memset(buf, 0, sizeof(struct scm_buffer_info_t));
buf->bit_depth = video_frame_buffer_info.bit_depth;
buf->flags = SCM_BF_DB;
if (type & SCM_BF_PIXEL)
buf->flags |= SCM_BF_PIXEL;
else
buf->flags |= SCM_BF_TEXT;
buf->height = video_frame_buffer_info.height;
buf->width = video_frame_buffer_info.width;
buf->size = video_frame_buffer_info.size;
void* buf_vaddr = kzalloc(video_frame_buffer_info.size, 0);
if (buf_vaddr == NULL)
goto failed;
buf->vaddr = buf_vaddr;
return buf;
failed:;
kfree(buf);
return (void *)-ENOMEM;
}
/**
* @brief 销毁双缓冲区
*
* @param buf
* @return int
*/
static int __destroy_buffer(struct scm_buffer_info_t *buf)
{
// 不能销毁帧缓冲区对象
if (unlikely(buf == &video_frame_buffer_info || buf == NULL))
return -EINVAL;
if (unlikely(buf->vaddr == NULL))
return -EINVAL;
if (unlikely(verify_area(buf->vaddr, buf->size) == true))
return -EINVAL;
// 是否双缓冲区
if (buf->flags & SCM_BF_FB)
return -EINVAL;
// 释放内存页
kfree((void*)buf->vaddr);
return 0;
}
/**
* @brief 初始化屏幕管理模块
*
*/
void scm_init()
{
list_init(&scm_framework_list);
spin_init(&scm_register_lock);
spin_init(&scm_screen_own_lock);
io_mfence();
scm_ui_max_id = 0;
__scm_alloc_enabled = false; // 禁用动态申请内存
__scm_double_buffer_enabled = false; // 禁用双缓冲
__current_framework = NULL;
}
/**
* @brief 检查ui框架结构体中的参数设置是否合法
*
* @param name 框架名称
* @param type 框架类型
* @param ops 框架的操作
* @return int
*/
static int __check_ui_param(const char *name, const uint8_t type, const struct scm_ui_framework_operations_t *ops)
{
if (name == NULL)
return -EINVAL;
if ((type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT) == 0)
return -EINVAL;
if (ops == NULL)
return -EINVAL;
if (ops->install == NULL || ops->uninstall == NULL || ops->enable == NULL || ops->disable == NULL ||
ops->change == NULL)
return -EINVAL;
return 0;
}
/**
* @brief 向屏幕管理器注册UI框架动态获取框架对象结构体
*
* @param name 框架名
* @param type 类型
* @param ops 框架操作方法
* @return int
*/
int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops)
{
// 若未启用动态申请,则返回。
if (unlikely(__scm_alloc_enabled == false))
return -EAGAIN;
// 检查参数合法性
if (__check_ui_param(name, type, ops) != 0)
return -EINVAL;
struct scm_ui_framework_t *ui = (struct scm_ui_framework_t *)kmalloc(sizeof(struct scm_ui_framework_t *), 0);
memset(ui, 0, sizeof(struct scm_ui_framework_t));
strncpy(ui->name, name, 15);
ui->type = type;
ui->ui_ops = ops;
list_init(&ui->list);
spin_lock(&scm_register_lock);
ui->id = scm_ui_max_id++;
spin_unlock(&scm_register_lock);
// 创建帧缓冲区
ui->buf = __create_buffer(ui->type);
if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
{
kfree(ui);
return -ENOMEM;
}
// 把ui框架加入链表
list_add(&scm_framework_list, &ui->list);
// 调用ui框架的回调函数以安装ui框架并将其激活
ui->ui_ops->install(ui->buf);
ui->ui_ops->enable(NULL);
if (__current_framework == NULL)
return scm_framework_enable(ui);
return 0;
}
/**
* @brief 向屏幕管理器注册UI框架静态设置的框架对象
*
* @param ui 框架结构体指针
* @return int 错误码
*/
int scm_register(struct scm_ui_framework_t *ui)
{
if (ui == NULL)
return -EINVAL;
if (__check_ui_param(ui->name, ui->type, ui->ui_ops) != 0)
return -EINVAL;
list_init(&ui->list);
spin_lock(&scm_register_lock);
ui->id = scm_ui_max_id++;
spin_unlock(&scm_register_lock);
ui->buf = __create_buffer(ui->type);
if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
return -ENOMEM;
// 把ui框架加入链表
list_add(&scm_framework_list, &ui->list);
// 调用ui框架的回调函数以安装ui框架并将其激活
ui->ui_ops->install(ui->buf);
ui->ui_ops->enable(NULL);
if (__current_framework == NULL)
return scm_framework_enable(ui);
return 0;
}
/**
* @brief 向屏幕管理器卸载UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister(struct scm_ui_framework_t *ui)
{
return 0;
}
/**
* @brief 向屏幕管理器卸载动态创建的UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister_alloc(struct scm_ui_framework_t *ui)
{
return 0;
}
/**
* @brief 允许动态申请内存
*
* @return int
*/
int scm_enable_alloc()
{
__scm_alloc_enabled = true;
return 0;
}
/**
* @brief 允许双缓冲区
*
* @return int
*/
int scm_enable_double_buffer()
{
if (__scm_double_buffer_enabled == true) // 已经开启了双缓冲区了, 直接退出
return 0;
__scm_double_buffer_enabled = true;
if (list_empty(&scm_framework_list)) // scm 框架链表为空
return 0;
// 逐个检查已经注册了的ui框架将其缓冲区更改为双缓冲
struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
// 这里的ptr不需要特判空指针吗 问题1
do
{
if (ptr->buf == &video_frame_buffer_info)
{
c_uart_send_str(COM1, "##init double buffer##\n");
struct scm_buffer_info_t *buf = __create_buffer(SCM_BF_DB | SCM_BF_PIXEL);
if ((uint64_t)(buf) == (uint64_t)-ENOMEM)
return -ENOMEM;
c_uart_send_str(COM1, "##to change double buffer##\n");
if (ptr->ui_ops->change(buf) != 0) // 这里的change回调函数不会是空指针吗 问题2
{
__destroy_buffer(buf);
kfree(buf);
}
}
} while (list_next(&ptr->list) != &scm_framework_list); // 枚举链表的每一个ui框架
// 设置定时刷新的对象
video_set_refresh_target(__current_framework->buf);
// 通知显示驱动,启动双缓冲
video_reinitialize(true);
return 0;
}
/**
* @brief 启用某个ui框架将它的帧缓冲区渲染到屏幕上
*
* @param ui 要启动的ui框架
* @return int 返回码
*/
int scm_framework_enable(struct scm_ui_framework_t *ui)
{
if (ui->buf->vaddr == NULL)
return -EINVAL;
spin_lock(&scm_screen_own_lock);
int retval = 0;
if (__scm_double_buffer_enabled == true)
{
retval = video_set_refresh_target(ui->buf);
if (retval == 0)
__current_framework = ui;
}
else
__current_framework = ui;
ui->ui_ops->enable(NULL);
spin_unlock(&scm_screen_own_lock);
return retval;
}
/**
* @brief 禁用某个ui框架将它的帧缓冲区从屏幕上移除
*
* @param ui 要禁用的ui框架
* @return int 返回码
*/
int scm_framework_disable(struct scm_ui_framework_t *ui)
{
if (ui->buf->vaddr == NULL)
return -EINVAL;
spin_lock(&scm_screen_own_lock);
if (ui != __current_framework)
return -EINVAL;
int retval = 0;
if (__scm_double_buffer_enabled == true)
{
retval = video_set_refresh_target(NULL);
if (retval == 0)
__current_framework = NULL;
}
else
__current_framework = NULL;
ui->ui_ops->disable(NULL);
spin_unlock(&scm_screen_own_lock);
return retval;
}
/**
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
*
*/
void scm_reinit()
{
scm_enable_alloc();
// video_reinitialize(false);
// 遍历当前所有使用帧缓冲区的框架,更新地址
// 逐个检查已经注册了的ui框架将其缓冲区更改为双缓冲
struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
do
{
if (ptr->buf == &video_frame_buffer_info)
{
ptr->ui_ops->change(&video_frame_buffer_info);
}
} while (list_next(&ptr->list) != &scm_framework_list);
return;
}

@ -1,120 +0,0 @@
#pragma once
#include <common/sys/types.h>
#include <common/glib.h>
// 帧缓冲区标志位
#define SCM_BF_FB (1 << 0) // 当前buffer是设备显存中的帧缓冲区
#define SCM_BF_DB (1 << 1) // 当前buffer是双缓冲
#define SCM_BF_TEXT (1 << 2) // 使用文本模式
#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
// ui框架类型
#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
/**
* @brief 帧缓冲区信息结构体
*
*/
struct scm_buffer_info_t
{
uint32_t width; // 帧缓冲区宽度pixel或columns
uint32_t height; // 帧缓冲区高度pixel或lines
uint32_t size; // 帧缓冲区大小bytes
uint32_t bit_depth; // 像素点位深度
uint64_t vaddr; // 帧缓冲区的地址
uint64_t flags; // 帧缓冲区标志位
};
/**
* @brief 上层ui框架应当实现的接口
*
*/
struct scm_ui_framework_operations_t
{
int (*install)(struct scm_buffer_info_t *buf); // 安装ui框架的回调函数
int (*uninstall)(void *args); // 卸载ui框架的回调函数
int (*enable)(void *args); // 启用ui框架的回调函数
int (*disable)(void *args); // 禁用ui框架的回调函数
int (*change)(struct scm_buffer_info_t *buf); // 改变ui框架的帧缓冲区的回调函数
};
struct scm_ui_framework_t
{
struct List list;
uint16_t id;
char name[16];
uint8_t type;
struct scm_ui_framework_operations_t *ui_ops;
struct scm_buffer_info_t *buf;
};
/**
* @brief 初始化屏幕管理模块
*
*/
void scm_init();
/**
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
*
*/
void scm_reinit();
/**
* @brief 向屏幕管理器注册UI框架动态获取框架对象结构体
*
* @param name 框架名
* @param type 类型
* @param ops 框架操作方法
* @return int
*/
int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops);
/**
* @brief 向屏幕管理器注册UI框架静态设置的框架对象
*
* @param ui 框架结构体指针
* @return int 错误码
*/
int scm_register(struct scm_ui_framework_t *ui);
/**
* @brief 向屏幕管理器卸载UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister(struct scm_ui_framework_t *ui);
/**
* @brief 向屏幕管理器卸载动态创建的UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister_alloc(struct scm_ui_framework_t *ui);
/**
* @brief 允许动态申请内存
*
* @return int
*/
int scm_enable_alloc();
/**
* @brief 允许双缓冲区
*
* @return int
*/
int scm_enable_double_buffer();
/**
* @brief 启用某个ui框架将它的帧缓冲区渲染到屏幕上
*
* @param ui 要启动的ui框架
* @return int 返回码
*/
int scm_framework_enable(struct scm_ui_framework_t *ui);
int scm_framework_disable(struct scm_ui_framework_t *ui);

@ -1,154 +0,0 @@
#include "textui.h"
#include <driver/uart/uart.h>
#include <common/errno.h>
#include "screen_manager.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;
extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap8*16大小 ps:位于font.h中
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
*/
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 = character->FRcolor & 0x00ffffff;
uint32_t BKcolor = character->BKcolor & 0x00ffffff;
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;
}
}

@ -1,372 +0,0 @@
#include "textui.h"
#include <driver/uart/uart.h>
#include "screen_manager.h"
#include <common/atomic.h>
#include <common/errno.h>
#include <common/printk.h>
#include <common/string.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;
static spinlock_t change_lock;
// 用于标记是否允许输出到屏幕
static atomic_t __put_window_enable_flag = {1};
/**
* @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);
c_uart_send_str(COM1, "textui_install_handler\n");
return 0;
}
int textui_uninstall_handler(void *args)
{
return 0;
}
int textui_enable_handler(void *args)
{
c_uart_send_str(COM1, "textui_enable_handler\n");
atomic_cmpxchg(&__put_window_enable_flag, 0, 1);
return 0;
}
int textui_disable_handler(void *args)
{
c_uart_send_str(COM1, "textui_disable_handler\n");
atomic_set(&__put_window_enable_flag, 0);
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);
textui_framework.buf = buf;
return 0;
}
struct scm_ui_framework_operations_t textui_ops = {
.install = &textui_install_handler,
.uninstall = &textui_uninstall_handler,
.change = &textui_change_handler,
.enable = &textui_enable_handler,
.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)) // 需要滚动屏幕
{
++window->top_vline;
if (unlikely(window->top_vline >= window->vlines_num))
window->top_vline = 0;
// 刷新所有行
textui_refresh_vlines(window, window->top_vline, window->vlines_num);
}
else
++window->vlines_used;
return 0;
}
/**
* @brief 真正向屏幕上输出字符的函数
*
* @param window
* @param character
* @return int
*/
static int __textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor,
uint32_t BKcolor)
{
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].FRcolor = FRcolor & 0xffffff;
vline->chars[vline->index].BKcolor = BKcolor & 0xffffff;
++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 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
{
if (unlikely(character == '\0'))
return 0;
if (!textui_is_chromatic(window->flags)) // 暂不支持纯文本窗口
return 0;
// uint64_t rflags = 0; // 加锁后rflags存储到这里
spin_lock_no_preempt(&window->lock);
c_uart_send(COM1, character);
// 如果禁止输出,直接返回
if(atomic_read(&__put_window_enable_flag) == 0)
{
spin_unlock_no_preempt(&window->lock);
return 0;
}
if (unlikely(character == '\n'))
{
// 换行时还需要输出\r
c_uart_send(COM1, '\r');
__textui_new_line(window, window->vline_operating);
// spin_unlock_irqrestore(&window->lock, rflags);
spin_unlock_no_preempt(&window->lock);
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, ' ', FRcolor, BKcolor);
}
}
else if (character == '\b') // 退格
{
char bufff[128] = {0};
--(window->vlines.chromatic[window->vline_operating].index);
{
uint16_t tmp = window->vlines.chromatic[window->vline_operating].index;
if (tmp >= 0)
{
window->vlines.chromatic[window->vline_operating].chars[tmp].c = ' ';
window->vlines.chromatic[window->vline_operating].chars[tmp].BKcolor = BKcolor & 0xffffff;
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
{
if (window->vlines.chromatic[window->vline_operating].index == window->chars_per_line)
__textui_new_line(window, window->vline_operating);
__textui_putchar_window(window, character, FRcolor, BKcolor);
}
// spin_unlock_irqrestore(&window->lock, rflags);
spin_unlock_no_preempt(&window->lock);
return 0;
}
/**
* @brief 在默认窗口上输出一个字符
*
* @param character 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
{
return textui_putchar_window(__private_info.default_window, character, FRcolor, BKcolor);
}
/**
* @brief 初始化text ui框架
*
* @return int
*/
int textui_init()
{
spin_init(&change_lock);
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 = 0;
// 注册框架到屏幕管理器
int retval = scm_register(&textui_framework);
if (retval != 0)
{
c_uart_send_str(COM1, "text ui init failed\n");
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;
c_uart_send_str(COM1, "text ui initialized\n");
return 0;
}
void enable_textui()
{
scm_framework_enable(&textui_framework);
}
void disable_textui()
{
scm_framework_disable(&textui_framework);
}

@ -1,187 +0,0 @@
#pragma once
#include <common/glib.h>
#include <common/sys/types.h>
#include <common/spinlock.h>
/*
textui中的几个对象的关系
textui_vline_normal_t
+--------------------------------+
| | textui_char_normal_t
textui_window_t | chars: textui_char_normal_t * | +--------------------------+
+----------------------------+ | | | |
| | +------> +--------> c: char |
| list:List | | | index: int16_t | +--------------------------+
| vlines_num:int16_t | | | |
| vlines_used:int16_t | | +--------------------------------+
| | |
| vlines +-----+ textui_char_chromatic_t
| | | textui_vline_chromatic_t +--------------------------+
| top_vline:int16_t | | +-------------------------------------+ | |
| vline_operating:int16_t | | | | | c: uint16_t |
| chars_per_line:int16_t | | | chars: textui_char_chromatic_t * | | |
| flags:uint8_t | | | | | FRcolor:24 |
| lock:spinlock_t | +------> +---> |
| | | index: int16_t | | BKcolor:24 |
| | | | | |
+----------------------------+ +-------------------------------------+ +--------------------------+
*/
// 文本窗口标志位
// 文本窗口是否为彩色
#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
{
unsigned c : 16;
// 前景色
unsigned FRcolor : 24; // rgb
// 背景色
unsigned BKcolor : 24; // rgb
};
// 注意!!! 请保持vline结构体的大小、成员变量命名相等
/**
* @brief 单色显示的虚拟行结构体
*
*/
struct textui_vline_normal_t
{
struct textui_char_normal_t *chars; // 字符对象数组
int16_t index; // 当前操作的位置
};
/**
* @brief 彩色显示的虚拟行结构体
*
*/
struct textui_vline_chromatic_t
{
struct textui_char_chromatic_t *chars;
int16_t index; // 当前操作的位置
};
/**
* @brief textu ui 框架的文本窗口结构体
*
*/
struct textui_window_t
{
struct List list;
uint32_t id; // 窗口id
int16_t vlines_num; // 虚拟行总数
int16_t vlines_used; // 当前已经使用了的虚拟行总数
// 指向虚拟行的数组的指针(二选一)
union
{
struct textui_vline_normal_t *normal;
struct textui_vline_chromatic_t *chromatic;
} vlines;
int16_t top_vline; // 位于最顶上的那一个虚拟行的行号
int16_t vline_operating; // 正在操作的vline
int16_t chars_per_line; // 每行最大容纳的字符数
uint8_t flags; // 窗口flag
spinlock_t lock; // 窗口操作锁
};
struct textui_private_info_t
{
int16_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 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
/**
* @brief 在默认窗口上输出一个字符
*
* @param character 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
/**
* @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
*/
int textui_init();
void enable_textui();
void disable_textui();

Binary file not shown.

@ -0,0 +1,90 @@
use super::textui::GlyphMapping;
pub mod spleen_font;
pub use spleen_font::SPLEEN_FONT_8x16 as FONT_8x16;
/// Stores the font bitmap and some additional info for each font.
#[derive(Clone, Copy)]
pub struct BitmapFont<'a> {
/// The raw bitmap data for the font.
bitmap: RawBitMap<'a>,
/// The char to glyph mapping.
glyph_mapping: &'a dyn GlyphMapping,
/// The size of each character in the raw bitmap data.
size: Size,
bytes_per_char: usize,
}
#[allow(dead_code)]
impl<'a> BitmapFont<'a> {
pub const fn new(
bitmap: RawBitMap<'a>,
glyph_mapping: &'a dyn GlyphMapping,
size: Size,
) -> Self {
Self {
bitmap,
glyph_mapping,
size,
bytes_per_char: (size.width + 7) / 8 * size.height,
}
}
/// Return the width of each character.
pub const fn width(&self) -> u32 {
self.size.width as u32
}
/// Return the height of each character.
pub const fn height(&self) -> u32 {
self.size.height as u32
}
#[inline(always)]
pub fn char_map(&self, character: char) -> &'a [u8] {
let index = self.glyph_mapping.index(character);
let pos = index * self.bytes_per_char;
return &self.bitmap.data[pos..pos + self.bytes_per_char];
}
}
#[derive(Clone, Copy)]
pub struct Size {
pub width: usize,
pub height: usize,
}
impl Size {
pub const fn new(width: usize, height: usize) -> Self {
Self { width, height }
}
}
#[derive(Clone, Copy)]
pub struct RawBitMap<'a> {
pub data: &'a [u8],
pub size: Size,
}
#[allow(dead_code)]
impl RawBitMap<'_> {
pub const fn new(data: &'static [u8], width: usize) -> Self {
let size = Size {
width: 128,
height: data.len() / width / 8,
};
Self { data, size }
}
pub const fn size(&self) -> Size {
self.size
}
pub const fn len(&self) -> usize {
self.data.len()
}
}

@ -0,0 +1,25 @@
use crate::libs::lib_ui::textui::GlyphMapping;
use super::{BitmapFont, RawBitMap, Size};
struct Mapping;
impl GlyphMapping for Mapping {
#[inline(always)]
fn index(&self, c: char) -> usize {
let c = c as usize;
match c {
0..=255 => c,
_ => '?' as usize - ' ' as usize,
}
}
}
const SPLEEN_GLYPH_MAPPING: Mapping = Mapping;
#[allow(non_upper_case_globals)]
pub const SPLEEN_FONT_8x16: BitmapFont<'static> = BitmapFont::new(
RawBitMap::new(include_bytes!("binaries/spleen-8x16.raw_bytes"), 128),
&SPLEEN_GLYPH_MAPPING,
Size::new(8, 16),
);

@ -0,0 +1,4 @@
pub mod font;
pub mod screen_manager;
pub mod textui;
pub mod textui_no_alloc;

@ -0,0 +1,58 @@
#pragma once
#include <common/sys/types.h>
#include <common/glib.h>
// 帧缓冲区标志位
#define SCM_BF_FB (1 << 0) // 当前buffer是设备显存中的帧缓冲区
#define SCM_BF_DB (1 << 1) // 当前buffer是双缓冲
#define SCM_BF_TEXT (1 << 2) // 使用文本模式
#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
// ui框架类型
#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
/**
* @brief 帧缓冲区信息结构体
*
*/
struct scm_buffer_info_t
{
uint32_t width; // 帧缓冲区宽度pixel或columns
uint32_t height; // 帧缓冲区高度pixel或lines
uint32_t size; // 帧缓冲区大小bytes
uint32_t bit_depth; // 像素点位深度
uint64_t vaddr; // 帧缓冲区的地址
uint64_t flags; // 帧缓冲区标志位
};
/**
* @brief 初始化屏幕管理模块
*
*/
extern void scm_init();
/**
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
*
*/
extern void scm_reinit();
/**
* @brief 允许双缓冲区
*
* @return int
*/
extern int scm_enable_double_buffer();
/**
* @brief 允许往窗口打印信息
*
*/
extern void scm_enable_put_to_window();
/**
* @brief 禁止往窗口打印信息
*
*/
extern void scm_disable_put_to_window();

@ -0,0 +1,475 @@
use core::{
fmt::Debug,
intrinsics::unlikely,
sync::atomic::{AtomicBool, AtomicU32, Ordering},
};
use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
use crate::{
driver::uart::uart::{c_uart_send_str, UartPort},
include::bindings::bindings::{
scm_buffer_info_t, video_frame_buffer_info, video_reinitialize, video_set_refresh_target,
},
libs::{rwlock::RwLock, spinlock::SpinLock},
mm::VirtAddr,
syscall::SystemError,
};
use lazy_static::lazy_static;
use super::textui_no_alloc::textui_init_no_alloc;
lazy_static! {
/// 全局的UI框架列表
pub static ref SCM_FRAMEWORK_LIST: SpinLock<LinkedList<Arc<dyn ScmUiFramework>>> =
SpinLock::new(LinkedList::new());
/// 当前在使用的UI框架
pub static ref CURRENT_FRAMEWORK: RwLock<Option<Arc<dyn ScmUiFramework>>> = RwLock::new(None);
}
/// 是否启用双缓冲
pub static SCM_DOUBLE_BUFFER_ENABLED: AtomicBool = AtomicBool::new(false);
bitflags! {
pub struct ScmBufferFlag:u8 {
// 帧缓冲区标志位
const SCM_BF_FB = 1 << 0; // 当前buffer是设备显存中的帧缓冲区
const SCM_BF_DB = 1 << 1; // 当前buffer是双缓冲
const SCM_BF_TEXT = 1 << 2; // 使用文本模式
const SCM_BF_PIXEL = 1 << 3; // 使用图像模式
}
}
#[derive(Clone, Debug)]
#[allow(dead_code)]
pub enum ScmFramworkType {
Text,
Gui,
Unused,
}
#[derive(Debug)]
pub enum ScmBuffer {
DeviceBuffer(Option<VirtAddr>),
DoubleBuffer(Option<Box<[u32]>>),
}
#[derive(Debug)]
pub struct ScmBufferInfo {
width: u32, // 帧缓冲区宽度pixel或columns
height: u32, // 帧缓冲区高度pixel或lines
size: u32, // 帧缓冲区大小bytes
bit_depth: u32, // 像素点位深度
pub buf: ScmBuffer,
flags: ScmBufferFlag, // 帧缓冲区标志位
}
impl Clone for ScmBufferInfo {
fn clone(&self) -> Self {
match self.buf {
ScmBuffer::DeviceBuffer(_) => ScmBufferInfo {
width: self.width,
height: self.height,
size: self.size,
bit_depth: self.bit_depth,
flags: self.flags,
buf: ScmBuffer::DeviceBuffer(Option::None),
},
ScmBuffer::DoubleBuffer(_) => ScmBufferInfo {
width: self.width,
height: self.height,
size: self.size,
bit_depth: self.bit_depth,
flags: self.flags,
buf: ScmBuffer::DoubleBuffer(Option::None),
},
}
}
}
impl ScmBufferInfo {
/// 创建新的帧缓冲区信息
///
/// ## 参数
///
/// - `buf_type` 帧缓冲区类型
///
/// ## 返回值
///
/// - `Result<Self, SystemError>` 创建成功返回新的帧缓冲区结构体,创建失败返回错误码
pub fn new(buf_type: ScmBufferFlag) -> Result<Self, SystemError> {
if unlikely(SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == false) {
let buf_info = ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
return Ok(buf_info);
} else {
// 创建双缓冲区
let mut frame_buffer_info: ScmBufferInfo =
ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
frame_buffer_info.flags = buf_type;
// 这里还是改成使用box来存储数组如果直接用vec存储在multiboot2_iter那里会报错不知为何
frame_buffer_info.buf = ScmBuffer::DoubleBuffer(Some(
Box::new(vec![
0;
unsafe { (video_frame_buffer_info.size / 4) as usize }
])
.into_boxed_slice(),
));
return Ok(frame_buffer_info);
}
}
// 重构了video后可以删除
fn vaddr(&mut self) -> VirtAddr {
match &self.buf {
ScmBuffer::DeviceBuffer(vaddr) => {
if !vaddr.is_none() {
vaddr.unwrap()
} else {
return VirtAddr::new(0);
}
}
ScmBuffer::DoubleBuffer(buf) => {
if !buf.is_none() {
let address = self.buf().as_ptr();
VirtAddr::new(address as usize)
} else {
return VirtAddr::new(0);
}
}
}
}
fn buf(&mut self) -> &mut [u32] {
let len = self.buf_size() / 4;
match &mut self.buf {
ScmBuffer::DoubleBuffer(buf) => match buf.as_mut() {
Some(buf) => buf,
None => panic!("Buffer is none"),
},
ScmBuffer::DeviceBuffer(vaddr) => match vaddr.as_mut() {
Some(vaddr) => {
let buf: &mut [u32] = unsafe {
core::slice::from_raw_parts_mut(vaddr.data() as *mut u32, len as usize)
};
return buf;
}
None => panic!("Buffer is none"),
},
}
}
pub fn buf_size(&self) -> u32 {
self.size
}
pub fn buf_height(&self) -> u32 {
self.height
}
pub fn buf_width(&self) -> u32 {
self.width
}
pub fn is_double_buffer(&self) -> bool {
match &self.buf {
ScmBuffer::DoubleBuffer(_) => true,
_ => false,
}
}
pub fn is_device_buffer(&self) -> bool {
match &self.buf {
ScmBuffer::DeviceBuffer(_) => true,
_ => false,
}
}
}
// 重构了video后可以删除
impl From<&scm_buffer_info_t> for ScmBufferInfo {
fn from(value: &scm_buffer_info_t) -> Self {
Self {
width: value.width,
height: value.height,
size: value.size,
bit_depth: value.bit_depth,
buf: ScmBuffer::DeviceBuffer(Some(VirtAddr::new(value.vaddr as usize))),
flags: ScmBufferFlag::from_bits_truncate(value.flags as u8),
}
}
}
impl Into<scm_buffer_info_t> for ScmBufferInfo {
fn into(mut self) -> scm_buffer_info_t {
let vaddr = self.vaddr();
scm_buffer_info_t {
width: self.width,
height: self.height,
size: self.size,
bit_depth: self.bit_depth,
vaddr: vaddr.data() as u64,
flags: self.flags.bits as u64,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct ScmUiFrameworkId(u32);
impl ScmUiFrameworkId {
/// 分配一个新的框架id
pub fn new() -> Self {
static MAX_ID: AtomicU32 = AtomicU32::new(0);
return ScmUiFrameworkId(MAX_ID.fetch_add(1, Ordering::SeqCst));
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ScmUiFrameworkMetadata {
id: ScmUiFrameworkId,
name: String,
framework_type: ScmFramworkType,
pub buf_info: ScmBufferInfo,
}
impl ScmUiFrameworkMetadata {
pub fn new(name: String, framework_type: ScmFramworkType) -> Self {
match framework_type {
ScmFramworkType::Text => {
let result = ScmUiFrameworkMetadata {
id: ScmUiFrameworkId::new(),
name,
framework_type: ScmFramworkType::Text,
buf_info: ScmBufferInfo::new(ScmBufferFlag::SCM_BF_TEXT).unwrap(),
};
return result;
}
ScmFramworkType::Gui => todo!(),
ScmFramworkType::Unused => todo!(),
}
}
pub fn buf_info(&self) -> ScmBufferInfo {
return self.buf_info.clone();
}
pub fn set_buf_info(&mut self, buf_info: ScmBufferInfo) {
self.buf_info = buf_info;
}
pub fn buf_is_none(&self) -> bool {
match &self.buf_info.buf {
ScmBuffer::DeviceBuffer(vaddr) => {
return vaddr.is_none();
}
ScmBuffer::DoubleBuffer(buf) => {
return buf.is_none();
}
}
}
pub fn buf(&mut self) -> &mut [u32] {
if self.buf_is_none() {
panic!("buf is none");
}
self.buf_info.buf()
}
}
pub trait ScmUiFramework: Sync + Send + Debug {
// 安装ui框架的回调函数
fn install(&self) -> Result<i32, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 卸载ui框架的回调函数
fn uninstall(&self) -> Result<i32, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 启用ui框架的回调函数
fn enable(&self) -> Result<i32, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 禁用ui框架的回调函数
fn disable(&self) -> Result<i32, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 改变ui框架的帧缓冲区的回调函数
fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
/// @brief 获取ScmUiFramework的元数据
/// @return 成功Ok(ScmUiFramework的元数据)
/// 失败Err(错误码)
fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
}
/// 初始化屏幕控制模块
///
/// ## 调用时机
///
/// 该函数在内核启动的早期进行调用。调用时,内存管理模块尚未初始化。
#[no_mangle]
pub extern "C" fn scm_init() {
SCM_DOUBLE_BUFFER_ENABLED.store(false, Ordering::SeqCst); // 禁用双缓冲
textui_init_no_alloc();
c_uart_send_str(UartPort::COM1.to_u16(), "\nfinish_scm_init\n\0".as_ptr());
}
/// 启用某个ui框架将它的帧缓冲区渲染到屏幕上
/// ## 参数
///
/// - framework 要启动的ui框架
pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
// 获取信息
let metadata = framework.metadata()?;
// if metadata.buf_info.buf.is_null() {
// return Err(SystemError::EINVAL);
// }
let mut current_framework = CURRENT_FRAMEWORK.write();
if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == true {
let buf: scm_buffer_info_t = metadata.buf_info.into();
let retval = unsafe { video_set_refresh_target(buf) };
if retval == 0 {
framework.enable()?;
}
} else {
framework.enable()?;
}
current_framework.replace(framework);
return Ok(0);
}
/// 向屏幕管理器注册UI框架
///
/// ## 参数
/// - framework 框架结构体
pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
// 把ui框架加入链表
SCM_FRAMEWORK_LIST.lock().push_back(framework.clone());
// 调用ui框架的回调函数以安装ui框架并将其激活
framework.install()?;
// 如果当前还没有框架获得了屏幕的控制权,就让其拿去
if CURRENT_FRAMEWORK.read().is_none() {
return scm_framework_enable(framework);
}
return Ok(0);
}
/// 允许双缓冲区
#[no_mangle]
pub extern "C" fn scm_enable_double_buffer() -> i32 {
let r = true_scm_enable_double_buffer().unwrap_or_else(|e| e.to_posix_errno());
if r.is_negative() {
c_uart_send_str(
UartPort::COM1.to_u16(),
"scm enable double buffer fail.\n\0".as_ptr(),
);
}
return r;
}
fn true_scm_enable_double_buffer() -> Result<i32, SystemError> {
if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) {
// 已经开启了双缓冲区了, 直接退出
return Ok(0);
}
let scm_list = SCM_FRAMEWORK_LIST.lock();
if scm_list.is_empty() {
// scm 框架链表为空
return Ok(0);
}
drop(scm_list);
SCM_DOUBLE_BUFFER_ENABLED.store(true, Ordering::SeqCst);
// 创建双缓冲区
let mut buf_info = ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
let mut refresh_target_buf: scm_buffer_info_t = buf_info.clone().into();
// 重构video后进行修改
refresh_target_buf.vaddr = buf_info.vaddr().data() as u64;
CURRENT_FRAMEWORK
.write()
.as_ref()
.unwrap()
.change(buf_info)?;
// 设置定时刷新的对象
unsafe { video_set_refresh_target(refresh_target_buf) };
// 遍历当前所有使用帧缓冲区的框架,更新为双缓冲区
for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
if !(*framework).metadata()?.buf_info.is_double_buffer() {
let new_buf_info =
ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
(*framework).change(new_buf_info)?;
}
}
// 通知显示驱动,启动双缓冲
unsafe { video_reinitialize(true) };
return Ok(0);
}
/// 允许往窗口打印信息
#[no_mangle]
pub fn scm_enable_put_to_window() {
// mm之前要继续往窗口打印信息时因为没有动态内存分配(rwlock与otion依然能用但是textui并没有往scm注册)且使用的是textui,要直接修改textui里面的值
if CURRENT_FRAMEWORK.read().is_none() {
super::textui::ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
} else {
let r = CURRENT_FRAMEWORK
.write()
.as_ref()
.unwrap()
.enable()
.unwrap_or_else(|e| e.to_posix_errno());
if r.is_negative() {
c_uart_send_str(
UartPort::COM1.to_u16(),
"scm_enable_put_to_window() failed.\n\0".as_ptr(),
);
}
}
}
/// 禁止往窗口打印信息
#[no_mangle]
pub fn scm_disable_put_to_window() {
// mm之前要停止往窗口打印信息时因为没有动态内存分配(rwlock与otion依然能用但是textui并没有往scm注册)且使用的是textui,要直接修改textui里面的值
if CURRENT_FRAMEWORK.read().is_none() {
super::textui::ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
assert!(super::textui::ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst) == false);
} else {
let r = CURRENT_FRAMEWORK
.write()
.as_ref()
.unwrap()
.disable()
.unwrap_or_else(|e| e.to_posix_errno());
if r.is_negative() {
c_uart_send_str(
UartPort::COM1.to_u16(),
"scm_disable_put_to_window() failed.\n\0".as_ptr(),
);
}
}
}
/// 当内存管理单元被初始化之后,重新处理帧缓冲区问题
#[no_mangle]
pub extern "C" fn scm_reinit() -> i32 {
let r = true_scm_reinit().unwrap_or_else(|e| e.to_posix_errno());
if r.is_negative() {
c_uart_send_str(UartPort::COM1.to_u16(), "scm reinit failed.\n\0".as_ptr());
}
return r;
}
fn true_scm_reinit() -> Result<i32, SystemError> {
unsafe { video_reinitialize(false) };
// 遍历当前所有使用帧缓冲区的框架,更新地址
for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
if framework.metadata()?.buf_info().is_device_buffer() {
framework.change(unsafe { ScmBufferInfo::from(&video_frame_buffer_info) })?;
}
}
scm_enable_put_to_window();
return Ok(0);
}

@ -0,0 +1,19 @@
#pragma once
#include <common/glib.h>
/**
* @brief 在默认窗口上输出一个字符
*
* @param character 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
extern int rs_textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
/**
* @brief 初始化text ui框架
*
* @return int
*/
extern int textui_init();

@ -0,0 +1,967 @@
use crate::{
driver::uart::uart::{c_uart_send, c_uart_send_str, UartPort},
include::bindings::bindings::video_frame_buffer_info,
kinfo,
libs::{lib_ui::font::FONT_8x16, spinlock::SpinLock},
syscall::SystemError,
};
use alloc::{boxed::Box, collections::LinkedList, string::ToString};
use alloc::{sync::Arc, vec::Vec};
use core::{
fmt::Debug,
intrinsics::unlikely,
ops::{Add, AddAssign, Sub},
sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering},
};
use super::{
screen_manager::{
scm_register, ScmBufferInfo, ScmFramworkType, ScmUiFramework, ScmUiFrameworkMetadata,
},
textui_no_alloc::no_init_textui_putchar_window,
};
/// 声明全局的TEXTUI_FRAMEWORK
static mut __TEXTUI_FRAMEWORK: Option<Box<TextUiFramework>> = None;
/// 每个字符的宽度和高度(像素)
pub const TEXTUI_CHAR_WIDTH: u32 = 8;
pub const TEXTUI_CHAR_HEIGHT: u32 = 16;
pub static mut TEXTUI_IS_INIT: bool = false;
pub static ENABLE_PUT_TO_WINDOW: AtomicBool = AtomicBool::new(true);
/// 获取TEXTUI_FRAMEWORK的可变实例
pub fn textui_framework() -> &'static mut TextUiFramework {
return unsafe { __TEXTUI_FRAMEWORK.as_mut().unwrap() };
}
/// 初始化TEXTUI_FRAMEWORK
pub unsafe fn textui_framwork_init() {
if __TEXTUI_FRAMEWORK.is_none() {
kinfo!("textuiframework init");
let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text);
// 为textui框架生成第一个窗口
let vlines_num = (metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as usize;
let chars_num = (metadata.buf_info().buf_width() / TEXTUI_CHAR_WIDTH) as usize;
let initial_window = TextuiWindow::new(
WindowFlag::TEXTUI_CHROMATIC,
vlines_num as i32,
chars_num as i32,
);
let current_window: Arc<SpinLock<TextuiWindow>> = Arc::new(SpinLock::new(initial_window));
let default_window = current_window.clone();
// 生成窗口链表并把上面窗口添加进textui框架的窗口链表中
let window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>> =
Arc::new(SpinLock::new(LinkedList::new()));
window_list.lock().push_back(current_window.clone());
__TEXTUI_FRAMEWORK = Some(Box::new(TextUiFramework::new(
metadata,
window_list,
current_window,
default_window,
)));
} else {
panic!("Try to init TEXTUI_FRAMEWORK twice!");
}
}
// window标志位
bitflags! {
pub struct WindowFlag: u8 {
// 采用彩色字符
const TEXTUI_CHROMATIC = 1 << 0;
}
}
/**
* @brief 黑白字符对象
*
*/
#[derive(Clone, Debug)]
struct TextuiCharNormal {
_data: u8,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
pub struct LineId(i32);
impl LineId {
pub fn new(num: i32) -> Self {
LineId(num)
}
pub fn check(&self, max: i32) -> bool {
self.0 < max && self.0 >= 0
}
pub fn data(&self) -> i32 {
self.0
}
}
impl Add<i32> for LineId {
type Output = LineId;
fn add(self, rhs: i32) -> Self::Output {
LineId::new(self.0 + rhs)
}
}
impl Sub<i32> for LineId {
type Output = LineId;
fn sub(self, rhs: i32) -> Self::Output {
LineId::new(self.0 - rhs)
}
}
impl Into<i32> for LineId {
fn into(self) -> i32 {
self.0.clone()
}
}
impl Into<u32> for LineId {
fn into(self) -> u32 {
self.0.clone() as u32
}
}
impl Into<usize> for LineId {
fn into(self) -> usize {
self.0.clone() as usize
}
}
impl Sub<LineId> for LineId {
type Output = LineId;
fn sub(mut self, rhs: LineId) -> Self::Output {
self.0 -= rhs.0;
return self;
}
}
impl AddAssign<LineId> for LineId {
fn add_assign(&mut self, rhs: LineId) {
self.0 += rhs.0;
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
pub struct LineIndex(i32);
impl LineIndex {
pub fn new(num: i32) -> Self {
LineIndex(num)
}
pub fn check(&self, chars_per_line: i32) -> bool {
self.0 < chars_per_line && self.0 >= 0
}
}
impl Add<LineIndex> for LineIndex {
type Output = LineIndex;
fn add(self, rhs: LineIndex) -> Self::Output {
LineIndex::new(self.0 + rhs.0)
}
}
impl Add<i32> for LineIndex {
// type Output = Self;
type Output = LineIndex;
fn add(self, rhs: i32) -> Self::Output {
LineIndex::new(self.0 + rhs)
}
}
impl Sub<i32> for LineIndex {
type Output = LineIndex;
fn sub(self, rhs: i32) -> Self::Output {
LineIndex::new(self.0 - rhs)
}
}
impl Into<i32> for LineIndex {
fn into(self) -> i32 {
self.0.clone()
}
}
impl Into<u32> for LineIndex {
fn into(self) -> u32 {
self.0.clone() as u32
}
}
impl Into<usize> for LineIndex {
fn into(self) -> usize {
self.0.clone() as usize
}
}
#[derive(Copy, Clone, Debug)]
pub struct FontColor(u32);
#[allow(dead_code)]
impl FontColor {
pub const BLUE: FontColor = FontColor::new(0, 0, 0xff);
pub const RED: FontColor = FontColor::new(0xff, 0, 0);
pub const GREEN: FontColor = FontColor::new(0, 0xff, 0);
pub const WHITE: FontColor = FontColor::new(0xff, 0xff, 0xff);
pub const BLACK: FontColor = FontColor::new(0, 0, 0);
pub const YELLOW: FontColor = FontColor::new(0xff, 0xff, 0);
pub const ORANGE: FontColor = FontColor::new(0xff, 0x80, 0);
pub const INDIGO: FontColor = FontColor::new(0x00, 0xff, 0xff);
pub const PURPLE: FontColor = FontColor::new(0x80, 0x00, 0xff);
pub const fn new(r: u8, g: u8, b: u8) -> Self {
let val = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
return FontColor(val & 0x00ffffff);
}
}
impl From<u32> for FontColor {
fn from(value: u32) -> Self {
return Self(value & 0x00ffffff);
}
}
impl Into<usize> for FontColor {
fn into(self) -> usize {
self.0.clone() as usize
}
}
impl Into<u32> for FontColor {
fn into(self) -> u32 {
self.0.clone()
}
}
impl Into<u16> for FontColor {
fn into(self) -> u16 {
self.0.clone() as u16
}
}
impl Into<u64> for FontColor {
fn into(self) -> u64 {
self.0.clone() as u64
}
}
/// 彩色字符对象
#[derive(Clone, Debug, Copy)]
pub struct TextuiCharChromatic {
c: Option<char>,
// 前景色
frcolor: FontColor, // rgb
// 背景色
bkcolor: FontColor, // rgb
}
#[derive(Debug)]
pub struct TextuiBuf<'a>(&'a mut [u32]);
impl TextuiBuf<'_> {
pub fn new(buf: &mut [u32]) -> TextuiBuf {
TextuiBuf(buf)
}
pub fn put_color_in_pixel(&mut self, color: u32, index: usize) {
let buf: &mut [u32] = self.0;
buf[index] = color;
}
pub fn get_index_of_next_line(now_index: usize) -> usize {
textui_framework().metadata.buf_info().buf_width() as usize + now_index
}
pub fn get_index_by_x_y(x: usize, y: usize) -> usize {
textui_framework().metadata.buf_info().buf_width() as usize * y + x
}
pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize {
// x 左上角列像素点位置
// y 左上角行像素点位置
let index_x: u32 = lineindex.into();
let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
let id_y: u32 = lineid.into();
let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
TextuiBuf::get_index_by_x_y(x as usize, y as usize)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Font([u8; 16]);
impl Font {
#[inline]
pub fn get_font(character: char) -> Font {
let x = FONT_8x16.char_map(character);
let mut data = [0u8; 16];
data.copy_from_slice(x);
return Font(data);
}
pub fn is_frcolor(&self, height: usize, width: usize) -> bool {
let w = self.0[height];
let testbit = 1 << (8 - width);
w & testbit != 0
}
}
impl TextuiCharChromatic {
pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self {
TextuiCharChromatic {
c,
frcolor,
bkcolor,
}
}
/// 将该字符对象输出到缓冲区
/// ## 参数
/// -line_id 要放入的真实行号
/// -index 要放入的真实列号
pub fn textui_refresh_character(
&self,
lineid: LineId,
lineindex: LineIndex,
) -> Result<i32, SystemError> {
// 找到要渲染的字符的像素点数据
let font: Font = Font::get_font(self.c.unwrap_or(' '));
let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex);
let mut buf = TextuiBuf::new(textui_framework().metadata.buf());
// 在缓冲区画出一个字体每个字体有TEXTUI_CHAR_HEIGHT行TEXTUI_CHAR_WIDTH列个像素点
for i in 0..TEXTUI_CHAR_HEIGHT {
let start = count;
for j in 0..TEXTUI_CHAR_WIDTH {
if font.is_frcolor(i as usize, j as usize) {
// 字,显示前景色
buf.put_color_in_pixel(self.frcolor.into(), count);
} else {
// 背景色
buf.put_color_in_pixel(self.bkcolor.into(), count);
}
count += 1;
}
count = TextuiBuf::get_index_of_next_line(start);
}
return Ok(0);
}
pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) {
// 找到要渲染的字符的像素点数据
let font = Font::get_font(self.c.unwrap_or(' '));
// x 左上角列像素点位置
// y 左上角行像素点位置
let index_x: u32 = lineindex.into();
let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
let id_y: u32 = lineid.into();
let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
// 找到输入缓冲区的起始地址位置
let fb = unsafe { video_frame_buffer_info.vaddr };
let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身
// 在缓冲区画出一个字体每个字体有TEXTUI_CHAR_HEIGHT行TEXTUI_CHAR_WIDTH列个像素点
for i in 0..TEXTUI_CHAR_HEIGHT {
// 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+y+i*缓冲区的宽度+x
let mut addr: *mut u32 = (fb
+ unsafe { video_frame_buffer_info.width } as u64 * 4 * (y as u64 + i as u64)
+ 4 * x as u64) as *mut u32;
testbit = 1 << (TEXTUI_CHAR_WIDTH + 1);
for _j in 0..TEXTUI_CHAR_WIDTH {
//从左往右逐个测试相应位
testbit >>= 1;
if (font.0[i as usize] & testbit as u8) != 0 {
unsafe { *addr = self.frcolor.into() }; // 字,显示前景色
} else {
unsafe { *addr = self.bkcolor.into() }; // 背景色
}
unsafe {
addr = (addr.offset(1)) as *mut u32;
}
}
}
}
}
/// 单色显示的虚拟行结构体
#[derive(Clone, Debug, Default)]
pub struct TextuiVlineNormal {
_characters: Vec<TextuiCharNormal>, // 字符对象数组
_index: i16, // 当前操作的位置
}
/// 彩色显示的虚拟行结构体
#[derive(Clone, Debug, Default)]
pub struct TextuiVlineChromatic {
chars: Vec<TextuiCharChromatic>, // 字符对象数组
index: LineIndex, // 当前操作的位置
}
impl TextuiVlineChromatic {
pub fn new(char_num: usize) -> Self {
let mut r = TextuiVlineChromatic {
chars: Vec::with_capacity(char_num),
index: LineIndex::new(0),
};
for _ in 0..char_num {
r.chars.push(TextuiCharChromatic::new(
None,
FontColor::BLACK,
FontColor::BLACK,
));
}
return r;
}
}
#[derive(Clone, Debug)]
pub enum TextuiVline {
Chromatic(TextuiVlineChromatic),
_Normal(TextuiVlineNormal),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct WindowId(u32);
impl WindowId {
pub fn new() -> Self {
static MAX_ID: AtomicU32 = AtomicU32::new(0);
return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst));
}
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct TextuiWindow {
// 虚拟行是个循环表,头和尾相接
id: WindowId,
// 虚拟行总数
vline_sum: i32,
// 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量)
vlines_used: i32,
// 位于最顶上的那一个虚拟行的行号
top_vline: LineId,
// 储存虚拟行的数组
vlines: Vec<TextuiVline>,
// 正在操作的vline
vline_operating: LineId,
// 每行最大容纳的字符数
chars_per_line: i32,
// 窗口flag
flags: WindowFlag,
}
impl TextuiWindow {
/// 使用参数初始化window对象
/// ## 参数
///
/// -flags 标志位
/// -vlines_num 虚拟行的总数
/// -chars_num 每行最大的字符数
pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self {
let mut initial_vlines = Vec::new();
for _ in 0..vlines_num {
let vline = TextuiVlineChromatic::new(chars_num as usize);
initial_vlines.push(TextuiVline::Chromatic(vline));
}
TextuiWindow {
id: WindowId::new(),
flags,
vline_sum: vlines_num,
vlines_used: 1,
top_vline: LineId::new(0),
vlines: initial_vlines,
vline_operating: LineId::new(0),
chars_per_line: chars_num,
}
}
/// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象
/// ## 参数
/// - window 窗口结构体
/// - vline_id 要刷新的虚拟行号
/// - start 起始字符号
/// - count 要刷新的字符数量
fn textui_refresh_characters(
&mut self,
vline_id: LineId,
start: LineIndex,
count: i32,
) -> Result<(), SystemError> {
let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
// 判断虚拟行参数是否合法
if unlikely(
!vline_id.check(self.vline_sum)
|| (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line,
) {
return Err(SystemError::EINVAL);
}
// 计算虚拟行对应的真实行(即要渲染的行)
let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面
if <LineId as Into<i32>>::into(actual_line_id) < 0 {
//真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行
actual_line_id = actual_line_id + actual_line_sum;
}
// 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入
if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)];
let mut i = 0;
let mut index = start;
while i < count {
if let TextuiVline::Chromatic(vline) = vline {
vline.chars[<LineIndex as Into<usize>>::into(index)]
.textui_refresh_character(actual_line_id, index)?;
index = index + 1;
}
i += 1;
}
}
return Ok(());
}
/// 重新渲染某个窗口的某个虚拟行
/// ## 参数
/// - window 窗口结构体
/// - vline_id 虚拟行号
fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> {
if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
return self.textui_refresh_characters(
vline_id,
LineIndex::new(0),
self.chars_per_line,
);
} else {
//todo支持纯文本字符()
todo!();
}
}
// 刷新某个窗口的start 到start + count行即将这些行输入到缓冲区
fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> {
let mut refresh_count = count;
for i in <LineId as Into<i32>>::into(start)
..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count)
{
self.textui_refresh_vline(LineId::new(i))?;
refresh_count -= 1;
}
//因为虚拟行是循环表
let mut refresh_start = 0;
while refresh_count > 0 {
self.textui_refresh_vline(LineId::new(refresh_start))?;
refresh_start += 1;
refresh_count -= 1;
}
return Ok(0);
}
/// 往某个窗口的缓冲区的某个虚拟行插入换行
/// ## 参数
/// - window 窗口结构体
/// - vline_id 虚拟行号
fn textui_new_line(&mut self) -> Result<i32, SystemError> {
// todo: 支持在两个虚拟行之间插入一个新行
let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
self.vline_operating = self.vline_operating + 1;
//如果已经到了最大行数则重新从0开始
if !self.vline_operating.check(self.vline_sum) {
self.vline_operating = LineId::new(0);
}
if let TextuiVline::Chromatic(vline) =
&mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
{
for i in 0..self.chars_per_line {
if let Some(v_char) = vline.chars.get_mut(i as usize) {
v_char.c = None;
v_char.frcolor = FontColor::BLACK;
v_char.bkcolor = FontColor::BLACK;
}
}
vline.index = LineIndex::new(0);
}
// 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。
if self.vlines_used == actual_line_sum {
self.top_vline = self.top_vline + 1;
if !self.top_vline.check(self.vline_sum) {
self.top_vline = LineId::new(0);
}
// 刷新所有行
self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
} else {
//换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1
self.vlines_used += 1;
}
return Ok(0);
}
/// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operatingwindow.vline_operating.index)
/// ## 参数
/// - window
/// - character
fn true_textui_putchar_window(
&mut self,
character: char,
frcolor: FontColor,
bkcolor: FontColor,
) -> Result<(), SystemError> {
// 启用彩色字符
if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
let mut line_index = LineIndex::new(0); //操作的列号
if let TextuiVline::Chromatic(vline) =
&mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
{
let index = <LineIndex as Into<usize>>::into(vline.index);
if let Some(v_char) = vline.chars.get_mut(index) {
v_char.c = Some(character);
v_char.frcolor = frcolor;
v_char.bkcolor = bkcolor;
}
line_index = vline.index;
vline.index = vline.index + 1;
}
self.textui_refresh_characters(self.vline_operating, line_index, 1)?;
// 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
if !line_index.check(self.chars_per_line - 1) {
self.textui_new_line()?;
}
} else {
// todo: 支持纯文本字符
todo!();
}
return Ok(());
}
/// 根据输入的一个字符在窗口上输出
/// ## 参数
/// - window 窗口
/// - character 字符
/// - FRcolor 前景色RGB
/// - BKcolor 背景色RGB
fn textui_putchar_window(
&mut self,
character: char,
frcolor: FontColor,
bkcolor: FontColor,
is_enable_window: bool,
) -> Result<(), SystemError> {
let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
//字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
if unlikely(character == '\0') {
return Ok(());
}
if unlikely(character == '\r') {
return Ok(());
}
// 暂不支持纯文本窗口
if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
return Ok(());
}
//进行换行操作
if character == '\n' {
// 换行时还需要输出\r
c_uart_send(UartPort::COM1.to_u16(), b'\r');
if is_enable_window == true {
self.textui_new_line()?;
}
return Ok(());
}
// 输出制表符
else if character == '\t' {
if is_enable_window == true {
if let TextuiVline::Chromatic(vline) =
&self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
{
//打印的空格数注意将每行分成一个个表格每个表格为8个字符
let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8;
while space_to_print > 0 {
self.true_textui_putchar_window(' ', frcolor, bkcolor)?;
space_to_print -= 1;
}
}
}
}
// 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
else if character == '\x08' {
if is_enable_window == true {
let mut tmp = LineIndex(0);
if let TextuiVline::Chromatic(vline) =
&mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
{
vline.index = vline.index - 1;
tmp = vline.index;
}
if <LineIndex as Into<i32>>::into(tmp) >= 0 {
if let TextuiVline::Chromatic(vline) =
&mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
{
if let Some(v_char) =
vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp))
{
v_char.c = Some(' ');
v_char.bkcolor = bkcolor;
}
}
return self.textui_refresh_characters(self.vline_operating, tmp, 1);
}
// 需要向上缩一行
if <LineIndex as Into<i32>>::into(tmp) < 0 {
// 当前行为空,需要重新刷新
if let TextuiVline::Chromatic(vline) =
&mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
{
vline.index = LineIndex::new(0);
for i in 0..self.chars_per_line {
if let Some(v_char) = vline.chars.get_mut(i as usize) {
v_char.c = None;
v_char.frcolor = FontColor::BLACK;
v_char.bkcolor = FontColor::BLACK;
}
}
}
// 上缩一行
self.vline_operating = self.vline_operating - 1;
if self.vline_operating.data() < 0 {
self.vline_operating = LineId(self.vline_sum - 1);
}
// 考虑是否向上滚动在top_vline上退格
if self.vlines_used > actual_line_sum {
self.top_vline = self.top_vline - 1;
if <LineId as Into<i32>>::into(self.top_vline) < 0 {
self.top_vline = LineId(self.vline_sum - 1);
}
}
//因为上缩一行所以显示在屏幕中的虚拟行少一
self.vlines_used -= 1;
self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
}
}
} else {
// 输出其他字符
c_uart_send(UartPort::COM1.to_u16(), character as u8);
if is_enable_window == true {
if let TextuiVline::Chromatic(vline) =
&self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
{
if !vline.index.check(self.chars_per_line) {
self.textui_new_line()?;
}
return self.true_textui_putchar_window(character, frcolor, bkcolor);
}
}
}
return Ok(());
}
}
impl Default for TextuiWindow {
fn default() -> Self {
TextuiWindow {
id: WindowId(0),
flags: WindowFlag::TEXTUI_CHROMATIC,
vline_sum: 0,
vlines_used: 1,
top_vline: LineId::new(0),
vlines: Vec::new(),
vline_operating: LineId::new(0),
chars_per_line: 0,
}
}
}
#[allow(dead_code)]
#[derive(Debug)]
pub struct TextUiFramework {
metadata: ScmUiFrameworkMetadata,
window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
actual_line: AtomicI32, // 真实行的数量textui的帧缓冲区能容纳的内容的行数
current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口
default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口
}
impl TextUiFramework {
pub fn new(
metadata: ScmUiFrameworkMetadata,
window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
current_window: Arc<SpinLock<TextuiWindow>>,
default_window: Arc<SpinLock<TextuiWindow>>,
) -> Self {
let actual_line =
AtomicI32::new((&metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as i32);
let inner = TextUiFramework {
metadata,
window_list,
actual_line,
current_window,
default_window,
};
return inner;
}
}
impl ScmUiFramework for &mut TextUiFramework {
// 安装ui框架的回调函数
fn install(&self) -> Result<i32, SystemError> {
c_uart_send_str(
UartPort::COM1.to_u16(),
"\ntextui_install_handler\n\0".as_ptr(),
);
return Ok(0);
}
// 卸载ui框架的回调函数
fn uninstall(&self) -> Result<i32, SystemError> {
return Ok(0);
}
// 启用ui框架的回调函数
fn enable(&self) -> Result<i32, SystemError> {
ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
return Ok(0);
}
// 禁用ui框架的回调函数
fn disable(&self) -> Result<i32, SystemError> {
ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
return Ok(0);
}
// 改变ui框架的帧缓冲区的回调函数
fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> {
let src_buf = textui_framework().metadata.buf();
textui_framework().metadata.set_buf_info(buf_info);
let dst_buf = textui_framework().metadata.buf();
dst_buf.copy_from_slice(src_buf);
return Ok(0);
}
/// 获取ScmUiFramework的元数据
/// ## 返回值
///
/// -成功Ok(ScmUiFramework的元数据)
/// -失败Err(错误码)
fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
let metadata = self.metadata.clone();
return Ok(metadata);
}
}
/// Mapping from characters to glyph indices.
pub trait GlyphMapping: Sync {
/// Maps a character to a glyph index.
///
/// If `c` isn't included in the font the index of a suitable replacement glyph is returned.
fn index(&self, c: char) -> usize;
}
impl<F> GlyphMapping for F
where
F: Sync + Fn(char) -> usize,
{
fn index(&self, c: char) -> usize {
self(c)
}
}
/// 在默认窗口上输出一个字符
/// ## 参数
/// - character 字符
/// - FRcolor 前景色RGB
/// - BKcolor 背景色RGB
#[no_mangle]
pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
return textui_putchar(
character as char,
FontColor::from(fr_color),
FontColor::from(bk_color),
)
.map(|_| 0)
.unwrap_or_else(|e| e.to_posix_errno());
}
pub fn textui_putchar(
character: char,
fr_color: FontColor,
bk_color: FontColor,
) -> Result<(), SystemError> {
if unsafe { TEXTUI_IS_INIT } {
return textui_framework()
.current_window
.lock()
.textui_putchar_window(
character,
fr_color,
bk_color,
ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
);
} else {
//未初始化暴力输出
return no_init_textui_putchar_window(
character,
fr_color,
bk_color,
ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
);
}
}
/// 初始化text ui框架
#[no_mangle]
pub extern "C" fn rs_textui_init() -> i32 {
let r = textui_init().unwrap_or_else(|e| e.to_posix_errno());
if r.is_negative() {
c_uart_send_str(UartPort::COM1.to_u16(), "textui init failed.\n\0".as_ptr());
}
return r;
}
fn textui_init() -> Result<i32, SystemError> {
unsafe { textui_framwork_init() };
let textui_framework = textui_framework();
unsafe { TEXTUI_IS_INIT = true };
scm_register(Arc::new(textui_framework))?;
c_uart_send_str(
UartPort::COM1.to_u16(),
"\ntext ui initialized\n\0".as_ptr(),
);
return Ok(0);
}

@ -0,0 +1,125 @@
use core::{
intrinsics::unlikely,
sync::atomic::{AtomicI32, Ordering},
};
use crate::{
driver::uart::uart::{c_uart_send, UartPort},
include::bindings::bindings::video_frame_buffer_info,
syscall::SystemError,
};
use super::textui::{
FontColor, LineId, LineIndex, TextuiCharChromatic, TEXTUI_CHAR_HEIGHT, TEXTUI_CHAR_WIDTH,
};
pub static TRUE_LINE_NUM: AtomicI32 = AtomicI32::new(0);
pub static CHAR_PER_LINE: AtomicI32 = AtomicI32::new(0);
/// textui 未初始化时直接向缓冲区写,不使用虚拟行
pub static NO_ALLOC_OPERATIONS_LINE: AtomicI32 = AtomicI32::new(0);
pub static NO_ALLOC_OPERATIONS_INDEX: AtomicI32 = AtomicI32::new(0);
/// 当系统刚启动的时候由于内存管理未初始化而texiui需要动态内存分配。因此只能暂时暴力往屏幕video_frame_buffer_info输出信息
pub fn textui_init_no_alloc() {
TRUE_LINE_NUM.store(
unsafe { (video_frame_buffer_info.height / TEXTUI_CHAR_HEIGHT) as i32 },
Ordering::SeqCst,
);
CHAR_PER_LINE.store(
unsafe { (video_frame_buffer_info.width / TEXTUI_CHAR_WIDTH) as i32 },
Ordering::SeqCst,
);
}
pub fn no_init_textui_putchar_window(
character: char,
frcolor: FontColor,
bkcolor: FontColor,
is_put_to_window: bool,
) -> Result<(), SystemError> {
if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) > TRUE_LINE_NUM.load(Ordering::SeqCst) {
NO_ALLOC_OPERATIONS_LINE.store(0, Ordering::SeqCst);
}
//字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
if unlikely(character == '\0') {
return Ok(());
}
c_uart_send(UartPort::COM1.to_u16(), character as u8);
// 进行换行操作
if unlikely(character == '\n') {
// 换行时还需要输出\r
c_uart_send(UartPort::COM1.to_u16(), b'\r');
if is_put_to_window == true {
NO_ALLOC_OPERATIONS_LINE.fetch_add(1, Ordering::SeqCst);
NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
}
return Ok(());
}
// 输出制表符
else if character == '\t' {
if is_put_to_window == true {
let char = TextuiCharChromatic::new(Some(' '), frcolor, bkcolor);
//打印的空格数注意将每行分成一个个表格每个表格为8个字符
let mut space_to_print = 8 - NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst) % 8;
while space_to_print > 0 {
char.no_init_textui_render_chromatic(
LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
);
NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
space_to_print -= 1;
}
return Ok(());
}
}
// 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
else if character == '\x08' {
if is_put_to_window == true {
NO_ALLOC_OPERATIONS_INDEX.fetch_sub(1, Ordering::SeqCst);
let op_char = NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst);
if op_char >= 0 {
let char = TextuiCharChromatic::new(Some(' '), frcolor, bkcolor);
char.no_init_textui_render_chromatic(
LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
);
NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
}
// 需要向上缩一行
if op_char < 0 {
// 上缩一行
NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
NO_ALLOC_OPERATIONS_LINE.fetch_sub(1, Ordering::SeqCst);
if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) < 0 {
NO_ALLOC_OPERATIONS_LINE.store(0, Ordering::SeqCst);
}
}
}
} else {
if is_put_to_window == true {
// 输出其他字符
let char = TextuiCharChromatic::new(Some(character), frcolor, bkcolor);
if NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)
== CHAR_PER_LINE.load(Ordering::SeqCst)
{
NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
NO_ALLOC_OPERATIONS_LINE.fetch_add(1, Ordering::SeqCst);
}
char.no_init_textui_render_chromatic(
LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
);
NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
}
}
return Ok(());
}

@ -7,6 +7,7 @@ pub mod ffi_convert;
pub mod int_like;
pub mod keyboard_parser;
pub mod lazy_init;
pub mod lib_ui;
pub mod list;
pub mod lockref;
pub mod mutex;

@ -5,7 +5,7 @@
#include <common/printk.h>
#include <common/spinlock.h>
#include <libs/libUI/textui.h>
#include <libs/lib_ui/textui.h>
#include <mm/mm.h>
#include <common/math.h>
@ -610,7 +610,7 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
{
current = *(buf + i);
// 输出
textui_putchar(current, FRcolor, BKcolor);
rs_textui_putchar(current, FRcolor, BKcolor);
}
io_mfence();
spin_unlock_irqrestore(&__printk_lock, rflags);

@ -1,35 +1,6 @@
#![allow(unused)]
use crate::{
driver::uart::uart::c_uart_send_str,
include::bindings::bindings::{printk_color, BLACK, WHITE},
};
use ::core::ffi::c_char;
use alloc::vec::Vec;
use core::{
fmt::{self, Write},
intrinsics::{likely, unlikely},
sync::atomic::{AtomicBool, Ordering},
};
use core::fmt::{self, Write};
// ====== 定义颜色 ======
/// 白色
pub const COLOR_WHITE: u32 = 0x00ffffff;
/// 黑色
pub const COLOR_BLACK: u32 = 0x00000000;
/// 红色
pub const COLOR_RED: u32 = 0x00ff0000;
/// 橙色
pub const COLOR_ORANGE: u32 = 0x00ff8000;
/// 黄色
pub const COLOR_YELLOW: u32 = 0x00ffff00;
/// 绿色
pub const COLOR_GREEN: u32 = 0x0000ff00;
/// 蓝色
pub const COLOR_BLUE: u32 = 0x000000ff;
/// 靛色
pub const COLOR_INDIGO: u32 = 0x0000ffff;
/// 紫色
pub const COLOR_PURPLE: u32 = 0x008000ff;
use super::lib_ui::textui::{textui_putchar, FontColor};
#[macro_export]
macro_rules! print {
@ -74,7 +45,7 @@ macro_rules! kinfo {
#[macro_export]
macro_rules! kwarn {
($($arg:tt)*) => {
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_YELLOW, $crate::libs::printk::COLOR_BLACK, "[ WARN ] ");
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::YELLOW, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ WARN ] ");
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
}
}
@ -82,7 +53,7 @@ macro_rules! kwarn {
#[macro_export]
macro_rules! kerror {
($($arg:tt)*) => {
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ ERROR ] ");
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ ERROR ] ");
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
}
}
@ -90,121 +61,30 @@ macro_rules! kerror {
#[macro_export]
macro_rules! kBUG {
($($arg:tt)*) => {
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ BUG ] ");
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ BUG ] ");
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
}
}
pub struct PrintkWriter;
/// 由于内存管理初始化完成之前,无法使用动态内存分配,所以需要在内存管理初始化完成之后才能使用动态内存分配
static ALLOW_ALLOC_ATOMIC: AtomicBool = AtomicBool::new(false);
static mut ALLOW_ALLOC_BOOL: bool = false;
impl PrintkWriter {
#[inline]
pub fn __write_fmt(&mut self, args: fmt::Arguments) {
self.write_fmt(args);
self.write_fmt(args).ok();
}
/// 调用C语言编写的printk_color,并输出白底黑字暂时只支持ascii字符
/// 并输出白底黑字
/// @param str: 要写入的字符
pub fn __write_string(&mut self, s: &str) {
if unlikely(!self.allow_alloc()) {
self.__write_string_on_stack(s);
return;
}
let str_to_print = self.__utf8_to_ascii(s);
unsafe {
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
for c in s.chars() {
textui_putchar(c, FontColor::WHITE, FontColor::BLACK).ok();
}
}
pub fn __write_string_color(&self, fr_color: u32, bk_color: u32, s: &str) {
if unlikely(!self.allow_alloc()) {
self.__write_string_on_stack(s);
return;
}
let str_to_print = self.__utf8_to_ascii(s);
unsafe {
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
}
}
#[inline]
fn allow_alloc(&self) -> bool {
// 由于allow_alloc只可能由false变为true
// 因此采用两种方式读取它一种是原子操作一种是普通的bool以优化性能。
if likely(unsafe { ALLOW_ALLOC_BOOL }) {
return true;
} else {
return ALLOW_ALLOC_ATOMIC.load(Ordering::SeqCst);
}
}
/// 允许动态内存分配
pub fn enable_alloc(&self) {
ALLOW_ALLOC_ATOMIC.store(true, Ordering::SeqCst);
unsafe {
ALLOW_ALLOC_BOOL = true;
}
}
/// 将s这个utf8字符串转换为ascii字符串
/// @param s 待转换的utf8字符串
/// @return Vec<u8> 转换结束后的Ascii字符串
pub fn __utf8_to_ascii(&self, s: &str) -> Vec<u8> {
let mut ascii_str: Vec<u8> = Vec::with_capacity(s.len() + 1);
for byte in s.bytes() {
match byte {
0..=127 => {
ascii_str.push(byte);
}
_ => {}
}
}
ascii_str.push(b'\0');
return ascii_str;
}
fn __write_string_on_stack(&self, s: &str) {
let s_len = s.len();
assert!(s_len < 1024, "s_len is too long");
let mut str_to_print: [u8; 1024] = [0; 1024];
let mut i = 0;
for byte in s.bytes() {
match byte {
0..=127 => {
str_to_print[i] = byte;
i += 1;
}
_ => {}
}
}
str_to_print[i] = b'\0';
unsafe {
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
}
}
fn __write_string_color_on_stack(&self, fr_color: u32, bk_color: u32, s: &str) {
let s_len = s.len();
assert!(s_len < 1024, "s_len is too long");
let mut str_to_print: [u8; 1024] = [0; 1024];
let mut i = 0;
for byte in s.bytes() {
match byte {
0..=127 => {
str_to_print[i] = byte;
i += 1;
}
_ => {}
}
}
str_to_print[i] = b'\0';
unsafe {
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
pub fn __write_string_color(&self, fr_color: FontColor, bk_color: FontColor, s: &str) {
for c in s.chars() {
textui_putchar(c, fr_color, bk_color).ok();
}
}
}
@ -219,6 +99,5 @@ impl fmt::Write for PrintkWriter {
#[doc(hidden)]
pub fn __printk(args: fmt::Arguments) {
use fmt::Write;
PrintkWriter.write_fmt(args).unwrap();
}

@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
use crate::arch::asm::irqflags::{local_irq_restore, local_irq_save};
use crate::arch::interrupt::{cli, sti};
use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t};
use crate::process::preempt::{preempt_disable, preempt_enable};
use crate::syscall::SystemError;