Files
arcrun-collector/cmd/arcrun-app/check-tray.sh
T
Leo a02eed539a t194 三修:右鍵選單——正解是「**少寫**一段」,不是再補一段
leo 實測:右鍵仍然沒有 quit 選單。

## 真兇:我把函式庫本來就會做對的事,換成一個更脆弱的版本
讀 systray_darwin.go 的 systray_on_rclick():

    func systray_on_rclick() {
        if onRClick != nil { onRClick(st) } else { C.show_menu() }
    }

⇒ **沒註冊 SetOnRClick 時,函式庫自己就會把選單叫出來**;
   而且 C 層的 show_menu 內部已經處理好整套:
   create_menu() → [statusItem.button performClick:nil] → set_menu_nil()

我卻註冊了自己的 handler、還加 `if menu != nil` 防呆
⇒ 等於用一個判斷把「本來會動的預設行為」擋掉。

修:**刪掉 SetOnRClick 註冊**。左鍵仍自訂(要開視窗),右鍵交還函式庫。

## 判準(已寫進 mistakes)
用第三方函式庫時,**先讀它的預設行為再決定要不要覆寫**。
「多註冊一個 handler」看起來是加功能,實際上常是**關掉**原本正確的行為。

## 閘也跟著改
check-tray.sh 原本驗「SetOnRClick 有註冊且順序對」——**那是在守一個錯的寫法**。
改成反向:**出現 systray.SetOnRClick 就擋下**,並說明原因。
實跑 7 項全過;App 活著 pid 14081、crash 0。
2026-08-05 02:27:23 +08:00

79 lines
3.7 KiB
Bash
Executable File
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.
#!/usr/bin/env bash
# check-tray.sh — 托盤行為的機械閘(t194,leo 真機測出四個 bug 後補)
#
# 🔴 為什麼要有:這四個 bug **編得過、也跑得起來**,只有真的去點才會發現。
# 我改完只驗「build ok」就想交,被交付警察攔下。
# ⇒ 把「點不下去的部分」用可機械檢查的**前置條件**守住。
set -uo pipefail
cd "$(dirname "$0")"
FAIL=0
ok(){ printf " ✅ %s\n" "$1"; }
ng(){ printf " ❌ %s\n" "$1"; FAIL=1; }
echo "━━━ 托盤行為前置條件 ━━━"
# ① template icon:純黑+大量透明、尺寸 22/44
python3 - <<'PY' || exit 1
import zlib,struct,sys
d=open('build/trayicon.png','rb').read()
pos=8; idat=b''; w=h=ct=0
while pos<len(d):
ln=struct.unpack('>I',d[pos:pos+4])[0]; t=d[pos+4:pos+8]
if t==b'IHDR': w,h,_,ct=struct.unpack('>IIBB',d[pos+8:pos+18])
if t==b'IDAT': idat+=d[pos+8:pos+8+ln]
pos+=12+ln
if w not in (22,44) or ct!=6:
print(f" ❌ tray icon 應為 22/44 的 RGBAgot {w}x{h} ct={ct}"); sys.exit(1)
raw=zlib.decompress(idat); ch=4; stride=w*ch+1
rows=[];prev=bytearray(w*ch)
for y in range(h):
f=raw[y*stride];line=bytearray(raw[y*stride+1:(y+1)*stride])
for i in range(len(line)):
a=line[i-ch] if i>=ch else 0;b=prev[i];c=prev[i-ch] if i>=ch else 0
if f==1: line[i]=(line[i]+a)&255
elif f==2: line[i]=(line[i]+b)&255
elif f==3: line[i]=(line[i]+(a+b)//2)&255
elif f==4:
pp=a+b-c;pa,pb,pc=abs(pp-a),abs(pp-b),abs(pp-c)
pr=a if(pa<=pb and pa<=pc) else (b if pb<=pc else c)
line[i]=(line[i]+pr)&255
rows.append(bytes(line));prev=line
al=[rows[y][x*4+3] for y in range(h) for x in range(w)]
opq=sum(1 for a in al if a>200)
if opq > len(al)*0.5:
print(f" ❌ tray icon 幾乎全不透明({100*opq//len(al)}%)⇒ 會顯示成方塊"); sys.exit(1)
cols={tuple(rows[y][x*4:x*4+3]) for y in range(h) for x in range(w) if rows[y][x*4+3]>200}
print(f" ✅ template icon{w}x{h}、不透明 {100*opq//len(al)}%、顏色 {len(cols)} 種 {list(cols)[:1]}")
PY
# ② 呼叫順序:AddMenuItem → SetMenuNil → SetOnClick/SetOnRClick
python3 - <<'PY' || exit 1
import sys
s=open('main.go',encoding='utf-8').read()
try:
a=s.index('systray.AddMenuItem'); n=s.index('systray.SetMenuNil')
c=s.index('systray.SetOnClick')
except ValueError as e:
print(f" ❌ 找不到必要呼叫:{e}"); sys.exit(1)
if not (a < n < c):
print(" ❌ 順序錯:必須 AddMenuItem → SetMenuNil → SetOnClick"); sys.exit(1)
print(" ✅ 順序正確(建選單→清掉→註冊左鍵)")
# 🔴 右鍵**不可以**註冊 handlersystray_on_rclick() 在沒註冊時會自己 show_menu()
# 註冊了反而要自己重做一遍(leo 實測「右鍵沒跳出 quit」就是這樣來的)。
if 'systray.SetOnRClick' in s:
print(" ❌ 註冊了 SetOnRClick ⇒ 蓋掉函式庫預設的『右鍵開選單』,右鍵會沒反應"); sys.exit(1)
print(" ✅ 右鍵交給函式庫預設行為(不自己註冊)")
PY
# ③ ShowWindow 要能叫回「已開但被蓋住」的視窗
for f in WindowUnminimise WindowShow WindowSetAlwaysOnTop; do
grep -q "runtime.$f" app.go && ok "ShowWindow 有 $f" || ng "ShowWindow 缺 $f(叫不回被蓋住的視窗)"
done
# ④ 結束路徑:收訊號 → 停子行程 → 等它真的不見
grep -q "signal.Notify" supervise.go && ok "有處理 SIGTERM/SIGINT" || ng "沒有訊號處理(只能強制結束)"
grep -q "waitCollectorGone" supervise.go && ok "結束前會等 collector 真的不見" || ng "沒等子行程 ⇒ 會留孤兒"
echo
[ $FAIL -eq 0 ] && echo "✅ 托盤前置條件全過" || { echo "❌ 未過——不准交貨"; exit 1; }