From 11e5c9b9159de2f8b6ba65b442039a4510bfcadc Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Tue, 3 Mar 2026 23:26:11 +0100 Subject: [PATCH] Set window icon on Admin Panel (title bar + taskbar) Embed the blue SyncWarden shield icon in the panel binary and set it as the window icon via Win32 SendMessage/WM_SETICON on startup. Uses the syncing (blue) variant as the status-independent panel icon. Co-Authored-By: Claude Opus 4.6 --- cmd/panel/icon_other.go | 7 ++++ cmd/panel/icon_windows.go | 85 ++++++++++++++++++++++++++++++++++++++ cmd/panel/main.go | 4 ++ cmd/panel/panel_icon.png | Bin 0 -> 9054 bytes 4 files changed, 96 insertions(+) create mode 100644 cmd/panel/icon_other.go create mode 100644 cmd/panel/icon_windows.go create mode 100644 cmd/panel/panel_icon.png diff --git a/cmd/panel/icon_other.go b/cmd/panel/icon_other.go new file mode 100644 index 0000000..ba64f8f --- /dev/null +++ b/cmd/panel/icon_other.go @@ -0,0 +1,7 @@ +//go:build !windows + +package main + +import "unsafe" + +func setWindowIcon(windowPtr unsafe.Pointer) {} diff --git a/cmd/panel/icon_windows.go b/cmd/panel/icon_windows.go new file mode 100644 index 0000000..869c643 --- /dev/null +++ b/cmd/panel/icon_windows.go @@ -0,0 +1,85 @@ +//go:build windows + +package main + +import ( + "bytes" + _ "embed" + "encoding/binary" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +//go:embed panel_icon.png +var panelIconPNG []byte + +func setWindowIcon(windowPtr unsafe.Pointer) { + hwnd := uintptr(windowPtr) + if hwnd == 0 { + return + } + + // Write a temp ICO file (Windows LoadImage needs a file path) + icoData := wrapPNG(panelIconPNG, 64, 64) + icoPath := filepath.Join(os.TempDir(), "syncwarden-panel.ico") + if err := os.WriteFile(icoPath, icoData, 0644); err != nil { + return + } + + user32 := syscall.NewLazyDLL("user32.dll") + loadImage := user32.NewProc("LoadImageW") + sendMessage := user32.NewProc("SendMessageW") + + pathW, _ := syscall.UTF16PtrFromString(icoPath) + + const ( + imageIcon = 1 + lrLoadFromFile = 0x0010 + wmSetIcon = 0x0080 + iconBig = 1 + iconSmall = 0 + ) + + hBig, _, _ := loadImage.Call(0, uintptr(unsafe.Pointer(pathW)), imageIcon, 32, 32, lrLoadFromFile) + if hBig != 0 { + sendMessage.Call(hwnd, wmSetIcon, iconBig, hBig) + } + + hSmall, _, _ := loadImage.Call(0, uintptr(unsafe.Pointer(pathW)), imageIcon, 16, 16, lrLoadFromFile) + if hSmall != 0 { + sendMessage.Call(hwnd, wmSetIcon, iconSmall, hSmall) + } +} + +func wrapPNG(pngData []byte, width, height int) []byte { + const headerSize = 6 + const entrySize = 16 + imageOffset := headerSize + entrySize + + buf := new(bytes.Buffer) + binary.Write(buf, binary.LittleEndian, uint16(0)) + binary.Write(buf, binary.LittleEndian, uint16(1)) + binary.Write(buf, binary.LittleEndian, uint16(1)) + + w := byte(width) + if width >= 256 { + w = 0 + } + h := byte(height) + if height >= 256 { + h = 0 + } + buf.WriteByte(w) + buf.WriteByte(h) + buf.WriteByte(0) + buf.WriteByte(0) + binary.Write(buf, binary.LittleEndian, uint16(1)) + binary.Write(buf, binary.LittleEndian, uint16(32)) + binary.Write(buf, binary.LittleEndian, uint32(len(pngData))) + binary.Write(buf, binary.LittleEndian, uint32(imageOffset)) + + buf.Write(pngData) + return buf.Bytes() +} diff --git a/cmd/panel/main.go b/cmd/panel/main.go index ef774cf..66d5eb1 100644 --- a/cmd/panel/main.go +++ b/cmd/panel/main.go @@ -19,6 +19,10 @@ func main() { w.SetTitle("SyncWarden — Admin Panel") w.SetSize(1024, 768, webview.HintNone) + + // Set window icon (title bar + taskbar) + setWindowIcon(w.Window()) + w.Navigate(*addr) w.Run() } diff --git a/cmd/panel/panel_icon.png b/cmd/panel/panel_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..85e61b1079cccc0f07074374d843632f7cad3b52 GIT binary patch literal 9054 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
b^oJ3ZqDH&# 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 Qr~m)}07*qoM6N<$f&`(n0ssI2 literal 0 HcmV?d00001