fix(statusbar): 全屏状态栏收合 — 上移出屏+停渲染+热区28保留+左缘指示条屏顶(agent-146)

- 根因: launcher/App 双进程各持SDK态, hello运行时全屏(set_fullscreen+set_collapsed)只改App进程, launcher仍expanded→画28px+时序闪
- SDK render_off(yoff): 顶条内容整体上移+裁顶, 收合 statusbar_collapsed_render 只画4px提示线(无时钟/图标/值)
- 热区保留: meow_ui_statusbar_hotzone() 收合时返回28(渲染与热区事件分离)→收合仍可下滑
- 左缘指示条: meow_ui_swipe_hint y=statusbar_height()=4 平移屏顶
- 模式感知: /tmp/meowapp_sbar(App进程SDK写0展开/1收合/2隐藏, launcher读); launch_app循环新变立即叠(消半秒闪)+过渡期~20ms高频刷(动画平滑)
- meow_ui.a=ed0267a9 launcher=7ea80408 hello=1a3ff13e 0warning; 宿主 test_sb_collapse/test_sb_statusbar ALL PASS
- 遗留: 全屏上收观感/收合下App前台打开通知中心归④M3(meow_ui_sys_notif_pull桩)
This commit is contained in:
MeowOS committed 2026-08-30 20:18:13 +08:00
1 parent 03962fffac
commit 1481ae00c4
8 files changed
+183 -33

No files matched your search

