feat: white-tone desktop + login crossfade + BUG-031 FAT chain fix + DESK-E texture panics

- BUG-031: fat32_io.h on-demand FAT sector read (FAT beyond 128KB cache walked OOB, font/wallpaper corrupted past first clusters); host unit test diff=0

- material pack: gen_textures.py wired into build.ps1, startMenuLogo.rgba packaged; missing wallpaper/logo/font now fatal (DESK-E02/E03/E04 red fatal screen)

- login->desktop crossfade 16 steps, boot typewriter screen removed

- IDE exit: Esc detaches and returns to desktop page

- white theme: KS_* light palette, g_wf_light taskbar, hardcoded dark fills replaced

- QEMU verified: labels/clock render, wallpaper + start logo loaded, zero spurious panic
This commit is contained in:
Linehu
2026-10-04 15:53:04 +08:00
parent 174af71b39
commit 5f01904be1
14 changed files with 160 additions and 96 deletions
+16 -15
View File
@@ -738,27 +738,28 @@ static inline du_u32 du_theme_accent(du_theme t) {
#define DP_KATE_DANGER 0xFFFF4D6Du /* --danger: #ff4d6d */ #define DP_KATE_DANGER 0xFFFF4D6Du /* --danger: #ff4d6d */
/* =================================================================== /* ===================================================================
* L1 — Winux-Kate 语义色值 * L1 — 桌面语义色值(白色调主题,去 winux-Kate 深色风)
* 底色白/浅灰,组件白卡片 + 浅灰描边,文字深灰,强调色深板岩。
* =================================================================== */ * =================================================================== */
#define KS_BG_PRIMARY DP_KATE_BG #define KS_BG_PRIMARY 0xFFF3F4F6u /* 页面底:浅灰 */
#define KS_BG_SECONDARY DP_KATE_PANEL_SOLID #define KS_BG_SECONDARY 0xFFFFFFFFu /* 面板:白 */
#define KS_BG_TERTIARY DP_KATE_BG2 #define KS_BG_TERTIARY 0xFFE9ECF0u /* 三级底:稍深浅灰 */
#define KS_TEXT_PRIMARY DP_KATE_TEXT #define KS_TEXT_PRIMARY 0xFF1A1A1Au /* 主文字:近黑 */
#define KS_TEXT_DIM DP_KATE_TEXT_DIM #define KS_TEXT_DIM 0xFF6B7280u /* 次文字:中灰 */
#define KS_TEXT_INVERT DP_KATE_BG #define KS_TEXT_INVERT 0xFFFFFFFFu /* accent 上的文字:白 */
#define KS_ACCENT DP_KATE_ACCENT #define KS_ACCENT 0xFF111827u /* 强调:深板岩(白底上高对比) */
#define KS_ACCENT2 DP_KATE_ACCENT2 #define KS_ACCENT2 0xFF4B5563u /* 次强调:中板岩 */
#define KS_ACCENT_DIM DP_KATE_ACCENT_DIM_SOLID #define KS_ACCENT_DIM 0xFFE5E7EBu /* 强调淡底:浅灰 */
#define KS_BORDER DP_KATE_PANEL_BORDER_SOLID #define KS_BORDER 0xFFD1D5DBu /* 边框:浅灰 */
#define KS_BORDER_FOCUS DP_KATE_ACCENT #define KS_BORDER_FOCUS 0xFF111827u /* 聚焦边框:深板岩 */
#define KS_BORDER_DIM 0xFF1A2840u /* 暗边框 */ #define KS_BORDER_DIM 0xFFE5E7EBu /* 暗边框:极浅灰 */
#define KS_DANGER DP_KATE_DANGER #define KS_DANGER 0xFFDC2626u /* 红 */
#define KS_WARN DP_KATE_WARN #define KS_WARN 0xFFD97706u /* 琥珀 */
/* =================================================================== /* ===================================================================
* Winux-Kate 布局常量(源自 theme.css / pages.css) * Winux-Kate 布局常量(源自 theme.css / pages.css)
+1 -1
View File
@@ -20,7 +20,7 @@ $(OUT): $(OBJECTS) linker.ld
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(LD) $(LDFLAGS) -o $@ $(OBJECTS) $(LD) $(LDFLAGS) -o $@ $(OBJECTS)
%.o: %.c %.o: %.c ../tools/fat32_io.h
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
clean: clean:
+1 -1
View File
@@ -188,7 +188,7 @@ static void redraw_all_fluent(void) {
for (u64 x = 0; x < g_fb_w; x++) line[x] = srcline[x]; for (u64 x = 0; x < g_fb_w; x++) line[x] = srcline[x];
} }
} else { } else {
du_fill_bg_gradient(&g_fb, 0xFF0A0E1Cu, 0xFF16264Au); du_fill_bg_gradient(&g_fb, 0xFFE9ECF0u, 0xFFF3F4F6u);
} }
} }
+1 -1
View File
@@ -342,7 +342,7 @@ void launch_pe_app(int app_id) {
{ {
u32 *p = (u32 *)g_pe_surf; u32 *p = (u32 *)g_pe_surf;
u64 n = (u64)cw * (u64)ch; u64 n = (u64)cw * (u64)ch;
for (u64 i = 0; i < n; i++) p[i] = 0xFF101418u; for (u64 i = 0; i < n; i++) p[i] = 0xFFF3F4F6u;
} }
win->app_state = &g_pe_state_dummy; /* draw_desktop_page 要求非空才调 on_draw */ win->app_state = &g_pe_state_dummy; /* draw_desktop_page 要求非空才调 on_draw */
+3 -3
View File
@@ -385,7 +385,7 @@ void blit_scanout_to_ide(int hx, int hy, int hw, int hh) {
const struct linux_compat_scanout_info *si = ide_scanout_state(); const struct linux_compat_scanout_info *si = ide_scanout_state();
if (!si || !si->enabled || !si->host_vaddr) { if (!si || !si->enabled || !si->host_vaddr) {
/* scanout 未就绪:X server 尚未 SET_SCANOUT,显示等待提示 */ /* scanout 未就绪:X server 尚未 SET_SCANOUT,显示等待提示 */
du_fill_rect(&g_fb, hx, hy, hw, hh, 0xFF051828u); du_fill_rect(&g_fb, hx, hy, hw, hh, KS_BG_SECONDARY);
draw_centered("WAITING FOR GUEST X SERVER . . .", draw_centered("WAITING FOR GUEST X SERVER . . .",
hx + hw / 2, hy + hh / 2 - 8, KS_TEXT_DIM, 0); hx + hw / 2, hy + hh / 2 - 8, KS_TEXT_DIM, 0);
return; return;
@@ -433,9 +433,9 @@ void blit_scanout_to_ide(int hx, int hy, int hw, int hh) {
int cov_w = (hw < sw) ? hw : sw; int cov_w = (hw < sw) ? hw : sw;
int cov_h = (hh < sh) ? hh : sh; int cov_h = (hh < sh) ? hh : sh;
if (cov_w < hw) if (cov_w < hw)
du_fill_rect(&g_fb, hx + cov_w, hy, hw - cov_w, cov_h, 0xFF051828u); du_fill_rect(&g_fb, hx + cov_w, hy, hw - cov_w, cov_h, KS_BG_SECONDARY);
if (cov_h < hh) if (cov_h < hh)
du_fill_rect(&g_fb, hx, hy + cov_h, hw, hh - cov_h, 0xFF051828u); du_fill_rect(&g_fb, hx, hy + cov_h, hw, hh - cov_h, KS_BG_SECONDARY);
} }
/* P7.6: 叠加 guest 硬件光标(ARGB alpha-blend 到 framebuffer)。 /* P7.6: 叠加 guest 硬件光标(ARGB alpha-blend 到 framebuffer)。
+69 -61
View File
@@ -7,6 +7,7 @@
* 原 "Winux-Kate 结构完整复刻" 布局说明见 pages.c 头注释; * 原 "Winux-Kate 结构完整复刻" 布局说明见 pages.c 头注释;
* M2-M4 将按 Win11 Fluent 桌面重构计划逐页替换。 * M2-M4 将按 Win11 Fluent 桌面重构计划逐页替换。
*/ */
#include "ascii_font.h" /* 顺序敏感:先于 desktop.h(g_ascii 导出) */
#include "desktop.h" #include "desktop.h"
#include "zhfont.h" /* M1: 中文位图字库(dbf 加载 + 中英混排渲染) */ #include "zhfont.h" /* M1: 中文位图字库(dbf 加载 + 中英混排渲染) */
#include "wallpaper.h" /* M2: 壁纸背景层缓存 */ #include "wallpaper.h" /* M2: 壁纸背景层缓存 */
@@ -78,84 +79,89 @@ static void load_fuck_config(void) {
} }
/* ============================================================ /* ============================================================
* Boot 屏(打字机) * 登录 → 桌面 crossfade(渐隐渐显)
* 登录最后一帧已在真实 fb 上;桌面首帧已由 redraw_all() 绘入
* sprite buffer。复用 WALLPAPER_STAGING(wallpaper_init 后已空闲)
* 保存登录帧,按 alpha 混合 16 步直写真实 fb。
* ============================================================ */ * ============================================================ */
static const char *BOOT_LINES[] = { #define XFADE_ADDR WALLPAPER_STAGING_ADDR /* 8MB 区,init 后空闲 */
"DESHAB DESKTOP v0.1.0", #define XFADE_STEPS 16
"DEAICUP STUDIO && LINEHU STUDIO",
"https://deaicup.com",
"https://github.com/Linehu-Studio",
};
#define BOOT_LINE_COUNT 4
static void busy_delay(u32 cycles) { static void busy_delay(u32 cycles) {
for (volatile u32 i = 0; i < cycles; i++) __asm__("pause"); for (volatile u32 i = 0; i < cycles; i++) __asm__("pause");
} }
static void boot_screen(void) { static void crossfade_login_to_desktop(void) {
int W = (int)g_fb_w, H = (int)g_fb_h; int W = (int)g_fb_w, H = (int)g_fb_h;
u32 *src = (u32 *)XFADE_ADDR; /* 登录帧 */
const u32 *dst = (const u32 *)g_fb.fb; /* 桌面帧(sprite buffer) */
u32 *out = (u32 *)g_real_fb;
u64 n = (u64)W * (u64)H;
/* M2 修复:保留 DSK 已绘制的启动画面(渐变背景 + 居中开机 Logo + /* 1. 保存登录最后一帧 */
* dcp/xj 角标),boot 屏叠加在其上下空白区——logo 不跳位、不重复、
* 不被覆盖。DSK logo 居中 157px:占据 H/2-78 .. H/2+78。 */
{ {
u64 pitch_u32 = g_fb_pitch / 4; u64 pitch_u32 = g_fb_pitch / 4;
for (u64 y = 0; y < g_fb_h; y++) { for (u64 y = 0; y < g_fb_h; y++) {
const u32 *src = (const u32 *)((const u8 *)g_real_fb + y * g_fb_pitch); const u32 *s = (const u32 *)((const u8 *)g_real_fb + y * g_fb_pitch);
u32 *dst = (u32 *)SPRITE_BUF_ADDR + y * pitch_u32; u32 *d = (u32 *)((u8 *)src + y * (u64)W * 4);
for (u64 x = 0; x < g_fb_w; x++) dst[x] = src[x]; for (u64 x = 0; x < g_fb_w; x++) d[x] = s[x];
} }
(void)pitch_u32;
} }
int lw = 46 * (int)DU_ASCII_STEP; /* 2. 桌面首帧绘入 sprite buffer(由调用方 redraw_all() 完成后进入本函数) */
int lx = (W - lw) / 2;
int ty = H / 2 - 220;
/* boot-title(logo 上方空白区)——一次性整行绘制(打字机效果已删) */ /* 3. alpha 混合直写真实 fb:out = src*(1-a) + dst*a */
const char *title = "DESHAB"; for (int step = 1; step <= XFADE_STEPS; step++) {
int tl = kstrlen(title); u32 a = (u32)(step * 256 / XFADE_STEPS);
du_draw_string(&g_fb, title, W / 2 - tl * (int)DU_ASCII_STEP, ty, u32 ia = 256 - a;
KS_ACCENT, 0, DU_ASCII_STEP * 2); for (u64 i = 0; i < n; i++) {
du_divider_h(&g_fb, W / 2 - 120, ty + 30, 240, KS_ACCENT); u32 s = src[i], d = dst[i];
u32 sr = (s >> 16) & 0xFF, sg = (s >> 8) & 0xFF, sb = s & 0xFF;
/* boot-subtitle(对应 Kate "由 Deaicup 工作室制作") */ u32 dr = (d >> 16) & 0xFF, dg = (d >> 8) & 0xFF, db = d & 0xFF;
draw_centered("DEAICUP STUDIO", W / 2, ty + 44, KS_ACCENT2, 0); out[i] = 0xFF000000u |
(((sr * ia + dr * a) >> 8) << 16) |
/* boot-lines(logo 下方空白区,H/2+110 起)——整屏一次绘制 */ (((sg * ia + dg * a) >> 8) << 8) |
int ly = H / 2 + 110; ((sb * ia + db * a) >> 8);
int bar_y = ly + BOOT_LINE_COUNT * ((int)DU_ASCII_LINE_H + 2) + 12; }
int bw = 260; busy_delay(40000);
for (int li = 0; li < BOOT_LINE_COUNT; li++) {
const char *s = BOOT_LINES[li];
u32 fg = (li == 1 || li == BOOT_LINE_COUNT - 1) ? KS_TEXT_DIM : KS_ACCENT2;
du_draw_string(&g_fb, ">", lx, ly, KS_ACCENT, 0, DU_ASCII_STEP);
du_draw_string(&g_fb, s, lx + (int)DU_ASCII_STEP, ly, fg, 0, DU_ASCII_STEP);
ly += (int)DU_ASCII_LINE_H + 2;
/* boot-bar: 渐变填充(accent → accent2) */
int fill = bw * (li + 1) / BOOT_LINE_COUNT;
du_rect_outline(&g_fb, W / 2 - bw / 2, bar_y, bw, 6, KS_BORDER, 1);
if (fill > 2) du_fill_rect_gradient(&g_fb, W / 2 - bw / 2 + 1, bar_y + 1,
fill - 2, 4, KS_ACCENT, KS_ACCENT2);
} }
flip_buffer();
/* boot-hint + credit(对应 Kate "SYSTEM ONLINE" + "© 2026 Deaicup Studio") */
draw_centered("SYSTEM ONLINE", W / 2, H - 64, KS_ACCENT2, 0);
draw_centered("(C) 2026 DEAICUP STUDIO", W / 2, H - 40, KS_TEXT_DIM, 0);
flip_buffer();
busy_delay(10000000);
} }
/* ============================================================ /* ============================================================
* 严格错误策略插桩(D 系列):错误不再降级,整屏 fatal + 错误码。 * 严格错误策略插桩(D 系列):错误不再降级,整屏 fatal + 错误码。
* 每个插桩点唯一 symbol(DSK-E<nn>)。 * 每个插桩点唯一 symbol(DESK-E<nn>)。
* ============================================================ */ * ============================================================ */
static void desktop_fatal(const char *sym) { static void desktop_fatal(const char *sym) {
/* 严格错误策略:任何错误不再降级,串口留档 + 停机。 /* 严格错误策略:串口留档 + 深红 fatal 屏(ASCII 18px 直写真实 fb)+ 停机 */
* (UI 层 fatal 屏由各 UI 组件就绪后的路径使用;此处不依赖任何子系统) */
slog(sym); slog(sym);
if (g_real_fb && g_fb_w && g_fb_h) {
u32 *fb = (u32 *)g_real_fb;
u64 pitch_u32 = g_fb_pitch / 4;
for (u64 y = 0; y < g_fb_h; y++)
for (u64 x = 0; x < g_fb_w; x++)
fb[y * pitch_u32 + x] = 0xFF3A0A0Au; /* 深红 */
/* 居中绘制 symbol(ASCII 字符走 11x18 位图,其余跳过) */
int len = 0;
while (sym[len]) len++;
int cw = 11, ch = 18;
int x0 = (int)(g_fb_w - (u64)len * cw) / 2;
int y0 = (int)g_fb_h / 2 - ch / 2;
for (int i = 0; i < len; i++) {
unsigned char c = (unsigned char)sym[i];
if (c < 32 || c > 126) continue;
const unsigned char *g = g_ascii[c - 32];
for (int py = 0; py < ch; py++) {
u32 *row = fb + (u64)(y0 + py) * pitch_u32;
for (int px = 0; px < cw; px++) {
if (g[py * cw + px])
row[x0 + i * cw + px] = 0xFFF2F2F2u; /* 白 */
}
}
}
}
for (;;) __asm__("cli; hlt"); for (;;) __asm__("cli; hlt");
} }
@@ -220,8 +226,7 @@ void dsk_entry(const dsk_boot_context *ctx) {
slog("[zhfont] dbf loaded (16px ok)"); slog("[zhfont] dbf loaded (16px ok)");
} else { } else {
slog_num("[zhfont] dbf load failed rc=", zrc); slog_num("[zhfont] dbf load failed rc=", zrc);
slog("[zhfont] CJK disabled (ASCII fallback)"); desktop_fatal("DESK-E04 FONT PACK MISSING");
for (;;) __asm__("hlt");
} }
} }
@@ -233,13 +238,16 @@ void dsk_entry(const dsk_boot_context *ctx) {
slog("[wallpaper] loaded + scaled"); slog("[wallpaper] loaded + scaled");
} else { } else {
slog_num("[wallpaper] load failed rc=", wrc); slog_num("[wallpaper] load failed rc=", wrc);
slog("[wallpaper] gradient fallback"); /* 严格错误策略:材质包(壁纸)缺失不降级,fatal 屏 + 错误码 */
desktop_fatal("DESK-E02 TEXTURE PACK MISSING");
} }
/* M2: 开始菜单 logo(textures/startMenuLogo.rgba → 0x8700000) */ /* M2: 开始菜单 logo(textures/startMenuLogo.rgba → 0x8700000) */
if (taskbar_init(f32_read_path_lfn_to_w) == 0) if (taskbar_init(f32_read_path_lfn_to_w) == 0)
slog("[taskbar] startMenu logo loaded"); slog("[taskbar] startMenu logo loaded");
else else {
slog("[taskbar] startMenu logo missing (glyph fallback)"); /* 严格错误策略:材质包(开始菜单 logo)缺失不降级 */
desktop_fatal("DESK-E03 STARTMENU LOGO MISSING");
}
g_page = 3; /* Fluent 默认进 DESKTOP 页 */ g_page = 3; /* Fluent 默认进 DESKTOP 页 */
} }
@@ -278,11 +286,11 @@ void dsk_entry(const dsk_boot_context *ctx) {
files_refresh(); files_refresh();
boot_screen(); /* 桌面首帧绘入 sprite buffer,然后从登录帧渐隐渐显到桌面(无 boot 屏) */
redraw_all();
crossfade_login_to_desktop();
g_booted = 1; g_booted = 1;
redraw_all();
flip_buffer(); /* M2 修复:boot 后立即上屏,打字机残留清屏 */
slog("desktop ready"); slog("desktop ready");
desktop_launch_pending_native(); desktop_launch_pending_native();
+7 -7
View File
@@ -14,7 +14,7 @@
void draw_topbar(void) { void draw_topbar(void) {
int W = (int)g_fb_w; int W = (int)g_fb_w;
du_fill_rect_gradient(&g_fb, 0, 0, W, KATE_TOPBAR_H, du_fill_rect_gradient(&g_fb, 0, 0, W, KATE_TOPBAR_H,
0xFF0A2840u, KS_BG_PRIMARY); 0xFFFFFFFFu, KS_BG_PRIMARY);
du_divider_h(&g_fb, 0, KATE_TOPBAR_H, W, KS_BORDER); du_divider_h(&g_fb, 0, KATE_TOPBAR_H, W, KS_BORDER);
int x = 12; int x = 12;
@@ -180,7 +180,7 @@ static void draw_slider(int x, int y, int w, int val, int rect_out[4]) {
static void draw_statusbar_full(void) { static void draw_statusbar_full(void) {
int W = (int)g_fb_w; int W = (int)g_fb_w;
int y = (int)g_fb_h - KATE_STATUSBAR_H; int y = (int)g_fb_h - KATE_STATUSBAR_H;
du_fill_rect(&g_fb, 0, y, W, KATE_STATUSBAR_H, 0xFF051828u); du_fill_rect(&g_fb, 0, y, W, KATE_STATUSBAR_H, KS_BG_SECONDARY);
du_divider_h(&g_fb, 0, y, W, KS_BORDER); du_divider_h(&g_fb, 0, y, W, KS_BORDER);
int x = 12; int x = 12;
@@ -420,7 +420,7 @@ void draw_ide(void) {
int top = KATE_TOPBAR_H; int top = KATE_TOPBAR_H;
/* ide-tabs(36px):dot + 实例标签 + "+ NEW IDE" + ide-hint(Kate 结构) */ /* ide-tabs(36px):dot + 实例标签 + "+ NEW IDE" + ide-hint(Kate 结构) */
du_fill_rect(&g_fb, 0, top, W, 36, 0xFF051828u); du_fill_rect(&g_fb, 0, top, W, 36, KS_BG_SECONDARY);
du_divider_h(&g_fb, 0, top + 36, W, KS_BORDER); du_divider_h(&g_fb, 0, top + 36, W, KS_BORDER);
int x = 12; int x = 12;
int ty = top + (36 - (int)DU_ASCII_LINE_H) / 2 + 1; int ty = top + (36 - (int)DU_ASCII_LINE_H) / 2 + 1;
@@ -507,7 +507,7 @@ void draw_ide(void) {
blit_scanout_to_ide(hx + 2, hy + 2, hw - 4, hh - 4); blit_scanout_to_ide(hx + 2, hy + 2, hw - 4, hh - 4);
} else { } else {
/* P8.1: 启动中--显示分阶段状态 + 详细信息 */ /* P8.1: 启动中--显示分阶段状态 + 详细信息 */
du_fill_rect(&g_fb, hx + 2, hy + 2, hw - 4, hh - 4, 0xFF051828u); du_fill_rect(&g_fb, hx + 2, hy + 2, hw - 4, hh - 4, KS_BG_SECONDARY);
draw_centered(g_launch_status[0] ? g_launch_status : draw_centered(g_launch_status[0] ? g_launch_status :
"STARTING VSCODE . . .", "STARTING VSCODE . . .",
W / 2, hy + hh / 2 - 20, KS_TEXT_DIM, 0); W / 2, hy + hh / 2 - 20, KS_TEXT_DIM, 0);
@@ -598,7 +598,7 @@ void draw_desktop_page(void) {
int W = (int)g_fb_w; int W = (int)g_fb_w;
int tb_y = (int)g_fb_h - KATE_TASKBAR_H; int tb_y = (int)g_fb_h - KATE_TASKBAR_H;
du_fill_rect_gradient(&g_fb, 0, tb_y, W, KATE_TASKBAR_H, du_fill_rect_gradient(&g_fb, 0, tb_y, W, KATE_TASKBAR_H,
0xFF0A2840u, KS_BG_PRIMARY); 0xFFFFFFFFu, KS_BG_PRIMARY);
du_divider_h(&g_fb, 0, tb_y, W, KS_BORDER); du_divider_h(&g_fb, 0, tb_y, W, KS_BORDER);
int x = 8; int x = 8;
@@ -683,7 +683,7 @@ void draw_custom_page(int cp_idx) {
cpage *cp = &g_cpages[cp_idx]; cpage *cp = &g_cpages[cp_idx];
/* ide-tabs 栏(36px):dot + 页名 + "+ NEW INSTANCE" + ide-hint(Kate 结构) */ /* ide-tabs 栏(36px):dot + 页名 + "+ NEW INSTANCE" + ide-hint(Kate 结构) */
du_fill_rect(&g_fb, 0, top, W, 36, 0xFF051828u); du_fill_rect(&g_fb, 0, top, W, 36, KS_BG_SECONDARY);
du_divider_h(&g_fb, 0, top + 36, W, KS_BORDER); du_divider_h(&g_fb, 0, top + 36, W, KS_BORDER);
int ty = top + (36 - (int)DU_ASCII_LINE_H) / 2 + 1; int ty = top + (36 - (int)DU_ASCII_LINE_H) / 2 + 1;
@@ -836,7 +836,7 @@ void draw_ctx_menu(void) {
g_ctx_rect[0] = x; g_ctx_rect[1] = y; g_ctx_rect[0] = x; g_ctx_rect[1] = y;
g_ctx_rect[2] = mw; g_ctx_rect[3] = mh; g_ctx_rect[2] = mw; g_ctx_rect[3] = mh;
du_fill_rect(&g_fb, x, y, mw, mh, 0xFF050A18u); du_fill_rect(&g_fb, x, y, mw, mh, KS_BG_SECONDARY);
du_rect_outline(&g_fb, x, y, mw, mh, KS_ACCENT, 1); du_rect_outline(&g_fb, x, y, mw, mh, KS_ACCENT, 1);
du_kate_glow_border(&g_fb, x, y, mw, mh, KS_ACCENT); du_kate_glow_border(&g_fb, x, y, mw, mh, KS_ACCENT);
+11
View File
@@ -482,6 +482,17 @@ int handle_key(u8 sc) {
if (sc == 0x01) { if (sc == 0x01) {
if (g_taskview) { g_taskview = 0; return 1; } if (g_taskview) { g_taskview = 0; return 1; }
if (g_ctx_open) { g_ctx_open = 0; return 1; } if (g_ctx_open) { g_ctx_open = 0; return 1; }
/* IDE 页:Esc = detach + 退回桌面页(IDE 退出通道) */
if (g_page == 2) {
if (g_ide_attached) {
g_ide_attached = 0;
g_input_forward_enabled = 0;
ide_attach_invalidate();
slog("ide detached (esc), input forwarding off");
}
page_switch(3);
return 1;
}
return 0; return 0;
} }
if (g_taskview || g_ctx_open) return 0; /* 模态期间吞掉按键 */ if (g_taskview || g_ctx_open) return 0; /* 模态期间吞掉按键 */
+3 -3
View File
@@ -32,7 +32,7 @@ int g_tb2_clk_rect[4];
#define TB_APPBTN 44 /* 应用钮边长 */ #define TB_APPBTN 44 /* 应用钮边长 */
#define TB_PAD 8 /* 条内边距 */ #define TB_PAD 8 /* 条内边距 */
static const wf_theme *tb_theme(void) { return &g_wf_dark; } static const wf_theme *tb_theme(void) { return &g_wf_light; }
/* ---- 开始菜单 logo(textures/startMenuLogo.rgba,加载失败回退字形) ---- */ /* ---- 开始菜单 logo(textures/startMenuLogo.rgba,加载失败回退字形) ---- */
static int g_smlogo_ok = 0; static int g_smlogo_ok = 0;
@@ -151,8 +151,8 @@ void taskbar_draw(void) {
g_tb2_app_rect[i][0] = x; g_tb2_app_rect[i][1] = byy; g_tb2_app_rect[i][0] = x; g_tb2_app_rect[i][1] = byy;
g_tb2_app_rect[i][2] = TB_APPBTN; g_tb2_app_rect[i][3] = TB_APPBTN; g_tb2_app_rect[i][2] = TB_APPBTN; g_tb2_app_rect[i][3] = TB_APPBTN;
wf_btn_state st = tb_hover_state(g_tb2_app_rect[i]); wf_btn_state st = tb_hover_state(g_tb2_app_rect[i]);
if (w->focused) du_wf_overlay(&g_fb, x, byy, TB_APPBTN, TB_APPBTN, 0x22FFFFFFu); if (w->focused) du_wf_overlay(&g_fb, x, byy, TB_APPBTN, TB_APPBTN, 0x22000000u);
else if (st == WF_BTN_HOVER) du_wf_overlay(&g_fb, x, byy, TB_APPBTN, TB_APPBTN, 0x22FFFFFFu); else if (st == WF_BTN_HOVER) du_wf_overlay(&g_fb, x, byy, TB_APPBTN, TB_APPBTN, 0x22000000u);
du_wf_icon(&g_fb, tb_app_icon(w->app_id), x + (TB_APPBTN - 22) / 2, du_wf_icon(&g_fb, tb_app_icon(w->app_id), x + (TB_APPBTN - 22) / 2,
byy + (TB_APPBTN - 22) / 2, 22, t->text_primary); byy + (TB_APPBTN - 22) / 2, 22, t->text_primary);
/* 运行指示条:底部 accent,聚焦加宽 */ /* 运行指示条:底部 accent,聚焦加宽 */
+2 -2
View File
@@ -250,7 +250,7 @@ void draw_window_frame(desktop_window *w) {
du_fill_rounded_rect(&g_fb, w->x, w->y, w->w, w->h, KS_BG_SECONDARY, 2); du_fill_rounded_rect(&g_fb, w->x, w->y, w->w, w->h, KS_BG_SECONDARY, 2);
du_fill_rect_gradient(&g_fb, w->x + 1, w->y + 1, w->w - 2, KATE_TITLEBAR_H - 1, du_fill_rect_gradient(&g_fb, w->x + 1, w->y + 1, w->w - 2, KATE_TITLEBAR_H - 1,
0xFF0A3050u, KS_BG_SECONDARY); KS_BG_TERTIARY, KS_BG_SECONDARY);
du_divider_h(&g_fb, w->x, w->y + KATE_TITLEBAR_H, w->w, KS_BORDER); du_divider_h(&g_fb, w->x, w->y + KATE_TITLEBAR_H, w->w, KS_BORDER);
du_fill_rect(&g_fb, w->x + 6, w->y + KATE_TITLEBAR_H / 2 - 2, 4, 4, KS_ACCENT2); du_fill_rect(&g_fb, w->x + 6, w->y + KATE_TITLEBAR_H / 2 - 2, 4, 4, KS_ACCENT2);
@@ -258,7 +258,7 @@ void draw_window_frame(desktop_window *w) {
du_draw_string(&g_fb, w->title, du_draw_string(&g_fb, w->title,
w->x + 14, w->x + 14,
w->y + (KATE_TITLEBAR_H - (i64)DU_ASCII_LINE_H) / 2 + 1, w->y + (KATE_TITLEBAR_H - (i64)DU_ASCII_LINE_H) / 2 + 1,
KS_ACCENT, 0xFF0A3050u, DU_ASCII_STEP); KS_ACCENT, KS_BG_SECONDARY, DU_ASCII_STEP);
int bx = w->x + w->w - CLOSE_BTN_OFFSET; int bx = w->x + w->w - CLOSE_BTN_OFFSET;
int by = w->y + (KATE_TITLEBAR_H - CLOSE_BTN_SIZE) / 2; int by = w->y + (KATE_TITLEBAR_H - CLOSE_BTN_SIZE) / 2;
+11 -1
View File
@@ -789,8 +789,18 @@ static inline int f32_read_file_by_clus(u32 clus, u32 size, u8 *out_buf, u32 buf
for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b]; for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b];
dst += fc_bytes; remaining -= fc_bytes; dst += fc_bytes; remaining -= fc_bytes;
u32 fo = fat_byte_off + fc * 4; u32 fo = fat_byte_off + fc * 4;
if (fo + 4 > sizeof(f32_disk)) break; if (fo + 4 <= sizeof(f32_disk)) {
fc = f32_r32(f32_disk + fo) & 0x0FFFFFFF; fc = f32_r32(f32_disk + fo) & 0x0FFFFFFF;
} else {
/* BUG-031 修复:FAT 超出 128KB 预读缓冲(sidecar FAT ~2.1MB)。
* 旧逻辑直接越界读 f32_disk 尾部得到垃圾簇号,链路走飞导致
* 大文件(字库/壁纸)第二簇起数据损坏。按需读取单 FAT 扇区
* (fo 为相对 LBA0 的字节偏移,直接换算扇区号)。 */
u8 fat_sec[512];
if (f32_read_sectors(fo / 512, 1, fat_sec) != 0)
return -7;
fc = f32_r32(fat_sec + (fo % 512)) & 0x0FFFFFFF;
}
} }
return 0; return 0;
} }
Binary file not shown.
+34
View File
@@ -759,6 +759,40 @@ if (Test-Path $PanicLogoPng) {
} else { } else {
Write-Host '[build] WARNING: ohMyLogo.png not found (panic screen keeps embedded data)' Write-Host '[build] WARNING: ohMyLogo.png not found (panic screen keeps embedded data)'
} }
# Generate desktop textures (PNG/webP -> raw RGBA for the desktop material pack)
$GenTex = Join-Path $Root 'CODE\desktop\gen_textures.py'
if (Test-Path $GenTex) {
$TexSrc = Join-Path $Root 'SYSTEM\system\deshab64\desktop\textures\startMenuLogo.png'
$TexStamp = Join-Path $Root 'SYSTEM\system\deshab64\desktop\textures\startMenuLogo.rgba'
$needTex = -not (Test-Path $TexStamp)
if ($needTex -and (Test-Path $TexSrc)) {
$needTex = (Get-Item $TexSrc).LastWriteTime -gt (Get-Item $TexStamp).LastWriteTime
}
if ($needTex) {
Write-Host '[build] Generating desktop textures (gen_textures.py)...'
$texDone = $false
$Python = $null
foreach ($p in @('C:\Users\林濬哲\AppData\Local\Programs\Python\Python312\python.exe',
'C:\msys64\mingw64\bin\python.exe',
'python', 'python3')) {
try { $cmd = Get-Command $p -ErrorAction Stop; $Python = $cmd.Source; break } catch {}
}
if ($Python) {
& $Python $GenTex
if ($LASTEXITCODE -eq 0) { $texDone = $true }
}
if (-not $texDone) {
# Fallback: WSL python3 (has Pillow on this machine)
$wslPath = ($GenTex -replace '^([A-Za-z]):', '/mnt/$1').ToLower()
& wsl python3 $wslPath
if ($LASTEXITCODE -eq 0) { $texDone = $true }
}
if (-not $texDone) {
Write-Host '[build] WARNING: desktop texture generation failed (material pack may be incomplete)'
}
}
}
try { try {
& $make -C "$DskDir" -f MAKEFILE "CC=$clang" "LD=$lld" & $make -C "$DskDir" -f MAKEFILE "CC=$clang" "LD=$lld"
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {