- 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>
274 lines
9.7 KiB
C
274 lines
9.7 KiB
C
/* 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);
|
||
}
|