图库: 修系统返回语义与打开册资源路径(M15)

- 返回手势:书库列表排除左缘 24px 系统返回带并清空残留拖拽态;library_go_up
  到 TF 根返回 0(app.c 退出 App),不再上溯系统目录;顶栏返回改为显式
  library_go_parent(访问放开,可越过 TF 根到 /)。lock 页继续自行消费返回。
- 打开册:缩略图源图改用预算解码(meow_img_load_file_dim,峰值数十 MB→~1MB);
  离开书库页停止后台探测/缩略图线程,避免与 open_book 争内存/FD;打开失败按
  errno 记日志,ENOMEM/EMFILE/ENFILE/EAGAIN/EINTR 自动重试一次;修 open_book
  自拷贝 snprintf 的未定义行为。
- 测试:test_browse_ui_host 增加 TF 根退出/顶栏上级/左缘不拖拽断言;新增
  test_open_book_host(封面图+含图子目录的父目录 → reader 打开的完整 UI 链路)。
This commit is contained in:
AskaEth committed 2026-11-05 13:03:20 +08:00
1 parent 5ac227b225
commit 3cbcaaaac1
7 files changed
+377 -13

No files matched your search

+29 -2
View File
@@ -42,6 +42,7 @@
#include "logic/reader/page_cache.h"
#include "logic/reader/nav.h"
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
@@ -79,6 +80,8 @@ static mr_book_handle g_handle; /* 目录册或档案册(M11 统一开册
static mr_book g_book;
static int g_count; /* 0=空册/不可读 */
static int g_open_err;
static uint64_t g_open_retry_at; /* 资源类打开失败(ENOMEM/EMFILE…)的自动重试时刻 */
static int g_open_retry_used; /* 1=本次进入已用过自动重试(避免反复重试) */
static int g_page; /* 翻页模式当前页;条漫模式=最近落位页 */
static int g_mode = MR_MODE_PAGED;
@@ -1158,6 +1161,7 @@ static void open_book_reset_state(void)
g_gen++; /* 作废旧册的异步结果 */
g_count = 0;
g_open_err = 0;
g_open_retry_at = 0;
g_page = 0;
g_woff = 0;
g_zoom_pct = 100;
@@ -1179,7 +1183,9 @@ static int open_book(const char *dir, int start_page, int mode)
{
if (!dir || !dir[0]) return 0;
open_book_reset_state();
snprintf(g_dir, sizeof g_dir, "%s", dir);
/* reader_page_enter 传入的 dir 就是 g_dir:自拷贝是 snprintf 的未定义行为,
* 其它调用(册间衔接)才需要复制。 */
if (dir != g_dir) snprintf(g_dir, sizeof g_dir, "%s", dir);
g_mode = mr_mode_valid(mode) ? mode : MR_MODE_PAGED;
int maxdim = g_vw > g_vh ? g_vw : g_vh;
@@ -1188,10 +1194,19 @@ static int open_book(const char *dir, int start_page, int mode)
int n = mr_book_open_auto(&g_book, &g_handle, g_dir, maxdim,
reader_load_page, reader_unload_page, NULL);
if (n < 0) {
int err = errno; /* opendir/malloc 失败原因(设备排障用) */
g_open_err = 1;
worker_start();
update_title();
meow_log(MEOW_LOG_WARN, "reader open failed: %s", g_dir);
meow_log(MEOW_LOG_WARN, "reader open failed: %s (errno=%d %s)", g_dir, err,
strerror(err));
/* 资源类失败(内存/FD 瞬时紧张)自动重试一次:library 页已在 on_leave 停止
* 后台解码,稍后内存回收后重开即可成功;权限/路径错误不重试。 */
if ((err == ENOMEM || err == EMFILE || err == ENFILE ||
err == EAGAIN || err == EINTR) && !g_open_retry_used) {
g_open_retry_used = 1;
g_open_retry_at = meow_ui_time_ms() + 200;
}
meow_ui_invalidate(0, 0, g_vw, g_vh);
return 0;
}
@@ -1602,6 +1617,15 @@ static void reader_tick(void)
int had_current = slot_find(current_page()) != NULL;
if (results_drain() && !had_current && slot_find(current_page()) && !g_dragging)
meow_ui_invalidate(0, 0, g_vw, g_vh);
/* 打开册的瞬时资源失败:稍后自动重试一次(进入本页时已停 library 后台解码)。 */
if (g_open_err && g_open_retry_at && now >= g_open_retry_at) {
g_open_retry_at = 0;
int mode = mr_cont_get_mode(g_dir, MR_MODE_PAGED);
int page = mr_cont_get_page(g_dir, 0);
open_book(g_dir, page, mode);
return;
}
if (g_fail_paint) {
g_fail_paint = 0;
if (!g_dragging) meow_ui_invalidate(0, 0, g_vw, g_vh);
@@ -1712,6 +1736,8 @@ static void reader_state_reset(void)
slots_free_all(); /* 静态槽位初值是 idx=0/img=NULL,先清空 */
g_count = 0;
g_open_err = 0;
g_open_retry_at = 0;
g_open_retry_used = 0;
g_page = 0;
g_mode = MR_MODE_PAGED;
g_fit = MR_FIT_WIDTH;
@@ -1869,6 +1895,7 @@ void mr_reader_open_dir(const char *path)
int mr_reader_ui_mode(void) { return g_mode; }
int mr_reader_ui_page(void) { return current_page(); }
int mr_reader_ui_count(void) { return g_count; }
int mr_reader_ui_open_err(void) { return g_open_err; }
int mr_reader_ui_jump_open(void) { return g_jump_open; }
int mr_reader_ui_jump_pending(void) { return mr_jump_active(&g_jump); }
#endif