Files
MeowOS-For-R3P2/patch_v2/sdk/test_meow_ui_view_event.c
T
AskaEth 38be5e78bc fix(sdk): 时钟 ABI 根因修复 — meow_ui_time 按 o32 time32 取时并链接期接管
真机 meow_ui_time_ms() 返回「低 32=秒×1000、高 32 随机」的根因不是 SDK 写法,
而是 zig 0.17 自带 musl 在 mipsel 上的 time64 ABI 自相矛盾:
- zig 头(mips-linux-musl/bits/alltypes.h)无条件 64 位 time_t、struct timespec 16 字节;
- zig 的 clang 给 32 位 mips 预定义 __ILP32__,musl 的 time64 回退分支
  `#if defined(SYS_x_time64) && !defined(__ILP32__)`(本意只排除 x32)被编译掉;
- 于是 libc 的 __clock_gettime64 实为 o32 time32 实现(SYS_clock_gettime 4263),
  只写 8 字节 {int32 sec; int32 nsec},与头的 16 字节布局错配。

修复(patch_v2/sdk/meow_ui_time.c):
- meow_ui_time_ms() 直接按内核 o32 ABI 取 8 字节 time32,再升 64 位毫秒;
- 同 TU 强定义 __clock_gettime/__clock_gettime64(归档先于 -lc,链接期接管,
  time()/gettimeofday()/pthread 定时等待的内部取时随之修正);
- 同源缺陷一并修:__nanosleep_time64/__clock_nanosleep(_time64) 转换 time32 后重发
  (修复前 usleep(16000) 等亚秒睡眠立即返回、变忙等空转);
- gfx/sys/input/cachegov 四处重复 now_ms 收敛到 meow_ui_time_ms;
- build_sdk.sh OBJS 增加 meow_ui_time;新增 test_meow_time 宿主单测、
  tools/clock_abi_probe.c 探针、CLOCK_ABI.md 根因/验证/影响面文档;
- 26 个宿主测试的编译注释补 meow_ui_time.c(cachegov 测试补时钟源)。

验证:宿主单测 PASS;anim(32)/view_event 宿主用例全过;build_sdk_host.sh --verify
76 成员全 MIPS32r2、0 warning;探针链接后无 libc cgt_init/__vdsosym,
__time64/__timedwait_cp 的取时指向本 TU,睡眠走 4166/4265 且用本地 8 字节结构。
2026-11-05 13:41:52 +08:00

