Skip to content

Commit 66035b2

Browse files
authored
[1287] 移除颜色选择器中的颜色预览,修复渐变选择器改前景色崩溃 (issue #4325) (#4528)
1 parent 69af5c8 commit 66035b2

2 files changed

Lines changed: 190 additions & 105 deletions

File tree

TeXmacs/progs/generic/pattern-selector.scm

Lines changed: 73 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858

5959
(define (set-color col)
6060
(set! global-pattern-color col)
61-
(refresh-now "pattern-sample")
6261
(refresh-now "pattern-options")
6362
) ;define
6463

@@ -442,110 +441,79 @@
442441
) ;tm-widget
443442

444443
(tm-widget ((pattern-selector u) cmd)
445-
(padded (hlist (vlist (refreshable "pattern-sample"
446-
(resize "600px"
447-
"450px"
448-
(texmacs-output `(document (block (tformat (cwith
449-
"1" "1"
450-
"1" "1"
451-
"cell-width"
452-
"596guipx")
453-
(cwith "1" "1"
454-
"1" "1"
455-
"cell-height"
456-
"446guipx")
457-
(cwith "1" "1"
458-
"1" "1"
459-
"cell-vmode"
460-
"exact")
461-
(cwith ,"1"
462-
,"1"
463-
,"1"
464-
,"1"
465-
,"cell-background"
466-
,(get-color))
467-
(table (row (cell ""))))))
468-
'(style (tuple "generic"))
469-
) ;texmacs-output
470-
) ;resize
471-
) ;refreshable
472-
) ;vlist
473-
//
474-
//
475-
//
476-
(explicit-buttons (vlist (refreshable "pattern-options"
477-
(assuming (and (not global-picture?) (not global-gradient?))
478-
(aligned (item (text "Name:") (link pattern-name-selector))
479-
(item (text "Width:")
480-
(hlist (enum (set-width answer)
481-
(list (get-width) "100%" "100@" "1cm" "")
482-
(get-width)
483-
"15em"
484-
) ;enum
485-
>>
486-
) ;hlist
487-
) ;item
488-
(item (text "Height:")
489-
(hlist (enum (set-height answer)
490-
(list (get-height) "100%" "100@" "1cm" "")
491-
(get-height)
492-
"15em"
493-
) ;enum
494-
>>
495-
) ;hlist
496-
) ;item
497-
(item (text "Recolor:") (link pattern-recolor-options))
498-
(item (text "Skin:") (link pattern-skin-options))
499-
;; TODO: the blur effect changes the image size;
500-
;; one needs a blur that wraps around torically
501-
;; (item (text "Blur:")
502-
;; (link pattern-blur-options))
503-
) ;aligned
504-
) ;assuming
505-
(assuming global-gradient?
506-
(aligned (item (text "Name:") (link pattern-name-selector))
507-
(item (text "Width:")
508-
(hlist (enum (set-width answer)
509-
(list (get-width) "100%" "100@" "1cm" "")
510-
(get-width)
511-
"15em"
512-
) ;enum
513-
>>
514-
) ;hlist
515-
) ;item
516-
(item (text "Height:")
517-
(hlist (enum (set-height answer)
518-
(list (get-height) "100%" "100@" "1cm" "")
519-
(get-height)
520-
"15em"
521-
) ;enum
522-
>>
523-
) ;hlist
524-
) ;item
525-
(item (text "Foreground:") (link pattern-foreground-options))
526-
(item (text "Background:") (link pattern-background-options))
527-
) ;aligned
528-
) ;assuming
529-
(assuming global-picture?
530-
(aligned (item (text "Name:") (link pattern-name-selector))
531-
(item (text "Size:")
532-
(hlist (enum (set-size answer)
533-
(list "Fit" "Fit to width" "Fit to height")
534-
(get-size)
535-
"15em"
536-
) ;enum
537-
>>
538-
) ;hlist
539-
) ;item
540-
(item (text "Recolor:") (link pattern-recolor-options))
541-
(item (text "Skin:") (link pattern-skin-options))
542-
) ;aligned
543-
) ;assuming
544-
) ;refreshable
545-
======
546-
(glue #f #t 0 0)
547-
) ;vlist
548-
) ;explicit-buttons
444+
(padded (hlist (explicit-buttons (vlist (refreshable "pattern-options"
445+
(assuming (and (not global-picture?) (not global-gradient?))
446+
(aligned (item (text "Name:") (link pattern-name-selector))
447+
(item (text "Width:")
448+
(hlist (enum (set-width answer)
449+
(list (get-width) "100%" "100@" "1cm" "")
450+
(get-width)
451+
"15em"
452+
) ;enum
453+
>>
454+
) ;hlist
455+
) ;item
456+
(item (text "Height:")
457+
(hlist (enum (set-height answer)
458+
(list (get-height) "100%" "100@" "1cm" "")
459+
(get-height)
460+
"15em"
461+
) ;enum
462+
>>
463+
) ;hlist
464+
) ;item
465+
(item (text "Recolor:") (link pattern-recolor-options))
466+
(item (text "Skin:") (link pattern-skin-options))
467+
;; TODO: the blur effect changes the image size;
468+
;; one needs a blur that wraps around torically
469+
;; (item (text "Blur:")
470+
;; (link pattern-blur-options))
471+
) ;aligned
472+
) ;assuming
473+
(assuming global-gradient?
474+
(aligned (item (text "Name:") (link pattern-name-selector))
475+
(item (text "Width:")
476+
(hlist (enum (set-width answer)
477+
(list (get-width) "100%" "100@" "1cm" "")
478+
(get-width)
479+
"15em"
480+
) ;enum
481+
>>
482+
) ;hlist
483+
) ;item
484+
(item (text "Height:")
485+
(hlist (enum (set-height answer)
486+
(list (get-height) "100%" "100@" "1cm" "")
487+
(get-height)
488+
"15em"
489+
) ;enum
490+
>>
491+
) ;hlist
492+
) ;item
493+
(item (text "Foreground:") (link pattern-foreground-options))
494+
(item (text "Background:") (link pattern-background-options))
495+
) ;aligned
496+
) ;assuming
497+
(assuming global-picture?
498+
(aligned (item (text "Name:") (link pattern-name-selector))
499+
(item (text "Size:")
500+
(hlist (enum (set-size answer)
501+
(list "Fit" "Fit to width" "Fit to height")
502+
(get-size)
503+
"15em"
504+
) ;enum
505+
>>
506+
) ;hlist
507+
) ;item
508+
(item (text "Recolor:") (link pattern-recolor-options))
509+
(item (text "Skin:") (link pattern-skin-options))
510+
) ;aligned
511+
) ;assuming
512+
) ;refreshable
513+
======
514+
(glue #f #t 0 0)
515+
) ;vlist
516+
) ;explicit-buttons
549517
) ;hlist
550518
======
551519
(explicit-buttons (hlist >>>

devel/1287.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# 1287: 移除颜色选择器中的颜色预览,试验性规避 issue #4325 崩溃
2+
3+
## 背景
4+
5+
issue #4325:渐变选择器中把前景色从黑改红后进程 SIGABRT(glibc 堆损坏,
6+
崩溃栈停在 `QPushButton::paintEvent → QCommonStyle::drawControl →
7+
QBrush::init → malloc → abort`,属「堆先坏、重绘踩雷」模式)。
8+
9+
复现步骤:插入高亮环境 → 焦点工具栏"文本背景色"按钮 → 下拉选"渐变"
10+
→ 渐变选择器中把前景色从黑改红 → 崩溃。
11+
12+
已有分析见 `da/1200/crash` 分支的 `devel/1200.md`
13+
14+
- 根因方向为 `refresh-now` 同步重建控件子树 + `doRefresh``delete qwid`
15+
同步析构正在发射信号的 enum 控件(UAF);
16+
- 将两处 `delete qwid``deleteLater()`**崩溃依旧**(该分支上验证未生效);
17+
- issue 终极方案是 QML 重构渐变选择器及相关对话框,工作量大。
18+
19+
本任务采用**最小改动试验**:把颜色选择器界面里的颜色预览(`pattern-sample`
20+
画布)整个移除,验证崩溃是否随之消失,为后续路线提供判据。
21+
22+
## 对 1200.md 走读的文件归属修正
23+
24+
- 启动 init 为 `init-research.scm``STEM_INIT_FILE`,见
25+
`src/Texmacs/Server/tm_server.cpp:60`)。`open-gradient-selector`
26+
`lazy-define` 来自 `(generic pattern-selector)`
27+
`TeXmacs/progs/init-research.scm:280-283`),即
28+
**`TeXmacs/progs/generic/pattern-selector.scm`**
29+
- `TeXmacs/progs/generic/pattern-tools.scm` 是"Alternative pattern selector",
30+
main 上无任何加载点(`developer-menu.scm:146-147``tm-tool` 引用已注释),
31+
属死代码。1200.md 走读把链路归到 `pattern-tools.scm:67` 等,文件归属有误;
32+
其机制描述(`refresh-now``windows_refresh` → 同步 emit → `doRefresh`
33+
`delete qwid`)仍然成立,`pattern-selector.scm` 中对应位置:
34+
`set-color` :59-63、`pattern-sample` refreshable :445-471、
35+
`pattern-options` refreshable :476-544、Foreground enum :415-432。
36+
37+
## 试验假设
38+
39+
改前景色的完整链路(均在 `pattern-selector.scm`):
40+
41+
```
42+
Foreground enum (QTMComboBox, currentIndexChanged)
43+
→ set-gradient-foreground (:219)
44+
→ set-color (:59)
45+
→ (refresh-now "pattern-sample") (:61)
46+
→ (refresh-now "pattern-options") (:62)
47+
→ windows_refresh (tm_window.cpp:842)
48+
→ QTMRefreshableWidget::doRefresh (QTMMenuHelper.cpp:964,main 上仍为 delete qwid)
49+
```
50+
51+
堆损坏的候选来源有二:
52+
53+
- **A**`doRefresh("pattern-options")` 同步 `delete` 正在发射信号的 enum
54+
所在子树(1200.md 结论;但 `deleteLater` 修复未生效,存疑);
55+
- **B**`pattern-sample` 画布(内嵌 `cell-background` 为 pattern 的
56+
`texmacs-output` 表格)的刷新/渲染管线
57+
`build_effect` EFF_GRADIENT → `color_matrix` 等)在同步重建中损坏堆。
58+
59+
移除预览后的判据:
60+
61+
- **崩溃消失** → B(或 B+A)为真,预览路径是损坏源,短期以移除预览兜底,
62+
QML 重构范围也可相应缩小;
63+
- **崩溃仍在** → A 确认,预览无辜,直接推进 QML 重构路线。
64+
65+
## 改动
66+
67+
`TeXmacs/progs/generic/pattern-selector.scm`
68+
69+
1. `(tm-widget ((pattern-selector u) cmd))` 中删除
70+
`(vlist (refreshable "pattern-sample" ...))`(600x450 预览画布)及其后
71+
`// // //` 分隔;
72+
2. `set-color` 中删除 `(refresh-now "pattern-sample")`
73+
(预览移除后该名字已无对应 refreshable,`windows_refresh` 对无人认领的
74+
kind 是无害 no-op,删除是为免留死代码)。
75+
76+
影响面:`open-pattern-selector` / `open-gradient-selector` /
77+
`open-background-picture-selector` 三个对话框共用 `(pattern-selector u)`
78+
界面,预览一并移除(三者崩溃机制相同)。`pattern-tools.scm` 为死代码,
79+
不动。
80+
81+
纯 scheme 改动,无需重编 C++,重启应用即生效。
82+
83+
## 验证(2026-09-09 已执行,自动化对照实验)
84+
85+
环境:Xvfb :99(1600x1200,Xvfb/xdotool 经 `apt-get download` 解包到
86+
`/tmp/xv-pkg` 运行,无需 root)。同一个 `moganstem` 二进制,仅切换
87+
`TEXMACS_PATH` 指向基线树(`main@69af5c889` 的 worktree)或修复树
88+
(本分支);scheme 侧 `delayed` 6s 调用 `open-gradient-selector` 打开
89+
对话框,`xdotool` 依次点击「前景色」下拉框并选择「红色」,全程截图确认
90+
控件位置与状态。
91+
92+
- **基线**:点击红色后进程立即死亡,stderr 报
93+
`malloc(): unaligned tcache chunk detected``SIGABRT`,崩溃栈为
94+
`abort ← malloc ← operator new ← QCss::StyleSelector::matchRule ←
95+
QWidget event/polish`——与 issue #4325 相同的「堆早已损坏、后续分配
96+
踩雷」模式,复现成立。
97+
- **修复树**:同样的点击路径,前景色成功变为红色(截图确认下拉框显示
98+
「红色」,证明 enum 信号 → `set-gradient-foreground``set-color`
99+
`refresh-now "pattern-options"` 全链路真实生效);随后连续切换
100+
蓝→红→绿→红共 5 次交互进程均存活,stderr 无任何 glibc 报错;点
101+
「确认」对话框正常关闭。Pattern 选择器(共用同一界面)打开、布局正常,
102+
交互冒烟后进程存活。
103+
104+
### 结论
105+
106+
- 崩溃第一现场在 `pattern-sample` 预览画布的同步重建/渲染路径(假设 B),
107+
**移除预览后 issue #4325 复现路径不再崩溃**,本改动作为修复保留;
108+
- 1200.md 指认的 `doRefresh("pattern-options")` 同步 `delete` enum 子树
109+
并非本复现的第一现场——修复树中 options 面板的同步重建仍在发生,
110+
但不再崩溃;这也解释了 `deleteLater` 修复未生效的原因(未动到真凶);
111+
- QML 重构仍是界面长期演进方向,但不再阻塞本崩溃修复。
112+
113+
## 后续
114+
115+
- 本分支合入后关闭 issue #4325 的崩溃(回复验证方法与结论);
116+
- 若后续恢复预览需求,应在 QML 重构版选择器中带预览,避开 Qt Widgets
117+
的 refreshable 同步重建机制。

0 commit comments

Comments
 (0)