Files
Deshab-OS/CODE/desktop/appreg.c
T

448 lines
17 KiB
C
Raw 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.
/* appreg.c — 应用注册表 + 桌面图标(M0 自 main.c 平移)
*
* 注册来源:内置 / LINUXAPP.CNF / PEAPPS.CNF / user/desktop/*.lnk
*/
#include "desktop.h"
/* ---- 全局状态 ---- */
app_descriptor g_apps[MAX_APPS];
int g_app_count = 0;
desktop_icon g_icons[MAX_ICONS];
int g_icon_count = 0;
/* ============================================================
* Winux-Kate 应用图标(40×40,青色几何图形)
* ============================================================ */
void draw_circle_outline(du_context *ctx, int cx, int cy, int r, u32 color) {
for (int dy = -r; dy <= r; dy++) {
for (int dx = -r; dx <= r; dx++) {
int d2 = dx * dx + dy * dy;
if (d2 <= r * r && d2 > (r - 1) * (r - 1)) {
du_pixel(ctx, cx + dx, cy + dy, color);
}
}
}
}
static void draw_icon_terminal(du_context *ctx, int cx, int cy) {
du_fill_rect(ctx, cx, cy, 40, 40, KS_BG_TERTIARY);
du_rect_outline(ctx, cx, cy, 40, 40, KS_ACCENT, 2);
du_fill_rect(ctx, cx + 8, cy + 12, 2, 2, KS_ACCENT2);
du_fill_rect(ctx, cx + 10, cy + 14, 2, 2, KS_ACCENT2);
du_fill_rect(ctx, cx + 12, cy + 16, 2, 2, KS_ACCENT2);
du_fill_rect(ctx, cx + 10, cy + 18, 2, 2, KS_ACCENT2);
du_fill_rect(ctx, cx + 8, cy + 20, 2, 2, KS_ACCENT2);
du_fill_rect(ctx, cx + 16, cy + 22, 8, 2, KS_ACCENT);
}
static void draw_icon_editor(du_context *ctx, int cx, int cy) {
du_fill_rect(ctx, cx, cy, 40, 40, KS_BG_TERTIARY);
du_rect_outline(ctx, cx, cy, 40, 40, KS_ACCENT, 2);
int widths[] = {24, 20, 22, 14, 20, 18};
for (int i = 0; i < 6; i++) {
du_fill_rect(ctx, cx + 8, cy + 8 + i * 4, widths[i], 2,
(i == 0) ? KS_ACCENT2 : KS_ACCENT);
}
}
static void draw_icon_folder(du_context *ctx, int cx, int cy) {
du_fill_rect(ctx, cx, cy, 40, 40, KS_BG_TERTIARY);
du_rect_outline(ctx, cx, cy, 40, 40, KS_BORDER, 2);
du_fill_rect(ctx, cx + 8, cy + 10, 12, 4, KS_ACCENT_DIM);
du_rect_outline(ctx, cx + 8, cy + 10, 12, 4, KS_ACCENT, 1);
du_fill_rect(ctx, cx + 6, cy + 14, 28, 16, KS_BG_SECONDARY);
du_rect_outline(ctx, cx + 6, cy + 14, 28, 16, KS_ACCENT, 1);
du_fill_rect(ctx, cx + 6, cy + 14, 28, 1, KS_ACCENT);
du_fill_rect(ctx, cx + 10, cy + 19, 12, 1, KS_ACCENT2);
du_fill_rect(ctx, cx + 10, cy + 23, 16, 1, KS_TEXT_DIM);
du_fill_rect(ctx, cx + 10, cy + 26, 10, 1, KS_TEXT_DIM);
}
static void draw_icon_calc(du_context *ctx, int cx, int cy) {
du_fill_rect(ctx, cx, cy, 40, 40, KS_BG_TERTIARY);
du_rect_outline(ctx, cx, cy, 40, 40, KS_ACCENT, 2);
du_fill_rect(ctx, cx + 6, cy + 6, 28, 8, KS_BG_PRIMARY);
du_rect_outline(ctx, cx + 6, cy + 6, 28, 8, KS_ACCENT2, 1);
du_fill_rect(ctx, cx + 28, cy + 8, 4, 4, KS_ACCENT2);
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
int bx = cx + 6 + c * 9;
int by = cy + 18 + r * 7;
du_fill_rect(ctx, bx, by, 7, 5, KS_ACCENT_DIM);
du_rect_outline(ctx, bx, by, 7, 5, KS_ACCENT, 1);
}
}
}
static void draw_icon_browser(du_context *ctx, int cx, int cy) {
du_fill_rect(ctx, cx, cy, 40, 40, KS_BG_TERTIARY);
du_rect_outline(ctx, cx, cy, 40, 40, KS_ACCENT, 2);
int ccx = cx + 20, ccy = cy + 20, r = 11;
draw_circle_outline(ctx, ccx, ccy, r, KS_ACCENT);
du_fill_rect(ctx, ccx - r, ccy, 2 * r + 1, 1, KS_ACCENT);
du_fill_rect(ctx, ccx, ccy - r, 1, 2 * r + 1, KS_ACCENT);
du_pixel(ctx, ccx, ccy, KS_ACCENT2);
}
void draw_app_icon(du_context *ctx, int app_id, int cx, int cy) {
switch (app_id) {
case 0: draw_icon_terminal(ctx, cx, cy); break;
case 1: draw_icon_editor(ctx, cx, cy); break;
case 2: draw_icon_folder(ctx, cx, cy); break;
case 3: draw_icon_calc(ctx, cx, cy); break;
case 4: draw_icon_browser(ctx, cx, cy); break;
default: draw_icon_terminal(ctx, cx, cy); break;
}
}
/* ============================================================
* 应用注册
* ============================================================ */
/* ---- VSCode Phase 5: LINUXAPP.CNF Linux 应用注册表 ----
* FAT32 根目录 LINUXAPP.CNF(8.3: LINUXAPPCNF),每行一个 Linux guest 应用:
* NAME|DISPLAY|/guest/path|args(args 可含空格,可省略)
* '#' 开头为注释。解析结果存静态池,app_descriptor.linux_path 指入。 */
#define LINUXAPP_MAX 8
static char g_lapp_name[LINUXAPP_MAX][12];
static char g_lapp_disp[LINUXAPP_MAX][16];
static char g_lapp_path[LINUXAPP_MAX][96];
static char g_lapp_args[LINUXAPP_MAX][96];
int g_vscode_app_id = -1; /* 第一个名为 "vscode" 的注册项 */
/* 字段拷贝:src[0..n) → dst(NUL 结尾),返回拷贝长度 */
static int lapp_field_copy(char *dst, int dst_cap, const char *src, int n) {
if (n >= dst_cap) n = dst_cap - 1;
for (int i = 0; i < n; i++) dst[i] = src[i];
dst[n] = 0;
return n;
}
#define UDESK_MAX 12
static char g_ud_name[UDESK_MAX][12];
static char g_ud_disp[UDESK_MAX][16];
static char g_ud_path[UDESK_MAX][96];
static char g_ud_elf[UDESK_MAX][12];
static char g_ud_files[UDESK_MAX][64];
static int g_ud_nfiles;
static int udesk_name_taken(const char *n) {
int i;
for (i = 0; i < g_app_count; i++) {
if (g_apps[i].name && fat32_lfn_streq_ci(g_apps[i].name, n)) return 1;
}
return 0;
}
static int udesk_collect_cb(const f32_entry *e, void *user) {
(void)user;
const char *nm = (e->has_lfn && e->long_name[0]) ? e->long_name : e->name;
if (e->is_dir || !nm[0]) return 0;
if (!fat32_lfn_ends_with_ci(nm, ".lnk")) return 0;
if (g_ud_nfiles >= UDESK_MAX) return 1;
lapp_field_copy(g_ud_files[g_ud_nfiles], 64, nm, kstrlen(nm));
g_ud_nfiles++;
return 0;
}
static int udesk_ascii_ok(const char *s) {
if (!s || !s[0]) return 0;
while (*s) {
if ((unsigned char)*s > 0x7E) return 0;
s++;
}
return 1;
}
static void udesk_parse_lnk(int slot, const u8 *data, u32 size) {
const char *lines[4];
int nlen[4];
int n = 0, i;
u32 pos = 0;
char kind[16];
if (slot < 0 || slot >= UDESK_MAX) return;
while (pos < size && n < 4) {
u32 eol = pos;
while (eol < size && data[eol] != '\n' && data[eol] != '\r') eol++;
lines[n] = (const char *)data + pos;
nlen[n] = (int)(eol - pos);
n++;
while (eol < size && (data[eol] == '\n' || data[eol] == '\r')) eol++;
pos = eol;
}
if (n < 2) return;
if (n >= 4 && nlen[3] > 0)
lapp_field_copy(g_ud_name[slot], 12, lines[3], nlen[3]);
else
lapp_field_copy(g_ud_name[slot], 12, lines[0], nlen[0]);
if (udesk_ascii_ok(g_ud_name[slot]) == 0) {
g_ud_name[slot][0] = 'a' + (char)slot;
g_ud_name[slot][1] = 0;
}
if (nlen[0] > 0 && udesk_ascii_ok(lines[0]))
lapp_field_copy(g_ud_disp[slot], 16, lines[0], nlen[0]);
else
kstrcpy(g_ud_disp[slot], g_ud_name[slot], 16);
lapp_field_copy(kind, 16, lines[1], nlen[1]);
g_ud_path[slot][0] = 0;
g_ud_elf[slot][0] = 0;
if (fat32_lfn_streq_ci(kind, "LINUX") || (n >= 3 && lines[2][0] == '/')) {
if (n >= 3)
lapp_field_copy(g_ud_path[slot], 96, lines[2], nlen[2]);
} else if (fat32_lfn_streq_ci(kind, "NATIVE")) {
return;
} else {
if (nlen[1] >= 11)
lapp_field_copy(g_ud_elf[slot], 12, lines[1], 11);
else
f32_name_to_83_w(kind, g_ud_elf[slot]);
g_ud_elf[slot][11] = 0;
}
if (udesk_name_taken(g_ud_name[slot])) return;
if (!g_ud_path[slot][0] && !g_ud_elf[slot][0]) return;
if (g_app_count >= MAX_APPS) return;
g_apps[g_app_count] = (app_descriptor){
g_ud_name[slot], g_ud_disp[slot], 720, 480,
0, 0, 0, 0,
g_ud_elf[slot][0] ? g_ud_elf[slot] : 0,
g_ud_path[slot][0] ? g_ud_path[slot] : 0, 0, 0, 0,
1 /* user_desktop:桌面只显示 .lnk */
};
g_app_count++;
slog("user/desktop icon:");
slog(g_ud_disp[slot]);
(void)i;
}
static void register_user_desktop_icons(void) {
u32 dclus = 0;
int i;
g_ud_nfiles = 0;
if (f32_find_path_dir_lfn_w("user/desktop", &dclus) != 0) {
slog("user/desktop missing, skip shared icons");
return;
}
if (f32_list_dir_w(dclus, udesk_collect_cb, 0) != 0) return;
for (i = 0; i < g_ud_nfiles && g_app_count < MAX_APPS; i++) {
char path[96];
u8 *data = 0;
u32 size = 0;
kstrcpy(path, "user/desktop/", 96);
kstrcat(path, g_ud_files[i], 96);
if (f32_read_path_lfn_w(path, &data, &size) != 0 || !data || !size) continue;
udesk_parse_lnk(i, data, size);
}
}
static void register_linux_apps(void) {
u8 *data = 0;
u32 size = 0;
char n11[11];
if (f32_name_to_83_w("LINUXAPP.CNF", n11) != 0) return;
if (f32_read_root_file_w(n11, &data, &size) != 0) return; /* 无配置文件:跳过 */
int li = 0; /* 已注册数量 */
u32 pos = 0;
while (pos < size && li < LINUXAPP_MAX && g_app_count < MAX_APPS) {
/* 取一行 */
u32 eol = pos;
while (eol < size && data[eol] != '\n' && data[eol] != '\r') eol++;
u32 line_len = eol - pos;
/* 跳过到下一行 */
u32 next = eol;
while (next < size && (data[next] == '\n' || data[next] == '\r')) next++;
if (line_len == 0 || data[pos] == '#') { pos = next; continue; }
/* 按 '|' 切 4 段:NAME|DISPLAY|PATH|ARGS */
const char *line = (const char *)data + pos;
int f0 = -1, f1 = -1, f2 = -1; /* 三个分隔符位置 */
for (u32 i = 0; i < line_len; i++) {
if (line[i] == '|') {
if (f0 < 0) f0 = (int)i;
else if (f1 < 0) f1 = (int)i;
else if (f2 < 0) { f2 = (int)i; break; }
}
}
if (f0 > 0 && f1 > f0) {
int path_beg = f1 + 1;
int path_end = (f2 > path_beg) ? f2 : (int)line_len;
int args_beg = (f2 > path_beg) ? f2 + 1 : (int)line_len;
lapp_field_copy(g_lapp_name[li], 12, line, f0);
lapp_field_copy(g_lapp_disp[li], 16, line + f0 + 1, f1 - f0 - 1);
lapp_field_copy(g_lapp_path[li], 96, line + path_beg, path_end - path_beg);
if (args_beg < (int)line_len)
lapp_field_copy(g_lapp_args[li], 96, line + args_beg, (int)line_len - args_beg);
else
g_lapp_args[li][0] = 0;
if (g_lapp_path[li][0] == '/') {
g_apps[g_app_count] = (app_descriptor){
g_lapp_name[li], g_lapp_disp[li], 1024, 768,
0, 0, 0, 0, 0,
g_lapp_path[li], g_lapp_args[li]
};
/* 记录 VSCode app id(IDE attach 共享启动路径用)。
* P7.4 匹配收紧:精确匹配 "VSCODE"(第 7 字符须为 NUL),
* VSCODE2 等多实例条目不占用共享启动入口。 */
if (g_vscode_app_id < 0 &&
g_lapp_name[li][0] == 'V' && g_lapp_name[li][1] == 'S' &&
g_lapp_name[li][2] == 'C' && g_lapp_name[li][3] == 'O' &&
g_lapp_name[li][4] == 'D' && g_lapp_name[li][5] == 'E' &&
g_lapp_name[li][6] == 0)
g_vscode_app_id = g_app_count;
g_app_count++;
li++;
}
}
pos = next;
}
}
/* ---- P5d: PEAPPS.CNF Windows PE 应用注册表 ----
* FAT32 根目录 PEAPPS.CNF(8.3: PEAPPS CNF),每行一个 Windows PE 应用:
* NAME|DISPLAY|path/file.exe|args('/' 分隔长路径,args 可含空格可省略)
* '#' 开头为注释。解析结果存静态池,app_descriptor.pe_file 指入。
* 仅适用于 GUI PE(消息循环驱动 pump);纯控制台 PE 不会触发消息空转,
* 窗口模式下桌面将无响应直到进程退出——控制台程序请走 CMD。 */
#define PEAPP_MAX 4
static char g_papp_name[PEAPP_MAX][12];
static char g_papp_disp[PEAPP_MAX][16];
static char g_papp_file[PEAPP_MAX][96];
static char g_papp_args[PEAPP_MAX][96];
static void register_pe_apps(void) {
u8 *data = 0;
u32 size = 0;
char n11[11];
if (f32_name_to_83_w("PEAPPS.CNF", n11) != 0) return;
if (f32_read_root_file_w(n11, &data, &size) != 0) return; /* 无配置文件:跳过 */
int pi = 0;
u32 pos = 0;
while (pos < size && pi < PEAPP_MAX && g_app_count < MAX_APPS) {
u32 eol = pos;
while (eol < size && data[eol] != '\n' && data[eol] != '\r') eol++;
u32 line_len = eol - pos;
u32 next = eol;
while (next < size && (data[next] == '\n' || data[next] == '\r')) next++;
if (line_len == 0 || data[pos] == '#') { pos = next; continue; }
/* 按 '|' 切 4 段:NAME|DISPLAY|FILE|ARGS */
const char *line = (const char *)data + pos;
int f0 = -1, f1 = -1, f2 = -1;
for (u32 i = 0; i < line_len; i++) {
if (line[i] == '|') {
if (f0 < 0) f0 = (int)i;
else if (f1 < 0) f1 = (int)i;
else if (f2 < 0) { f2 = (int)i; break; }
}
}
if (f0 > 0 && f1 > f0) {
int file_beg = f1 + 1;
int file_end = (f2 > file_beg) ? f2 : (int)line_len;
int args_beg = (f2 > file_beg) ? f2 + 1 : (int)line_len;
lapp_field_copy(g_papp_name[pi], 12, line, f0);
lapp_field_copy(g_papp_disp[pi], 16, line + f0 + 1, f1 - f0 - 1);
lapp_field_copy(g_papp_file[pi], 96, line + file_beg, file_end - file_beg);
if (args_beg < (int)line_len)
lapp_field_copy(g_papp_args[pi], 96, line + args_beg, (int)line_len - args_beg);
else
g_papp_args[pi][0] = 0;
if (g_papp_file[pi][0]) {
g_apps[g_app_count] = (app_descriptor){
g_papp_name[pi], g_papp_disp[pi], 720, 540,
0, 0, pe_win_on_draw, 0, 0, 0, 0,
g_papp_file[pi], g_papp_args[pi]
};
g_app_count++;
pi++;
}
}
pos = next;
}
}
void register_apps(void) {
/* 命令行1:shell.elf(原生命令行 + 可运行 Linux 程序)*/
g_apps[0] = (app_descriptor){
"shell", "Terminal", 720, 480,
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"
};
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
};
g_app_count++;
g_apps[3] = (app_descriptor){
"fileman", "Files", 500, 400,
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
};
g_app_count++;
g_apps[5] = (app_descriptor){
"browser", "Browser", 700, 500,
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++;
/* Settings — 系统设置(内核 FUCK 配置 + 网络 NETCONF 配置)*/
g_apps[7] = (app_descriptor){
"settings", "Settings", 760, 540,
0, 0, 0, 0, "SETTINGSELF"
};
g_app_count++;
/* VSCode Phase 5: Linux guest 应用(VSCode 等),来自 LINUXAPP.CNF */
register_linux_apps();
/* P5d: Windows PE 应用,来自 PEAPPS.CNF */
register_pe_apps();
register_user_desktop_icons();
}
/* M2: 桌面图标 = user/desktop/*.lnk 用户快捷方式(user_desktop 标记)。
* 内置应用(editor/calc/settings…)不落桌面——经任务栏/开始菜单启动。
* 布局沿用 canvas padding 24px,列宽 104px,gap 18px,左→右换行。 */
void setup_desktop_icons(void) {
int pad = KATE_ICON_PAD; /* 24 */
int x = pad;
int y = g_fluent ? (pad + 8) : (KATE_TOPBAR_H + KATE_PAGE_PAD + pad);
int max_x = (int)g_fb_w - pad; /* canvas 右缘 */
for (int i = 0; i < g_app_count; i++) {
if (g_icon_count >= MAX_ICONS) break;
if (!g_apps[i].user_desktop) continue; /* M2: 只显示 .lnk 快捷方式 */
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 = i;
g_icons[g_icon_count].x = x;
g_icons[g_icon_count].y = y;
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;
}
}