153 lines
8.0 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.
/* test_meow_ui_view_event.c — M7.0a 缺口#7 宿主验证:meow_view 事件接线 + 递归 enter/leave。
*
* A 部(无 run 循环,直调 meow_view_*):递归 enter/leave 顺序 + 运行期动态挂子视图立即进入
* (view.c meow_view_add_child 修正)+ 子>父 on_event 路由。
* B 部(经 meow_ui_run 主循环):把语义事件注入队列 → run 循环先经 meow_view_dispatch_event
* 路由,命中的事件不再落 App on_* 回调(on_tap/on_key/on_swipe/long_press 零触发),未命中
* 的事件照常回落 App 回调——验证「接线于 meow_ui_run、于 §6.4 分流之上」。
*
* 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global):
* gcc -Wall -Wextra -o test_meow_ui_view_event test_meow_ui_view_event.c test_host_stub.c \
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
* 运行:./test_meow_ui_view_event
*/
#include "meow_ui.h"
#include "meow_ui_internal.h" /* MEOW_EV_* */
#include "meow_ui_view.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
static int g_fail = 0;
#define CHECK(cond, name) do { \
if (cond) printf(" PASS %s\n", name); \
else { printf(" FAIL %s\n", name); g_fail++; } } while (0)
/* ---------- A 部:递归 enter/leave 顺序 + 运行期动态挂子 ---------- */
static int g_trace[16]; static int g_trace_n = 0;
static void vtrace_enter(meow_view *v, void *ctx) { (void)ctx; g_trace[g_trace_n++] = v->id; }
static void vtrace_leave(meow_view *v, void *ctx) { (void)ctx; g_trace[g_trace_n++] = -v->id; }
static int g_child3_hits = 0;
static int vev_child3(meow_view *v, int ev, int a, int b, void *ctx)
{ (void)v;(void)ctx; if (ev == MEOW_EV_TAP && a == 33 && b == 33) { g_child3_hits++; return 1; } return 0; }
/* ---------- B 部:run 循环接线 ---------- */
static int g_tap_calls = 0, g_key_calls = 0, g_swipe_calls = 0, g_lp_calls = 0;
static void app_on_tap(int x, int y) { (void)x;(void)y; g_tap_calls++; }
static void app_on_key(int k, int d) { (void)k;(void)d; g_key_calls++; }
static void app_on_swipe(int dir, int dx, int dy) { (void)dir;(void)dx;(void)dy; g_swipe_calls++; }
static void app_lp(int x, int y) { (void)x;(void)y; g_lp_calls++; }
/* 父 view:消费 TAP@(10,10) 与 LONG_PRESS(任何)。 */
static int vev_parent(meow_view *v, int ev, int a, int b, void *ctx)
{ (void)v;(void)ctx;
if (ev == MEOW_EV_TAP && a == 10 && b == 10) return 1;
if (ev == MEOW_EV_LONG_PRESS) return 1;
return 0; }
/* 子 view:消费 KEY(任何)与 SWIPE_LEFT。 */
static int vev_child(meow_view *v, int ev, int a, int b, void *ctx)
{ (void)v;(void)b;(void)ctx;
if (ev == MEOW_EV_KEY) return 1;
if (ev == MEOW_EV_SWIPE && a == MEOW_SWIPE_LEFT) return 1;
return 0; }
static void *driver(void *arg)
{
(void)arg;
usleep(700000); /* 等 startup cooldown(500ms) 过后再发 */
meow_input_inject(MEOW_EV_KEY, MEOW_KEY_VOLUMEUP, 1); /* child 消费 → app_on_key 不触发 */
usleep(80000);
meow_input_inject(MEOW_EV_TAP, 10, 10); /* parent 消费 → app_on_tap 不触发 */
usleep(80000);
meow_input_inject(MEOW_EV_TAP, 50, 50); /* 无 view 命中 → 回落 app_on_tap */
usleep(80000);
meow_input_inject(MEOW_EV_SWIPE, MEOW_SWIPE_LEFT, 80); /* child 消费 → app_on_swipe 不触发 */
usleep(80000);
meow_input_inject(MEOW_EV_SWIPE, MEOW_SWIPE_RIGHT, 80); /* 无 view 命中 → 回落 app_on_swipe */
usleep(80000);
meow_input_inject(MEOW_EV_LONG_PRESS, 10, 10); /* parent 消费 → long_press 不触发 */
usleep(80000);
meow_ui_request_exit();
return NULL;
}
int main(void)
{
setenv("MEOW_UI_DUMP", "/tmp/view_event.ppm", 1);
meow_ui_opts o = { 480, 720 };
assert(meow_ui_init(&o) == 0);
/* ================= A 部:递归 enter/leave + 动态挂子 ================= */
printf("A: recursive enter/leave + runtime child add\n");
{
static const meow_view_hooks ph = { .on_enter = vtrace_enter, .on_leave = vtrace_leave,
.on_event = vev_parent };
static const meow_view_hooks ch = { .on_enter = vtrace_enter, .on_leave = vtrace_leave,
.on_event = vev_child };
static const meow_view_hooks c3 = { .on_enter = vtrace_enter, .on_leave = vtrace_leave,
.on_event = vev_child3 };
meow_view *pv = meow_view_create(1, MEOW_VIEW_ACTIVITY, &ph, NULL);
meow_view *cv = meow_view_create(2, MEOW_VIEW_CONTAINER, &ch, NULL);
assert(meow_view_add_child(pv, cv) == 0);
g_trace_n = 0;
meow_view_page_push(1); /* pv.enter → cv.enter */
CHECK(g_trace_n == 2 && g_trace[0] == 1 && g_trace[1] == 2, "push: parent.enter -> child.enter");
/* 运行期动态挂第三个子视图(父已 ENTERED)→ 立即进入(view.c 修正) */
meow_view *c3v = meow_view_create(3, MEOW_VIEW_CONTAINER, &c3, NULL);
g_trace_n = 0;
assert(meow_view_add_child(pv, c3v) == 0);
CHECK(g_trace_n == 1 && g_trace[0] == 3, "runtime add-child-while-entered -> child.enter fires");
/* 新挂子 view 参与事件路由:命中 (33,33) 被子 3 消费 */
g_child3_hits = 0;
CHECK(meow_view_dispatch_event(MEOW_EV_TAP, 33, 33) == 1 && g_child3_hits == 1,
"runtime-added child participates in dispatch");
/* 离开:子视图(挂载序 2 → 3)先后离开 → 父(递归离开,子->父) */
g_trace_n = 0;
meow_view_page_pop();
CHECK(g_trace_n == 3 && g_trace[0] == -2 && g_trace[1] == -3 && g_trace[2] == -1,
"pop: child2.leave -> child3.leave -> parent.leave");
meow_view_free(pv); /* 递归释放 2/3 */
printf(" PASS A: recursive order + dynamic child\n");
}
/* ================= B 部:meow_ui_run 接线(§6.4 之上) ================= */
printf("B: meow_view_dispatch_event wired into meow_ui_run\n");
{
static const meow_view_hooks ph = { .on_event = vev_parent };
static const meow_view_hooks ch = { .on_event = vev_child };
meow_view *pv = meow_view_create(20, MEOW_VIEW_ACTIVITY, &ph, NULL);
meow_view *cv = meow_view_create(21, MEOW_VIEW_CONTAINER, &ch, NULL);
assert(meow_view_add_child(pv, cv) == 0);
meow_view_page_push(20); /* 进入父+子(g_top_view=20) */
g_tap_calls = g_key_calls = g_swipe_calls = g_lp_calls = 0;
meow_ui_set_long_press_cb(app_lp);
meow_ui_events ev; memset(&ev, 0, sizeof ev);
ev.on_tap = app_on_tap; ev.on_key = app_on_key; ev.on_swipe = app_on_swipe;
pthread_t thd; pthread_create(&thd, NULL, driver, NULL);
meow_ui_run(&ev); /* 阻塞直到 driver 里 request_exit */
pthread_join(thd, NULL);
CHECK(g_key_calls == 0, "KEY consumed by child -> app_on_key NOT called");
CHECK(g_tap_calls == 1, "TAP(10,10) consumed by parent; TAP(50,50) fell through -> exactly 1 on_tap");
CHECK(g_swipe_calls == 1, "SWIPE_LEFT consumed by child; SWIPE_RIGHT fell through -> exactly 1 on_swipe");
CHECK(g_lp_calls == 0, "LONG_PRESS consumed by parent -> long_press cb NOT called");
printf(" PASS B: run loop routes through views, fallback preserved\n");
meow_view_page_pop();
meow_view_free(pv);
}
meow_ui_shutdown();
printf(g_fail ? "\nRESULT: %d FAIL(S)\n" : "\nRESULT: ALL PASS\n", g_fail);
return g_fail;
}