diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-10 11:00:16 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-10 11:50:34 +0200 |
commit | 5cb7a511dbdfc78a6fa5a7361df11420b08afb2b (patch) | |
tree | 8f65c9637aff82014ce02adb1d6420734464bcf1 /ui/iconprovider.go | |
parent | service: fix user logout (diff) | |
download | wireguard-windows-5cb7a511dbdfc78a6fa5a7361df11420b08afb2b.tar.xz wireguard-windows-5cb7a511dbdfc78a6fa5a7361df11420b08afb2b.zip |
ui: somewhat aggressively cache icons
Diffstat (limited to '')
-rw-r--r-- | ui/iconprovider.go | 92 |
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 } |