diff --git a/CODE/UTSM/MAKEFILE b/CODE/UTSM/MAKEFILE index db1c835..c24d4d4 100644 --- a/CODE/UTSM/MAKEFILE +++ b/CODE/UTSM/MAKEFILE @@ -26,7 +26,7 @@ all: $(OUT) -include $(DEPS) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\boot" mkdir "$(ROOT)\SYSTEM\boot" + @mkdir -p $(dir $@) $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/cmd/MAKEFILE b/CODE/cmd/MAKEFILE index 616e02b..191f254 100644 --- a/CODE/cmd/MAKEFILE +++ b/CODE/cmd/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64" mkdir "$(ROOT)\SYSTEM\system\deshab64" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/desktop/MAKEFILE b/CODE/desktop/MAKEFILE index 3d6f2f9..498e641 100644 --- a/CODE/desktop/MAKEFILE +++ b/CODE/desktop/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64" mkdir "$(ROOT)\SYSTEM\system\deshab64" + @mkdir -p $(dir $@) $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/desktop/main.c b/CODE/desktop/main.c index f451b35..201c3b7 100644 --- a/CODE/desktop/main.c +++ b/CODE/desktop/main.c @@ -19,8 +19,6 @@ */ #include "../UTSM/include/utsm/dsk.h" -/* Linux 兼容层服务接口(reserved[5],exec/file_list/file_read) */ -#include "../UTSM/include/utsm/linux_compat.h" /* block 设备函数类型(从 kernel_api + 0xA8 获取 block_api,read @ +0x10, write @ +0x18) */ typedef int (*desktop_block_read_fn)(u32 index, u64 lba, u32 count, void *buffer); @@ -44,11 +42,6 @@ typedef long long i64; static __inline__ void outb(u16 port, u8 value) { __asm__ volatile("outb %0,%1"::"a"(value),"Nd"(port)); } static __inline__ u8 inb(u16 port) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(port)); return v; } -/* Linux 桌面应用配置契约(da_linuxapp_parse / DA_LINUXAPP_* 常量)。 - * DA_NO_PORTIO:本文件已自带 outb/inb,跳过头文件内同名定义。 */ -#define DA_NO_PORTIO -#include "../tools/desktop_app.h" - static void sputc(char c) { for (unsigned int i=0; i<100000; i++) { if (inb(COM1+5)&0x20) break; } outb(COM1, (unsigned char)c); @@ -78,7 +71,6 @@ static void redraw_all(void); static int ps2_mouse_poll(void); static void draw_statusbar_full(void); static void files_refresh(void); -static void shortcuts_refresh(void); /* ============================================================ * 常量(Winux-Kate 布局) @@ -172,10 +164,6 @@ typedef struct { app_draw_fn on_draw; app_destroy_fn on_destroy; const char *elf_name; - /* Linux 兼容层命令(Phase 5,如 "/usr/bin/neofetch")。与 elf_name 互斥: - * 两者同时设置时 elf_name 优先(走外部 ELF 全屏宿主),linux_cmd 被忽略; - * 仅设置 linux_cmd 时必须提供 on_create(内置终端窗口承载执行)。 */ - const char *linux_cmd; } app_descriptor; /* 桌面图标 */ @@ -186,16 +174,7 @@ typedef struct { int selected; } desktop_icon; -/* 桌面快捷方式(从 SYSTEM/user/desktop 目录加载 .lnk 文件) */ -typedef struct { - char display_name[24]; /* 显示名称(UTF-8) */ - char elf_name[11]; /* ELF 文件名(FAT32 8.3) */ - char icon_type[12]; /* 图标类型:editor/folder/browser/terminal */ - int x, y; /* 桌面位置 */ - int selected; /* 选中状态 */ -} desktop_shortcut; - -#define MAX_ICONS 24 /* 桌面图标槽(内置应用 + 用户快捷方式) */ +#define MAX_ICONS 8 /* 工作区 */ typedef struct { @@ -260,22 +239,14 @@ static int g_dragging = 0; static int g_drag_win = -1; static int g_drag_off_x, g_drag_off_y; -/* 应用表(16 = 6 内置 + DA_LINUXAPP_MAX 8 个 Linux 应用 + 余量) */ -#define MAX_APPS 16 +/* 应用表 */ +#define MAX_APPS 8 static app_descriptor g_apps[MAX_APPS]; static int g_app_count = 0; -/* Linux 兼容层服务运行态(register_linux_apps 设置):0 时 Linux 图标置灰, - * 双击仍开终端窗口并提示不可用原因(lnx_on_create 运行时复查)。 */ -static int g_lnx_svc_up = 0; - static desktop_icon g_icons[MAX_ICONS]; static int g_icon_count = 0; -/* 用户快捷方式(从 SYSTEM/user/desktop 加载) */ -static desktop_shortcut g_shortcuts[MAX_ICONS]; -static int g_shortcut_count = 0; - /* ---- Kate 外壳状态 ---- */ static int g_booted = 0; static int g_page = 1; /* 1..3 内置, 4..8 自定义 */ @@ -549,27 +520,7 @@ static void draw_icon_browser(du_context *ctx, int cx, int cy) { du_pixel(ctx, ccx, ccy, KS_ACCENT2); } -/* Linux 应用图标:暗底终端 + 霓虹绿 >_ 提示符(与 bash 终端同色板)。 - * 服务不可用时 accent 传 KS_TEXT_DIM(置灰,点击仍给原因提示)。 */ -static void draw_icon_linux(du_context *ctx, int cx, int cy, u32 accent) { - du_fill_rect(ctx, cx, cy, 40, 40, KS_BG_PRIMARY); - du_rect_outline(ctx, cx, cy, 40, 40, accent, 2); - /* '>' 折线 */ - du_fill_rect(ctx, cx + 8, cy + 12, 2, 2, accent); - du_fill_rect(ctx, cx + 10, cy + 14, 2, 2, accent); - du_fill_rect(ctx, cx + 12, cy + 16, 2, 2, accent); - du_fill_rect(ctx, cx + 10, cy + 18, 2, 2, accent); - du_fill_rect(ctx, cx + 8, cy + 20, 2, 2, accent); - /* '_' 光标块 */ - du_fill_rect(ctx, cx + 16, cy + 22, 8, 2, accent); -} - static void draw_app_icon(du_context *ctx, int app_id, int cx, int cy) { - /* Linux 应用走专属图标(暗底绿提示符),其余保持原有映射 */ - if (app_id >= 0 && app_id < g_app_count && g_apps[app_id].linux_cmd) { - draw_icon_linux(ctx, cx, cy, g_lnx_svc_up ? KS_ACCENT2 : KS_TEXT_DIM); - return; - } switch (app_id) { case 0: draw_icon_terminal(ctx, cx, cy); break; case 1: draw_icon_editor(ctx, cx, cy); break; @@ -1154,269 +1105,6 @@ static void bash_on_draw(void *state, app_ctx *ctx) { __attribute__((unused)) static void bash_on_destroy(void *state) { (void)state; } -/* ============================================================ - * Linux 兼容层应用 (Phase 5) - * 图标 → 终端风格窗口 → linux_compat_service.exec 同步执行。 - * exec 是同步阻塞调用(park-and-resume 到 Linux guest 完成才返回), - * 无 out_cb 流式回调:先绘制 running 状态再阻塞,返回后一次性 - * 把 stdout 缓冲追加进终端并显示 [exit N]。 - * ============================================================ */ - -static const linux_compat_service *g_lxc_svc = 0; - -#define LNX_MAX_WINS 8 /* 与 MAX_WINDOWS 对齐:任何窗口都可能是 Linux 终端 */ -#define LNX_OUT_CAP 16384 /* exec stdout 收集缓冲 */ - -typedef struct { - bash_state term; /* 复用 bash 终端字符网格(无输入行) */ - int finished; /* 0=running 1=已返回 */ - int rc; /* exec 返回值(0 成功,负值失败) */ - u64 exit_code; /* guest 进程退出码 */ -} lnx_state; - -static lnx_state g_lnx_states[LNX_MAX_WINS]; -static int g_lnx_used[LNX_MAX_WINS]; -static char g_lnx_out[LNX_OUT_CAP]; /* 同步单发,可全窗口共享 */ - -/* Linux 应用注册名/命令持久池(f32_data 会被后续文件操作复用,必须拷出) */ -static char g_lnx_name_pool[DA_LINUXAPP_MAX][12]; -static char g_lnx_cmd_pool[DA_LINUXAPP_MAX][64]; -static char g_lnx_id_pool[DA_LINUXAPP_MAX][8]; - -/* 追加无符号十进制到终端 */ -static void lnx_put_u64(bash_state *t, u64 v, u32 color) { - char tmp[20]; - int n = 0; - if (v == 0) tmp[n++] = '0'; - while (v && n < 20) { tmp[n++] = (char)('0' + (v % 10)); v /= 10; } - while (n > 0) bash_putc(t, tmp[--n], color); -} - -static void lnx_put_i64(bash_state *t, i64 v, u32 color) { - if (v < 0) { bash_putc(t, '-', color); lnx_put_u64(t, (u64)(-v), color); } - else lnx_put_u64(t, (u64)v, color); -} - -/* 追加 exec 输出到终端:剥离 ANSI CSI 转义序列,忽略 \r,\t 展开为 2 空格, - * 其余控制字符丢弃(终端字体仅 ASCII,非 ASCII 字节由 du_draw_char 钳为空格)。 */ -static void lnx_append(bash_state *t, const char *buf, u64 len, u32 color) { - int esc = 0; - for (u64 i = 0; i < len; i++) { - char c = buf[i]; - if (esc) { - /* CSI: ESC [ 参数... 结束字节(0x40-0x7E);其它 ESC 序列同理吞掉 */ - if (c >= 0x40 && c <= 0x7E) esc = 0; - continue; - } - if (c == 0x1B) { esc = 1; continue; } - if (c == '\r') continue; - if (c == '\t') { bash_putc(t, ' ', color); bash_putc(t, ' ', color); continue; } - if ((u8)c < 32 && c != '\n') continue; - bash_putc(t, c, color); - } -} - -/* 终端内容绘制:全量重绘(与 editor_draw_to 同策略),无输入行 */ -static void lnx_draw_to(lnx_state *s, int cx, int cy, int cw, int ch) { - bash_state *t = &s->term; - du_fill_rect(&g_fb, cx, cy, cw, ch, KS_BG_PRIMARY); - for (int r = 0; r < t->rows; r++) { - for (int c = 0; c < t->cols; c++) { - int idx = r * TERM_MAX_COLS + c; - if (t->ch[idx] == ' ') continue; - int px = cx + (int)DU_SPACE_SM + c * (int)DU_ASCII_STEP; - int py = cy + (int)DU_SPACE_SM + r * (int)DU_ASCII_LINE_H; - if (px + (int)DU_ASCII_CELL_W > cx + cw) continue; - if (py + (int)DU_ASCII_CELL_H > cy + ch) continue; - du_draw_char(&g_fb, (char)t->ch[idx], px, py, t->fg[idx], KS_BG_PRIMARY); - } - } -} - -/* ---- 窗口适配 ---- */ -static void *lnx_on_create(app_ctx *ctx) { - int slot = -1; - for (int i = 0; i < LNX_MAX_WINS; i++) { - if (!g_lnx_used[i]) { slot = i; break; } - } - if (slot < 0) return 0; - g_lnx_used[slot] = 1; - - lnx_state *s = &g_lnx_states[slot]; - app_descriptor *app = &g_apps[ctx->win->app_id]; - - bash_reset(&s->term, ctx->client_w, ctx->client_h); - s->finished = 0; - s->rc = 0; - s->exit_code = 0; - - /* 标题:显示名 + Linux 标记 */ - { - for (int i = 0; i < 48; i++) ctx->win->title[i] = 0; - char t[48]; - int ti = 0; - const char *d = app->display_name; - while (d[ti] && ti < 38) { t[ti] = d[ti]; ti++; } - const char *suf = " . Linux"; - int j = 0; - while (suf[j] && ti < 47) { t[ti++] = suf[j++]; } - t[ti] = 0; - kstrcpy(ctx->win->title, t, 48); - } - - /* 命令回显 */ - bash_puts(&s->term, "$ ", KS_ACCENT2); - bash_puts(&s->term, app->linux_cmd, KS_TEXT_PRIMARY); - bash_putc(&s->term, '\n', 0); - - /* 服务运行时复查(注册后 guest 仍可能不可用) */ - if (!g_lxc_svc || !g_lxc_svc->is_available()) { - bash_puts(&s->term, "linux: compat service unavailable\n", KS_DANGER); - bash_puts(&s->term, "[exit -1]\n", KS_DANGER); - s->finished = 1; - s->rc = -1; - return s; - } - - /* running 状态提示:先呈现窗口再进入同步阻塞 exec */ - bash_puts(&s->term, "running... (sync exec, UI will freeze)\n", KS_TEXT_DIM); - ctx->win->app_state = s; /* 让 redraw_all 能看到本窗口内容 */ - redraw_all(); - flip_buffer(); - - /* 分词:linux_cmd → path + argv(就地切分副本) */ - char cmdline[96]; - kstrcpy(cmdline, app->linux_cmd, 96); - const char *argv[8]; - int argc = 0; - char *p = cmdline; - while (*p && argc < 8) { - while (*p == ' ') p++; - if (!*p) break; - argv[argc++] = p; - while (*p && *p != ' ') p++; - if (*p) *p++ = 0; - } - if (argc == 0) { - bash_puts(&s->term, "linux: empty command\n", KS_DANGER); - s->finished = 1; - s->rc = -1; - return s; - } - - /* 绝对路径直接使用;裸命令补 /bin/ 前缀(与 shell linux 命令一致) */ - char path[96]; - if (argv[0][0] == '/') { - kstrcpy(path, argv[0], 96); - } else { - kstrcpy(path, "/bin/", 96); - kstrcat(path, argv[0], 96); - } - - u64 out_len = 0, exit_code = 0; - slog("linux exec"); - int rc = g_lxc_svc->exec(path, argc, argv, - g_lnx_out, LNX_OUT_CAP - 1, - &out_len, &exit_code); - - s->rc = rc; - s->exit_code = exit_code; - s->finished = 1; - - if (rc != 0) { - bash_puts(&s->term, "linux: exec failed (rc=", KS_DANGER); - lnx_put_i64(&s->term, rc, KS_DANGER); - bash_puts(&s->term, ")\n", KS_DANGER); - bash_puts(&s->term, "[exit -1]\n", KS_DANGER); - return s; - } - - /* 输出回显(一次性追加;exec 无流式回调) */ - if (out_len > 0) { - lnx_append(&s->term, g_lnx_out, out_len, KS_TEXT_PRIMARY); - if (g_lnx_out[out_len - 1] != '\n') bash_putc(&s->term, '\n', 0); - if (out_len >= LNX_OUT_CAP - 1) - bash_puts(&s->term, "[output truncated]\n", KS_TEXT_DIM); - } - - /* 退出码:0 绿 / 非 0 琥珀 */ - u32 ec_color = (exit_code == 0) ? KS_ACCENT2 : KS_WARN; - bash_puts(&s->term, "[exit ", ec_color); - lnx_put_u64(&s->term, exit_code, ec_color); - bash_puts(&s->term, "]\n", ec_color); - return s; -} - -static void lnx_on_draw(void *state, app_ctx *ctx) { - lnx_draw_to((lnx_state *)state, ctx->client_x, ctx->client_y, - ctx->client_w, ctx->client_h); -} - -static void lnx_on_destroy(void *state) { - lnx_state *s = (lnx_state *)state; - for (int i = 0; i < LNX_MAX_WINS; i++) { - if (&g_lnx_states[i] == s) { g_lnx_used[i] = 0; break; } - } -} - -/* ---- Linux 应用注册 ---- - * 无论服务是否可用都注册图标:可用时双击即同步 exec;不可用(VMX 缺失/ - * guest 未驻留)时图标置灰(g_lnx_svc_up=0),双击由 lnx_on_create 运行时 - * 复查并显示 "linux: compat service unavailable [exit -1]",绝不 panic。 - * 配置:FAT32 根目录 LINUXAPP.CNF(8.3 名 LINUXAPPCNF),每行 显示名|linux命令; - * 文件缺失或无有效行时回退内置默认列表(echo hello / uname -a / ls -l /, - * 三条均为 Arch rootfs 与 initramfs busybox 环境共有的可执行命令)。 */ -static void register_linux_apps(void) { - g_lnx_svc_up = (g_lxc_svc && g_lxc_svc->is_available()) ? 1 : 0; - if (!g_lxc_svc) slog("linux apps: service absent (icons greyed)"); - else if (!g_lnx_svc_up) slog("linux apps: service unavailable (icons greyed)"); - - da_linux_app ents[DA_LINUXAPP_MAX]; - int n = 0; - - u8 *data = 0; - u32 size = 0; - if (f32_read_root_file(DA_LINUXAPP_CNF_83, &data, &size) == 0 && size > 0) { - n = da_linuxapp_parse((const char *)data, size, ents, DA_LINUXAPP_MAX); - } - - if (n <= 0) { - /* 内置默认保底(guest 中确定存在的命令) */ - kstrcpy(g_lnx_name_pool[0], "HELLO", 12); - kstrcpy(g_lnx_cmd_pool[0], "/bin/echo hello from deshab linux", 64); - kstrcpy(g_lnx_name_pool[1], "UNAME", 12); - kstrcpy(g_lnx_cmd_pool[1], "/bin/uname -a", 64); - kstrcpy(g_lnx_name_pool[2], "LS", 12); - kstrcpy(g_lnx_cmd_pool[2], "/bin/ls -l /", 64); - n = 3; - slog("linux apps: builtin defaults"); - } else { - for (int i = 0; i < n; i++) { - kstrcpy(g_lnx_name_pool[i], ents[i].name, 12); - kstrcpy(g_lnx_cmd_pool[i], ents[i].cmd, 64); - } - slog("linux apps: loaded LINUXAPP.CNF"); - } - - for (int i = 0; i < n && g_app_count < MAX_APPS; i++) { - char *id = g_lnx_id_pool[i]; - id[0] = 'l'; id[1] = 'n'; id[2] = 'x'; id[3] = (char)('0' + i); id[4] = 0; - g_apps[g_app_count] = (app_descriptor){ - id, g_lnx_name_pool[i], 720, 480, - lnx_on_create, 0, lnx_on_draw, lnx_on_destroy, - 0, g_lnx_cmd_pool[i] - }; - g_app_count++; - { - char msg[64]; - kstrcpy(msg, "linux app registered: ", 64); - kstrcat(msg, g_lnx_name_pool[i], 64); - slog(msg); - } - } - slog("linux apps registered"); -} - /* ============================================================ * 文本编辑器 (Editor) — 面板/IDE/窗口共用核心 * ============================================================ */ @@ -1739,86 +1427,67 @@ static void register_apps(void) { /* 命令行1:shell.elf(原生命令行 + 可运行 Linux 程序)*/ g_apps[0] = (app_descriptor){ "shell", "Terminal", 720, 480, - 0, 0, 0, 0, "SHELL ELF", 0 + 0, 0, 0, 0, "SHELL ELF" }; g_app_count++; /* 命令行2:cmd.elf(Windows 风格命令行 + PE/EXE 执行)*/ g_apps[1] = (app_descriptor){ "cmd", "CMD", 720, 480, - 0, 0, 0, 0, "CMD ELF", 0 + 0, 0, 0, 0, "CMD ELF" }; g_app_count++; g_apps[2] = (app_descriptor){ "editor", "Editor", 600, 450, - editor_on_create, editor_on_event, editor_on_draw, editor_on_destroy, 0, 0 + editor_on_create, editor_on_event, editor_on_draw, editor_on_destroy, 0 }; g_app_count++; g_apps[3] = (app_descriptor){ "fileman", "Files", 500, 400, - 0, 0, 0, 0, "FILEMAN ELF", 0 + 0, 0, 0, 0, "FILEMAN ELF" }; g_app_count++; g_apps[4] = (app_descriptor){ "calc", "Calculator", 280, 400, - calc_on_create, calc_on_event, calc_on_draw, calc_on_destroy, 0, 0 + calc_on_create, calc_on_event, calc_on_draw, calc_on_destroy, 0 }; g_app_count++; g_apps[5] = (app_descriptor){ "browser", "Browser", 700, 500, - 0, 0, 0, 0, "BROWSER ELF", 0 + 0, 0, 0, 0, "BROWSER ELF" + }; + g_app_count++; + /* ProEdit — 增强版文本编辑器(语法高亮、设置、目录浏览)*/ + g_apps[6] = (app_descriptor){ + "proedit", "ProEdit", 750, 550, + 0, 0, 0, 0, "PROEDIT ELF" }; g_app_count++; - - /* Linux 兼容层应用:无论服务是否可用都注册图标(不可用时置灰, - * 双击仍开终端窗口提示原因,见 register_linux_apps / lnx_on_create) */ - register_linux_apps(); } /* Winux-Kate .desktop-grid:canvas padding 24px,列宽 104px,gap 18px, * 左→右排列,超出画布宽度则换行(align-content: start) * - * 桌面图标来源: - * 1. 用户快捷方式(SYSTEM/user/desktop 目录) - * 2. 内置应用(editor, browser 等) + * 注意:Terminal 和 CMD 已在第一页 Dashboard(TERM-01 / TERM-02), + * 桌面不再重复显示其图标。 */ static void setup_desktop_icons(void) { int pad = KATE_ICON_PAD; /* 24 */ int x = pad; int y = KATE_TOPBAR_H + KATE_PAGE_PAD + pad; int max_x = (int)g_fb_w - pad; /* canvas 右缘 */ - - /* 先加载用户快捷方式 */ - shortcuts_refresh(); - for (int i = 0; i < g_shortcut_count && g_icon_count < MAX_ICONS; i++) { + for (int i = 0; i < g_app_count; i++) { + if (!g_apps[i].on_create && !g_apps[i].elf_name) continue; + /* 跳过 Terminal 和 CMD(已在 Dashboard 第一页) */ + if (g_apps[i].name[0] == 's' && g_apps[i].name[1] == 'h' && g_apps[i].name[2] == 'e') continue; + if (g_apps[i].name[0] == 'c' && g_apps[i].name[1] == 'm' && g_apps[i].name[2] == 'd') continue; if (x > pad && x + KATE_ICON_W > max_x) { x = pad; y += KATE_ICON_H + KATE_ICON_GAP; } - /* 将快捷方式转换为桌面图标(app_id = -1 表示快捷方式) */ - g_icons[g_icon_count].app_id = -1; /* 标记为快捷方式 */ + g_icons[g_icon_count].app_id = i; g_icons[g_icon_count].x = x; g_icons[g_icon_count].y = y; - g_icons[g_icon_count].label = g_shortcuts[i].display_name; - g_icons[g_icon_count].selected = 0; - g_shortcuts[i].x = x; /* 记录位置用于点击检测 */ - g_shortcuts[i].y = y; - g_icon_count++; - x += KATE_ICON_W + KATE_ICON_GAP; - } - - /* 再追加 Linux 应用图标(register_linux_apps 已登记进 g_apps,带 linux_cmd)。 - * 服务不可用时图标仍上架但置灰(draw_app_icon 查 g_lnx_svc_up), - * 双击开终端窗口提示原因,与可用时同一入口。 */ - for (int a = 0; a < g_app_count && g_icon_count < MAX_ICONS; a++) { - if (!g_apps[a].linux_cmd) continue; - if (x > pad && x + KATE_ICON_W > max_x) { - x = pad; - y += KATE_ICON_H + KATE_ICON_GAP; - } - g_icons[g_icon_count].app_id = a; - g_icons[g_icon_count].x = x; - g_icons[g_icon_count].y = y; - g_icons[g_icon_count].label = g_apps[a].display_name; + g_icons[g_icon_count].label = g_apps[i].display_name; g_icons[g_icon_count].selected = 0; g_icon_count++; x += KATE_ICON_W + KATE_ICON_GAP; @@ -1842,10 +1511,7 @@ typedef struct { u32 type,flags; u64 offset,vaddr,paddr,filesz,memsz,align; } dt typedef struct { i64 tag; u64 val; } dt_elf64_dyn; typedef struct { u64 offset; u64 info; i64 addend; } dt_elf64_rela; -/* 外部工具 ELF 加载缓冲。fileman/editor 等工具 include fat32_io.h - * 带 ~388KB BSS(f32_disk+f32_data),其 .elf 的 memsz 可达 ~470KB。 - * 1MB 容量覆盖当前所有工具 ELF 并留余量。BSS 是 NOBITS 不占 desktop.elf 文件空间。 */ -static u8 g_elf_image[1048576]; +static u8 g_elf_image[262144]; static int dt_load_elf(u8 *data, u32 data_size, void **entry_out) { const dt_elf64_ehdr *eh = (const dt_elf64_ehdr *)data; @@ -2023,43 +1689,6 @@ static void files_refresh(void) { else g_files_loaded = 0; } -/* 加载桌面快捷方式(从 SYSTEM/user/desktop 目录读取 .lnk 文件) - * 快捷方式文件格式(纯文本,UTF-8): - * 第1行:显示名称(如 "编辑器") - * 第2行:ELF文件名(FAT32 8.3,如 "EDITOR ELF") - * 第3行:图标类型(如 "editor") - */ -static void shortcuts_refresh(void) { - g_shortcut_count = 0; - if (!g_block_read) return; - - /* 读取 desktop 目录下的 .lnk 文件 */ - /* 简化实现:直接读取预定义的快捷方式 */ - - /* 内置快捷方式列表(暂时硬编码,后续可改为读取.lnk文件) */ - static const struct { - const char *name; - const char *elf; - const char *icon; - } builtin_shortcuts[] = { - { "编辑器", "EDITOR ELF", "editor" }, - { "文件管理", "FILEMAN ELF", "folder" }, - { "浏览器", "BROWSER ELF", "browser" }, - { "终端", "SHELL ELF", "terminal" }, - }; - - int count = sizeof(builtin_shortcuts) / sizeof(builtin_shortcuts[0]); - for (int i = 0; i < count && g_shortcut_count < MAX_ICONS; i++) { - desktop_shortcut *s = &g_shortcuts[g_shortcut_count]; - kstrcpy(s->display_name, builtin_shortcuts[i].name, 24); - kstrcpy(s->elf_name, builtin_shortcuts[i].elf, 11); - kstrcpy(s->icon_type, builtin_shortcuts[i].icon, 12); - s->x = 0; s->y = 0; - s->selected = 0; - g_shortcut_count++; - } -} - /* 双击打开文件 → 载入 DASHBOARD EDITOR */ static void files_open(int idx) { if (idx < 0 || idx >= g_file_count) return; @@ -2474,20 +2103,7 @@ static void draw_desktop_icons(void) { du_kate_desktop_icon(&g_fb, ic->x, ic->y, ic->label, ic->selected); int ix = ic->x + (KATE_ICON_W - KATE_ICON_IMG) / 2; int iy = ic->y + 10; - - /* 根据图标来源绘制不同图标 */ - if (ic->app_id >= 0) { - /* 内置应用图标 */ - draw_app_icon(&g_fb, ic->app_id, ix, iy); - } else if (i < g_shortcut_count) { - /* 快捷方式图标(根据 icon_type 选择) */ - const char *icon = g_shortcuts[i].icon_type; - if (icon[0] == 'e' && icon[1] == 'd') draw_icon_editor(&g_fb, ix, iy); - else if (icon[0] == 'f') draw_icon_folder(&g_fb, ix, iy); - else if (icon[0] == 'b') draw_icon_browser(&g_fb, ix, iy); - else if (icon[0] == 't') draw_icon_terminal(&g_fb, ix, iy); - else draw_icon_editor(&g_fb, ix, iy); /* 默认 */ - } + draw_app_icon(&g_fb, ic->app_id, ix, iy); } } @@ -3291,15 +2907,7 @@ static int desktop_click(int mx, int my, int dbl) { int ix = g_icons[i].x, iy = g_icons[i].y; if (mx >= ix && mx < ix + ICON_W && my >= iy && my < iy + ICON_H) { if (dbl && g_icons[i].selected) { - /* 根据图标来源选择启动方式 */ - if (g_icons[i].app_id >= 0) { - /* 内置应用 */ - launch_app(g_icons[i].app_id); - } else if (i < g_shortcut_count) { - /* 快捷方式:加载外部 ELF */ - slog("launching shortcut"); - launch_external_elf(g_shortcuts[i].elf_name); - } + launch_app(g_icons[i].app_id); } else { for (int j = 0; j < g_icon_count; j++) g_icons[j].selected = 0; g_icons[i].selected = 1; @@ -3544,22 +3152,6 @@ void dsk_entry(const dsk_boot_context *ctx) { g_fb.fb = (du_u32 *)SPRITE_BUF_ADDR; f32_init(g_block_read, g_block_write); - /* Linux 兼容层服务(reserved[5],magic 校验)—— 需在 register_apps 前就绪 */ - { - u64 lxc_addr = ctx->reserved[5]; - if (lxc_addr) { - const linux_compat_service *lxc = (const linux_compat_service *)lxc_addr; - if (lxc->magic == LINUX_COMPAT_MAGIC) { - g_lxc_svc = lxc; - slog("linux_compat service ok"); - } else { - slog("linux_compat magic mismatch"); - } - } else { - slog("linux_compat service absent"); - } - } - tsc_calibrate(); g_rtc_boot_sec = rtc_day_sec(); g_last_sec = g_rtc_boot_sec; diff --git a/CODE/dsk/MAKEFILE b/CODE/dsk/MAKEFILE index 762b8c0..f5b414e 100644 --- a/CODE/dsk/MAKEFILE +++ b/CODE/dsk/MAKEFILE @@ -18,7 +18,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64" mkdir "$(ROOT)\SYSTEM\system\deshab64" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/firstInit/MAKEFILE b/CODE/firstInit/MAKEFILE index 5d38b78..8ded914 100644 --- a/CODE/firstInit/MAKEFILE +++ b/CODE/firstInit/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\user\use" mkdir "$(ROOT)\SYSTEM\system\user\use" + @mkdir -p "$(ROOT)/SYSTEM/system/user/use" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/login/MAKEFILE b/CODE/login/MAKEFILE index 339efb9..e70048f 100644 --- a/CODE/login/MAKEFILE +++ b/CODE/login/MAKEFILE @@ -17,7 +17,7 @@ all: $(OUT) # 构建后用 patch_login_hash.ps1 计算 .text SHA256 并写入 .hashseg $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\user\use" mkdir "$(ROOT)\SYSTEM\system\user\use" + @mkdir -p "$(ROOT)/SYSTEM/system/user/use" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) @echo [login] patching .text SHA256 into .hashseg... powershell -NoProfile -ExecutionPolicy Bypass -File $(PATCHER) $@ diff --git a/CODE/mouse/MAKEFILE b/CODE/mouse/MAKEFILE index 6749ecf..4023dcc 100644 --- a/CODE/mouse/MAKEFILE +++ b/CODE/mouse/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64\mouse" mkdir "$(ROOT)\SYSTEM\system\deshab64\mouse" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64/mouse" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/netman/MAKEFILE b/CODE/netman/MAKEFILE index 4130935..e9120a5 100644 --- a/CODE/netman/MAKEFILE +++ b/CODE/netman/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64\network" mkdir "$(ROOT)\SYSTEM\system\deshab64\network" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64/network" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/shell/MAKEFILE b/CODE/shell/MAKEFILE index 135dee0..cf24916 100644 --- a/CODE/shell/MAKEFILE +++ b/CODE/shell/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64" mkdir "$(ROOT)\SYSTEM\system\deshab64" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/tools/browser/MAKEFILE b/CODE/tools/browser/MAKEFILE index 7d04ada..8744064 100644 --- a/CODE/tools/browser/MAKEFILE +++ b/CODE/tools/browser/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64\tools" mkdir "$(ROOT)\SYSTEM\system\deshab64\tools" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64/tools" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/tools/curl/MAKEFILE b/CODE/tools/curl/MAKEFILE index d0bef11..dff6b0e 100644 --- a/CODE/tools/curl/MAKEFILE +++ b/CODE/tools/curl/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64\tools" mkdir "$(ROOT)\SYSTEM\system\deshab64\tools" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64/tools" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/tools/desktop_app_linux.h b/CODE/tools/desktop_app_linux.h new file mode 100644 index 0000000..4cbbd34 --- /dev/null +++ b/CODE/tools/desktop_app_linux.h @@ -0,0 +1,447 @@ +/* desktop_app_linux.h — Deshab 应用 Linux 预览后端 (SDL2) + * + * 允许在 Linux 开发机上预览 Deshab-OS 应用的 UI 效果。 + * 使用方法: + * 1. # +define DA_LINUX_PREVIEW 1 * 2. #include "desktop_app_linux.h" + * 3. 实现 dsk_entry() 函数(与 Deshab-OS 版本相同) + * 4. 编译:make -f Makefile.linux + * + * 编译后会在 X11/Wayland 窗口中显示应用 UI,可用于调试布局和渲染。 + */ + +#ifndef DESHAB_DESKTOP_APP_LINUX_H +#define DESHAB_DESKTOP_APP_LINUX_H + +#include +#include +#include +#include +#include + +/* =================================================================== + * 基础类型(与 desktop_app.h 一致) + * =================================================================== */ + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int64_t i64; + +/* =================================================================== + * 颜色常量(与 desktop_app.h 一致) + * =================================================================== */ + +#define DA_BG_PRIMARY 0xFF0A1428u +#define DA_BG_SECONDARY 0xFF0F1E38u +#define DA_BG_TERTIARY 0xFF162848u +#define DA_TEXT_PRIMARY 0xFFE8E8F0u +#define DA_TEXT_DIM 0xFF6A6A88u +#define DA_ACCENT 0xFF00A8CCu +#define DA_ACCENT_LIGHT 0xFF44CCF0u +#define DA_BORDER 0xFF284888u +#define DA_BORDER_FOCUS 0xFF44CCF0u +#define DA_CURSOR_COLOR 0xFF00A8CCu +#define DA_SUCCESS 0xFF40C880u +#define DA_ERROR 0xFFFF4466u +#define DA_WARNING 0xFFF0A030u + +#define DA_TITLEBAR_H 28 +#define DA_BORDER_W 2 +#define DA_STATUSBAR_H 20 + +/* =================================================================== + * 渲染上下文(SDL2 版本) + * =================================================================== */ + +typedef struct { + Uint32 *pixels; /* SDL2 像素缓冲 */ + int width; + int height; + int pitch; /* 行字节宽 */ + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; +} da_app_context; + +/* =================================================================== + * ASCII 字体声明(需要从 ascii_bitmaps.c 包含) + * =================================================================== */ + +/* 如果外部未定义字体,则声明 extern */ +/* 在 notes_preview.c 中 include ascii_bitmaps.c 后会定义实际变量 */ +#ifndef DA_FONT_DEFINED +extern const unsigned char *g_ascii[]; +extern int g_ascii_w; +extern int g_ascii_h; +#else +/* 使用 extern 引用 ascii_bitmaps.c 中定义的 static 变量 */ +/* 注意:ascii_bitmaps.c 需要改为非 static */ +extern const unsigned char g_ascii[][11*18]; +extern int g_ascii_w; +extern int g_ascii_h; +#endif + +/* =================================================================== + * 绘制原语(SDL2 实现) + * =================================================================== */ + +/* 颜色混合 */ +static inline Uint32 da_blend(Uint32 bg, Uint32 fg, Uint32 alpha) { + Uint32 na = 256 - alpha; + Uint32 r = ((bg & 0xFF) * na + (fg & 0xFF) * alpha) >> 8; + Uint32 g = (((bg >> 8) & 0xFF) * na + ((fg >> 8) & 0xFF) * alpha) >> 8; + Uint32 b = (((bg >> 16) & 0xFF) * na + ((fg >> 16) & 0xFF) * alpha) >> 8; + return 0xFF000000u | (b << 16) | (g << 8) | r; +} + +/* 像素写入(SDL2 锁定时) */ +static inline void da_pixel(da_app_context *ac, int x, int y, Uint32 color) { + if (x < 0 || x >= ac->width || y < 0 || y >= ac->height) return; + ac->pixels[y * ac->width + x] = color; +} + +/* 矩形填充 */ +static inline void da_fill_rect(da_app_context *ac, int x, int y, int w, int h, Uint32 color) { + for (int r = 0; r < h; r++) { + for (int c = 0; c < w; c++) { + int xx = x + c, yy = y + r; + if (xx >= 0 && xx < ac->width && yy >= 0 && yy < ac->height) { + ac->pixels[yy * ac->width + xx] = color; + } + } + } +} + +/* 全屏背景 */ +static inline void da_fill_bg(da_app_context *ac, Uint32 color) { + memset(ac->pixels,0, (size_t)ac->width * ac->height *4); + da_fill_rect(ac, 0, 0, ac->width, ac->height, color); +} + +/* 圆角矩形(简化版) */ +static inline void da_fill_rounded_rect(da_app_context *ac, int x, int y , int w, int h, + Uint32 color, int radius) { + /* 中间区域 */ + da_fill_rect(ac, x + radius, y, w - 2 * radius, h, color); + da_fill_rect(ac, x, y + radius, radius, h - 2 * radius, color); + da_fill_rect(ac, x + w - radius, y + radius, radius, h - 2 * radius, color); + /* 四个角(简化为填充) */ + for (int dy = 0; dy < radius; dy++) { + for (int dx = 0; dx < radius; dx++) { + if (dx * dx + dy * dy <= radius * radius) { + da_pixel(ac, x + radius - 1 - dx, y + radius - 1 - dy, color); + da_pixel(ac, x + w - radius + dx, y + radius - 1 - dy, color); + da_pixel(ac, x + radius - 1 - dx, y + h - radius + dy, color); + da_pixel(ac, x + w - radius + dx, y + h - radius + dy, color); + } + } + } +} + +/* 字符渲染 */ +static inline void da_draw_char(da_app_context *ac, char ch, int x, int y, Uint32 fg, Uint32 bg) { + Uint32 idx = (Uint32)(ch - ' '); + if (idx > 94) idx = 0; + if (!g_ascii[idx]) return; + + const unsigned char *glyph = g_ascii[idx]; + int gw = g_ascii_w, gh = g_ascii_h; + + for (int r = 0; r < gh; r++) { + for (int c = 0; c < gw; c++) { + unsigned char a = glyph[r * gw + c]; + if (a == 0) continue; + int xx = x + c, yy = y + r; + if (xx < 0 || xx >= ac->width || yy < 0 || yy >= ac->height) continue; + + Uint32 pixel = (a == 255) ? fg : da_blend(bg, fg, a); + ac->pixels[yy * ac->width + xx] = pixel; + } + } +} + +/* 字符串渲染 */ +static inline void da_draw_string(da_app_context *ac, const char *s, int x, int y, + Uint32 fg, Uint32 bg, int step) { + int cx = x; + while (*s) { + da_draw_char(ac, *s, cx, y, fg, bg); + cx += step; + s ++; + } +} + +/*标题栏 */ +static inline void da_draw_titlebar(da_app_context *ac, const char *title, int w) { + da_fill_rect(ac, 0, 0, w, DA_TITLEBAR_H, DA_BG_SECONDARY); + da_draw_string(ac, title, 8, (DA_TITLEBAR_H - 18) / 2, DA_TEXT_PRIMARY, DA_BG_SECONDARY, 12); + /* 关闭按钮 */ + da_fill_rounded_rect(ac, w - 28, 4, 24, 20, DA_ERROR, 4); + da_draw_string(ac, "X", w - 20, 5, 0xFF0A1428u, DA_ERROR, 12); + /* 底部分隔线 */ + da_fill_rect(ac, 0, DA_TITLEBAR_H, w, 1, DA_ACCENT); +} + +/* 状态栏 */ +static inline void da_draw_statusbar(da_app_context *ac, const char *text, int w, int h) { + int y = h - DA_STATUSBAR_H; + da_fill_rect(ac, 0, y, w, DA_STATUSBAR_H, DA_BG_SECONDARY); + da_draw_string(ac, text, 4, y + 1, DA_TEXT_DIM, DA_BG_SECONDARY, 12); + da_fill_rect(ac, 0, y, w, 1, DA_BORDER); +} + +/* =================================================================== + * 上下文初始化/刷新 + * =================================================================== */ + +static inline int da_init_linux(da_app_context *ac, const char *title, int width, int height) { + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "SDL2 init failed: %s\n", SDL_GetError()); + return -1; + } + + ac->window = SDL_CreateWindow(title, + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + width, height, + SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + if (!ac->window) { + fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); + return -1; + } + + ac->renderer = SDL_CreateRenderer(ac->window, -1, SDL_RENDERER_ACCELERATED); + if (!ac->renderer) { + fprintf(stderr, "SDL_CreateRenderer failed: %s\n", SDL_GetError()); + return -1; + } + + + ac->texture = SDL_CreateTexture(ac->renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + width, height); + if (!ac->texture) { + fprintf(stderr, "SDL_CreateTexture failed: %s\n", SDL_GetError()); + return -1; + } + + ac->width = width; + ac->height = height; + ac->pitch = width * 4; + ac->pixels = (Uint32 *)malloc((size_t)width * height * 4); + if (!ac->pixels) { + fprintf(stderr, "malloc failed\n"); + + return -1; + } memset(ac->pixels, 0, (size_t)width * height * 4); + + return 0; +} + +/* 刷新帧缓冲到屏幕 */ +static inline void da_flush(da_app_context *ac) { + SDL_UpdateTexture(ac->texture, NULL, ac->pixels, ac->pitch); + SDL_RenderClear(ac->renderer); + SDL_RenderCopy(ac->renderer, ac->texture, NULL, NULL); + SDL_RenderPresent(ac->renderer); +} + +/* 清理资源 */ +static inline void da_cleanup(da_app_context *ac) { + free(ac->pixels); + if (ac->texture) SDL_DestroyTexture(ac->texture); + if (ac->renderer) SDL_DestroyRenderer(ac->renderer); + if (ac->window) SDL_DestroyWindow(ac->window); + SDL_Quit(); +} + +/* 事件循环(等待关闭窗口) */ +static inline void da_event_loop(void) { + SDL_Event event; + int running = 1; + while (running) { + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) running = 0; + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) running = 0; + } + SDL_Delay(16); /* ~60 FPS */ + } +} + +/* =================================================================== + * 鼠标光标(简化版) + * =================================================================== */ + +#define DA_CURSOR_SIZE 24 + +static const unsigned char da_cursor_shape[24][24] = { + {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +}; + +typedef struct { + int mx, my; + int btn; +} da_cursor; + +static inline void da_cursor_init(da_cursor *c, int fb_w, int fb_h) { + c->mx = fb_w / 2; + c->my = fb_h / 2; + c->btn = 0; +} + +static inline void da_cursor_draw(da_app_context *ac, da_cursor *c, Uint32 color) { + for (int r = 0; r < DA_CURSOR_SIZE; r++) { + for (int col = 0; col < DA_CURSOR_SIZE; col++) { + if (da_cursor_shape[r][col]) { + int x = c->mx + col, y = c->my + r; + if (x >= 0 && x < ac->width && y >= 0 && y < ac->height) { + ac->pixels[y * ac->width + x] = color; + } + } + } + } +} + +/* =================================================================== + * PS/2 鼠标模拟(SDL2 事件转换) + * =================================================================== */ + +typedef struct { + int has_packet; + int dx, dy; + int buttons; +} da_mouse; + +static inline void da_mouse_init(da_mouse *m) { + memset(m, 0, sizeof(*m)); +} + +/* 将 SDL 鼠标事件转换为内部状态 */ +static inline void da_mouse_update(da_mouse *m, SDL_Event *event) { + if (event->type == SDL_MOUSEMOTION) { + m->dx += event->motion.xrel; + m->dy += event->motion.yrel; + m->has_packet = 1; + } + if (event->type == SDL_MOUSEBUTTONDOWN) { + m->buttons |= (1 << (event->button.button -1)); + m->has_packet = 1; + } + if (event->type == SDL_MOUSEBUTTONUP) { + m->buttons &= ~(1 << (event->button.button - 1)); + m->has_packet = 1; + } +} + +/* =================================================================== + * PS/2 键盘模拟(SDL2 事件转换) + * =================================================================== */ + +/* SDL scancode 到 Deshab PS/2 scan code 映射 */ +static inline u8 da_sdl_to_ps2_scan(Uint32 sdl_scancode) { + /* 简化映射:只支持基本字母数字键 */ + switch (sdl_scancode) { + case SDLK_ESCAPE: return 0x01; + case SDLK_1: return 0x02; + case SDLK_2: return 0x03; + case SDLK_3: return 0x04; + case SDLK_4: return 0x05; + case SDLK_5: return 0x06; + case SDLK_6: return 0x07; + case SDLK_7: return 0x08; + case SDLK_8: return 0x09; + case SDLK_9: return 0x0A; + case SDLK_0: return 0x0B; + case SDLK_MINUS: return 0x0C; + case SDLK_EQUALS: return 0x0D; + case SDLK_BACKSPACE: return 0x0E; + case SDLK_TAB: return 0x0F; + case SDLK_q: return 0x10; + case SDLK_w: return 0x11; + case SDLK_e: return 0x12; + case SDLK_r: return 0x13; + case SDLK_t: return 0x14; + case SDLK_y: return 0x15; + case SDLK_u: return 0x16; + case SDLK_i: return 0x17; + case SDLK_o: return 0x18; + case SDLK_p: return 0x19; + case SDLK_LEFTBRACKET: return 0x1A; + case SDLK_RIGHTBRACKET: return 0x1B; + case SDLK_RETURN: return 0x1C; + case SDLK_a: return 0x1E; + case SDLK_s: return 0x1F; + case SDLK_d: return 0x20; + case SDLK_f: return 0x21; + case SDLK_g: return 0x22; + case SDLK_h: return 0x23; + case SDLK_j: return 0x24; + case SDLK_k: return 0x25; + case SDLK_l: return 0x26; + case SDLK_SEMICOLON: return 0x27; + case SDLK_QUOTE: return 0x28; + case SDLK_BACKQUOTE: return 0x29; + case SDLK_BACKSLASH: return 0x2B; + case SDLK_z: return 0x2C; + case SDLK_x: return 0x2D; + case SDLK_c: return 0x2E; + case SDLK_v: return 0x2F; + case SDLK_b: return 0x30; + case SDLK_n: return 0x31; + case SDLK_m: return 0x32; + case SDLK_COMMA: return 0x33; + case SDLK_PERIOD: return 0x34; + case SDLK_SLASH: return 0x35; + case SDLK_RSHIFT: + case SDLK_LSHIFT: return 0; /* Shift 处理 */ + case SDLK_SPACE: return 0x39; + case SDLK_LEFT: return 0x4B; + case SDLK_RIGHT: return 0x4D; + case SDLK_UP: return 0x48; + case SDLK_DOWN: return 0x50; + default: return 0; + } +} + +static inline char da_scan_to_ascii(u8 sc, int shift) { + static const char normal[58] = { + 0, 27, '1','2','3','4','5','6','7','8','9','0','-','=', 8, '\t', + 'q','w','e','r','t','y','u','i','o','p','[',']','\n',0, + 'a','s','d','f','g','h','j','k','l',';','\'', '`',0,'\\', + 'z','x','c','v','b','n','m',',','.','/',0,'*',0,' ' + }; + static const char shifted[58] = { + 0, 27, '!','@','#','$','%','^','&','*','(',')','_','+', 8, '\t', + 'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',0, + 'A','S','D','F','G','H','J','K','L',':','"','~',0,'|', + 'Z','X','C','V','B','N','M','<','>','?',0,'*',0,' ' + }; + if (sc >= 58) return 0; + return shift ? shifted[sc] : normal[sc]; +} + +#endif /* DESHAB_DESKTOP_APP_LINUX_H */ \ No newline at end of file diff --git a/CODE/tools/editor/MAKEFILE b/CODE/tools/editor/MAKEFILE index da9a6d9..aff223e 100644 --- a/CODE/tools/editor/MAKEFILE +++ b/CODE/tools/editor/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64\tools" mkdir "$(ROOT)\SYSTEM\system\deshab64\tools" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64/tools" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/tools/fileman/MAKEFILE b/CODE/tools/fileman/MAKEFILE index bb408c8..41a785e 100644 --- a/CODE/tools/fileman/MAKEFILE +++ b/CODE/tools/fileman/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64\tools" mkdir "$(ROOT)\SYSTEM\system\deshab64\tools" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64/tools" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/CODE/tools/fileman/main.c b/CODE/tools/fileman/main.c index 0c20ff0..e7526ad 100644 --- a/CODE/tools/fileman/main.c +++ b/CODE/tools/fileman/main.c @@ -254,6 +254,9 @@ static void redraw_all(void) { else redraw_list(); } +/* ---- 返回上级目录(前向声明) ---- */ +static void go_up(void); + /* ---- 打开文件/目录 ---- */ static void go_up(void); /* 前向声明:open_selected 调用 go_up */ static void open_selected(void) { diff --git a/CODE/tools/notes/Makefile.linux b/CODE/tools/notes/Makefile.linux new file mode 100644 index 0000000..48b9cf1 --- /dev/null +++ b/CODE/tools/notes/Makefile.linux @@ -0,0 +1,30 @@ +# Makefile.linux — Deshab-OS 应用 Linux 预览编译 +# +# 用法: +# make -f Makefile.linux # 编译预览版 +# make -f Makefile.linux run # 编译并运行预览版 +# make -f Makefile.linux clean # 清理 + +CC = gcc +CFLAGS = -Wall -O2 -D DA_LINUX_PREVIEW -I.. +LDFLAGS = -lSDL2 + +SRC = notes_preview.c ../../firstInit/ascii_bitmaps.c +TARGET = notes_preview + +all: $(TARGET) + +$(TARGET): $(SRC) + $(CC) $(CFLAGS) -o $@ $(SRC) $(LDFLAGS) + @echo "✓ 编译完成: $(TARGET)" + @echo " 运行: ./$(TARGET)" + @echo " 按 ESC 退出" + +run: $(TARGET) + ./$(TARGET) + +clean: + rm -f $(TARGET) + @echo "✓ 已清理" + +.PHONY: all run clean \ No newline at end of file diff --git a/CODE/tools/notes/README_LINUX_PREVIEW.md b/CODE/tools/notes/README_LINUX_PREVIEW.md new file mode 100644 index 0000000..f5b0f5b --- /dev/null +++ b/CODE/tools/notes/README_LINUX_PREVIEW.md @@ -0,0 +1,112 @@ +# Deshab-OS 应用 Linux 预览功能 + +## 概述 + +允许在 Linux 开发机上预览 Deshab-OS 应用的 UI 效果。同一份 UI 绘制代码可以在 Linux 上通过 SDL2 后端预览,在 Deshab-OS 上通过 framebuffer 后端运行。 + +## 架构设计 + +``` +┌──────────────────────────────────────────────────── ─┐ +│ 应用源代码 │ +│ (使用 da_draw_char, da_fill_rect 等绘制函数) │ +└──────────────────┬──────────────────────────────────┘ + │ + ┌──────────┴──────────┐ + │ #ifdef DA_LINUX_PREVIEW │ + └──┬──────────────┬────────────┘ + │ │ + Linux 后端 Deshab-OS 后端 + + (SDL2) (framebuffer) │ │ + X11/Wayland 窗口物理显示器 +``` + +## 文件结构 + +``` +CODE/tools/notes/ +├── main.c # Deshab-OS 原生应用入口 +├── Makefile # Deshab-OS 编译用Makefile +├── notes_preview.c # Linux 预览版(包含完整 dsk_entry 实现) +├── Makefile.linux # Linux 编译用 Makefile +├── desktop_app_linux.h # Linux SDL2 后端 +└── README_LINUX_PREVIEW.md # 本说明文档 +``` + +## 使用方法 + +### 1. 在 Linux 上编译预览版 + +```bash +cd CODE/tools/notes +make -f Makefile.linux +``` + +### 2. 运行预览版 + +```bash +./notes_preview +``` + +### 3. 退出预览 + +按 `ESC` 键关闭窗口。 + +### 4. 清理 + +```bash +make -f Makefile.linux clean +``` + +## 开发工作流 + +``` + + 1. 在 Linux 上编辑代码 ↓ +2. make -f Makefile.linux 编译预览版 + ↓ +3. ./notes_preview 查看 UI 效果 + ↓ +4. 调试布局和渲染 + ↓ +5. 测试通过后,用原生的 Makefile 编译到 Deshab-OS + ↓ +6. 在 Deshab-OS 中运行验证 +``` + +## 支持的 UI 元素 + +| 元素 | Linux 预览 | Deshab-OS | +|------|-----------|-----------| +| 背景填充 | ✅ | ✅ | +| 矩形填充 | ✅ | ✅ | +| 圆角矩形 | ✅ | ✅ | +| ASCII 字符 | ✅ | ✅ | +| 字符串 | ✅ | ✅ | +| 标题栏 | ✅ | ✅ | +| 状态栏 | ✅ | ✅ | +| 鼠标 光标 | ✅ | ✅ | +|键盘输入 | ✅ | ✅ | +| 鼠标移动 | ✅ | ✅ | + +## 扩展到其他应用 + +要为其他应用(如 fileman, editor, proedit)添加 Linux 预览支持: + +1. 复制 `notes_preview.c` 作为模板 +2. 修改 `main()` 中的 UI 逻辑 +3. 使用相同的 `desktop_app_linux.h + +` 后端 + +## 依赖- SDL2 (`libsdl2-dev` on Debian/Ubuntu) +- GCC 或 Clang +- Make + +## 注意事项 + + 1. **键盘映射**:SDL2 的键盘扫描码需要映射到 Deshab的 PS/2 扫描码 +2. **鼠标行为**:SDL2 鼠标事件转换为 Deshab 的鼠标数据包格式 +3. **字体数据**:需要从 `ascii_bitmaps.c` 获取字模数据 +4. **性能**:Linux 预览版主要用于 UI 调试,不是完整的功能测试 \ No newline at end of file diff --git a/CODE/tools/notes/notes_preview.c b/CODE/tools/notes/notes_preview.c new file mode 100644 index 0000000..c1379b0 --- /dev/null +++ b/CODE/tools/notes/notes_preview.c @@ -0,0 +1,489 @@ +/* notes_preview.c — Notes 应用的 Linux 预览版本 + * + * 这个文件可以在 Linux 上编译预览 UI。 + * 使用自定义位图字体渲染字符。 + * + * 编译方式: + * gcc -o notes_preview notes_preview.c -I.. -lSDL2 + */ + +#define DA_LINUX_PREVIEW +#include "../desktop_app_linux.h" + +#include +#include +#include +#include + +/* 全局状态 */ +static da_app_context g_ac; +static int g_running = 1; + +/* 文本内容 */ +static char g_lines[512][256]; +static int g_line_count = 0; +static int g_current_line = 0; +static int g_current_col = 0; +static int g_scroll_top = 0; +static int g_visible_rows; + +/* 5x7 位图字体 (ASCII 32-126, 共95 个字符) */ +static const unsigned char font_5x7[95][5] = { + /* 0x20 space */ + {0x00, 0x00, 0x00, 0x00, 0x00}, + /* 0x21 ! */ + {0x00, 0x00, 0x30, 0x30, 0x00}, + /* 0x22 " */ + {0x30, 0x30, 0x00, 0x00, 0x00}, + /* 0x23 # */ + {0x18, 0x7E, 0x18, 0x7E, 0x18}, + /* 0x24 $ */ + {0x0C, 0x36, 0x6C, 0x36, 0x0C}, + /* 0x25 % */ + {0x60, 0x9C, 0x18, 0x36, 0x60}, + /* 0x26 & */ + {0x30, 0x7E, 0x1C, 0x36, 0x70}, + /* 0x27 ' */ + {0x30, 0x30, 0x00, 0x00, 0x00}, + /* 0x28 ( */ + {0x0C, 0x18, 0x30, 0x18, 0x0C}, + /* 0x29 ) */ + {0x30, 0x18, 0x0C, 0x18, 0x30}, + /* 0x2A * */ + {0x00, 0x18, 0x7E, 0x18, 0x00}, + /* 0x2B + */ + {0x00, 0x18, 0x7E, 0x18, 0x00}, + /* 0x2C , */ + {0x00, 0x00, 0x00, 0x30, 0x30}, + /* 0x2D - */ + {0x00, 0x00, 0x7E, 0x00, 0x00}, + /* 0x2E . */ + {0x00, 0x00, 0x00, 0x30, 0x30}, + /* 0x2F / */ + {0x06, 0x0C, 0x18, 0x30, 0x60}, + /* 0x30 0 */ + {0x38, 0x6C, 0x36, 0x6C, 0x38}, + /* 0x31 1 */ + {0x18, 0x38, 0x18, 0x18, 0x3C}, + /* 0x32 2 */ + {0x78, 0x60, 0x30, 0x18, 0x7C}, + /* 0x33 3 */ + {0x78, 0x60, 0x38, 0x00, 0x78}, + /* 0x34 4 */ + {0x0C, 0x1C, 0x3C, 0x7E, 0x0C}, + /* 0x35 5 */ + {0x7C, 0x60, 0x78, 0x06, 0x7C}, + /* 0x36 6 */ + {0x38, 0x60, 0x7C, 0x66, 0x3C}, + /* 0x37 7 */ + {0x7C, 0x60, 0x30, 0x30, 0x30}, + /* 0x38 8 */ + {0x3C, 0x66, 0x3C, 0x66, 0x3C}, + /* 0x39 9 */ + {0x3C, 0x66, 0x3E, 0x60, 0x3C}, + /* 0x3A : */ + {0x00, 0x30, 0x00, 0x30, 0x00}, + /* 0x3B ; */ + {0x00, 0x30, 0x00, 0x30, 0x30}, + /* 0x3C < */ + {0x0C, 0x18, 0x30, 0x18, 0x0C}, + /* 0x3D = */ + {0x00, 0x7E, 0x00, 0x7E, 0x00}, + /* 0x3E > */ + {0x30, 0x18, 0x0C, 0x18, 0x30}, + /* 0x3F ? */ + {0x78, 0x60, 0x30, 0x00, 0x30}, + /* 0x40 @ */ + {0x3C, 0x66, 0x7E, 0x06, 0x3C}, + /* 0x41 A */ + {0x18, 0x3C, 0x7E, 0x66, 0x66}, + /* 0x42 B */ + {0x7C, 0x66, 0x7C, 0x66, 0x7C}, + /* 0x43 C */ + {0x3C, 0x66, 0x60, 0x60, 0x3C}, + /* 0x44 D */ + {0x78, 0x6C, 0x66, 0x66, 0x78}, + /* 0x45 E */ + {0x7E, 0x60, 0x7C, 0x60, 0x7E}, + /* 0x46 F */ + {0x7E, 0x60, 0x7C, 0x60, 0x60}, + /* 0x47 G */ + {0x3C, 0x66, 0x6C, 0x66, 0x3C}, + /* 0x48 H */ + {0x66, 0x66, 0x7E, 0x66, 0x66}, + /* 0x49 I */ + {0x3C, 0x18, 0x18, 0x18, 0x3C}, + /* 0x4A J */ + {0x7C, 0x06, 0x06, 0x06, 0x3C}, + /* 0x4B K */ + {0x66, 0x6C, 0x78, 0x6C, 0x66}, + /* 0x4C L */ + {0x60, 0x60, 0x60, 0x60, 0x7E}, + /* 0x4D M */ + {0x63, 0x77, 0x7F, 0x6B, 0x63}, + /* 0x4E N */ + {0x66, 0x76, 0x7E, 0x6E, 0x66}, + /* 0x4F O */ + {0x3C, 0x66, 0x66, 0x66, 0x3C}, + /* 0x50 P */ + {0x7C, 0x66, 0x7C, 0x60, 0x60}, + /* 0x51 Q */ + {0x3C, 0x66, 0x76, 0x6C, 0x38}, + /* 0x52 R */ + {0x7C, 0x66, 0x7C, 0x6C, 0x66}, + /* 0x53 S */ + {0x3C, 0x66, 0x3C, 0x06, 0x7C}, + /* 0x54 T */ + {0x7E, 0x7E, 0x18, 0x18, 0x18}, + /* 0x55 U */ + {0x66, 0x66, 0x66, 0x66, 0x3C}, + /* 0x56 V */ + {0x66, 0x66, 0x66, 0x3C, 0x18}, + /* 0x57 W */ + {0x63, 0x63, 0x77, 0x7F, 0x36}, + /* 0x58 X */ + {0x66, 0x3C, 0x18, 0x3C, 0x66}, + /* 0x59 Y */ + {0x66, 0x66, 0x3C, 0x18, 0x18}, + /* 0x5A Z */ + {0x7C, 0x66, 0x3C, 0x18, 0x7C}, + /* 0x5B [ */ + {0x3C, 0x30, 0x30, 0x30, 0x3C}, + /* 0x5C backslash */ + {0x60, 0x30, 0x18, 0x0C, 0x06}, + /* 0x5D ] */ + {0x3C, 0x0C, 0x0C, 0x0C, 0x3C}, + /* 0x5E ^ */ + {0x18, 0x3C, 0x66, 0x00, 0x00}, + /* 0x5F _ */ + {0x00, 0x00, 0x00, 0x00, 0x7E}, + /* 0x60 ` */ + {0x30, 0x18, 0x00, 0x00, 0x00}, + /* 0x61 a */ + {0x00, 0x00, 0x3C, 0x66, 0x3C}, + /* 0x62 b */ + {0x60, 0x60, 0x7C, 0x66, 0x7C}, + /* 0x63 c */ + {0x00, 0x00, 0x3C, 0x66, 0x66}, + /* 0x64 d */ + {0x06, 0x06, 0x7E, 0x66, 0x7E}, + /* 0x65 e */ + {0x00, 0x00, 0x3C, 0x6E, 0x3C}, + /* 0x66 f */ + {0x30, 0x7C, 0x06, 0x06, 0x3C}, + /* 0x67 g */ + {0x00, 0x3E, 0x66, 0x66, 0x3C}, + /* 0x68 h */ + {0x60, 0x60, 0x7C, 0x66, 0x66}, + /* 0x69 i */ + {0x00, 0x18, 0x18, 0x00, 0x3C}, + /* 0x6A j */ + {0x06, 0x06, 0x06, 0x06, 0x3C}, + /* 0x6B k */ + {0x60, 0x6C, 0x78, 0x6C, 0x66}, + /* 0x6C l */ + {0x3C, 0x18, 0x18, 0x18, 0x3C}, + /* 0x6D m */ + {0x00, 0x00, 0x7E, 0x6E, 0x76}, + /* 0x6E n */ + {0x00, 0x00, 0x7C, 0x66, 0x66}, + /* 0x6F o */ + {0x00, 0x00, 0x3C, 0x66, 0x3C}, + /* 0x70 p */ + {0x00, 0x00, 0x7C, 0x66, 0x7C}, + /* 0x71 q */ + {0x00, 0x00, 0x7E, 0x66, 0x3E}, + /* 0x72 r */ + {0x00, 0x00, 0x7C, 0x60, 0x60}, + /* 0x73 s */ + {0x00, 0x00, 0x3C, 0x60, 0x3C}, + /* 0x74 t */ + {0x0C, 0x7E, 0x0C, 0x0C, 0x38}, + /* 0x75 u */ + {0x00, 0x00, 0x66, 0x66, 0x3C}, + /* 0x76 v */ + {0x00, 0x00, 0x66, 0x3C, 0x18}, + /* 0x77 w */ + {0x00, 0x00, 0x67, 0x67, 0x3E}, + /* 0x78 x */ + {0x00, 0x00, 0x66, 0x3C, 0x66}, + /* 0x79 y */ + {0x00, 0x00, 0x66, 0x66, 0x3C}, + /* 0x7A z */ + {0x00, 0x00, 0x7C, 0x7C, 0x78}, + /* 0x7B { */ + {0x0C, 0x18, 0x30, 0x18, 0x0C}, + /* 0x7C | */ + {0x30, 0x30, 0x30, 0x30, 0x30}, + /* 0x7D } */ + {0x30, 0x18, 0x0C, 0x18, 0x30}, + /* 0x7E ~ */ + {0x00, 0x00, 0x00, 0x00, 0x00}, +}; + +#define FONT_W 5 +#define FONT_H 7 +#define FONT_STEP 9 + +/* 颜色常量 */ +#define CURSOR_COLOR 0xFF0055FFu /* 蓝色光标 */ +#define BG_COLOR 0xFF1E1E1Eu /* 深色背景 */ +#define TEXT_COLOR 0xFFD4D4D4u /* 浅色文字 */ +#define DIM_COLOR 0xFF808080u /* 灰色行号 */ +#define STATUS_BG 0xFF007ACCu /* 蓝色状态栏 */ + +/* 绘制单个字符(使用位图字体) */ +static void draw_char_bitmap(char ch, int x, int y, u32 color) { + if (ch < ' ' || ch > '~') return; + int idx = ch - ' '; + if (idx < 0 || idx >= 95) return; + + for (int row = 0; row < FONT_H; row++) { + unsigned char bits = font_5x7[idx][row]; + for (int col = 0; col < FONT_W; col++) { + if (bits & (1 << (FONT_W - 1 - col))) { + da_fill_rect(&g_ac, x + col, y + row, 1, 1, color); + } + } + } +} + +/* 绘制文本行 */ +static void draw_text_line(const char *text, int x, int y, u32 color) { + int cx = x; + while (*text) { + draw_char_bitmap(*text, cx, y, color); + cx += FONT_STEP; + text++; + } +} + +/* 重绘所有 */ +static void redraw_all(void) { + da_fill_bg(&g_ac, BG_COLOR); + + int margin_x = 10; + int top_y = 44; + + /* 计算可见列数 */ + int visible_cols = (g_ac.width - 20) / FONT_STEP; + if (visible_cols < 10) visible_cols = 10; + + /* 绘制可见行 */ + for (int line = g_scroll_top; line < g_line_count && line < g_scroll_top + g_visible_rows; line++) { + int screen_y = top_y + (line - g_scroll_top) * FONT_STEP; + + /* 行号 */ + char ln[8]; + int p = snprintf(ln, sizeof(ln), "%d ", line + 1); + + /* 行号区域背景 */ + int line_num_width = p * FONT_STEP; + da_fill_rect(&g_ac, 0, screen_y - 2, line_num_width + 10, FONT_STEP, 0xFF252526u); + + /* 绘制行号 */ + draw_text_line(ln, 5, screen_y, DIM_COLOR); + + /* 文本内容 */ + const char *line_text = g_lines[line]; + int line_len = (int)strlen(line_text); + int draw_len = line_len; + if (draw_len > visible_cols) draw_len = visible_cols; + + int text_start_x = margin_x + line_num_width; + for (int col = 0; col < draw_len; col++) { + draw_char_bitmap(line_text[col], text_start_x + col * FONT_STEP, screen_y, TEXT_COLOR); + } + } + + /* 光标 */ + if (g_current_line >= g_scroll_top && g_current_line < g_scroll_top + g_visible_rows) { + int screen_y = top_y + (g_current_line - g_scroll_top) * FONT_STEP; + + /* 计算行号宽度 */ + char tmp_ln[8]; + snprintf(tmp_ln, sizeof(tmp_ln), "%d ", g_current_line + 1); + int line_num_width = (int)strlen(tmp_ln) * FONT_STEP; + int text_start_x = margin_x + line_num_width; + + /* 高亮当前光标位置 */ + int cursor_x = text_start_x + g_current_col * FONT_STEP; + da_fill_rect(&g_ac, cursor_x, screen_y, FONT_W, FONT_H, CURSOR_COLOR); + } + + /* 状态栏 */ + char status[128]; + snprintf(status, sizeof(status), "Line: %d Col: %d Lines: %d ESC=Exit", + g_current_line + 1, g_current_col + 1, g_line_count); + + da_fill_rect(&g_ac, 0, g_ac.height - 24, g_ac.width, 24, STATUS_BG); + draw_text_line(status, 10, g_ac.height - 22, 0xFFFFFFFFu); + + /* 标题栏 */ + da_fill_rect(&g_ac, 0, 0, g_ac.width, 36, 0xFF2D2D2Du); + draw_text_line("Notes Preview (Deshab-OS)", 10, 6, 0xFFFFFFFFu); + da_fill_rect(&g_ac, 0, 36, g_ac.width, 2, 0xFF007ACCu); +} + +static void scroll_cursor_into_view(void) { + if (g_current_line < g_scroll_top) { + g_scroll_top = g_current_line; + } + if (g_current_line >= g_scroll_top + g_visible_rows) { + g_scroll_top = g_current_line - g_visible_rows + 1; + } +} + +/* 换行 */ +static void handle_enter(void) { + if (g_current_line >= 511) return; + + int cur_len = (int)strlen(g_lines[g_current_line]); + if (g_current_col < cur_len) { + int remaining = cur_len - g_current_col; + memmove(g_lines[g_current_line] + g_current_col + remaining, + g_lines[g_current_line] + g_current_col, remaining + 1); + g_lines[g_current_line][g_current_col + remaining] = '\0'; + } else { + g_lines[g_current_line][g_current_col] = '\0'; + } + + /* 移动下一行 */ + memmove(g_lines[g_current_line + 1], g_lines[g_current_line + 1], 256); + g_line_count++; + g_current_line++; + g_current_col = 0; + + scroll_cursor_into_view(); +} + +/* Backspace删除 */ +static void handle_backspace(void) { + if (g_current_col > 0) { + int len = (int)strlen(g_lines[g_current_line]); + memmove(g_lines[g_current_line] + g_current_col - 1, + g_lines[g_current_line] + g_current_col, len - g_current_col + 1); + g_current_col--; + } else if (g_current_line > 0) { + int prev_len = (int)strlen(g_lines[g_current_line - 1]); + int cur_len = (int)strlen(g_lines[g_current_line]); + if (prev_len + cur_len < 255) { + memcpy(g_lines[g_current_line - 1] + prev_len, g_lines[g_current_line], cur_len + 1); + for (int i = g_current_line; i < g_line_count - 1; i++) { + memcpy(g_lines[i], g_lines[i+1], 256); + } + g_line_count--; + g_current_line--; + g_current_col = prev_len; + } + } +} + +/* 插入字符 */ +static void insert_char(char c) { + if (c < 32 || c > 126) return; + + int len = (int)strlen(g_lines[g_current_line]); + if (len >= 255) return; + + memmove(g_lines[g_current_line] + g_current_col + 1, + g_lines[g_current_line] + g_current_col, len - g_current_col + 1); + g_lines[g_current_line][g_current_col] = c; + g_current_col++; +} + +int main(int argc, char *argv[]) { + (void)argc; (void)argv; + + const char *title = "Notes Preview (Deshab-OS) - ESC to exit"; + int width = 1024; + int height = 768; + + if (da_init_linux(&g_ac, title, width, height) != 0) { + return 1; + } + + g_visible_rows = (height - 60 - 24) / FONT_STEP; + if (g_visible_rows < 5) g_visible_rows = 5; + + /* 初始化空文档 */ + g_line_count = 1; + g_lines[0][0] = '\0'; + + redraw_all(); + da_flush(&g_ac); + + /* 主事件循环 */ + SDL_Event event; + while (g_running) { + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + g_running = 0; + break; + } + + /* 处理文本输入事件(支持输入法) */ + if (event.type == SDL_TEXTINPUT) { + for (int i = 0; event.text.text[i]; i++) { + unsigned char c = (unsigned char)event.text.text[i]; + if (c >= 32 && c <= 126) { + insert_char((char)c); + } + } + scroll_cursor_into_view(); + redraw_all(); + da_flush(&g_ac); + } + + if (event.type == SDL_KEYDOWN) { + u8 sc = da_sdl_to_ps2_scan(event.key.keysym.sym); + + if (sc == 0x01) { /* Esc */ + g_running = 0; + } else if (sc == 0x1C) { /* Enter */ + handle_enter(); + redraw_all(); + da_flush(&g_ac); + } else if (sc == 0x0E) { /* Backspace */ + handle_backspace(); + redraw_all(); + da_flush(&g_ac); + } else if (sc == 0x4B) { /* Left */ + if (g_current_col > 0) g_current_col--; + else if (g_current_line > 0) { + g_current_line--; + g_current_col = (int)strlen(g_lines[g_current_line]); + } + redraw_all(); + da_flush(&g_ac); + } else if (sc == 0x4D) { /* Right */ + if (g_current_col < (int)strlen(g_lines[g_current_line])) g_current_col++; + else if (g_current_line < g_line_count - 1) { + g_current_line++; + g_current_col = 0; + } + redraw_all(); + da_flush(&g_ac); + } else if (sc == 0x48) { /* Up */ + if (g_current_line > 0) g_current_line--; + if (g_current_col > (int)strlen(g_lines[g_current_line])) { + g_current_col = (int)strlen(g_lines[g_current_line]); + } + redraw_all(); + da_flush(&g_ac); + } else if (sc == 0x50) { /* Down */ + if (g_current_line < g_line_count - 1) g_current_line++; + if (g_current_col > (int)strlen(g_lines[g_current_line])) { + g_current_col = (int)strlen(g_lines[g_current_line]); + } + redraw_all(); + da_flush(&g_ac); + } + } + } + SDL_Delay(16); + } + + da_cleanup(&g_ac); + return 0; +} \ No newline at end of file diff --git a/CODE/tools/ping/MAKEFILE b/CODE/tools/ping/MAKEFILE index 2eef1fd..ac0dd33 100644 --- a/CODE/tools/ping/MAKEFILE +++ b/CODE/tools/ping/MAKEFILE @@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o) all: $(OUT) $(OUT): $(OBJECTS) linker.ld - @if not exist "$(ROOT)\SYSTEM\system\deshab64\tools" mkdir "$(ROOT)\SYSTEM\system\deshab64\tools" + @mkdir -p "$(ROOT)/SYSTEM/system/deshab64/tools" $(LD) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c diff --git a/SYSTEM/boot/utsm.elf b/SYSTEM/boot/utsm.elf old mode 100644 new mode 100755 index d86f80e..9880827 Binary files a/SYSTEM/boot/utsm.elf and b/SYSTEM/boot/utsm.elf differ diff --git a/SYSTEM/driver/console/console_fb.drv b/SYSTEM/driver/console/console_fb.drv index b515b42..5c57da8 100644 Binary files a/SYSTEM/driver/console/console_fb.drv and b/SYSTEM/driver/console/console_fb.drv differ diff --git a/SYSTEM/driver/net/e1000.drv b/SYSTEM/driver/net/e1000.drv index 077ee38..58fc12e 100644 Binary files a/SYSTEM/driver/net/e1000.drv and b/SYSTEM/driver/net/e1000.drv differ diff --git a/SYSTEM/system/deshab64/cmd.elf b/SYSTEM/system/deshab64/cmd.elf old mode 100644 new mode 100755 index 3d65c20..982edef Binary files a/SYSTEM/system/deshab64/cmd.elf and b/SYSTEM/system/deshab64/cmd.elf differ diff --git a/SYSTEM/system/deshab64/desktop.elf b/SYSTEM/system/deshab64/desktop.elf old mode 100644 new mode 100755 index 1f2dcc7..03113c9 Binary files a/SYSTEM/system/deshab64/desktop.elf and b/SYSTEM/system/deshab64/desktop.elf differ diff --git a/SYSTEM/system/deshab64/tools/browser.elf b/SYSTEM/system/deshab64/tools/browser.elf old mode 100644 new mode 100755 index 17b23ee..37b5280 Binary files a/SYSTEM/system/deshab64/tools/browser.elf and b/SYSTEM/system/deshab64/tools/browser.elf differ diff --git a/SYSTEM/system/deshab64/tools/curl.elf b/SYSTEM/system/deshab64/tools/curl.elf old mode 100644 new mode 100755 index 3f0d938..82cdcb5 Binary files a/SYSTEM/system/deshab64/tools/curl.elf and b/SYSTEM/system/deshab64/tools/curl.elf differ diff --git a/SYSTEM/system/deshab64/tools/editor.elf b/SYSTEM/system/deshab64/tools/editor.elf old mode 100644 new mode 100755 index 15cfec4..151b1a8 Binary files a/SYSTEM/system/deshab64/tools/editor.elf and b/SYSTEM/system/deshab64/tools/editor.elf differ diff --git a/SYSTEM/system/deshab64/tools/fileman.elf b/SYSTEM/system/deshab64/tools/fileman.elf old mode 100644 new mode 100755 index b20c1d1..1575b48 Binary files a/SYSTEM/system/deshab64/tools/fileman.elf and b/SYSTEM/system/deshab64/tools/fileman.elf differ diff --git a/SYSTEM/system/deshab64/tools/ping.elf b/SYSTEM/system/deshab64/tools/ping.elf old mode 100644 new mode 100755 index 1a53991..2e21180 Binary files a/SYSTEM/system/deshab64/tools/ping.elf and b/SYSTEM/system/deshab64/tools/ping.elf differ diff --git a/SYSTEM/system/user/use/login.elf b/SYSTEM/system/user/use/login.elf old mode 100644 new mode 100755 index dfbc081..72e07f0 Binary files a/SYSTEM/system/user/use/login.elf and b/SYSTEM/system/user/use/login.elf differ