Files
LinehuandCursor 8554a82677 feat(panic): FUCK [panic] mode=strict|fallback + realtest image variant
- UTSM panic_full returns in fallback mode (logs [PANIC:FALLBACK] + code + hit
  count); panic_halt keeps always-halt sites (CPU exception, VMM-E11 LA57,
  VMM-E15 DSK jump, UTSM-E42 test hook). Call sites given safe continuations.
- Mode passed to DSK/FirstInit/login/desktop via DSK_BOOT_FLAG_PANIC_FALLBACK;
  DKM kernel_api.panic / kern.log.panic return to driver; ext4 fatal aborts the
  op via setjmp/longjmp and DSK falls back to FAT32 ESP.
- build.ps1/Makefile: dev=strict, release=fallback, new realtest (release
  options + strict); default -Variant all; serialized iso packing under -j.
- Fix '*/' inside comments (dkm.h, kernel_api.h, bus.c) that broke the build.
- Includes pending work: dkm_bus service bus, mt7920/wlan drivers, desktop
  files/startmenu/prank, pe-tools, diskinfo, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 23:57:19 +08:00

274 lines
9.7 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* wm.c — 窗口管理(win_*)+ 窗口装饰绘制(M0 自 main.c 平移)
*/
#include "desktop.h"
/* ---- 全局状态 ---- */
desktop_window g_windows[MAX_WINDOWS];
int g_win_count = 0;
static int g_next_win_id = 1;
int g_focused_win = -1;
/* 拖拽状态 */
int g_dragging = 0;
int g_drag_win = -1;
int g_drag_off_x, g_drag_off_y;
/* ============================================================
* 窗口管理
* ============================================================ */
desktop_window *win_find(int id) {
for (int i = 0; i < g_win_count; i++) {
if (g_windows[i].id == id) return &g_windows[i];
}
return 0;
}
desktop_window *win_find_at(int mx, int my) {
for (int i = g_win_count - 1; i >= 0; i--) {
desktop_window *w = &g_windows[i];
if (!w->visible || w->minimized) continue;
if (w->ws != g_ws_cur) continue;
if (mx >= w->x && mx < w->x + w->w && my >= w->y && my < w->y + w->h) {
return w;
}
}
return 0;
}
static void win_bring_to_front(desktop_window *w) {
int idx = -1;
for (int i = 0; i < g_win_count; i++) {
if (g_windows[i].id == w->id) { idx = i; break; }
}
if (idx < 0 || idx == g_win_count - 1) return;
desktop_window tmp = g_windows[idx];
for (int i = idx; i < g_win_count - 1; i++) {
g_windows[i] = g_windows[i+1];
}
g_windows[g_win_count - 1] = tmp;
}
void win_focus(desktop_window *w) {
int id = w->id; /* bring_to_front 会重排数组,先保存 id 避免悬空指针 */
win_bring_to_front(w);
for (int i = 0; i < g_win_count; i++)
g_windows[i].focused = (g_windows[i].id == id);
g_focused_win = id;
if (g_win_count > 0) g_windows[g_win_count - 1].minimized = 0;
}
desktop_window *win_create(int app_id, const char *title, int x, int y, int w, int h) {
if (g_win_count >= MAX_WINDOWS) return 0;
desktop_window *win = &g_windows[g_win_count++];
int id = g_next_win_id++;
win->id = id;
win->x = x; win->y = y; win->w = w; win->h = h;
win->visible = 1;
win->focused = 1;
win->minimized = 0;
win->app_id = app_id;
win->app_state = 0;
win->closing = 0;
win->dirty = 1;
win->ws = g_ws_cur;
for (int i = 0; i < 47 && title[i]; i++) win->title[i] = title[i];
win->title[47] = 0;
for (int i = 0; i < g_win_count - 1; i++) g_windows[i].focused = 0;
g_focused_win = id;
return win;
}
void win_destroy(desktop_window *w) {
int idx = -1;
int id = w->id;
for (int i = 0; i < g_win_count; i++) {
if (g_windows[i].id == id) { idx = i; break; }
}
if (idx < 0) return;
/* 直接隐藏窗口(去掉关闭动画以避免卡顿和闪屏) */
w->visible = 0;
if (w->app_id >= 0 && w->app_id < g_app_count && g_apps[w->app_id].on_destroy && w->app_state) {
g_apps[w->app_id].on_destroy(w->app_state);
}
/* 挪位之后 w 指向的是下一扇窗口,关闭判断必须用挪位前记下的 id。 */
for (int i = idx; i < g_win_count - 1; i++) g_windows[i] = g_windows[i+1];
g_win_count--;
if (g_focused_win == id) {
g_focused_win = -1;
for (int i = g_win_count - 1; i >= 0; i--) {
if (g_windows[i].ws == g_ws_cur && g_windows[i].visible && !g_windows[i].minimized) {
g_focused_win = g_windows[i].id;
g_windows[i].focused = 1;
break;
}
}
}
}
/* 窗口标题栏高度(M2:Fluent 36px / KATE 28px) */
int win_titlebar_h(void) {
return g_fluent ? 36 : KATE_TITLEBAR_H;
}
/* P5d: 关闭请求。运行中的 PE 窗口不能直接 win_destroy(run_windowed 阻塞中,
* pump 持有窗口 id)——按 pe_window_host 协作契约 inject WM_CLOSE,
* PE 自愿退出后由 launch_pe_app 收尾销毁。 */
void win_close_request(desktop_window *w) {
if (g_pe_running && w->id == g_pe_win_id && g_pe_svc && g_pe_svc->inject_input) {
g_pe_svc->inject_input(PE_WM_CLOSE, 0, 0, 0, 0);
return;
}
win_destroy(w);
}
int ws_win_count(int ws) {
int n = 0;
for (int i = 0; i < g_win_count; i++)
if (g_windows[i].ws == ws && g_windows[i].visible) n++;
return n;
}
/* ============================================================
* 窗口装饰绘制
* ============================================================ */
/* M2:Fluent 窗口框架 —— 圆角 8、36px 标题栏、右上三钮、投影。
* 窗口按钮命中区(WM_FLUENT_TB=36px 标题栏,三钮各 46×36)。 */
#define WM_FLUENT_TB 36
#define WM_BTN_W 46
static int wm_fluent_hit_btn(desktop_window *w, int mx, int my, int btn) {
int bx = w->x + w->w - WM_BTN_W * btn;
return mx >= bx && mx < bx + WM_BTN_W &&
my >= w->y && my < w->y + WM_FLUENT_TB;
}
/* 静态状态:正在操作的三钮(0=无 1=min 2=max 3=close) */
static int g_wm_btn_hover = 0;
int win_hit_close_btn(desktop_window *w, int mx, int my) {
/* 绘制顺序是 min=*3、max=*2、close=*1(最右)。命中必须跟绘制同一序号。 */
if (g_fluent) return wm_fluent_hit_btn(w, mx, my, 1);
int bx = w->x + w->w - CLOSE_BTN_OFFSET;
int by = w->y + (KATE_TITLEBAR_H - CLOSE_BTN_SIZE) / 2;
return mx >= bx && mx < bx + CLOSE_BTN_SIZE &&
my >= by && my < by + CLOSE_BTN_SIZE;
}
int win_hit_min_btn(desktop_window *w, int mx, int my) {
return g_fluent ? wm_fluent_hit_btn(w, mx, my, 3) : 0;
}
int win_hit_max_btn(desktop_window *w, int mx, int my) {
return g_fluent ? wm_fluent_hit_btn(w, mx, my, 2) : 0;
}
static void draw_window_frame_fluent(desktop_window *w) {
/* 投影 + 亚克力底(窗口主体用不透明深色,性能优先) */
du_rect_outline(&g_fb, w->x - 2, w->y - 2, w->w + 4, w->h + 4,
du_blend(du_pixel_read(&g_fb, w->x - 2, w->y - 2), 0xFF000000u, 70), 10);
du_fill_rounded_rect(&g_fb, w->x, w->y, w->w, w->h, 0xFF2B2B2Bu, 8);
du_rect_outline(&g_fb, w->x, w->y, w->w, w->h,
w->focused ? 0xFF4A4A4Au : 0xFF3F3F3Fu, 8);
/* 标题栏(36px,无强调色,仅底部分隔线) */
du_fill_rect(&g_fb, w->x + 1, w->y + 1, w->w - 2, WM_FLUENT_TB - 1, 0xFF2B2B2Bu);
du_divider_h(&g_fb, w->x + 1, w->y + WM_FLUENT_TB, w->w - 2, 0xFF3A3A3Au);
du_draw_string(&g_fb, w->title,
w->x + 14,
w->y + (WM_FLUENT_TB - (i64)DU_ASCII_LINE_H) / 2,
w->focused ? 0xFFFFFFFFu : 0xFFC8C8C8u, 0xFF2B2B2Bu, DU_ASCII_STEP);
/* 右上三钮:最小化 / 最大化 / 关闭(hover:前两钮浅灰,关闭钮红) */
int by = w->y;
int iy = by + WM_FLUENT_TB / 2;
/* min */
{
int bx = w->x + w->w - WM_BTN_W * 3;
if (g_wm_btn_hover == 1)
du_fill_rect(&g_fb, bx, by, WM_BTN_W, WM_FLUENT_TB, 0xFF3A3A3Au);
du_fill_rect(&g_fb, bx + 16, iy, 14, 2, 0xFFFFFFFFu);
}
/* max */
{
int bx = w->x + w->w - WM_BTN_W * 2;
if (g_wm_btn_hover == 2)
du_fill_rect(&g_fb, bx, by, WM_BTN_W, WM_FLUENT_TB, 0xFF3A3A3Au);
du_rect_outline(&g_fb, bx + 17, iy - 7, 13, 13, 0xFFFFFFFFu, 1);
}
/* close:hover 红 #E81123 */
{
int bx = w->x + w->w - WM_BTN_W;
if (g_wm_btn_hover == 3)
du_fill_rect(&g_fb, bx, by, WM_BTN_W, WM_FLUENT_TB, 0xFFC42B1Cu);
/* × 用两条 2px 对角线 */
for (int i = 0; i < 11; i++) {
du_pixel(&g_fb, bx + 18 + i, iy - 5 + i, 0xFFFFFFFFu);
du_pixel(&g_fb, bx + 19 + i, iy - 5 + i, 0xFFFFFFFFu);
du_pixel(&g_fb, bx + 18 + i, iy + 5 - i, 0xFFFFFFFFu);
du_pixel(&g_fb, bx + 19 + i, iy + 5 - i, 0xFFFFFFFFu);
}
}
}
int win_hit_titlebar(desktop_window *w, int mx, int my) {
int tb = g_fluent ? WM_FLUENT_TB : KATE_TITLEBAR_H;
if (g_fluent && (win_hit_close_btn(w, mx, my) || win_hit_max_btn(w, mx, my) ||
win_hit_min_btn(w, mx, my)))
return 0; /* 三钮区域不算标题栏拖拽 */
return mx >= w->x && mx < w->x + w->w &&
my >= w->y && my < w->y + tb;
}
/* 窗口按钮 hover 状态跟踪(绘制前调用;btn 0=无) */
void wm_set_btn_hover(int btn) { g_wm_btn_hover = btn; }
/* 当前鼠标悬停的窗口按钮(0=无 1=min 2=max 3=close),-1=不在窗口上 */
int wm_detect_btn_hover(desktop_window *w, int mx, int my) {
if (!w) return 0;
if (win_hit_close_btn(w, mx, my)) return 3;
if (win_hit_max_btn(w, mx, my)) return 2;
if (win_hit_min_btn(w, mx, my)) return 1;
return 0;
}
void draw_window_frame(desktop_window *w) {
if (!w->visible || w->minimized) return;
if (g_fluent) {
draw_window_frame_fluent(w);
return;
}
/* ---- Winux-Kate 风格(fluent=0 回退路径) ---- */
u32 border = w->focused ? KS_BORDER_FOCUS : KS_BORDER;
if (w->focused) {
du_kate_glow_border(&g_fb, w->x, w->y, w->w, w->h, KS_ACCENT);
}
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,
KS_BG_TERTIARY, KS_BG_SECONDARY);
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_draw_string(&g_fb, w->title,
w->x + 14,
w->y + (KATE_TITLEBAR_H - (i64)DU_ASCII_LINE_H) / 2 + 1,
KS_ACCENT, KS_BG_SECONDARY, DU_ASCII_STEP);
int bx = w->x + w->w - CLOSE_BTN_OFFSET;
int by = w->y + (KATE_TITLEBAR_H - CLOSE_BTN_SIZE) / 2;
du_rect_outline(&g_fb, bx, by, CLOSE_BTN_SIZE, CLOSE_BTN_SIZE, KS_DANGER, 1);
du_draw_string(&g_fb, "X", bx + 3, by - 1,
KS_DANGER, KS_BG_SECONDARY, DU_ASCII_STEP);
du_rect_outline(&g_fb, w->x, w->y, w->w, w->h, border, 2);
}