5860ef72df
leo:右鍵仍然沒用。這次先做**最小重現**才動手,結果推翻了我前兩次的判斷。 ## 真兇(實測,非推論) systray.go:83 的 setInternalLoop(true) **只在 systray.Run() 裡呼叫**; RunWithExternalLoop 沒有 ⇒ registerSystray() 第一行就 `if (!internalLoop) return;` ⇒ **delegate 從沒建立** ⇒ onReady 不會被呼叫、enable_on_click 不會執行、左右鍵事件根本不存在。 最小重現(scratchpad/traytest):RunWithExternalLoop + onReady 印 "READY" ⇒ **READY 從未印出**。托盤自始至終沒被建立過。 (左鍵之所以「第一次能開」是 Wails 自己開的窗,與托盤無關。) ## 正解:原生 NSStatusItem(tray_darwin.m + tray_darwin.go) 左鍵=開視窗;右鍵=暫時掛選單、performClick、再拿掉(不常駐 setMenu:, 否則按鈕 action 不會被呼叫、左鍵也會變成彈選單——與 systray 那個坑同源)。 ## 過程中踩到、也寫進閘的三個坑 ① dispatch_async(main_queue) **無效**:Wails 佔住主執行緒後不跑標準 run loop, 排進去的 block 永遠不執行(log 只印到 "dispatching…")⇒ 改 performSelectorOnMainThread ② NSStatusBar 需要 NSApp 已初始化:在 wails.Run() 之前呼叫 ⇒ 靜默失敗、icon 不出現 ③ 🔴 **我一度對著 `go build` 產的 stub 除錯**——沒帶 Wails build tags 的執行檔 一跑就印 "Wails applications will not build without the correct build tags" 並退出, 我卻以為是「托盤沒建起來」,白繞一圈。**驗 Wails App 一定要用 wails build 的產物。** ## 實測證據(AppleScript 從 UI 層查,最貼近使用者看到的) menu bar 數=2,status item 數=1 ← 選單列 icon 真的存在 collector 同步啟動、正常結束無孤兒 三支機械閘全過(閘也改成驗原生實作:不可 dispatch_async/必須 performSelectorOnMainThread/不可常駐 setMenu/不可再依賴 energye/systray)。 ⚠️ 仍未驗:左右鍵的**實際點擊行為**要 leo 手動點。
41 lines
951 B
Go
41 lines
951 B
Go
//go:build darwin
|
||
|
||
package main
|
||
|
||
/*
|
||
#cgo CFLAGS: -x objective-c
|
||
#cgo LDFLAGS: -framework Cocoa
|
||
#include <stdlib.h>
|
||
void createTray(const char *iconBytes, int iconLen, const char *tooltip, const char *quitTitle);
|
||
*/
|
||
import "C"
|
||
import "unsafe"
|
||
|
||
// trayApp 讓 C 回呼找得到 App(cgo 匯出函式不能帶 Go 參數)。
|
||
var trayApp *App
|
||
|
||
//export trayOnLeftClick
|
||
func trayOnLeftClick() {
|
||
if trayApp != nil {
|
||
trayApp.ShowWindow()
|
||
}
|
||
}
|
||
|
||
//export trayOnQuit
|
||
func trayOnQuit() {
|
||
if trayApp != nil {
|
||
trayApp.Quit()
|
||
}
|
||
}
|
||
|
||
// setupTray 建立選單列 icon。
|
||
// ⚠️ **必須在主執行緒呼叫**(NSStatusItem 內部會 new NSWindow)。
|
||
func setupTray(app *App) {
|
||
trayApp = app
|
||
tip := C.CString("Arcrun — 你的知識庫同步小幫手")
|
||
quit := C.CString("結束 Arcrun")
|
||
defer C.free(unsafe.Pointer(tip))
|
||
defer C.free(unsafe.Pointer(quit))
|
||
C.createTray((*C.char)(unsafe.Pointer(&trayIcon[0])), C.int(len(trayIcon)), tip, quit)
|
||
}
|