三特性: 字体分层(gen_font.py --charset + meow_font_reload_tier + font.load_full + 尺寸标记) + 全屏机制/状态栏收合(meow_ui_sys/input) + 通知#6 TF转储(CSV+10MB+开机清板载+内存表)

This commit is contained in:
MeowOS Dev committed 2026-08-30 11:46:29 +08:00
1 parent 0b4d1d3215
commit a2673d5922
18 files changed
+819 -80

No files matched your search

+191 -45
View File
@@ -791,9 +791,14 @@ static void draw_text(int x, int y, const char *s, int scale, uint32_t color)
#define MEOW_FONTS_CFG "MeowOS/fonts"
#define FONT_PRESETS_MAX 17 /* 1 默认 + ≤16 卡内字体(防爆) */
static const char *font_presets[FONT_PRESETS_MAX]; /* SC_PRESET 值 = 卡根相对路径 */
static const char *font_preset_labels[FONT_PRESETS_MAX]; /* SC_PRESET 中文标签 */
static const char *font_preset_labels[FONT_PRESETS_MAX]; /* SC_PRESET 中文标签(含档位大小标记) */
/* M2.5x 字体档位:每套的 charset 档("common"/"gbk"/"full",取自 font.json,缺省 "common")
* 与 glyph_count(信息用)。供档位分层装载(meow_font_effective_paths_tiered)与设置页标注。 */
static const char *font_preset_tiers[FONT_PRESETS_MAX];
static int font_preset_glyphs[FONT_PRESETS_MAX];
static char font_preset_val_buf[FONT_PRESETS_MAX][320]; /* 值持久存储(指向上面指针数组) */
static char font_preset_label_buf[FONT_PRESETS_MAX][64]; /* 标签持久存储 */
static char font_preset_label_buf[FONT_PRESETS_MAX][80]; /* 标签持久存储 */
static char font_preset_tier_buf[FONT_PRESETS_MAX][8]; /* charset 持久存储 */
static int font_presets_n = 0; /* 运行时动态计数(默认=1,仅"默认字体") */
static int mfont_ready = 0;
static int mfont_forced = 0; /* font.file 变更→强制真实(un)load,跳过 SDK 复用捷径 */
@@ -821,6 +826,11 @@ static int meow_font_resolve_path(const char *ref, char *out, int olen)
return 0;
}
/* 前向声明:meow_font_ensure 在下方 font 区中调用(定义在 meow_font_effective_paths_tiered 处)。 */
static int meow_font_effective_tier(int app_tier);
static int meow_font_effective_paths_tiered(int tier, char *out_png, int plen,
char *out_idx, int ilen, char *out_family, int flen);
/* 解析 font.file 指向的 png + 派生同目录 idx(font.png → font.idx)。
* 仅当指向的 png 存在(access R_OK)返回 0;否则 -1(交由回退链)。
* 返回 0:out_png/out_idx 已填设备绝对路径。 */
@@ -838,22 +848,25 @@ static int meow_font_resolve_selected(char *out_png, int png_len, char *out_idx,
return 0;
}
/* 尝试加载字库;成功返回 1。优先级(M2.5x):
* 1) font.file(设置键,真正接管加载;相对路径按卡根解析)→ 存在且能 load 即用;
/* 尝试加载字库;成功返回 1。优先级(M2.5x,font.load_full 已接入):
* 0) 生效档 = font.load_full ? gbk : common(launcher 自身 UI 跟随系统大字库开关);
* 1) 生效字体(tier 解析,tier0 即 font.file 所选;相对路径按卡根解析);
* 2) 卡 MeowOS/fonts/default/font.png(默认字库);
* 3) 固件 /usr/share/meowos/font/font.png。
* A-1/A-2:SDK meow_ui_init() 已用同一 meow_font.o 加载过(可能成功也可能未成功)。
* 当 font.file 指向「默认卡字库」或未设置时复用 SDK 已加载状态,避免重复 unload+reload;
* 当 font.file 指向自定义字库时必须显式 load(SDK 只加载默认,不读 font.file)。
* mfont_forced=1(font.file 变更触发)时无条件真实 reload,跳过上述两条捷径。
* 当字体指向「默认卡字库」或未设置时复用 SDK 已加载状态,避免重复 unload+reload;
* 当字体指向自定义字库时必须显式 load(SDK 只加载默认,不读 font.file)。
* mfont_forced=1(font.file/font.load_full 变更触发)时无条件真实 reload,跳过上述捷径。
* 全失败 → mfont_ready=0,ui_draw 回退 5x7 点阵(系统不死)。 */
static int meow_font_ensure(void)
{
if (mfont_ready && !mfont_forced) return 1;
mfont_forced = 0;
char fpng[320], fidx[320];
int have_sel = (meow_font_resolve_selected(fpng, sizeof fpng, fidx, sizeof fidx) == 0);
char fpng[400], fidx[400], fam[96];
int tier = meow_font_effective_tier(MEOW_FONT_TIER_COMMON); /* launcher 自身 UI 跟随 load_full */
int have_sel = (meow_font_effective_paths_tiered(tier, fpng, sizeof fpng,
fidx, sizeof fidx, fam, sizeof fam) == 0);
/* SDK 已加载且所选字库为「默认卡字库」(或未设置)→ 复用,避免重复解码。 */
if (meow_gfx_mfont_ready() && (!have_sel || !strcmp(fpng, UI_FONT_PNG_CARD))) {
@@ -862,15 +875,15 @@ static int meow_font_ensure(void)
return 1;
}
/* font.file 优先。 */
/* 生效字体优先(tier=common 时即 font.file;load_full → 大字库 gbk 档)。 */
if (have_sel && meow_font_load(fpng, fidx) == 0) {
mfont_ready = 1;
logmsg("meow_font: loaded font.file %s (%d/%d sizes)",
fpng, meow_font_has_size(28), meow_font_has_size(20));
logmsg("meow_font: loaded %s (%d/%d sizes), tier=%d", fpng,
meow_font_has_size(28), meow_font_has_size(20), tier);
return 1;
}
if (have_sel)
logmsg("meow_font: font.file %s load failed, fallback", fpng);
logmsg("meow_font: %s load failed, fallback", fpng);
/* 卡默认 → 固件。 */
if (meow_font_load(UI_FONT_PNG_CARD, UI_FONT_IDX_CARD) == 0 ||
meow_font_load(UI_FONT_PNG_SYS, UI_FONT_IDX_SYS) == 0) {
@@ -915,17 +928,79 @@ static int meow_font_effective_paths(char *out_png, int plen, char *out_idx, int
return -1;
}
/* 【tier 选择入口,font 域占位】按字体档位取「当前生效字体」png/idx,供 launch_app 注入
* MEOW_FONT_PNG/IDX/APP(配合 MEOW_FONT_TIER)。基座只实现 tier=COMMON(=meow_font_effective_paths);
* tier>0 的大字库(GBK/Full)绝对路径由后续 font 代理据此演进填充(约定 MeowOS/fonts/<family>/
* <tier>/…,或 settings 键 font.tier_gbk / font.tier_full —— 见 MEOW_APP_SDK.md 字体分层)。
* 未实现前暂回退全局字体。返回 0 成功,-1 无可用。 */
/* 档位 → font.json charset 字符串名(common/gbk/full)。 */
static const char *font_tier_charset(int tier)
{
if (tier >= MEOW_FONT_TIER_FULL) return "full";
if (tier >= MEOW_FONT_TIER_GBK) return "gbk";
return "common";
}
/* 生效档:app 声明档(0/1/2,越界 clamp)合并「加载大字库」开关(font.load_full)。
* 开 → 强制 ≥GBK(gbk≈20k 档大字库);关(默认)→ 保持 app 声明(缺省 common≈4k)。
* 断言:0<=返回<=2。 */
static int meow_font_effective_tier(int app_tier)
{
if (app_tier < MEOW_FONT_TIER_COMMON) app_tier = MEOW_FONT_TIER_COMMON;
if (app_tier > MEOW_FONT_TIER_FULL) app_tier = MEOW_FONT_TIER_FULL;
int lf = 0;
if (meow_settings_get_bool("font.load_full", &lf) == 0 && lf)
if (app_tier < MEOW_FONT_TIER_GBK) app_tier = MEOW_FONT_TIER_GBK;
return app_tier;
}
/* 【tier 选择入口,M2.5x 已实现】按字体档位取「当前生效字体」png/idx,供 launch_app 注入
* MEOW_FONT_PNG/IDX/APP(配合 MEOW_FONT_TIER)。口径(MEOWOS_SPEC_REF §5.2/§5.7.8):
* - 生效档 = max(app 声明档, font.load_full ? GBK : COMMON):系统「加载大字库」开 →
* 强制 ≥gbk;
* - tier<=common → 走既有 meow_font_effective_paths(font.file/卡默认/固件);
* - tier>0 → 在已扫描的 MeowOS/fonts/<family>/ 里找 charset 匹配(gbk 请求接受 gbk/full;
* full 请求接受 full)的那套,以其 font.png/idx 绝对路径返回(family = 目录名);
* - 找不到匹配的大字库 → 回退 meow_font_effective_paths(避免 app 直接点到固件小库)。
* 返回 0 成功(out_png/out_idx/out_family 已填),-1 无可用。 */
static int meow_font_effective_paths_tiered(int tier, char *out_png, int plen,
char *out_idx, int ilen, char *out_family, int flen)
{
if (tier == MEOW_FONT_TIER_COMMON || tier < MEOW_FONT_TIER_COMMON)
int eff = meow_font_effective_tier(tier); /* 合并 font.load_full:开 → 强制 ≥GBK */
if (eff <= MEOW_FONT_TIER_COMMON)
return meow_font_effective_paths(out_png, plen, out_idx, ilen, out_family, flen);
/* TODO(font 代理):按 tier 解析大字库绝对路径(GBK/Full);暂回退全局(tier0)。 */
/* 大字库:从扫描结果选 charset 匹配的一套。
* 打分(高优先):gbk 请求 → gbk=2 > full=1;full 请求 → full=2 > gbk=1(降级可接受)。 */
const char *want = font_tier_charset(eff);
char ref[320];
int found_family = -1, best_score = 0;
for (int i = 0; i < font_presets_n; i++) {
const char *cs = font_preset_tiers[i] ? font_preset_tiers[i] : "common";
int score = 0;
if (!strcmp(cs, want)) score = 2;
else if (!strcmp(cs, "full") || !strcmp(cs, "gbk")) score = 1; /* 降级 */
if (score > best_score) { best_score = score; found_family = i; }
}
if (found_family >= 0)
snprintf(ref, sizeof ref, "%s", font_presets[found_family]);
if (found_family >= 0) {
/* 相对路径按卡根解析为设备绝对路径(与 meow_font_effective_paths 同源)。 */
if (meow_font_resolve_path(ref, out_png, plen) != 0) return -1;
if (access(out_png, R_OK) != 0) goto fallback;
snprintf(out_idx, ilen, "%s", out_png);
size_t n = strlen(out_idx);
if (n > 4 && !strcmp(out_idx + n - 4, ".png")) {
out_idx[n-4] = '.'; out_idx[n-3] = 'i'; out_idx[n-2] = 'd';
out_idx[n-1] = 'x'; out_idx[n] = 0;
}
const char *prefix = "/MeowOS/fonts/";
const char *p = strstr(out_png, prefix);
if (p) {
const char *q = p + strlen(prefix);
const char *end = strrchr(q, '/');
int rest = end ? (int)(end - q) : 0;
if (rest > 0 && rest < flen) { memcpy(out_family, q, rest); out_family[rest] = 0; }
else snprintf(out_family, flen, "default");
} else snprintf(out_family, flen, "default");
return 0;
}
fallback:
/* 无匹配大字库/不可读 → 回退全局(font.file 所选;其可能是大字库或默认)。 */
return meow_font_effective_paths(out_png, plen, out_idx, ilen, out_family, flen);
}
@@ -942,7 +1017,10 @@ static void meow_font_reload_multifont(void)
int on = 0;
meow_settings_get_bool("display.multi_font", &on);
char gpng[400], gidx[400], gfam[96];
if (meow_font_effective_paths(gpng, sizeof gpng, gidx, sizeof gidx, gfam, sizeof gfam) != 0)
/* 全局跟生效档(合并 font.load_full → 大字库),与 meow_font_ensure 同源,避免槽0实际装载与
* 此处理解不一致(多字体去重以全局 png 为基准)。 */
if (meow_font_effective_paths_tiered(meow_font_effective_tier(MEOW_FONT_TIER_COMMON),
gpng, sizeof gpng, gidx, sizeof gidx, gfam, sizeof gfam) != 0)
return; /* 无全局字体:无法多字体 */
/* 各类候选(静态缓冲保活;config_multifont 同步读取,不持指针) */
static char cpng[MEOW_FCLS_COUNT][400], cidx[MEOW_FCLS_COUNT][400];
@@ -1666,9 +1744,12 @@ static int font_sha_eq(const char *a, const char *b)
/* 解析 font.json:提取 name / sha256_png / sha256_idx(文件缺失或解析不出则留空)。 */
static void meow_font_json_probe(const char *json_path, char *name, int nlen,
char *sha_png, int slen, char *sha_idx, int xlen)
char *sha_png, int slen, char *sha_idx, int xlen,
char *charset, int clen, int *glyph_count)
{
name[0] = 0; sha_png[0] = 0; sha_idx[0] = 0;
if (charset) charset[0] = 0;
if (glyph_count) *glyph_count = 0;
FILE *f = fopen(json_path, "r");
if (!f) return;
char buf[256];
@@ -1676,14 +1757,39 @@ static void meow_font_json_probe(const char *json_path, char *name, int nlen,
if (!name[0]) json_str(buf, "name", name, nlen);
if (!sha_png[0]) json_str(buf, "sha256_png", sha_png, slen);
if (!sha_idx[0]) json_str(buf, "sha256_idx", sha_idx, xlen);
/* M2.5x 字体档位:charset(common|gbk|full)+ glyph_count(信息用,驱动档位分层/标注)。 */
if (charset && !charset[0]) {
char v[8] = "";
if (json_str(buf, "charset", v, sizeof v) > 0 && v[0])
snprintf(charset, clen, "%s", v);
}
if (glyph_count && *glyph_count == 0) {
char v[16] = "";
if (json_str(buf, "glyph_count", v, sizeof v) > 0 && v[0])
*glyph_count = atoi(v);
}
}
fclose(f);
}
/* 探测一个 <dirpath>/<family> 套件是否合法:三件套齐全 → 解析 label + 校验 sha。
* 返回 1=进列表,0=跳过(缺组件/json 不可读)。sha 失败仅 WARN。 */
/* 档位大小标记(设置页字体选项标注):common≈4k / gbk≈20k / full。
* 由 font.json 的 charset + glyph_count 派生;缺 charset 回退 common。 */
static void font_tier_marker(const char *charset, int glyph_count, char *out, int olen)
{
const char *tier = (charset && charset[0]) ? charset : "common";
if (!strcmp(tier, "full")) { snprintf(out, olen, "full"); return; }
if (glyph_count > 0)
snprintf(out, olen, "%s≈%dk", tier, (glyph_count + 500) / 1000);
else
snprintf(out, olen, "%s", tier);
}
/* 探测一个 <dirpath>/<family> 套件是否合法:三件套齐全 → 解析 label + 档位 + 校验 sha。
* 返回 1=进列表,0=跳过(缺组件/json 不可读)。sha 失败仅 WARN。
* 输出:label=显示名+大小标记 `名字(common≈4k)`;charset/glyph_count=档位信息。 */
static int meow_font_probe_family(const char *dirpath, const char *family,
char *label, int llen)
char *label, int llen,
char *charset, int clen, int *glyph_count)
{
char ppath[400], ipath[400], jpath[400];
snprintf(ppath, sizeof ppath, "%s/font.png", dirpath);
@@ -1694,9 +1800,15 @@ static int meow_font_probe_family(const char *dirpath, const char *family,
return 0;
}
char name[64] = "", jsha_png[80] = "", jsha_idx[80] = "";
char cs[8] = ""; int gc = 0;
meow_font_json_probe(jpath, name, sizeof name, jsha_png, sizeof jsha_png,
jsha_idx, sizeof jsha_idx);
snprintf(label, llen, "%s", name[0] ? name : family); /* 显示名:name 或回退目录名 */
jsha_idx, sizeof jsha_idx, cs, sizeof cs, &gc);
/* 显示名 = 名 + 档位大小标记(如 `default(common≈4k)` / `gbk≈20k` / `full`) */
char marker[24];
font_tier_marker(cs, gc, marker, sizeof marker);
snprintf(label, llen, "%s(%s)", name[0] ? name : family, marker);
if (charset) snprintf(charset, clen, "%s", cs[0] ? cs : "common");
if (glyph_count) *glyph_count = gc;
/* 完整性校验:仅 WARN,不硬失败;该套仍标记可选。 */
char apng[80] = "", aidx[80] = "";
if (font_sha256_file(ppath, apng, sizeof apng) != 0)
@@ -1707,7 +1819,7 @@ static int meow_font_probe_family(const char *dirpath, const char *family,
logmsg("fonts: '%s' sha256(idx) 不可用,跳过校验", family);
else if (jsha_idx[0] && !font_sha_eq(aidx, jsha_idx))
logmsg("fonts: '%s' WARN sha256_idx 不匹配(仍可选)", family);
logmsg("fonts: add '%s' (%s)", label, family);
logmsg("fonts: add '%s' (%s) charset=%s glyph_count=%d", label, family, cs[0]?cs:"common", gc);
return 1;
}
@@ -1717,7 +1829,20 @@ static void meow_font_scan_presets_root(const char *card_root)
{
font_presets_n = 0;
font_presets[0] = "MeowOS/fonts/default/font.png"; /* 默认字库 = MeowOS/fonts/default */
font_preset_labels[0] = "默认字体";
font_preset_labels[0] = font_preset_label_buf[0]; /* 指向缓冲(运行时派生含大小标记) */
/* 默认套也读 font.json 档位(存在则跟真实档,缺则 common);档位信息供分层装载/标注。 */
{
char jp[400], cs[8] = ""; int gc = 0;
char nm0[64] = "", sp0[80] = "", si0[80] = "";
snprintf(jp, sizeof jp, "%s/%s/default/font.json", card_root, MEOW_FONTS_CFG);
meow_font_json_probe(jp, nm0, sizeof nm0, sp0, sizeof sp0, si0, sizeof si0,
cs, sizeof cs, &gc);
char mk[24]; font_tier_marker(cs, gc, mk, sizeof mk);
snprintf(font_preset_label_buf[0], sizeof font_preset_label_buf[0], "默认字体(%s)", mk);
snprintf(font_preset_tier_buf[0], sizeof font_preset_tier_buf[0], "%s", cs[0]?cs:"common");
font_preset_tiers[0] = font_preset_tier_buf[0];
font_preset_glyphs[0] = gc;
}
font_presets_n = 1;
char root[340];
snprintf(root, sizeof root, "%s/%s", card_root, MEOW_FONTS_CFG);
@@ -1726,16 +1851,20 @@ static void meow_font_scan_presets_root(const char *card_root)
struct dirent *de;
while ((de = readdir(d)) && font_presets_n < FONT_PRESETS_MAX) {
if (de->d_name[0] == '.') continue;
char dirpath[400], label[64];
char dirpath[400], label[80], cs[8] = ""; int gc = 0;
snprintf(dirpath, sizeof dirpath, "%s/%s", root, de->d_name);
if (meow_font_probe_family(dirpath, de->d_name, label, sizeof label) == 0)
if (meow_font_probe_family(dirpath, de->d_name, label, sizeof label,
cs, sizeof cs, &gc) == 0)
continue; /* 缺组件/损坏 → 跳过该套 */
int i = font_presets_n;
snprintf(font_preset_val_buf[i], sizeof font_preset_val_buf[i],
"%s/%s/font.png", MEOW_FONTS_CFG, de->d_name);
snprintf(font_preset_label_buf[i], sizeof font_preset_label_buf[i], "%s", label);
snprintf(font_preset_tier_buf[i], sizeof font_preset_tier_buf[i], "%s", cs[0]?cs:"common");
font_presets[i] = font_preset_val_buf[i];
font_preset_labels[i] = font_preset_label_buf[i];
font_preset_tiers[i] = font_preset_tier_buf[i];
font_preset_glyphs[i] = gc;
font_presets_n++;
}
closedir(d);
@@ -2321,17 +2450,14 @@ static void settings_sync_cache_listener(const char *key)
else if (!strcmp(key, "power.forceoff_ms")) { int v; if (meow_settings_get_int("power.forceoff_ms", &v) == 0) power_forceoff_ms = v; }
}
/* ---- 通知 dump 回调占位(通知#6 转储 TF 卡;接线/占位,不做 TF 写)----
/* ---- 通知 dump 回调(通知#6 转储 TF 卡;做成真)----
* meow_notif 在 TTL 到点(meow_notif_tick,§8 10s)调用此回调归档一条通知,随后释放槽。
* 基座只把回调挂上来(见 settings_load 的 meow_notif_set_dump_cb);真实 TF 落盘
* (按 NOTIFICATION_SYSTEM.md §8 / TF_CARD_LAYOUT.md 写 <卡>/MeowOS/notify/...)由后续
* 通知代理在回调体内实现。注意 meow_notif.c 的 archive_one 自身已 log 一行 "dump: ...",
* 故本回调保持轻量(避免重复刷屏),落盘逻辑填在下方 TODO 处。 */
* 本回调把 meow_notif 结构体转成一行 CSV 追加写入 <卡>/MeowOS/notifications/notifications.log
* (含 mkdir -p 与按总大小滚动截断、保留最新 10MB),落盘实现在 meow_notif.c 的
* meow_notif_dump_tf()。无卡/不可写仅打点降级(NOTIFICATION_SYSTEM.md §5/§8 + MEWSPEC §5.3)。 */
static void notif_dump_tf_placeholder(const meow_notif_t *n)
{
(void)n;
/* TODO(通知代理, M2c):在此写 TF 卡 <MeowOS>/notify/<date>/<id>.json 等;
* 基座不实现,仅保留挂接点(触发时机=meow_notif_tick 内 10s 到点/止机转储)。 */
meow_notif_dump_tf(n);
}
/* 启动加载(M2.11/M2.24):统一由 meow_settings 后端读 settings.conf;
@@ -2342,7 +2468,7 @@ static void settings_load(void)
{
meow_settings_init(); /* 幂等:注册默认 + 读 settings.conf */
meow_notif_init(); /* M2a:通知存储初始化(幂等,读 notify.* 配额) */
meow_notif_set_dump_cb(notif_dump_tf_placeholder); /* 基座(通知#6):挂 dump 回调(TF 转储占位,M2c 落盘由后续代理实现) */
meow_notif_set_dump_cb(notif_dump_tf_placeholder); /* 通知#6:挂 dump 回调 = TF 转储(meow_notif_dump_tf:一行 CSV 追加 + 10MB 滚动截断) */
if (!settings_cache_registered) {
meow_settings_add_listener(settings_sync_cache_listener);
settings_cache_registered = 1;
@@ -4483,6 +4609,10 @@ static const srow_t SMENU[] = {
/* 字体主题 */
{ "字体主题", NULL, SC_HEADER, 0,0,0, NULL,NULL,0 },
{ "字体文件", "font.file", SC_PRESET, 0,0,0, font_presets, font_preset_labels, 0 },
/* M2.5x 字体档位分层/按需大字库:「加载大字库」= font.load_full(int 0/1 默认 0)。
* 开 → 强制全系统用大字库 gbk≈20k 档(覆盖 app 未声明/覆盖默认 font.file);
* 关(默认)→ 小字库 common≈4k,仅 app 声明 fonts:"full" 才大字库。 */
{ "加载大字库", "font.load_full", SC_SWITCH, 0,0,0, NULL,NULL,0 },
/* M2.5x 多字体:开关 + 6 个字符类别字体(preset=可用 MeowOS/fonts/<family>/ 列表;
* 值空 = 跟随全局 font.file)。仅开关开启时 6 行可见(s_row_visible)。 */
{ "多字体", "display.multi_font", SC_SWITCH, 0,0,0, NULL,NULL,0 },
@@ -5433,6 +5563,20 @@ static void s_commit(const srow_t *r, int save_now)
meow_font_reload_multifont(); /* M2.5x:全局字体变更 → 重配多字体(各类跟随全局者随之更新) */
meow_dirty_full(); /* 字体变化可能影响所有文本渲染,整帧重绘 */
}
/* M2.5x「加载大字库」开关(font.load_full)变更 → 强制重载 launcher 自身字体(小/大字库切换),
* 并重配多字体;大字库 atlas 大,meow_font_ensure 先 unload 旧再 load 新(防双驻留)。 */
else if (!strcmp(r->key, "font.load_full")) {
mfont_ready = 0;
mfont_forced = 1; /* 跳过 SDK 复用捷径,强制按生效档(gbk/common)真实 reload */
if (!meow_font_ensure())
logmsg("font.load_full: reload failed -> dotmatrix fallback");
else {
int lf = 0; meow_settings_get_bool("font.load_full", &lf);
logmsg("font.load_full: reloaded (load_full=%d)", lf);
}
meow_font_reload_multifont();
meow_dirty_full();
}
/* M2.5x 多字体:开关或任一类别字体变更 → 重新去重装载类别字库并重绘(多字体可能影响文本渲染)。 */
else if (!strcmp(r->key, "display.multi_font") || !strncmp(r->key, "font.class_", 11)) {
meow_font_reload_multifont();
@@ -6846,12 +6990,14 @@ static int launch_app(struct app *a)
meow_settings_get_bool("display.multi_font", &mf_on);
snprintf(env_mf, sizeof env_mf, "MEOW_MULTI_FONT=%d", mf_on ? 1 : 0);
envp[ne++] = env_mf;
/* M2.x(基座):字库档 MEOW_FONT_TIER=<0|1|2> —— 按 app.json "fonts" 声明注入;
* 0=默认4K常用(未声明/缺省),1=大字库GBK,2=Full。SDK meow_ui_gfx 读入存档,
* 真正按档装载大字库由后续 font 代理实现(见 meow_font_effective_paths_tiered)。 */
snprintf(env_tier, sizeof env_tier, "MEOW_FONT_TIER=%d", a->fonts);
/* M2.5x:字库档 MEOW_FONT_TIER=<0|1|2> —— 按 app.json "fonts" 声明注入,并合并
* 「加载大字库」开关(font.load_full → 强制 ≥GBK)得**生效档**;0=默认4K常用,
* 1=大字库GBK,2=Full。SDK meow_ui_gfx 读入存档并按档装载(见
* meow_font_effective_paths_tiered;真正装载由 meow_font_reload_tier 实现)。 */
int eff_tier = meow_font_effective_tier(a->fonts);
snprintf(env_tier, sizeof env_tier, "MEOW_FONT_TIER=%d", eff_tier);
envp[ne++] = env_tier;
have_global = (meow_font_effective_paths_tiered(a->fonts, fpng, sizeof fpng,
have_global = (meow_font_effective_paths_tiered(eff_tier, fpng, sizeof fpng,
fidx, sizeof fidx, fam, sizeof fam) == 0);
if (have_global) {
snprintf(env_fpng, sizeof env_fpng, "MEOW_FONT_PNG=%s", fpng);