Binary file not shown.
+86 -13
View File
@@ -3035,6 +3035,7 @@ static void meow_sys_light(void)
#define SB_BAR_Y 0
#define SB_BAR_H 28 /* rows 0..27;分隔线在 y=28 不在此(40→28,用户定) */
#define SB_FONT 20 /* 状态栏字体 28→20(28px 栏放不下 28 号;垂直居中锚点见 sb_text_y) */
#define MEOW_SBAR_ANIM_MS 200 /* App 前台全屏/收合切换的顶条「上移出屏」过渡时长(ms,agent-146) */
#if 0 /* [RETIRED Stage-One] 旧自绘状态栏的时钟/右侧包围盒变量,仅供 sb_redraw 用,现已退役 */
static int g_sb_clock_x, g_sb_clock_y, g_sb_clock_w, g_sb_clock_h;
static int g_sb_right_x, g_sb_right_y, g_sb_right_w, g_sb_right_h;
@@ -8884,14 +8885,52 @@ static void meow_write_app_state(int immersive)
/* ---- App 前台状态栏叠加(「同一个状态栏」闭环,FRAMEWORK_DESIGN §10.2 / MEOW_APP_SDK §3.1)----
* App 前台时状态栏由 launcher(系统进程)作为**常驻**系统叠加层绘制顶条 28px(App 进程不渲染、
* 只 inset,§6.1 ③)。本函数由 launch_app 的 waitpid 循环定时调用:
* 1) 刷新权威数据 meow_sys_light()(电池/WiFi/音量/蓝牙)+ 喂 SDK → 唯一数据源(主界面与 App 一致);
* 2) 标脏顶条 + meow_ui_flush() → SDK present() 在上屏前把全局状态栏画进 back_buf 顶部 MUI_SBAR_H
* 行并原子 blit 到 buffer0(仅顶条);
* 3) 只 blit 顶条(不碰 y>=28 的 App 内容)→ 不覆盖 App、不 SIGSTOP App(App 继续播/响应)。
* 与通知中心/电源菜单(SIGSTOP + 全屏叠画)的差异:状态栏常驻、非模态、只碰顶条。 */
* 1) 读 App 顶条模式(/tmp/meowapp_sbar,App 进程 SDK 写)→ 感知全屏/收合态(agent-146);
* 2) 刷新权威数据 meow_sys_light()(电池/WiFi/音量/蓝牙)+ 喂 SDK → 唯一数据源(主界面与 App 一致);
* 3) 标脏「当前可见条高」+ meow_ui_flush() → SDK present() 画顶条/收合提示线并原子 blit(仅可见条高);
* 4) 只 blit 可见条高(收合时其余行=App 内容,保留)→ 不覆盖 App、不 SIGSTOP App(App 继续播/响应)。
* 与通知中心/电源菜单(SIGSTOP + 全屏叠画)的差异:状态栏常驻、非模态、只碰顶条。
* 全屏/收合:见「全屏状态栏收合(agent-146)」——收合只叠提示线(无时钟/图标/值),热区事件与渲染分离。 */
/* App 前台顶条模式文件(App 进程 SDK 写,launcher 读;与 /tmp/meowapp_state 语义独立)。
* 值:'0'=展开 28px 整条;'1'=收合(提示线);'2'=隐藏(沉浸 inset0)。 */
#define MEOW_SBAR_MODE_FILE "/tmp/meowapp_sbar"
/* 上次读到的 App 顶条模式(用于在 launch_app waitpid 循环里判「模式新变 → 立即叠一次」)。
* 高整文件作用域;每次启动 App 前重置为 -1(强制首帧同步一次)。 */
static int g_sb_mode_last = -1;
/* 读 App 顶条模式:0=展开 1=收合 2=隐藏;-1=无文件/读取失败(按展开处理,默认安全)。 */
static int app_sbar_mode_read(void)
{
int fd = open(MEOW_SBAR_MODE_FILE, O_RDONLY);
if (fd < 0) return -1;
char ch[8];
int n = read(fd, ch, sizeof ch - 1);
close(fd);
if (n <= 0) return -1;
if (ch[0] == '1') return 1;
if (ch[0] == '2') return 2;
return 0;
}
static void app_overlay_statusbar(void)
{
if (!back_buf_ok || !fb) return; /* 无 SDK back_buf(直写模式):无法叠加,跳过 */
int mode = app_sbar_mode_read();
if (mode == 2) { /* 全屏隐藏(immersive,inset=0):launcher 不叠顶条 */
meow_ui_set_fullscreen(1);
meow_ui_statusbar_set_collapsed(0);
return; /* 无内容可叠:交 App 全屏(其 present inset0 已写满屏) */
}
if (mode == 1) { /* 收合:SDK 切收合(上移过渡 + 提示线),无时钟/图标/值 */
meow_ui_set_fullscreen(0);
meow_ui_statusbar_set_collapsed(1);
meow_ui_statusbar_animate(MEOW_SBAR_ANIM_MS); /* 平滑上移/恢复过渡时长 */
} else { /* 展开(默认/无文件):整条 28px */
meow_ui_set_fullscreen(0);
meow_ui_statusbar_set_collapsed(0);
}
meow_sys_light(); /* 刷新 g_sys(电池/WiFi/音量/蓝牙;唯一权威源) */
meow_theme_reload(); /* SDK 状态栏主题随 launcher 换肤(重读 settings) */
meow_ui_feed f;
@@ -8905,8 +8944,14 @@ static void app_overlay_statusbar(void)
f.vol = g_sys.vol;
f.brightness = g_sys.brightness;
meow_ui_sys_feed(&f); /* 喂权威快照 + 置 force(顶条必重画) */
meow_dirty_add(0, 0, fb_xres, SB_BAR_H); /* 标脏顶条 → present() 时 SDK 重画状态栏(仅顶条) */
meow_ui_flush(); /* SDK present:vsync + 原子 blit 脏区(仅顶条) */
/* 撤销 set_collapsed 可能引发的「整帧脏」:launcher 在 App 上叠加只应 blit 顶条,绝不能整帧 blit
* (否则会把自身 back_buf 的 stale 菜单内容盖到 App 内容上,属灾难性回归——agent-146)。
* 随后只标「心跳」脏(顶条左上角 1px)唤醒 present();实际 blit 区由 SDK 渲染在 present() 内标脏决定
* (render_off 画 [0, 28-off) 可见条高 / 收合稳定画 [0,4) 提示线 / 展开画 [0,28) 整条),故上移时
* 只 blit 可见条高、其余行保留 App 内容 —— 平滑上收无残留、不黑框。 */
meow_gfx_dirty_reset();
meow_dirty_add(0, SB_BAR_Y, 1, 1);
meow_ui_flush(); /* SDK present:vsync + 原子 blit(区随渲染标脏) */
}
static int launch_app(struct app *a);
@@ -9127,8 +9172,11 @@ static int launch_app(struct app *a)
memcpy(save_keys, kp_keys.cur, sizeof save_keys);
/* 「同一个状态栏」闭环:App 前台状态栏由 launcher 常驻叠加(顶条 28px、非模态、不 SIGSTOP App)。
* 立即叠一次(App 首帧前顶条就有),其后每 ~1s 重画(时钟每秒变 + 数据新鲜)。app 级
* fullscreen 声明(沉浸,整条隐藏)时不叠。 */
* fullscreen 声明(沉浸,整条隐藏)时不叠。agent-146:读 App 顶条模式(meowapp_sbar),App 运行时
* 全屏/收合 → launcher 顶条切收合提示线(无时钟/图标/值),热区事件与渲染分离。 */
unsigned long long last_sb_overlay_ms = 0;
g_sb_mode_last = -1; /* 强制首帧同步(进入新 App 会话清零,避免沿用上一 App 的缓存态) */
unlink(MEOW_SBAR_MODE_FILE); /* 清可能残留的上一 App 顶条模式(崩溃/被杀未清),防新 App 误收合 */
if (!a->fullscreen) app_overlay_statusbar();
/* M2.24:清上一次会话可能残留的电源菜单标记,只认本次新 watchdog 生成的请求。 */
unlink(POWMENU_MARKER);
@@ -9226,12 +9274,29 @@ static int launch_app(struct app *a)
app_last_input = now_ms(); /* M2.17:菜单交互即输入,重置应用会话自动息屏计时 */
if (pm_ret != 0) break; /* 关机/重启/回HibyOS:系统通常已 reboot,防御性退出 */
}
/* 「同一个状态栏」闭环:常驻顶条每 ~1s 重画(时钟/数据新鲜;仅标脏顶条上屏,不碰 App 内容)。 */
if (!a->fullscreen && now_ms() - last_sb_overlay_ms >= 1000) {
last_sb_overlay_ms = now_ms();
app_overlay_statusbar();
/* 「同一个状态栏」闭环:常驻顶条叠加(agent-146 全屏收合接入)。
* - 展开态每 ~1s 慢刷(时钟/数据新鲜;仅标脏顶条上屏,不碰 App 内容);
* - App 顶条模式新变(进入/退出全屏收合)→ 立即叠一次(即时切换,消除「半秒闪」);
* - 收合/恢复过渡期(meow_ui_statusbar_animating)每 ~30ms 快刷驱动平滑上移出屏。 */
if (!a->fullscreen) {
unsigned long long now2 = now_ms();
int m = app_sbar_mode_read();
if (m != g_sb_mode_last) {
g_sb_mode_last = m;
last_sb_overlay_ms = now2;
app_overlay_statusbar();
} else if (meow_ui_statusbar_animating()) {
if (now2 - last_sb_overlay_ms >= 30) {
last_sb_overlay_ms = now2;
app_overlay_statusbar();
}
} else if (now2 - last_sb_overlay_ms >= 1000) {
last_sb_overlay_ms = now2;
app_overlay_statusbar();
}
}
usleep(100000);
/* 顶条收合/恢复过渡期把循环睡得短些(~20ms),驱动更平滑的上移出屏;稳定后回 100ms。 */
usleep(meow_ui_statusbar_animating() ? 20000 : 100000);
}
if (wpid > 0) {
/* reap the watchdog: SIGTERM then wait up to 2s (it exits when the
@@ -9244,6 +9309,14 @@ static int launch_app(struct app *a)
}
}
meow_write_app_state(-1); /* GESTURE_BACK §2.4:应用退出,清 immersive 状态 */
/* agent-146:App 退出 → 清顶条模式文件 + 复位 launcher SDK 收合/全屏态(菜单恢复整条 28px)。
* 模式文件由 App 进程 SDK 写;此处 launcher 在退出时清理,防下一 App 读到残留 '1'(收合) 误收合。 */
unlink(MEOW_SBAR_MODE_FILE);
g_sb_mode_last = -1;
meow_ui_statusbar_set_collapsed(0);
meow_ui_statusbar_animate(0); /* 回菜单:顶条恢复整条,瞬切(不做上移动画) */
meow_ui_set_fullscreen(0);
meow_dirty_add(0, SB_BAR_Y, fb_xres, SB_BAR_H); /* 菜单状态栏需重画整条(恢复展开) */
/* M2.24:应用运行期音量由 watchdog 写(settings.conf 同源)。返回菜单前 re-load,
* 让菜单音量/状态栏与真实 DAC 一致(watchdog 可能已改)。 */
settings_load();