aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/iconprovider.go
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-05-10 11:00:16 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-10 11:50:34 +0200
commit0ba51d151035eb80512d20eb5285ff84f1b4deab (patch)
tree8f65c9637aff82014ce02adb1d6420734464bcf1 /ui/iconprovider.go
parentservice: fix user logout (diff)
downloadwireguard-windows-0ba51d151035eb80512d20eb5285ff84f1b4deab.tar.xz
wireguard-windows-0ba51d151035eb80512d20eb5285ff84f1b4deab.zip
ui: somewhat aggressively cache icons
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'ui/iconprovider.go')
-rw-r--r--ui/iconprovider.go92
1 files changed, 71 insertions, 21 deletions
diff --git a/ui/iconprovider.go b/ui/iconprovider.go
index e2647939..9f6cc433 100644
--- a/ui/iconprovider.go
+++ b/ui/iconprovider.go
@@ -12,29 +12,47 @@ import (
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/service"
"path"
+ "syscall"
)
-func iconWithOverlayForState(state service.TunnelState, size int) (*walk.Icon, error) {
- wireguardIcon, err := walk.NewIconFromResourceWithSize("$wireguard.ico", walk.Size{size, size})
+type widthAndState struct {
+ width int
+ state service.TunnelState
+}
+
+type widthAndDllIdx struct {
+ width int
+ idx int32
+ dll string
+}
+
+var cachedOverlayIconsForWidthAndState = make(map[widthAndState]*walk.Icon)
+
+func iconWithOverlayForState(state service.TunnelState, size int) (icon *walk.Icon, err error) {
+ icon = cachedOverlayIconsForWidthAndState[widthAndState{size, state}]
+ if icon != nil {
+ return
+ }
+ wireguardIcon, err := loadLogoIcon(size)
if err != nil {
- return nil, err
+ return
}
- defer wireguardIcon.Dispose()
iconSize := wireguardIcon.Size()
bmp, err := walk.NewBitmapWithTransparentPixels(iconSize)
if err != nil {
- return nil, err
+ return
}
defer bmp.Dispose()
canvas, err := walk.NewCanvasFromImage(bmp)
if err != nil {
- return nil, err
+ return
}
defer canvas.Dispose()
- if err := canvas.DrawImage(wireguardIcon, walk.Point{}); err != nil {
- return nil, err
+ err = canvas.DrawImage(wireguardIcon, walk.Point{})
+ if err != nil {
+ return
}
w := int(float64(iconSize.Width) * 0.65)
@@ -42,44 +60,76 @@ func iconWithOverlayForState(state service.TunnelState, size int) (*walk.Icon, e
bounds := walk.Rectangle{iconSize.Width - w, iconSize.Height - h, w, h}
overlayIcon, err := iconForState(state, bounds.Width)
if err != nil {
- return nil, err
+ return
}
defer overlayIcon.Dispose()
- if err := canvas.DrawImageStretched(overlayIcon, bounds); err != nil {
- return nil, err
+ err = canvas.DrawImageStretched(overlayIcon, bounds)
+ if err != nil {
+ return
}
canvas.Dispose()
- icon, err := walk.NewIconFromBitmap(bmp)
- if err != nil {
- return nil, err
+ icon, err = walk.NewIconFromBitmap(bmp)
+ if err == nil {
+ cachedOverlayIconsForWidthAndState[widthAndState{size, state}] = icon
}
- return icon, nil
+ return
}
+var cachedIconsForWidthAndState = make(map[widthAndState]*walk.Icon)
+
func iconForState(state service.TunnelState, size int) (icon *walk.Icon, err error) {
+ icon = cachedIconsForWidthAndState[widthAndState{size, state}]
+ if icon != nil {
+ return
+ }
switch state {
case service.TunnelStarted:
icon, err = loadSystemIcon("imageres", 101, size)
-
case service.TunnelStopped:
icon, err = walk.NewIconFromResourceWithSize("dot-gray.ico", walk.Size{size, size}) //TODO: replace with real icon
-
default:
icon, err = loadSystemIcon("shell32", 238, size) //TODO: this doesn't look that great overlayed on the app icon
}
+ if err == nil {
+ cachedIconsForWidthAndState[widthAndState{size, state}] = icon
+ }
return
}
-func loadSystemIcon(dll string, index int32, size int) (*walk.Icon, error) {
+var cachedSystemIconsForWidthAndDllIdx = make(map[widthAndDllIdx]*walk.Icon)
+
+func loadSystemIcon(dll string, index int32, size int) (icon *walk.Icon, err error) {
+ icon = cachedSystemIconsForWidthAndDllIdx[widthAndDllIdx{size, index, dll}]
+ if icon != nil {
+ return
+ }
system32, err := windows.GetSystemDirectory()
if err != nil {
- return nil, err
+ return
}
var hicon win.HICON
ret := win.SHDefExtractIcon(windows.StringToUTF16Ptr(path.Join(system32, dll+".dll")), index, 0, &hicon, nil, uint32(size))
if ret != 0 {
- return nil, fmt.Errorf("Unable to find icon %d of %s due to error %d", index, dll, ret)
+ return nil, fmt.Errorf("Unable to find icon %d of %s: %v", index, dll, syscall.Errno(ret))
+ }
+ icon, err = walk.NewIconFromHICON(hicon)
+ if err == nil {
+ cachedSystemIconsForWidthAndDllIdx[widthAndDllIdx{size, index, dll}] = icon
+ }
+ return
+}
+
+var cachedLogoIconsForWidth = make(map[int]*walk.Icon)
+
+func loadLogoIcon(size int) (icon *walk.Icon, err error) {
+ icon = cachedLogoIconsForWidth[size]
+ if icon != nil {
+ return
+ }
+ icon, err = walk.NewIconFromResourceWithSize("$wireguard.ico", walk.Size{size, size})
+ if err == nil {
+ cachedLogoIconsForWidth[size] = icon
}
- return walk.NewIconFromHICON(hicon)
+ return
}