Set window icon on Admin Panel (title bar + taskbar)
All checks were successful
Release / build (push) Successful in 2m34s
All checks were successful
Release / build (push) Successful in 2m34s
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 <noreply@anthropic.com>
This commit is contained in:
7
cmd/panel/icon_other.go
Normal file
7
cmd/panel/icon_other.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func setWindowIcon(windowPtr unsafe.Pointer) {}
|
||||
85
cmd/panel/icon_windows.go
Normal file
85
cmd/panel/icon_windows.go
Normal file
@@ -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()
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
BIN
cmd/panel/panel_icon.png
Normal file
BIN
cmd/panel/panel_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
Reference in New Issue
Block a user