diff --git a/patch_v2/hello_app/hello b/patch_v2/hello_app/hello index f83ff87..d770cf4 100755 Binary files a/patch_v2/hello_app/hello and b/patch_v2/hello_app/hello differ diff --git a/patch_v2/hello_app/hello.c b/patch_v2/hello_app/hello.c index 5178d91..396fd7e 100644 --- a/patch_v2/hello_app/hello.c +++ b/patch_v2/hello_app/hello.c @@ -3,12 +3,15 @@ * 契约(MEOW_APP_SDK.md §1/§3/§6):应用只调 meow_ui API —— 屏幕(back_buf + * flush 上屏)与输入(meow_ui_run 事件循环)由框架接管;不再 open/mmap/ioctl * /dev/fb0、不再读 /dev/input/event*。本应用验证「清屏 + 画文本 + 画按钮 + - * 响应触摸」这一最小工作闭环。 + * 响应触摸」这一最小工作闭环,并集成了通知触发按钮(meow_notify_send,§9.1) + * 用于端到端测试通知链路(SDK → IPC → launcher 中央存储 → 10s TTL 落盘)。 * * 交互: * - 点按钮 → tap 计数 +1(按钮标签实时更新); + * - 通知触发行(6 个按钮):每个点击 meow_notify_send() 发一条不同参数的通知, + * 覆盖 普通INFO / 媒体(单例) / HIGH紧急度 / 进度(40%) / 常驻 / 跳转Activity; + * - CANCEL LAST 按钮:meow_notify_cancel(最近一次 send 的 id); * - 左缘左滑(抬手触发)→ 请求退出(回应用列表);滑动过程顶部出现随位移增长的进度条; - * - 物理键 POWER 不再映射 exit(§3.4.1:物理键系统统一管理,电源键=纯息屏/亮屏); * - 空闲时 on_tick 每秒刷新一行状态(含运行秒数)。 * * 宿主/qemu 离屏:设 MEOW_UI_DUMP= 时,首帧 flush 即把 back_buf 写成 @@ -26,6 +29,12 @@ #include static meow_widget *g_btn; +static meow_widget *g_nbtn[6]; /* 通知触发按钮行 */ +static meow_widget *g_cancel; /* 取消最近一条通知 */ +static meow_widget *g_fs_btn; /* FULLSCREEN 进入按钮(主界面) */ +static int g_fullscreen = 0; /* 1=处于全屏视图(点任意处退出回主界面) */ +static const char *g_notif_labels[6] = { "INFO", "MEDIA", "HIGH", "PROG", "ONGO", "TGT" }; +static uint32_t g_last_notif = 0; /* 最近一次 send 返回的 id,供 cancel */ static int g_taps = 0; static int g_secs = 0; static char g_btn_label[32] = "TAP ME"; @@ -34,23 +43,152 @@ static char g_btn_label[32] = "TAP ME"; * 删除自造轮子的 hellolog()(自读 MEOW_LOG_DIR + snprintf + fopen/fprintf)。 */ static void on_sigterm(int s) { (void)s; meow_ui_request_exit(); } +/* 通知触发:对应第 which 个按钮(0..5)。SDK 端 meow_notify_send() 自动注册未声明 + * 类型(本应用用到 4 种:GENERAL / MEDIA / PROGRESS / MESSAGE,均在 4 种上限内), + * 超时语义见 meow_ui.h §9.1;媒体类型为单例(重发替换)。 */ +static void notif_send(int which) +{ + meow_notify n; + memset(&n, 0, sizeof n); + n.progress = -1; /* 缺省不显示进度条 */ + n.timeout_ms = MEOW_NOTIFY_TIMEOUT_NEVER; + n.urgency = MEOW_NOTIFY_URG_NORMAL; + const char *label = "?"; + + switch (which) { + case 0: /* 普通 INFO */ + label = "INFO"; + n.cat = MEOW_NOTIFY_CAT_GENERAL; + n.title = "测试-普通通知"; + n.body = "普通 INFO 通知,timeout=5000ms"; + n.timeout_ms = 5000; + break; + case 1: /* 媒体单例(ongoing,不自动过期) */ + label = "MEDIA"; + n.cat = MEOW_NOTIFY_CAT_MEDIA; + n.urgency = MEOW_NOTIFY_URG_LOW; + n.title = "测试-媒体通知"; + n.body = "媒体单例,正在播放,timeout=-1 常驻"; + n.timeout_ms = MEOW_NOTIFY_TIMEOUT_ONGOING; + break; + case 2: /* HIGH 紧急度 */ + label = "HIGH"; + n.cat = MEOW_NOTIFY_CAT_GENERAL; + n.urgency = MEOW_NOTIFY_URG_HIGH; + n.title = "测试-紧急度HIGH"; + n.body = "高紧急度:顶部横幅+提示音"; + n.timeout_ms = 3000; + break; + case 3: /* 进度通知 */ + label = "PROG"; + n.cat = MEOW_NOTIFY_CAT_PROGRESS; + n.title = "测试-进度通知"; + n.body = "下载进度 40%"; + n.timeout_ms = 8000; + n.progress = 40; + break; + case 4: /* 常驻(timeout=-1,不自动过期,需手动取消) */ + label = "ONGO"; + n.cat = MEOW_NOTIFY_CAT_GENERAL; + n.title = "测试-常驻通知"; + n.body = "常驻不自动过期(timeout=-1),需手动取消"; + n.timeout_ms = MEOW_NOTIFY_TIMEOUT_ONGOING; + break; + case 5: /* 带 target_activity(SDK 结构暂无 icon 字段,故只填跳转目标) */ + label = "TGT"; + n.cat = MEOW_NOTIFY_CAT_MESSAGE; + n.title = "测试-跳转Activity"; + n.body = "点击跳转 target_activity=main"; + n.timeout_ms = 6000; + n.target_activity = "main"; + break; + default: + return; + } + + uint32_t id = meow_notify_send(&n); + g_last_notif = id; + meow_log(MEOW_LOG_INFO, + "notify btn=%s id=%u cat=%s urg=%s tmo=%d prog=%d target=%s title=%s", + label, (unsigned)id, meow_notify_category_str(n.cat), + meow_notify_urgency_str(n.urgency), n.timeout_ms, n.progress, + n.target_activity ? n.target_activity : "-", + n.title ? n.title : "-"); +} + +static void notif_cancel(void) +{ + int r = meow_notify_cancel(g_last_notif); + meow_log(MEOW_LOG_INFO, "notify cancel id=%u result=%d", (unsigned)g_last_notif, r); + g_last_notif = 0; +} + +/* 进入/退出全屏视图(MeowOS 全屏机制,§3.1): + * - fullscreen(1) + collapsed(1):状态栏「上收出屏只留提示线」(不完全沉浸,inset=4px), + * 顶部提示线热区仍可下拉,左缘返回手势(app 已注册 on_swipe)仍生效——SDK 自动处理,非 app 拦截; + * - fullscreen(0) + collapsed(0):恢复整条状态栏主界面。 + * SDK 基座默认瞬切(g_sbar_collapse_anim_ms=0);如需过渡动画可先 meow_ui_statusbar_animate(ms)。 */ +static void set_fullscreen(int on) +{ + g_fullscreen = on ? 1 : 0; + meow_ui_set_fullscreen(g_fullscreen); + meow_ui_statusbar_set_collapsed(g_fullscreen); + meow_log(MEOW_LOG_INFO, g_fullscreen ? "fullscreen ON (collapsed)" : "fullscreen OFF (restore)"); +} + static void redraw(void) { const meow_theme *th = meow_theme_get(); int sb = meow_ui_statusbar_height(); /* A-0 全局状态栏 inset:内容下移避免被盖 */ + if (g_fullscreen) { + /* 全屏页:纯色占满 + 居中提示;点任意处 / 左缘左滑(SDK on_swipe)返回 */ + meow_ui_clear(th->accent); + meow_ui_text_center(240, 330, "FULLSCREEN ACTIVE", 28, 0xFFFFFF); + meow_ui_text_center(240, 366, "tap anywhere = back to home", 20, 0xFFFFFF); + meow_ui_text_center(240, 394, "(left-edge swipe also returns)", 20, 0xFFFFFF); + meow_ui_flush(); + return; + } meow_ui_clear(th->bg); meow_ui_text_center(240, sb + 8, "MEOWOS HELLO", 28, th->fg); meow_ui_text_center(240, sb + 38, "SDK: meow_ui.a", 20, th->dim); meow_widget_draw(g_btn); + meow_ui_text_center(240, 372, "tap = send notification (see log)", 20, th->dim); + for (int i = 0; i < 6; i++) meow_widget_draw(g_nbtn[i]); + meow_widget_draw(g_cancel); + meow_widget_draw(g_fs_btn); char line[64]; snprintf(line, sizeof line, "taps=%d uptime=%ds", g_taps, g_secs); - meow_ui_text_center(240, 500, line, 20, th->dim); + meow_ui_text_center(240, 516, line, 20, th->dim); meow_ui_text(20, 660, "left-swipe = exit", 20, th->dim); meow_ui_flush(); } static void on_tap(int x, int y) { + if (g_fullscreen) { + /* 全屏页:点任意处退出回主界面(左缘左滑由 SDK on_swipe 处理,见下) */ + set_fullscreen(0); + redraw(); + return; + } + for (int i = 0; i < 6; i++) { + if (meow_widget_hit(g_nbtn[i], x, y)) { + notif_send(i); + redraw(); + return; + } + } + if (meow_widget_hit(g_cancel, x, y)) { + notif_cancel(); + redraw(); + return; + } + if (meow_widget_hit(g_fs_btn, x, y)) { + set_fullscreen(1); + redraw(); + return; + } if (meow_widget_hit(g_btn, x, y)) { g_taps++; snprintf(g_btn_label, sizeof g_btn_label, "TAPPED x%d", g_taps); @@ -107,11 +245,18 @@ int main(void) signal(SIGTERM, on_sigterm); /* 看门狗返回键 → 干净退出 */ g_btn = meow_btn_create(120, 300, 240, 64, g_btn_label); + for (int i = 0; i < 6; i++) + g_nbtn[i] = meow_btn_create(3 + i * 80, 400, 74, 56, g_notif_labels[i]); + g_cancel = meow_btn_create(36, 464, 200, 42, "CANCEL LAST"); + g_fs_btn = meow_btn_create(244, 464, 200, 42, "FULLSCREEN"); redraw(); meow_ui_events ev = { on_key, on_tap, on_swipe, on_tick, on_swipe_progress }; meow_ui_run(&ev); + for (int i = 0; i < 6; i++) meow_widget_free(g_nbtn[i]); + meow_widget_free(g_cancel); + meow_widget_free(g_fs_btn); meow_widget_free(g_btn); meow_ui_shutdown(); meow_log(MEOW_LOG_INFO, "exit"); diff --git a/patch_v2/meow_launcherd/meow_launcherd b/patch_v2/meow_launcherd/meow_launcherd index 398ad75..558053b 100755 Binary files a/patch_v2/meow_launcherd/meow_launcherd and b/patch_v2/meow_launcherd/meow_launcherd differ diff --git a/patch_v2/meow_launcherd/meow_launcherd.c b/patch_v2/meow_launcherd/meow_launcherd.c index a1470c9..dbf2df7 100644 --- a/patch_v2/meow_launcherd/meow_launcherd.c +++ b/patch_v2/meow_launcherd/meow_launcherd.c @@ -944,7 +944,7 @@ 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 (meow_settings_get_switch("font.load_full", &lf) == 0 && lf) if (app_tier < MEOW_FONT_TIER_GBK) app_tier = MEOW_FONT_TIER_GBK; return app_tier; } @@ -1015,7 +1015,7 @@ static void meow_font_reload_multifont(void) "font.class_cjk", "font.class_cjk_sym", "font.class_num", "font.class_latin", "font.class_latin_sym", "font.class_other" }; int on = 0; - meow_settings_get_bool("display.multi_font", &on); + meow_settings_get_switch("display.multi_font", &on); char gpng[400], gidx[400], gfam[96]; /* 全局跟生效档(合并 font.load_full → 大字库),与 meow_font_ensure 同源,避免槽0实际装载与 * 此处理解不一致(多字体去重以全局 png 为基准)。 */ @@ -4530,6 +4530,7 @@ typedef struct { #define NET_LIST_WIFI_SCAN 3 /* 附近WiFi:WiFi 扫描结果(按 BSSID 去重,只读展示) */ #define NET_LIST_BT_NEARBY 4 /* 蓝牙附近设备(已配对 + 扫描发现;下拉,只读展示) */ #define NET_LIST_BT_MODE 5 /* 蓝牙当前连接模式(只读信息;对应"蓝牙模式"行,s_net_get 显示) */ +#define NET_LIST_ABOUT 6 /* 系统设置「关于本机」:只读设备信息弹窗(复用 s_dd_modal) */ #define S_NET_MAX 8 /* 网络下拉一次最多展示项(屏幕高度限制) */ /* SC_PRESET 预设表(路径/枚举字符串的"预设项,自定义文件选择留后期") */ @@ -4639,6 +4640,9 @@ static const srow_t SMENU[] = { { "音量上限", "audio.volume_max", SC_SLIDER, 0,100,1, NULL,NULL,0 }, { "音量跳步", "audio.volume_step", SC_SLIDER, 1,5,1, NULL,NULL,0 }, { "输出设备", "audio.output", SC_PRESET, 0,0,0, out_presets, out_preset_labels, OUT_PRESETS_N }, + /* 关于(设置列表最底;「关于本机」点开 s_about_open 弹只读设备信息框) */ + { "关于", NULL, SC_HEADER, 0,0,0, NULL,NULL,0 }, + { "关于本机", NULL, SC_LIST, 0,0,0, NULL,NULL,0, NET_LIST_ABOUT }, }; #define SMENU_N ((int)(sizeof SMENU / sizeof SMENU[0])) @@ -4673,7 +4677,7 @@ static int s_row_visible(int i) { const srow_t *r = &SMENU[i]; if (r->key && !strncmp(r->key, "font.class_", 11)) { - int on = 0; meow_settings_get_bool("display.multi_font", &on); + int on = 0; meow_settings_get_switch("display.multi_font", &on); return on; } return 1; @@ -5380,6 +5384,7 @@ static int s_net_get(const srow_t *r, char *buf, int len) case NET_LIST_WIFI_SCAN: snprintf(buf, len, "%d 个附近WiFi", g_net_scan_n); return 0; case NET_LIST_BT_NEARBY: snprintf(buf, len, "%d 台设备", g_net_bt_n); return 0; case NET_LIST_BT_MODE: snprintf(buf, len, "%s", g_bt_mode); return 0; + case NET_LIST_ABOUT: snprintf(buf, len, "MeowOS v%s", g_meowos_version); return 0; } snprintf(buf, len, "-"); return 0; @@ -5415,6 +5420,10 @@ static void s_net_sync_from_sys(void) s_net_refresh(); } +/* M2.5x 系统设置「关于本机」:复用 s_dd_modal 弹只读设备信息(定义见下,供 s_net_open 分发)。 + * 前置声明:s_net_open 在其定义之前调用它。 */ +static void s_about_open(void); + /* 打开 SC_LIST 网络下拉(重新解析最新列表):已保存=可 select_network 连接; * 附近WiFi(扫描)/蓝牙设备(附近扫描+已配对)=只读展示(选择即关闭;带密码/配对仍留后期)。 * 返回后刷新缓存。 */ @@ -5469,12 +5478,108 @@ static void s_net_open(const srow_t *r) else for (int i = 0; i < n; i++) { snprintf(back[i], sizeof back[i], "%s", items[i].name); txt[i] = back[i]; } s_dd_modal(r->label, txt, n, -1); /* 只读展示 */ break; + case NET_LIST_ABOUT: + s_about_open(); /* M2.5x 系统设置「关于本机」:只读设备信息弹窗 */ + return; /* 不上网/蓝牙缓存刷新(信息已现场读取) */ default: return; } s_net_refresh(); } +/* M2.5x 系统设置「关于本机」:复用 s_dd_modal(与「WiFi连接状态」弹窗同款)列只读设备信息, + * 点卡片外/返回即关。信息源:settings system.hostname / g_meowos_version(=/etc/meowos_version) / + * uname -r / /proc/cpuinfo / /proc/meminfo / df / wpa_cli status / hciconfig / fb 分辨率+状态栏高。 + * 只展示安全信息(不含任何密钥/凭证);实时读,短超时不阻塞主循环;行数 ≤12 适配下拉视口。 + * 说明:launcher/bootmenu/watchdog/meow_v 未单独暴露版本号,统一以 /etc/meowos_version 的 + * MeowOS 版本表示(与固件打包同源);无独立固件版本文件。 */ +static void s_about_open(void) +{ + char info[12][96]; + const char *item[12]; + int n = 0; + char host[64]; + char *o; + + /* 设备名(settings system.hostname;缺省 meowos) */ + if (meow_settings_get_str("system.hostname", host, sizeof host) != 0 || !host[0]) + snprintf(host, sizeof host, "meowos"); + snprintf(info[n++], sizeof info[0], "设备名: %s", host); + + /* MeowOS / 固件版本(/etc/meowos_version;与固件打包同源) */ + snprintf(info[n++], sizeof info[0], "MeowOS: v%s", g_meowos_version); + + /* 内核版本 */ + o = popen_read_tmo(400, "PATH=/bin:/sbin:/usr/bin:/usr/sbin uname -r 2>/dev/null"); + if (o) { for (char *p = o; *p; p++) if (*p == '\n' || *p == '\r') { *p = 0; break; } + snprintf(info[n++], sizeof info[0], "内核: %s", o[0] ? o : "-"); free(o); } + else snprintf(info[n++], sizeof info[0], "内核: -"); + + /* CPU(/proc/cpuinfo:Processor/CPU model/Hardware/system type 任取首非空行) */ + o = popen_read_tmo(500, + "PATH=/bin:/sbin:/usr/bin:/usr/sbin awk -F: '/(model name|cpu model|system type|machine|hardware)/{print $2; exit}' /proc/cpuinfo 2>/dev/null"); + if (o) { char *q = o; for (char *p = o; *p; p++) if (*p == '\n' || *p == '\r') { *p = 0; break; } + while (*q == ' ' || *q == '\t') q++; + snprintf(info[n++], sizeof info[0], "CPU: %s", q[0] ? q : "-"); free(o); } + else snprintf(info[n++], sizeof info[0], "CPU: -"); + + /* 内存(/proc/meminfo MemTotal / MemAvailable,KB→MB) */ + long mtot = 0, mavail = 0; + o = popen_read_tmo(500, "PATH=/bin:/sbin:/usr/bin:/usr/sbin awk '/^MemTotal:/{print $2}/^MemAvailable:/{print $2}' /proc/meminfo 2>/dev/null"); + if (o) { if (sscanf(o, "%ld%ld", &mtot, &mavail) < 2) mavail = 0; free(o); } + if (mtot > 0) snprintf(info[n++], sizeof info[0], "内存: %ld/%ld MB", mavail / 1024, mtot / 1024); + else snprintf(info[n++], sizeof info[0], "内存: -"); + + /* 板载 /usr/data:df -k → 可用/总量(MB) */ + long dfree = 0, dtot = 0; + o = popen_read_tmo(600, "PATH=/bin:/sbin:/usr/bin:/usr/sbin df -k /usr/data 2>/dev/null | awk 'NR==2{print $4, $2}'"); + if (o) { if (sscanf(o, "%ld%ld", &dfree, &dtot) < 2) dtot = 0; free(o); } + if (dtot > 0) snprintf(info[n++], sizeof info[0], "板载: %ld/%ld MB", dfree / 1024, dtot / 1024); + else snprintf(info[n++], sizeof info[0], "板载: -"); + + /* TF 卡 /usr/data/mnt/sd_0:卡在(/proc/mounts 含该挂载点)则 df,否则「无卡」 */ + if (card_present()) { + long sfree = 0, stot = 0; + o = popen_read_tmo(600, "PATH=/bin:/sbin:/usr/bin:/usr/sbin df -k /usr/data/mnt/sd_0 2>/dev/null | awk 'NR==2{print $4, $2}'"); + if (o) { if (sscanf(o, "%ld%ld", &sfree, &stot) < 2) stot = 0; free(o); } + if (stot > 0) snprintf(info[n++], sizeof info[0], "TF卡: %ld/%ld MB", sfree / 1024, stot / 1024); + else snprintf(info[n++], sizeof info[0], "TF卡: -"); + } else { + snprintf(info[n++], sizeof info[0], "TF卡: 无卡"); + } + + /* 当前屏幕分辨率 + 状态栏高 */ + snprintf(info[n++], sizeof info[0], "屏幕: %dx%d 状态栏%dpx", fb_xres, fb_yres, (int)SB_BAR_H); + + /* WiFi:连上则 SSID(decode)+ 本机IP + 本机MAC;未连接显示「未连接」 */ + if (wlan_connected()) { + char ss[64]; net_wifi_ssid(ss, sizeof ss); + snprintf(info[n++], sizeof info[0], "WiFi: %s", ss[0] ? ss : "已连接"); + o = popen_read_tmo(1200, "PATH=/bin:/sbin:/usr/bin:/usr/sbin wpa_cli -i wlan0 status 2>/dev/null"); + char ip[32] = "", mac[24] = ""; + if (o) { + char *p = o; + while (p && *p) { + char *e = strchr(p, '\n'); if (e) *e = 0; + if (!strncmp(p, "ip_address=", 11)) snprintf(ip, sizeof ip, "%s", p + 11); + else if (!strncmp(p, "address=", 8)) snprintf(mac, sizeof mac, "%s", p + 8); + p = e ? e + 1 : NULL; + } + free(o); + } + if (ip[0]) snprintf(info[n++], sizeof info[0], "本机IP: %s", ip); + if (mac[0]) snprintf(info[n++], sizeof info[0], "本机MAC: %s", mac); + } else { + snprintf(info[n++], sizeof info[0], "WiFi: 未连接"); + } + + /* 蓝牙:hci_powered 决定开/关 */ + snprintf(info[n++], sizeof info[0], "蓝牙: %s", hci_powered() ? "开" : "关"); + + for (int i = 0; i < n && i < 12; i++) item[i] = info[i]; + s_dd_modal("关于本机", item, n, -1); /* cur=-1:只读展示,无预勾选 */ +} + /* ---- 控件绘制(MD3 形态;全部用主题角色色,无散落硬编码)---- */ static void s_draw_switch(int x, int y, int on, const meow_ui_theme_t *th) @@ -5571,7 +5676,7 @@ static void s_commit(const srow_t *r, int save_now) if (!meow_font_ensure()) logmsg("font.load_full: reload failed -> dotmatrix fallback"); else { - int lf = 0; meow_settings_get_bool("font.load_full", &lf); + int lf = 0; meow_settings_get_switch("font.load_full", &lf); logmsg("font.load_full: reloaded (load_full=%d)", lf); } meow_font_reload_multifont(); @@ -5649,7 +5754,7 @@ static void draw_settings_page(int sel, int scroll_off) } else if (r->ctrl == SC_SWITCH) { ui_draw(SET_CARD_X + 16, sy + (SROW_H - meow_font_line_height(22)) / 2, r->label, th->on_surface, 22); - int on = 0; meow_settings_get_bool(r->key, &on); + int on = 0; meow_settings_get_switch(r->key, &on); s_draw_switch(SET_CARD_X + SET_CARD_W - 16 - 48, sy + (SROW_H - 28) / 2, on, th); } else if (r->ctrl == SC_SLIDER) { int ly = sy + (SROW_H - meow_font_line_height(22)) / 2 - 6; /* 标题略上移,给下方滑条留位 */ @@ -6217,8 +6322,8 @@ static void run_settings_page(void) const srow_t *r = &SMENU[idx]; sel = idx; need_paint = 1; sel_changed = 1; if (r->ctrl == SC_SWITCH) { - int on = 0; meow_settings_get_bool(r->key, &on); - meow_settings_set_bool(r->key, !on); + int on = 0; meow_settings_get_switch(r->key, &on); + meow_settings_set_switch(r->key, !on); s_commit(r, 1); } else if (r->ctrl == SC_LIST) { /* M2.39 网络列表行:开下拉(重新解析)+ 重绘 + 排空本页 tfd @@ -6987,7 +7092,7 @@ static int launch_app(struct app *a) char fpng[400], fidx[400], fam[96]; int have_global; int mf_on = 0; - meow_settings_get_bool("display.multi_font", &mf_on); + meow_settings_get_switch("display.multi_font", &mf_on); snprintf(env_mf, sizeof env_mf, "MEOW_MULTI_FONT=%d", mf_on ? 1 : 0); envp[ne++] = env_mf; /* M2.5x:字库档 MEOW_FONT_TIER=<0|1|2> —— 按 app.json "fonts" 声明注入,并合并 diff --git a/patch_v2/meow_launcherd/meow_settings.c b/patch_v2/meow_launcherd/meow_settings.c index 67bace2..20026c7 100644 --- a/patch_v2/meow_launcherd/meow_settings.c +++ b/patch_v2/meow_launcherd/meow_settings.c @@ -501,6 +501,40 @@ int meow_settings_set_bool(const char *key, int v) return MEOW_OK; } +/* ---- 开关型(M2.5x)---- + * 开关 = SET_BOOL,或 SET_INT 且取值域恰为 {0,1}(如 display.multi_font / font.load_full, + * 见 SYSTEM_SETTINGS §1「int 0/1」)。实体设置页 SC_SWITCH 与字体逻辑用通用读写, + * 避免对 SET_INT 开关误用 get_bool/set_bool(类型不符必失败 → 点不动/恒 OFF/6 类行恒隐藏)。 */ +static int is_switch_like(meow_setting *s) +{ + if (!s) return 0; + if (s->type == SET_BOOL) return 1; + if (s->type == SET_INT && s->min == 0 && s->max == 1) return 1; + return 0; +} + +int meow_settings_get_switch(const char *key, int *out) +{ + meow_setting *s = find_set(key); + if (!s) return MEOW_ERR_NOENT; + if (!g_inited) return MEOW_ERR_NOTINIT; + if (!out) return MEOW_ERR_INVAL; + if (!is_switch_like(s)) return MEOW_ERR_INVAL; + if (s->type == SET_BOOL) *out = (s->cur[0] == '1'); + else *out = (atoi(s->cur) != 0); + return MEOW_OK; +} + +int meow_settings_set_switch(const char *key, int v) +{ + meow_setting *s = find_set(key); + if (!s) return MEOW_ERR_NOENT; + if (!g_inited) return MEOW_ERR_NOTINIT; + if (!is_switch_like(s)) return MEOW_ERR_INVAL; + if (s->type == SET_BOOL) return meow_settings_set_bool(key, v); + return meow_settings_set_int(key, v ? 1 : 0); /* SET_INT 0/1:写 0/1(clamp 到 {0,1}) */ +} + /* ---- listener ---- */ int meow_settings_add_listener(meow_settings_listener cb) { diff --git a/patch_v2/meow_launcherd/meow_settings.h b/patch_v2/meow_launcherd/meow_settings.h index 34aac2c..d7a2e89 100644 --- a/patch_v2/meow_launcherd/meow_settings.h +++ b/patch_v2/meow_launcherd/meow_settings.h @@ -81,6 +81,14 @@ int meow_settings_set_str (const char *key, const char *v);/* 长度截断 MEOW int meow_settings_set_enum(const char *key, int idx); /* 校验枚举合法,越界拒绝 */ int meow_settings_set_bool(const char *key, int v); +/* M2.5x:开关型键的通用读写。开关 = SET_BOOL,或 SET_INT 且取值域恰为 {0,1} + * (如 display.multi_font / font.load_full,二者按 SYSTEM_SETTINGS §1 用 int 0/1 存储)。 + * 实体设置页 SC_SWITCH 控件与字体逻辑统一走本对接口——若对这些 SET_INT 开关误用 + * get_bool/set_bool,类型不符(SET_BOOL 才接受)必返回 MEOW_ERR_INVAL,导致开关 + * 「点不动/恒 OFF/多字体 6 类行恒隐藏」。返回值语义同其它 get 系列 / set 系列。 */ +int meow_settings_get_switch(const char *key, int *out); /* 0/1;SET_BOOL 或 SET_INT 0/1 */ +int meow_settings_set_switch(const char *key, int v); /* 同上;写入 clamp 并广播 */ + /* ---- 变更通知(set 成功后广播 key 字符串)---- */ int meow_settings_add_listener(meow_settings_listener cb); int meow_settings_remove_listener(meow_settings_listener cb);